From: Igor Mitsyanko Date: Thu, 10 May 2012 17:33:55 +0000 (+0400) Subject: tizen FGLES: make kfgles a static module X-Git-Tag: 2.2.1_release^2~83^2~7^2~61 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=eb9768891385506b26b197d5223f2f0806725f36;p=sdk%2Femulator%2Femulator-kernel.git tizen FGLES: make kfgles a static module Add config option to kernel configuration. Signed-off-by: Igor Mitsyanko --- diff --git a/arch/arm/configs/tizen_defconfig b/arch/arm/configs/tizen_defconfig index d2f194997f06..1dc2fd6bf271 100644 --- a/arch/arm/configs/tizen_defconfig +++ b/arch/arm/configs/tizen_defconfig @@ -1304,6 +1304,7 @@ CONFIG_MFD_WM8994=y # CONFIG_DRM=y CONFIG_DRM_KMS_HELPER=y +CONFIG_TIZEN_FGLES=y # CONFIG_DRM_LOAD_EDID_FIRMWARE is not set # diff --git a/arch/arm/mach-exynos/mach-tizen.c b/arch/arm/mach-exynos/mach-tizen.c index eb902996b660..9128a46f4cfb 100644 --- a/arch/arm/mach-exynos/mach-tizen.c +++ b/arch/arm/mach-exynos/mach-tizen.c @@ -270,6 +270,19 @@ static struct s3c_fb_platdata tizen_fb_pdata __initdata = { .setup_gpio = exynos4_fimd0_gpio_setup_24bpp, }; +#ifdef CONFIG_TIZEN_FGLES +static struct resource tizen_fgles_resources[] = { + [0] = DEFINE_RES_MEM(0xcf000000, 0x100000), +}; + +struct platform_device tizen_fgles_device = { + .name = "kfgles2", + .id = 0, + .resource = tizen_fgles_resources, + .num_resources = ARRAY_SIZE(tizen_fgles_resources), +}; +#endif /* CONFIG_VIRTIO_BLK */ + static void tizen_lcd_power_on(struct plat_lcd_data *pd, unsigned int power) { int gpio = EXYNOS4_GPE1(5); @@ -1348,6 +1361,9 @@ static struct platform_device *tizen_devices[] __initdata = { &tizen_gpio_keys, &tizen_lcd_device, &tizen_backlight_device, +#ifdef CONFIG_TIZEN_FGLES + &tizen_fgles_device, +#endif &max8903_fixed_reg_dev, &tizen_max8903_device, &cam_vt_cam15_fixed_rdev, diff --git a/drivers/gpu/Makefile b/drivers/gpu/Makefile index cc9277885dd0..61f6aaa661a3 100644 --- a/drivers/gpu/Makefile +++ b/drivers/gpu/Makefile @@ -1 +1 @@ -obj-y += drm/ vga/ stub/ +obj-y += drm/ vga/ stub/ fgles/ diff --git a/drivers/gpu/fgles/Kconfig b/drivers/gpu/fgles/Kconfig new file mode 100644 index 000000000000..333afbdc7e03 --- /dev/null +++ b/drivers/gpu/fgles/Kconfig @@ -0,0 +1,41 @@ +# +# Exynos Video configuration +# + +menuconfig TIZEN_FGLES + bool "Tizen fake GLES passthrough driver support" + depends on MACH_TIZEN && (DRM || FB) + default n + help + This module enables openGLES passthrough from emulated system + to hypervisor (for example, QEMU). Must be used together with fake + (hypervisor-aware) openGLES libraries. + +if TIZEN_FGLES + +config TIZEN_FGLES_FLOAT_ABI + int "FGLES floating point procedure call interface" + default 1 + help + Specify which floating point ABI calling standard to use: + 1 - arm_softfpu + 2 - arm_hardfpu + "1" is the right choice in majority of situations. + Note that the hard-float and soft-float ABIs are not link-compatible. + You must compile your entire program with the same ABI, and link with + a compatible set of libraries. + +config TIZEN_FGLES_MINOR + int "FGLES device node minor number" + default 128 + help + Specify minor number for /dev/kfgles2 device node. + Major number for kfgles2 is always 10 (MISC devices). + +config TIZEN_FGLES_DEBUG + bool "FGLES calls debug messages" + default no + help + Enable FGLES debug messages. + +endif # TIZEN_FGLES diff --git a/drivers/gpu/fgles/Makefile b/drivers/gpu/fgles/Makefile new file mode 100644 index 000000000000..977dbd24d765 --- /dev/null +++ b/drivers/gpu/fgles/Makefile @@ -0,0 +1,8 @@ +# +# Makefile for the exynos video drivers. +# + +ccflags-y := -Idrivers/gpu/fgles +asflags-y := -Idrivers/gpu/fgles + +obj-$(CONFIG_TIZEN_FGLES) += kfgles2_main.o kfgles2_hcalls.o diff --git a/drivers/gpu/fgles/kfgles2_hcalls.S b/drivers/gpu/fgles/kfgles2_hcalls.S new file mode 100644 index 000000000000..ee92a296d425 --- /dev/null +++ b/drivers/gpu/fgles/kfgles2_hcalls.S @@ -0,0 +1,38 @@ +/* Copyright (c) 2009 Nokia Corporation + * + * 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 or + * (at your option) any later version of the License. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +.text + +.extern kfgles2_base_egl; + +/* + * Cause an interrupt at the host machine by writing + * to a special area. + */ +.macro HCALL NAME, BASE, NUM +.global \NAME +.func \NAME +\NAME: + push {r4,fp} + ldr r4,=\BASE + ldr r4,[r4] + str r4,[r4, #\NUM*0x04] + pop {r4,fp} + bx lr + .size \NAME, . - \NAME +.endfunc +.endm + +HCALL kfgles2_host_init_egl, kfgles2_base_egl, 0 +HCALL kfgles2_host_exit_egl, kfgles2_base_egl, 1 + +.end + diff --git a/drivers/gpu/fgles/kfgles2_hcalls.h b/drivers/gpu/fgles/kfgles2_hcalls.h new file mode 100644 index 000000000000..38ea209b9598 --- /dev/null +++ b/drivers/gpu/fgles/kfgles2_hcalls.h @@ -0,0 +1,32 @@ +/* Copyright (c) 2009-2010 Nokia Corporation + * + * 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 or + * (at your option) any later version of the License. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#ifndef HCALLS_H_ +#define HCALLS_H_ + +/** + * kfgles2_host_init_XX - create host handle + * + * Inform host machine that a create and return + * new client handle, or 0 to indicate error. + */ +uint32_t kfgles2_host_init_egl(uint32_t abi); + +/** + * kfgles2_host_exit_XX - release host handle + * @id ID of the client disconnected + * + * Inform host machine that a client is disconnected. + */ +void kfgles2_host_exit_egl(uint32_t id); + +#endif /* HCALLS_H_ */ + diff --git a/drivers/gpu/fgles/kfgles2_main.c b/drivers/gpu/fgles/kfgles2_main.c new file mode 100644 index 000000000000..05fbbef5e23b --- /dev/null +++ b/drivers/gpu/fgles/kfgles2_main.c @@ -0,0 +1,345 @@ +/* Copyright (c) 2009-2010 Nokia Corporation + * + * 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 or + * (at your option) any later version of the License. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "kfgles2_hcalls.h" + +/* TODO: figure out default value dynamically. */ +static unsigned int kfgles2_abi = CONFIG_TIZEN_FGLES_FLOAT_ABI; +module_param(kfgles2_abi, uint, 0644); +MODULE_PARM_DESC(kfgles2_abi, "procedure call interface"); + +static unsigned int kfgles2_last_client = 0; + +#ifdef CONFIG_TIZEN_FGLES_DEBUG +static bool debug = true; +#else +static bool debug = false; +#endif + +module_param(debug, bool, 0644); +MODULE_PARM_DESC(debug, "enable debug prints"); + +#define KFGLES2_PRINT(format, args...) \ + do { if (debug) printk(KERN_DEBUG "kfgles2: DEBUG: " format, ##args); } while (0) + +#if CONFIG_TIZEN_FGLES_FLOAT_ABI != 1 && CONFIG_TIZEN_FGLES_FLOAT_ABI != 2 +#error fake GLES module float ABI wrong value! +#endif + +typedef enum +{ + EGL = 0, + ES11 = 1, + ES20 = 2, + VG1 = 3, +} API_ENUM; + +#define MAX_APIS 10 +//EGL always needs to exist and be the first +static API_ENUM KFGLES2_SUPPORTED_API[] = {EGL,ES11,ES20,VG1}; + +#define KFGLES2_DEVICE "kfgles2" +static int kfgles2_minor = CONFIG_TIZEN_FGLES_MINOR; +module_param(kfgles2_minor, uint, 0644); +MODULE_PARM_DESC(kfgles2_minor, "Minor number to be used when registering miscdev"); + +static unsigned long kfgles2_hwbase = 0; + +#define KFGLES2_HWSIZE 0x00100000 +#define KFGLES2_NUM_API (sizeof(KFGLES2_SUPPORTED_API) / sizeof(API_ENUM)) +#define KFGLES2_BLOCKSIZE (KFGLES2_HWSIZE / KFGLES2_NUM_API) //num APIs + EGL + +static unsigned long KFGLES2_BASE_ADDR[MAX_APIS]; +/* + Value set through ioctl system call +*/ +static unsigned int kfgles2_api = EGL; + +/* Client specific data holder. */ +struct kfgles2_client { + uint32_t nr; + void* offset; + unsigned long buffer; + int count; +}; + +void __iomem *kfgles2_base_egl; +static DEFINE_MUTEX(kfgles2_mutex); + +static void kfgles2_vopen(struct vm_area_struct *vma) +{ + struct kfgles2_client *client; + mutex_lock(&kfgles2_mutex); + client=vma->vm_private_data; + client->count++; + KFGLES2_PRINT("client %d: one user more! %d.\n", client->nr, client->count); + mutex_unlock(&kfgles2_mutex); +} + +/* Release a mapped register area, and disconnect the client. */ +static void kfgles2_vclose(struct vm_area_struct *vma) +{ + struct kfgles2_client *client; + mutex_lock(&kfgles2_mutex); + client=vma->vm_private_data; + + KFGLES2_PRINT("munmap called!\n"); + + if (client) { + if (client->count > 1) { + KFGLES2_PRINT("client %d: one user less! %d.\n", client->nr, client->count); + client->count--; + } else { + + KFGLES2_PRINT("Exiting client ID %d.\n", client->nr); + kfgles2_host_exit_egl(client->nr); + + + KFGLES2_PRINT("Freeing...\n"); + kfree(client); + } + } + + vma->vm_private_data = 0; + mutex_unlock(&kfgles2_mutex); +} + +/* Operations for kernel to deal with a mapped register area. */ +static struct vm_operations_struct kfgles2_vops = +{ + .close = kfgles2_vclose, + .open = kfgles2_vopen, +}; + +/* Nothing to do when opening the file. */ +static int kfgles2_open(struct inode *inode, struct file *filep) +{ + return 0; +} + +/* Nothing to do when closing the file. */ +static int kfgles2_release(struct inode *inode, struct file *filep) +{ + return 0; +} +/* Used to set the API, es11/20 */ +static long kfgles2_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) +{ + kfgles2_api = cmd; + KFGLES2_PRINT("ioctl called: cmd=%d, kfgles2_api=%d\n",cmd,kfgles2_api); + return 0; +} + +/* Map a register area for connecting client. */ +static int kfgles2_mmap(struct file *filep, struct vm_area_struct *vma) +{ + struct kfgles2_client *client; + int ret; + unsigned long pfn; + + mutex_lock(&kfgles2_mutex); + KFGLES2_PRINT("mmap called!\n"); + + KFGLES2_PRINT("remap_pfn_range: vm_start=0x%lx, vm_end=0x%lx, vm_pgoff=0x%lx\n",vma->vm_start, vma->vm_end, vma->vm_pgoff); + client = 0; + if (!vma->vm_pgoff) { + KFGLES2_PRINT("EGL root requested!\n"); + kfgles2_last_client = 0; + kfgles2_api = 0; + } else { + kfgles2_api = (unsigned int)(vma->vm_pgoff -1); + switch (kfgles2_api) { + case EGL: + KFGLES2_PRINT("Requesting EGL client block..\n"); + if (!(client = kmalloc(sizeof(*client), GFP_KERNEL))) { + return -ENOMEM; + } + client->nr = kfgles2_host_init_egl(kfgles2_abi); + client->count = 1; + kfgles2_last_client = client->nr; + KFGLES2_PRINT("-> Got %d!\n", client->nr); + break; + case ES11: + KFGLES2_PRINT("Requesting ES11 client block..\n"); + break; + case ES20: + KFGLES2_PRINT("Requesting ES20 client block..\n"); + break; + default: + KFGLES2_PRINT("Error: Requesting UNKNOWN client block!..\n"); + ret = -1; + goto failure; + break; + } + } + + + pfn = ((KFGLES2_BASE_ADDR[kfgles2_api]) >> PAGE_SHIFT) + kfgles2_last_client + 1; + vma->vm_flags |= VM_IO | VM_RESERVED; + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + + if ((ret = remap_pfn_range(vma, + vma->vm_start, + pfn, + vma->vm_end - vma->vm_start, + vma->vm_page_prot)) < 0) + { + KFGLES2_PRINT("remap failed!\n"); + goto failure; + } + + KFGLES2_PRINT("remap_pfn_range: vm_start=0x%lx, vm_end=0x%lx, pfn=0x%lx, vm_pgoff=0x%lx, ret=0x%x\n",vma->vm_start, vma->vm_end, pfn, vma->vm_pgoff, ret); + if (client) { + vma->vm_private_data = client; + vma->vm_ops = &kfgles2_vops; + } + if (kfgles2_last_client) + KFGLES2_PRINT("remap successfull for client %d block %d!\n", kfgles2_last_client, kfgles2_api); + else + KFGLES2_PRINT("remap successfull for root!\n"); + + mutex_unlock(&kfgles2_mutex); + return 0; +failure: + mutex_unlock(&kfgles2_mutex); + kfree(client); + return ret; +} + +/* Operations for kernel to deal with the device file. */ +static const struct file_operations kfgles2_fops = { + .owner = THIS_MODULE, + .open = kfgles2_open, + .release = kfgles2_release, + .mmap = kfgles2_mmap, + .unlocked_ioctl = kfgles2_ioctl, +}; + +static struct miscdevice kfgles2_miscdev = { + .name = KFGLES2_DEVICE, + .fops = &kfgles2_fops +}; + +/* Module initialization. */ +static int __devinit kfgles2_probe(struct platform_device *pdev) +{ + int err = 0, i; + struct resource *mem; + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (mem) { + kfgles2_hwbase = mem->start; + if (!devm_request_mem_region(&pdev->dev, mem->start, KFGLES2_HWSIZE, + pdev->name)) { + return -EBUSY; + } + } else { + if (!kfgles2_hwbase) { + return -EINVAL; + } + if (!devm_request_mem_region(&pdev->dev, kfgles2_hwbase, KFGLES2_HWSIZE, + pdev->name)) { + return -EBUSY; + } + } + + for ( i = 0; i < KFGLES2_NUM_API; i++) + { + KFGLES2_BASE_ADDR[i] = kfgles2_hwbase + KFGLES2_BLOCKSIZE * i; + KFGLES2_PRINT("Base %d = %lx.\n", i, KFGLES2_BASE_ADDR[i]); + } + + printk(KERN_INFO "loading kfgles2 module (%s).\n", + (kfgles2_abi == 1) ? "arm_softfp" + : (kfgles2_abi == 2) ? "arm_hardfp" : "unknown abi"); + kfgles2_miscdev.minor = kfgles2_minor; + + if (!(kfgles2_base_egl = ioremap(KFGLES2_BASE_ADDR[EGL], KFGLES2_HWSIZE))) + { + KFGLES2_PRINT("ERROR: failed to map EGL hardware block.\n"); + return -ENOMEM; + } + + if (misc_register(&kfgles2_miscdev) < 0) + goto out_map; + + mutex_init(&kfgles2_mutex); + + goto out; + +out_map: + iounmap(kfgles2_base_egl); +out: + return err; +} + +/* Module cleanup. */ +static int __devexit kfgles2_remove(struct platform_device *pdev) +{ + int ret = 0; + printk(KERN_INFO "kfgles2 module removed.\n"); + + if ((ret = misc_deregister(&kfgles2_miscdev))) { + return ret; + } + if(kfgles2_base_egl) { + iounmap(kfgles2_base_egl); + kfgles2_base_egl = 0; + } + return ret; +} + +/* Platform driver */ + +static struct of_device_id kfgles2_match[] = { + { .compatible = "kfgles2", }, + {}, +}; +MODULE_DEVICE_TABLE(of, kfgles2_match); + +static struct platform_driver kfgles2_driver = { + .probe = kfgles2_probe, + .remove = __devexit_p(kfgles2_remove), + .driver = { + .name = "kfgles2", + .owner = THIS_MODULE, + .of_match_table = kfgles2_match, + }, +}; + +static int __init kfgles2_init(void) +{ + return platform_driver_register(&kfgles2_driver); +} + +static void __exit kfgles2_exit(void) +{ + platform_driver_unregister(&kfgles2_driver); +} + +module_init(kfgles2_init); +module_exit(kfgles2_exit); + +MODULE_AUTHOR("Jean Fairlie "); +MODULE_AUTHOR("Joonas Lahtinen "); +MODULE_AUTHOR("Pablo Virolainen "); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("QEMU OpenGL ES accelerator module"); diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index a290be51a1f4..4bbbf1dc4afd 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -23,6 +23,8 @@ source "drivers/gpu/drm/Kconfig" source "drivers/gpu/stub/Kconfig" +source "drivers/gpu/fgles/Kconfig" + config VGASTATE tristate default n