tizen FGLES: make kfgles a static module
authorIgor Mitsyanko <i.mitsyanko@samsung.com>
Thu, 10 May 2012 17:33:55 +0000 (21:33 +0400)
committerEvgeny Voevodin <e.voevodin@samsung.com>
Fri, 14 Sep 2012 05:42:17 +0000 (09:42 +0400)
Add config option to kernel configuration.

Signed-off-by: Igor Mitsyanko <i.mitsyanko@samsung.com>
arch/arm/configs/tizen_defconfig
arch/arm/mach-exynos/mach-tizen.c
drivers/gpu/Makefile
drivers/gpu/fgles/Kconfig [new file with mode: 0644]
drivers/gpu/fgles/Makefile [new file with mode: 0644]
drivers/gpu/fgles/kfgles2_hcalls.S [new file with mode: 0644]
drivers/gpu/fgles/kfgles2_hcalls.h [new file with mode: 0644]
drivers/gpu/fgles/kfgles2_main.c [new file with mode: 0644]
drivers/video/Kconfig

index d2f194997f06dec7677ef5fd736caed7014962c3..1dc2fd6bf271b9d42bae0ccaa253d694ed3d58a2 100644 (file)
@@ -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
 
 #
index eb902996b66067fb6e827013b5f253e074459613..9128a46f4cfbd28cf67c96ecc89fc7a00aae95ac 100644 (file)
@@ -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,
index cc9277885dd071b2da83edeae9250b6ea5985020..61f6aaa661a3c60e07b355bdf2a910fc9485ca4a 100644 (file)
@@ -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 (file)
index 0000000..333afbd
--- /dev/null
@@ -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 (file)
index 0000000..977dbd2
--- /dev/null
@@ -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 (file)
index 0000000..ee92a29
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.
+ */
+
+.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 (file)
index 0000000..38ea209
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.
+ */
+#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 (file)
index 0000000..05fbbef
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/io.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/slab.h>
+#include <linux/miscdevice.h>
+#include <linux/platform_device.h>
+
+#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 <jean.fairlie at nomovok.com>");
+MODULE_AUTHOR("Joonas Lahtinen <joonas.lahtinen at nomovok.com>");
+MODULE_AUTHOR("Pablo Virolainen <pablo.virolainen at nomovok.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("QEMU OpenGL ES accelerator module");
index a290be51a1f4a2f412aa80976c85a396eb60db30..4bbbf1dc4afd7caa3d95419f23711a322b4f3f9c 100644 (file)
@@ -23,6 +23,8 @@ source "drivers/gpu/drm/Kconfig"
 
 source "drivers/gpu/stub/Kconfig"
 
+source "drivers/gpu/fgles/Kconfig"
+
 config VGASTATE
        tristate
        default n