summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Jansa <Martin.Jansa@gmail.com>2009-12-22 15:24:20 +0100
committerMartin Jansa <Martin.Jansa@gmail.com>2009-12-23 09:11:24 +0100
commitc3bfaaa2b9b5e6b9595758a4d2ed05940bf20722 (patch)
tree931209da9f27bbedb8f34c52af4af008c39d07bf
parent1a4c43bfb1031c97780528e2bfe83eefb1af114c (diff)
linux-openmoko-2.6.32: enable glamo DRM
Signed-off-by: Martin Jansa <Martin.Jansa@gmail.com>
-rw-r--r--recipes/linux/linux-openmoko-2.6.32/0001-DRM-for-platform-devices.patch458
-rw-r--r--recipes/linux/linux-openmoko-2.6.32/0001-glamo-drm-use-dev_set_drvdata-instead-of-setting-dri.patch29
-rw-r--r--recipes/linux/linux-openmoko-2.6.32/0002-Glamo-DRM-and-KMS-driver.patch3818
-rw-r--r--recipes/linux/linux-openmoko-2.6.32/0002-glamo-drm-select-DRM_KMS_HELPER-for-crtc-functions.patch24
-rw-r--r--recipes/linux/linux-openmoko-2.6.32/0003-Work-on-Glamo-core-for-DRM.patch252
-rw-r--r--recipes/linux/linux-openmoko-2.6.32/0004-Add-JBT6k74-hook-for-use-by-KMS.patch49
-rw-r--r--recipes/linux/linux-openmoko-2.6.32/om-gta02/defconfig163
-rw-r--r--recipes/linux/linux-openmoko-2.6.32_git.bb10
8 files changed, 4734 insertions, 69 deletions
diff --git a/recipes/linux/linux-openmoko-2.6.32/0001-DRM-for-platform-devices.patch b/recipes/linux/linux-openmoko-2.6.32/0001-DRM-for-platform-devices.patch
new file mode 100644
index 0000000000..2c9b611165
--- /dev/null
+++ b/recipes/linux/linux-openmoko-2.6.32/0001-DRM-for-platform-devices.patch
@@ -0,0 +1,458 @@
+From da270cf61e67d912b38e314719511efc4c2ea085 Mon Sep 17 00:00:00 2001
+From: Thomas White <taw@bitwiz.org.uk>
+Date: Tue, 20 Oct 2009 15:52:30 +0200
+Subject: [PATCH 1/4] DRM for platform devices
+
+This modifies the DRM core in a small number of places to allow platform
+devices to be used for direct rendering, alongside PCI devices.
+
+Signed-off-by: Thomas White <taw@bitwiz.org.uk>
+---
+ drivers/gpu/drm/Kconfig | 2 +-
+ drivers/gpu/drm/drm_bufs.c | 2 +-
+ drivers/gpu/drm/drm_drv.c | 27 ++++++++++
+ drivers/gpu/drm/drm_info.c | 27 ++++++++--
+ drivers/gpu/drm/drm_ioctl.c | 118 ++++++++++++++++++++++++++++++-------------
+ drivers/gpu/drm/drm_stub.c | 76 +++++++++++++++++++++++++++-
+ drivers/gpu/drm/drm_sysfs.c | 6 ++-
+ include/drm/drmP.h | 13 +++++
+ 8 files changed, 224 insertions(+), 47 deletions(-)
+
+diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
+index 39b393d..cef3d2c 100644
+--- a/drivers/gpu/drm/Kconfig
++++ b/drivers/gpu/drm/Kconfig
+@@ -6,7 +6,7 @@
+ #
+ menuconfig DRM
+ tristate "Direct Rendering Manager (XFree86 4.1.0 and higher DRI support)"
+- depends on (AGP || AGP=n) && PCI && !EMULATED_CMPXCHG && MMU
++ depends on (AGP || AGP=n) && !EMULATED_CMPXCHG && MMU
+ select I2C
+ select I2C_ALGOBIT
+ help
+diff --git a/drivers/gpu/drm/drm_bufs.c b/drivers/gpu/drm/drm_bufs.c
+index 6246e3f..b9f15bf 100644
+--- a/drivers/gpu/drm/drm_bufs.c
++++ b/drivers/gpu/drm/drm_bufs.c
+@@ -188,7 +188,7 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset,
+ switch (map->type) {
+ case _DRM_REGISTERS:
+ case _DRM_FRAME_BUFFER:
+-#if !defined(__sparc__) && !defined(__alpha__) && !defined(__ia64__) && !defined(__powerpc64__) && !defined(__x86_64__)
++#if !defined(__sparc__) && !defined(__alpha__) && !defined(__ia64__) && !defined(__powerpc64__) && !defined(__x86_64__) && !defined(__arm__)
+ if (map->offset + (map->size-1) < map->offset ||
+ map->offset < virt_to_phys(high_memory)) {
+ kfree(map);
+diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
+index b39d7bf..a7861e8 100644
+--- a/drivers/gpu/drm/drm_drv.c
++++ b/drivers/gpu/drm/drm_drv.c
+@@ -247,6 +247,7 @@ int drm_lastclose(struct drm_device * dev)
+ */
+ int drm_init(struct drm_driver *driver)
+ {
++#ifdef CONFIG_PCI
+ struct pci_dev *pdev = NULL;
+ const struct pci_device_id *pid;
+ int i;
+@@ -280,11 +281,37 @@ int drm_init(struct drm_driver *driver)
+ drm_get_dev(pdev, pid, driver);
+ }
+ }
++#endif
+ return 0;
+ }
+
+ EXPORT_SYMBOL(drm_init);
+
++/**
++ * Call this to associate a drm_driver with a platform_device.
++ *
++ * \return zero on success or a negative number on failure.
++ *
++ * This is a replacement for drm_init(), but for platform drivers.
++ * In this case, the caller must provide the matching platform_device
++ *
++ * since there is no physical bus to scan through.
++ *
++ * \sa drm_init
++ *
++ */
++int drm_platform_init(struct drm_driver *driver, struct platform_device *pdev,
++ void *priv)
++{
++ DRM_DEBUG("\n");
++
++ INIT_LIST_HEAD(&driver->device_list);
++
++ return drm_get_platform_dev(pdev, driver, priv);
++}
++
++EXPORT_SYMBOL(drm_platform_init);
++
+ void drm_exit(struct drm_driver *driver)
+ {
+ struct drm_device *dev, *tmp;
+diff --git a/drivers/gpu/drm/drm_info.c b/drivers/gpu/drm/drm_info.c
+index f0f6c6b..838c2ee 100644
+--- a/drivers/gpu/drm/drm_info.c
++++ b/drivers/gpu/drm/drm_info.c
+@@ -52,12 +52,28 @@ int drm_name_info(struct seq_file *m, void *data)
+ return 0;
+
+ if (master->unique) {
+- seq_printf(m, "%s %s %s\n",
+- dev->driver->pci_driver.name,
+- pci_name(dev->pdev), master->unique);
++
++ if (drm_core_is_platform(dev)) {
++ seq_printf(m, "%s %s %s\n",
++ dev->driver->name,
++ dev_name(&dev->platform_dev->dev),
++ master->unique);
++ } else {
++ seq_printf(m, "%s %s %s\n",
++ dev->driver->pci_driver.name,
++ pci_name(dev->pdev), master->unique);
++ }
++
+ } else {
+- seq_printf(m, "%s %s\n", dev->driver->pci_driver.name,
+- pci_name(dev->pdev));
++
++ if (drm_core_is_platform(dev)) {
++ seq_printf(m, "%s %s\n", dev->driver->name,
++ dev_name(&dev->platform_dev->dev));
++ } else {
++ seq_printf(m, "%s %s\n", dev->driver->pci_driver.name,
++ pci_name(dev->pdev));
++ }
++
+ }
+
+ return 0;
+@@ -325,4 +341,3 @@ int drm_vma_info(struct seq_file *m, void *data)
+ }
+
+ #endif
+-
+diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c
+index 9b9ff46..133ef29 100644
+--- a/drivers/gpu/drm/drm_ioctl.c
++++ b/drivers/gpu/drm/drm_ioctl.c
+@@ -83,7 +83,6 @@ int drm_setunique(struct drm_device *dev, void *data,
+ {
+ struct drm_unique *u = data;
+ struct drm_master *master = file_priv->master;
+- int domain, bus, slot, func, ret;
+
+ if (master->unique_len || master->unique)
+ return -EBUSY;
+@@ -101,28 +100,46 @@ int drm_setunique(struct drm_device *dev, void *data,
+
+ master->unique[master->unique_len] = '\0';
+
+- dev->devname = kmalloc(strlen(dev->driver->pci_driver.name) +
+- strlen(master->unique) + 2, GFP_KERNEL);
+- if (!dev->devname)
+- return -ENOMEM;
++ if ( !drm_core_is_platform(dev) ) {
+
+- sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name,
+- master->unique);
++ int domain, bus, slot, func, ret;
+
+- /* Return error if the busid submitted doesn't match the device's actual
+- * busid.
+- */
+- ret = sscanf(master->unique, "PCI:%d:%d:%d", &bus, &slot, &func);
+- if (ret != 3)
+- return -EINVAL;
+- domain = bus >> 8;
+- bus &= 0xff;
++ /* PCI device */
++ dev->devname = kmalloc(strlen(dev->driver->pci_driver.name) +
++ strlen(master->unique) + 2, GFP_KERNEL);
++ if (!dev->devname)
++ return -ENOMEM;
+
+- if ((domain != drm_get_pci_domain(dev)) ||
+- (bus != dev->pdev->bus->number) ||
+- (slot != PCI_SLOT(dev->pdev->devfn)) ||
+- (func != PCI_FUNC(dev->pdev->devfn)))
+- return -EINVAL;
++ sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name,
++ master->unique);
++
++ /* Return error if the busid submitted doesn't match the
++ * device's actual busid.
++ */
++ ret = sscanf(master->unique, "PCI:%d:%d:%d", &bus, &slot, &func);
++ if (ret != 3)
++ return -EINVAL;
++ domain = bus >> 8;
++ bus &= 0xff;
++
++ if ((domain != drm_get_pci_domain(dev)) ||
++ (bus != dev->pdev->bus->number) ||
++ (slot != PCI_SLOT(dev->pdev->devfn)) ||
++ (func != PCI_FUNC(dev->pdev->devfn)))
++ return -EINVAL;
++
++ } else {
++
++ /* Platform device */
++ dev->devname = kmalloc(strlen(dev->driver->name) +
++ strlen(master->unique) + 2, GFP_KERNEL);
++ if (!dev->devname)
++ return -ENOMEM;
++
++ sprintf(dev->devname, "%s@%s", dev->driver->name,
++ master->unique);
++
++ }
+
+ return 0;
+ }
+@@ -141,23 +158,52 @@ static int drm_set_busid(struct drm_device *dev, struct drm_file *file_priv)
+ if (master->unique == NULL)
+ return -ENOMEM;
+
+- len = snprintf(master->unique, master->unique_len, "pci:%04x:%02x:%02x.%d",
+- drm_get_pci_domain(dev),
+- dev->pdev->bus->number,
+- PCI_SLOT(dev->pdev->devfn),
+- PCI_FUNC(dev->pdev->devfn));
+- if (len >= master->unique_len)
+- DRM_ERROR("buffer overflow");
+- else
+- master->unique_len = len;
+-
+- dev->devname = kmalloc(strlen(dev->driver->pci_driver.name) +
+- master->unique_len + 2, GFP_KERNEL);
+- if (dev->devname == NULL)
+- return -ENOMEM;
++ if ( !drm_core_is_platform(dev) ) {
++
++ /* PCI device */
+
+- sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name,
+- master->unique);
++ len = snprintf(master->unique, master->unique_len,
++ "pci:%04x:%02x:%02x.%d",
++ drm_get_pci_domain(dev),
++ dev->pdev->bus->number,
++ PCI_SLOT(dev->pdev->devfn),
++ PCI_FUNC(dev->pdev->devfn));
++ if (len >= master->unique_len)
++ DRM_ERROR("buffer overflow");
++ else
++ master->unique_len = len;
++
++ dev->devname = kmalloc(strlen(dev->driver->pci_driver.name) +
++ master->unique_len + 2, GFP_KERNEL);
++ if (dev->devname == NULL)
++ return -ENOMEM;
++
++ sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name,
++ master->unique);
++
++ } else {
++
++ /* Platform device */
++
++ int len;
++
++ len = snprintf(master->unique, master->unique_len,
++ "platform:%s", dev->platform_dev->name);
++
++ if (len >= master->unique_len)
++ DRM_ERROR("buffer overflow");
++ else
++ master->unique_len = len;
++
++ dev->devname = kmalloc(strlen(dev->driver->name)
++ + master->unique_len + 2, GFP_KERNEL);
++ if (dev->devname == NULL)
++ return -ENOMEM;
++
++ sprintf(dev->devname, "%s@%s", dev->driver->name,
++ master->unique);
++
++ }
+
+ return 0;
+ }
+diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c
+index 55bb8a8..a7069ad 100644
+--- a/drivers/gpu/drm/drm_stub.c
++++ b/drivers/gpu/drm/drm_stub.c
+@@ -230,8 +230,10 @@ static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev,
+ idr_init(&dev->drw_idr);
+
+ dev->pdev = pdev;
+- dev->pci_device = pdev->device;
+- dev->pci_vendor = pdev->vendor;
++ if (pdev) {
++ dev->pci_device = pdev->device;
++ dev->pci_vendor = pdev->vendor;
++ }
+
+ #ifdef __alpha__
+ dev->hose = pdev->sysdata;
+@@ -449,6 +451,76 @@ err_g1:
+ EXPORT_SYMBOL(drm_get_dev);
+
+ /**
++ *
++ * Register a platform device as a DRM device
++ *
++ * \param pdev - platform device structure
++ * \param driver - the matching drm_driver structure
++ * \return zero on success or a negative number on failure.
++ *
++ * Attempt to gets inter module "drm" information. If we are first
++ * then register the character device and inter module information.
++ * Try and register, if we fail to register, backout previous work.
++ *
++ * \sa drm_get_dev
++ */
++int drm_get_platform_dev(struct platform_device *pdev,
++ struct drm_driver *driver, void *priv)
++{
++ struct drm_device *dev;
++ int ret;
++ DRM_DEBUG("\n");
++
++ dev = kmalloc(sizeof(*dev), GFP_KERNEL);
++ if (!dev)
++ return -ENOMEM;
++ dev->dev_private = priv;
++
++ if ((ret = drm_fill_in_dev(dev, NULL, NULL, driver))) {
++ printk(KERN_ERR "DRM: Fill_in_dev failed.\n");
++ goto err_g1;
++ }
++ dev->platform_dev = pdev;
++
++ if (drm_core_check_feature(dev, DRIVER_MODESET)) {
++ ret = drm_get_minor(dev, &dev->control, DRM_MINOR_CONTROL);
++ if (ret)
++ goto err_g2;
++ }
++
++ if ((ret = drm_get_minor(dev, &dev->primary, DRM_MINOR_LEGACY)))
++ goto err_g3;
++
++ if (dev->driver->load) {
++ ret = dev->driver->load(dev, 0);
++ if (ret)
++ goto err_g3;
++ }
++
++ /* setup the grouping for the legacy output */
++ if (drm_core_check_feature(dev, DRIVER_MODESET)) {
++ ret = drm_mode_group_init_legacy_group(dev, &dev->primary->mode_group);
++ if (ret)
++ goto err_g3;
++ }
++
++ list_add_tail(&dev->driver_item, &driver->device_list);
++
++ DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n",
++ driver->name, driver->major, driver->minor, driver->patchlevel,
++ driver->date, dev->primary->index);
++
++ return 0;
++
++err_g3:
++ drm_put_minor(&dev->primary);
++err_g2:
++err_g1:
++ kfree(dev);
++ return ret;
++}
++
++/**
+ * Put a secondary minor number.
+ *
+ * \param sec_minor - structure to be released
+diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c
+index f7a615b..fea2b71 100644
+--- a/drivers/gpu/drm/drm_sysfs.c
++++ b/drivers/gpu/drm/drm_sysfs.c
+@@ -482,7 +482,11 @@ int drm_sysfs_device_add(struct drm_minor *minor)
+ int err;
+ char *minor_str;
+
+- minor->kdev.parent = &minor->dev->pdev->dev;
++ if (minor->dev->pdev) {
++ minor->kdev.parent = &minor->dev->pdev->dev;
++ } else {
++ minor->kdev.parent = &minor->dev->platform_dev->dev;
++ }
+ minor->kdev.class = drm_class;
+ minor->kdev.release = drm_sysfs_device_release;
+ minor->kdev.devt = minor->device;
+diff --git a/include/drm/drmP.h b/include/drm/drmP.h
+index 45b67d9..66253f9 100644
+--- a/include/drm/drmP.h
++++ b/include/drm/drmP.h
+@@ -55,6 +55,7 @@
+ #include <linux/mm.h>
+ #include <linux/cdev.h>
+ #include <linux/mutex.h>
++#include <linux/platform_device.h>
+ #if defined(__alpha__) || defined(__powerpc__)
+ #include <asm/pgtable.h> /* For pte_wrprotect */
+ #endif
+@@ -113,6 +114,7 @@ extern void drm_ut_debug_printk(unsigned int request_level,
+ #define DRIVER_IRQ_VBL2 0x800
+ #define DRIVER_GEM 0x1000
+ #define DRIVER_MODESET 0x2000
++#define DRIVER_IS_PLATFORM 0x4000
+
+ /***********************************************************************/
+ /** \name Begin the DRM... */
+@@ -981,6 +983,7 @@ struct drm_device {
+ wait_queue_head_t buf_writers; /**< Processes waiting to ctx switch */
+
+ struct drm_agp_head *agp; /**< AGP data */
++ struct platform_device *platform_dev; /**< platform device structure */
+
+ struct pci_dev *pdev; /**< PCI device structure */
+ int pci_vendor; /**< PCI vendor id */
+@@ -1091,12 +1094,20 @@ static inline int drm_mtrr_del(int handle, unsigned long offset,
+ }
+ #endif
+
++static inline int drm_core_is_platform(struct drm_device *dev)
++{
++ return drm_core_check_feature(dev, DRIVER_IS_PLATFORM);
++}
++
+ /******************************************************************/
+ /** \name Internal function definitions */
+ /*@{*/
+
+ /* Driver support (drm_drv.h) */
+ extern int drm_init(struct drm_driver *driver);
++extern int drm_platform_init(struct drm_driver *driver,
++ struct platform_device *pdev,
++ void *dev_private);
+ extern void drm_exit(struct drm_driver *driver);
+ extern int drm_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+@@ -1314,6 +1325,8 @@ extern int drm_dropmaster_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+ struct drm_master *drm_master_create(struct drm_minor *minor);
+ extern struct drm_master *drm_master_get(struct drm_master *master);
++extern int drm_get_platform_dev(struct platform_device *pdev,
++ struct drm_driver *driver, void *priv);
+ extern void drm_master_put(struct drm_master **master);
+ extern int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
+ struct drm_driver *driver);
+--
+1.6.5.3
+
diff --git a/recipes/linux/linux-openmoko-2.6.32/0001-glamo-drm-use-dev_set_drvdata-instead-of-setting-dri.patch b/recipes/linux/linux-openmoko-2.6.32/0001-glamo-drm-use-dev_set_drvdata-instead-of-setting-dri.patch
new file mode 100644
index 0000000000..d9afec8830
--- /dev/null
+++ b/recipes/linux/linux-openmoko-2.6.32/0001-glamo-drm-use-dev_set_drvdata-instead-of-setting-dri.patch
@@ -0,0 +1,29 @@
+From eadea0d7bda93fec0e2c7a3b675fc6ab21cdfe61 Mon Sep 17 00:00:00 2001
+From: Martin Jansa <Martin.Jansa@gmail.com>
+Date: Tue, 22 Dec 2009 16:11:27 +0100
+Subject: [PATCH 1/2] glamo-drm: use dev_set_drvdata instead of setting driver_data directly
+
+* driver_data is private since 2.6.32
+ http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=b4028437876866aba4747a655ede00f892089e14
+
+Signed-off-by: Martin Jansa <Martin.Jansa@gmail.com>
+---
+ drivers/mfd/glamo/glamo-drm-drv.c | 2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/mfd/glamo/glamo-drm-drv.c b/drivers/mfd/glamo/glamo-drm-drv.c
+index 81215f4..4352091 100644
+--- a/drivers/mfd/glamo/glamo-drm-drv.c
++++ b/drivers/mfd/glamo/glamo-drm-drv.c
+@@ -355,7 +355,7 @@ out_release_regs:
+ release_mem_region(gdrm->reg->start, resource_size(gdrm->reg));
+ out_free:
+ kfree(gdrm);
+- pdev->dev.driver_data = NULL;
++ dev_set_drvdata(&pdev->dev, NULL);
+ return rc;
+ }
+
+--
+1.6.6.rc4
+
diff --git a/recipes/linux/linux-openmoko-2.6.32/0002-Glamo-DRM-and-KMS-driver.patch b/recipes/linux/linux-openmoko-2.6.32/0002-Glamo-DRM-and-KMS-driver.patch
new file mode 100644
index 0000000000..4a837e9b08
--- /dev/null
+++ b/recipes/linux/linux-openmoko-2.6.32/0002-Glamo-DRM-and-KMS-driver.patch
@@ -0,0 +1,3818 @@
+From 01435b6f8fba2031e6941756a6a4e42be553f4a0 Mon Sep 17 00:00:00 2001
+From: Thomas White <taw@bitwiz.org.uk>
+Date: Tue, 20 Oct 2009 16:14:55 +0200
+Subject: [PATCH 2/4] Glamo DRM and KMS driver
+
+This adds the Glamo DRM and KMS driver, but not the modifications needed
+elsewhere to support it.
+
+Signed-off-by: Thomas White <taw@bitwiz.org.uk>
+---
+ drivers/gpu/drm/drm_stub.c | 2 +-
+ drivers/mfd/glamo/Kconfig | 15 +
+ drivers/mfd/glamo/Makefile | 5 +-
+ drivers/mfd/glamo/glamo-buffer.c | 372 ++++++++++++++
+ drivers/mfd/glamo/glamo-buffer.h | 60 +++
+ drivers/mfd/glamo/glamo-cmdq.c | 528 ++++++++++++++++++++
+ drivers/mfd/glamo/glamo-cmdq.h | 49 ++
+ drivers/mfd/glamo/glamo-display.c | 875 +++++++++++++++++++++++++++++++++
+ drivers/mfd/glamo/glamo-display.h | 39 ++
+ drivers/mfd/glamo/glamo-drm-drv.c | 453 +++++++++++++++++
+ drivers/mfd/glamo/glamo-drm-private.h | 156 ++++++
+ drivers/mfd/glamo/glamo-fence.c | 329 +++++++++++++
+ drivers/mfd/glamo/glamo-fence.h | 36 ++
+ drivers/mfd/glamo/glamo-kms-fb.c | 540 ++++++++++++++++++++
+ drivers/mfd/glamo/glamo-kms-fb.h | 41 ++
+ include/drm/Kbuild | 1 +
+ include/drm/glamo_drm.h | 153 ++++++
+ 17 files changed, 3652 insertions(+), 2 deletions(-)
+ create mode 100644 drivers/mfd/glamo/glamo-buffer.c
+ create mode 100644 drivers/mfd/glamo/glamo-buffer.h
+ create mode 100644 drivers/mfd/glamo/glamo-cmdq.c
+ create mode 100644 drivers/mfd/glamo/glamo-cmdq.h
+ create mode 100644 drivers/mfd/glamo/glamo-display.c
+ create mode 100644 drivers/mfd/glamo/glamo-display.h
+ create mode 100644 drivers/mfd/glamo/glamo-drm-drv.c
+ create mode 100644 drivers/mfd/glamo/glamo-drm-private.h
+ create mode 100644 drivers/mfd/glamo/glamo-fence.c
+ create mode 100644 drivers/mfd/glamo/glamo-fence.h
+ create mode 100644 drivers/mfd/glamo/glamo-kms-fb.c
+ create mode 100644 drivers/mfd/glamo/glamo-kms-fb.h
+ create mode 100644 include/drm/glamo_drm.h
+
+diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c
+index a7069ad..5e3d65a 100644
+--- a/drivers/gpu/drm/drm_stub.c
++++ b/drivers/gpu/drm/drm_stub.c
+@@ -471,7 +471,7 @@ int drm_get_platform_dev(struct platform_device *pdev,
+ int ret;
+ DRM_DEBUG("\n");
+
+- dev = kmalloc(sizeof(*dev), GFP_KERNEL);
++ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+ dev->dev_private = priv;
+diff --git a/drivers/mfd/glamo/Kconfig b/drivers/mfd/glamo/Kconfig
+index 8c93bcb..375e5db 100644
+--- a/drivers/mfd/glamo/Kconfig
++++ b/drivers/mfd/glamo/Kconfig
+@@ -39,3 +39,18 @@ config MFD_GLAMO_MCI
+ neo1973 GTA-02.
+
+ If unsure, say N.
++
++config MFD_GLAMO_DRM
++ tristate "Glamo direct rendering and kernel modesetting support"
++ depends on MFD_GLAMO && DRM
++ select FB_CFB_FILLRECT
++ select FB_CFB_COPYAREA
++ select FB_CFB_IMAGEBLIT
++ help
++ Direct Rendering Manager interface for the S-Media Glamo chip, as
++ used in Openmoko FreeRunner (GTA02).
++
++ This DRM driver includes kernel modesetting (KMS) support. As such,
++ do not select MFD_GLAMO_FB above if you choose to enable this option.
++
++ If unsure, say N.
+diff --git a/drivers/mfd/glamo/Makefile b/drivers/mfd/glamo/Makefile
+index ebf26f7..d5ebf8f 100644
+--- a/drivers/mfd/glamo/Makefile
++++ b/drivers/mfd/glamo/Makefile
+@@ -1,5 +1,5 @@
+ #
+-# Makefile for the Smedia Glamo framebuffer driver
++# Makefile for the Smedia Glamo driver(s)
+ #
+
+ obj-$(CONFIG_MFD_GLAMO) += glamo-core.o
+@@ -8,4 +8,7 @@ obj-$(CONFIG_MFD_GLAMO_SPI) += glamo-spi.o
+
+ obj-$(CONFIG_MFD_GLAMO_FB) += glamo-fb.o
+ obj-$(CONFIG_MFD_GLAMO_MCI) += glamo-mci.o
++obj-$(CONFIG_MFD_GLAMO_DRM) += glamo-drm.o
+
++glamo-drm-objs := glamo-drm-drv.o glamo-cmdq.o glamo-buffer.o \
++ glamo-display.o glamo-kms-fb.o glamo-fence.o
+diff --git a/drivers/mfd/glamo/glamo-buffer.c b/drivers/mfd/glamo/glamo-buffer.c
+new file mode 100644
+index 0000000..45500d3
+--- /dev/null
++++ b/drivers/mfd/glamo/glamo-buffer.c
+@@ -0,0 +1,372 @@
++/*
++ * SMedia Glamo 336x/337x memory management
++ *
++ * Copyright (c) 2009 Thomas White <taw@bitwiz.org.uk>
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ *
++ * Memory mapping functions based on i915_gem.c, to which the following
++ * notice applies:
++ *
++ * Copyright © 2008 Intel Corporation
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice (including the next
++ * paragraph) shall be included in all copies or substantial portions of the
++ * Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++ * IN THE SOFTWARE.
++ *
++ * Authors:
++ * Eric Anholt <eric@anholt.net>
++ */
++
++
++#include <drm/drmP.h>
++#include <drm/glamo_drm.h>
++
++#include "glamo-drm-private.h"
++#include "glamo-cmdq.h" /* For glamo_cmdq_blank() */
++
++
++struct drm_gem_object *glamo_gem_object_alloc(struct drm_device *dev, int size,
++ int alignment)
++{
++ struct drm_gem_object *obj;
++ struct glamodrm_handle *gdrm;
++ struct drm_glamo_gem_object *gobj;
++
++ gdrm = dev->dev_private;
++
++ size = roundup(size, PAGE_SIZE);
++
++ obj = drm_gem_object_alloc(dev, size);
++ if (obj == NULL) return NULL;
++
++ /* See glamodrm_gem_init_object() below */
++ gobj = obj->driver_private;
++
++ /* Allocate memory for this object in VRAM */
++ gobj->block = drm_mm_search_free(gdrm->mmgr, size, alignment, 1);
++ if (!gobj->block) {
++ goto fail;
++ }
++ gobj->block = drm_mm_get_block(gobj->block, size, alignment);
++ if (!gobj->block) {
++ goto fail;
++ }
++
++ /* Arrange for the contents to be set to zero */
++ glamo_cmdq_blank(gdrm, obj);
++
++ return obj;
++
++fail:
++ mutex_lock(&dev->struct_mutex);
++ drm_gem_object_unreference(obj);
++ mutex_unlock(&dev->struct_mutex);
++ printk(KERN_INFO "[glamo-drm] Failed to allocate object\n");
++
++ return NULL;
++}
++
++
++int glamo_ioctl_gem_create(struct drm_device *dev, void *data,
++ struct drm_file *file_priv)
++{
++ struct drm_glamo_gem_create *args = data;
++ struct drm_gem_object *obj;
++ int handle, ret, alignment, size;
++
++ /* Alignment must be a non-zero multiple of 2 */
++ alignment = args->alignment;
++ if ( alignment < 2 ) alignment = 2;
++ if ( alignment % 2 ) alignment *= 2;
++
++ /* Size must be similarly sanitised */
++ size = args->size;
++ if ( size < 2 ) size = 2;
++ if ( size % 2 ) size += 1;
++
++ /* Create an object */
++ obj = glamo_gem_object_alloc(dev, size, alignment);
++ if ( obj == NULL ) return -ENOMEM;
++
++ /* Create a handle for it */
++ ret = drm_gem_handle_create(file_priv, obj, &handle);
++ mutex_lock(&dev->struct_mutex);
++ drm_gem_object_handle_unreference(obj);
++ mutex_unlock(&dev->struct_mutex);
++ if (ret) goto fail;
++
++ /* Return */
++ args->handle = handle;
++ return 0;
++
++fail:
++ mutex_lock(&dev->struct_mutex);
++ drm_gem_object_unreference(obj);
++ mutex_unlock(&dev->struct_mutex);
++ printk(KERN_INFO "[glamo-drm] Failed to allocate object\n");
++ return ret;
++}
++
++
++int glamodrm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
++{
++ struct drm_gem_object *obj = vma->vm_private_data;
++ struct drm_device *dev = obj->dev;
++ struct drm_glamo_gem_object *gobj = obj->driver_private;
++ struct glamodrm_handle *gdrm = dev->dev_private;
++ pgoff_t page_offset;
++ unsigned long pfn;
++ int ret = 0;
++
++ /* We don't use vmf->pgoff since that has the fake offset */
++ page_offset = ((unsigned long)vmf->virtual_address - vma->vm_start) >>
++ PAGE_SHIFT;
++
++ mutex_lock(&dev->struct_mutex);
++ pfn = ((gdrm->vram->start + GLAMO_OFFSET_FB + gobj->block->start)
++ >> PAGE_SHIFT) + page_offset;
++ ret = vm_insert_pfn(vma, (unsigned long)vmf->virtual_address, pfn);
++ mutex_unlock(&dev->struct_mutex);
++
++ switch (ret) {
++ case -ENOMEM:
++ case -EAGAIN:
++ return VM_FAULT_OOM;
++ case -EFAULT:
++ case -EBUSY:
++ DRM_ERROR("can't insert pfn?? fault or busy...\n");
++ return VM_FAULT_SIGBUS;
++ default:
++ return VM_FAULT_NOPAGE;
++ }
++}
++
++
++static int glamo_gem_create_mmap_offset(struct drm_gem_object *obj)
++{
++ struct drm_device *dev = obj->dev;
++ struct drm_gem_mm *mm = dev->mm_private;
++ struct drm_glamo_gem_object *gobj = obj->driver_private;
++ struct drm_map_list *list;
++ struct drm_local_map *map;
++ int ret = 0;
++
++ /* Set the object up for mmap'ing */
++ list = &obj->map_list;
++ list->map = kzalloc(sizeof(struct drm_map_list), GFP_KERNEL);
++ if (!list->map)
++ return -ENOMEM;
++
++ map = list->map;
++ map->type = _DRM_GEM;
++ map->size = obj->size;
++ map->handle = obj;
++
++ /* Get a DRM GEM mmap offset allocated... */
++ list->file_offset_node = drm_mm_search_free(&mm->offset_manager,
++ obj->size / PAGE_SIZE, 0, 0);
++ if (!list->file_offset_node) {
++ DRM_ERROR("failed to allocate offset for bo %d\n", obj->name);
++ ret = -ENOMEM;
++ goto out_free_list;
++ }
++
++ list->file_offset_node = drm_mm_get_block(list->file_offset_node,
++ obj->size / PAGE_SIZE, 0);
++ if (!list->file_offset_node) {
++ ret = -ENOMEM;
++ goto out_free_list;
++ }
++
++ list->hash.key = list->file_offset_node->start;
++ if (drm_ht_insert_item(&mm->offset_hash, &list->hash)) {
++ DRM_ERROR("failed to add to map hash\n");
++ goto out_free_mm;
++ }
++
++ /* By now we should be all set, any drm_mmap request on the offset
++ * below will get to our mmap & fault handler */
++ gobj->mmap_offset = ((uint64_t) list->hash.key) << PAGE_SHIFT;
++
++ return 0;
++
++out_free_mm:
++ drm_mm_put_block(list->file_offset_node);
++out_free_list:
++ kfree(list->map);
++
++ return ret;
++}
++
++
++int glamo_ioctl_gem_mmap(struct drm_device *dev, void *data,
++ struct drm_file *file_priv)
++{
++ struct drm_glamo_gem_mmap *args = data;
++ struct drm_gem_object *obj;
++ struct drm_glamo_gem_object *gobj;
++ int ret;
++
++ obj = drm_gem_object_lookup(dev, file_priv, args->handle);
++ if (obj == NULL)
++ return -EBADF;
++
++ mutex_lock(&dev->struct_mutex);
++
++ gobj = obj->driver_private;
++ if (!gobj->mmap_offset) {
++ ret = glamo_gem_create_mmap_offset(obj);
++ if (ret) {
++ mutex_unlock(&dev->struct_mutex);
++ return ret;
++ }
++ }
++
++ args->offset = gobj->mmap_offset;
++
++ drm_gem_object_unreference(obj);
++ mutex_unlock(&dev->struct_mutex);
++
++ return 0;
++}
++
++
++int glamo_ioctl_gem_pin(struct drm_device *dev, void *data,
++ struct drm_file *file_priv)
++{
++ printk(KERN_INFO "glamo_ioctl_gem_pin\n");
++ return 0;
++}
++
++
++int glamo_ioctl_gem_unpin(struct drm_device *dev, void *data,
++ struct drm_file *file_priv)
++{
++ printk(KERN_INFO "glamo_ioctl_gem_unpin\n");
++ return 0;
++}
++
++
++int glamo_ioctl_gem_pread(struct drm_device *dev, void *data,
++ struct drm_file *file_priv)
++{
++ printk(KERN_INFO "glamo_ioctl_gem_pread\n");
++ return 0;
++}
++
++
++int glamo_ioctl_gem_pwrite(struct drm_device *dev, void *data,
++ struct drm_file *file_priv)
++{
++ printk(KERN_INFO "glamo_ioctl_gem_pwrite\n");
++ return 0;
++}
++
++
++int glamodrm_gem_init_object(struct drm_gem_object *obj)
++{
++ struct drm_glamo_gem_object *gobj;
++
++ /* Allocate a private structure */
++ gobj = kzalloc(sizeof(*gobj), GFP_KERNEL);
++ if (!gobj) return -ENOMEM;
++
++ obj->driver_private = gobj;
++ gobj->obj = obj;
++
++ return 0;
++}
++
++
++void glamodrm_gem_free_object(struct drm_gem_object *obj)
++{
++ struct drm_glamo_gem_object *gobj;
++ struct drm_map_list *list;
++ struct drm_device *dev;
++ struct drm_gem_mm *mm;
++ struct drm_local_map *map;
++
++ dev = obj->dev;
++ mm = dev->mm_private;
++ gobj = obj->driver_private;
++
++ /* Free the VRAM */
++ if ( gobj->block != NULL ) {
++ drm_mm_put_block(gobj->block);
++ }
++
++ /* Release mappings */
++ list = &obj->map_list;
++ drm_ht_remove_item(&mm->offset_hash, &list->hash);
++ if (list->file_offset_node) {
++ drm_mm_put_block(list->file_offset_node);
++ list->file_offset_node = NULL;
++ }
++ map = list->map;
++ if (map) {
++ kfree(map);
++ list->map = NULL;
++ }
++
++ /* Free the private structure */
++ kfree(obj->driver_private);
++}
++
++
++/* Memory management initialisation */
++int glamo_buffer_init(struct glamodrm_handle *gdrm)
++{
++ gdrm->mmgr = kzalloc(sizeof(struct drm_mm), GFP_KERNEL);
++ drm_mm_init(gdrm->mmgr, 0, gdrm->vram_size);
++
++ /* Reserve a scratch buffer. We do this outside the protections
++ * of the other GEM code. To do this safely, the allocation must
++ * be a multiple of PAGE_SIZE. */
++ gdrm->scratch = drm_mm_search_free(gdrm->mmgr, PAGE_SIZE, 4, 1);
++ if ( gdrm->scratch ) {
++ gdrm->scratch = drm_mm_get_block(gdrm->scratch, PAGE_SIZE, 4);
++ }
++ if ( !gdrm->scratch ) {
++ printk(KERN_WARNING "[glamo-drm] Couldn't allocate"
++ " scratch buffer!\n");
++ }
++
++ return 0;
++}
++
++
++/* Memory management finalisation */
++int glamo_buffer_final(struct glamodrm_handle *gdrm)
++{
++ drm_mm_takedown(gdrm->mmgr);
++ kfree(gdrm->mmgr);
++ return 0;
++}
+diff --git a/drivers/mfd/glamo/glamo-buffer.h b/drivers/mfd/glamo/glamo-buffer.h
+new file mode 100644
+index 0000000..41f18fd
+--- /dev/null
++++ b/drivers/mfd/glamo/glamo-buffer.h
+@@ -0,0 +1,60 @@
++/*
++ * SMedia Glamo 336x/337x memory management
++ *
++ * Copyright (c) 2009 Thomas White <taw@bitwiz.org.uk>
++ *
++ * 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., 5