DRM for platform devices
authorThomas White <taw@bitwiz.org.uk>
Sat, 22 May 2010 16:59:58 +0000 (18:59 +0200)
committerThomas White <taw@bitwiz.org.uk>
Sat, 22 May 2010 16:59:58 +0000 (18:59 +0200)
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
drivers/gpu/drm/drm_bufs.c
drivers/gpu/drm/drm_drv.c
drivers/gpu/drm/drm_info.c
drivers/gpu/drm/drm_ioctl.c
drivers/gpu/drm/drm_stub.c
drivers/gpu/drm/drm_sysfs.c
include/drm/drmP.h

index 305c590..7244cef 100644 (file)
@@ -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
index f7ba82e..30ce982 100644 (file)
@@ -189,7 +189,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);
index 4a66201..769d12b 100644 (file)
@@ -250,6 +250,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;
@@ -283,11 +284,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;
index f0f6c6b..838c2ee 100644 (file)
@@ -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
-
index 9b9ff46..133ef29 100644 (file)
@@ -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;
 }
index a0c365f..7e7eba6 100644 (file)
@@ -246,8 +246,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;
@@ -465,6 +467,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 = kzalloc(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
index 25bbd30..947e731 100644 (file)
@@ -488,7 +488,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;
index 2f3b3a0..43894ec 100644 (file)
@@ -56,6 +56,7 @@
 #include <linux/cdev.h>
 #include <linux/mutex.h>
 #include <linux/slab.h>
+#include <linux/platform_device.h>
 #if defined(__alpha__) || defined(__powerpc__)
 #include <asm/pgtable.h>       /* For pte_wrprotect */
 #endif
@@ -144,6 +145,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... */
@@ -1014,6 +1016,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 */
@@ -1124,12 +1127,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 long drm_ioctl(struct file *filp,
                      unsigned int cmd, unsigned long arg);
@@ -1350,6 +1361,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);