From 2ec20c69573ac255b3aefd4306f4aaed16c310bc Mon Sep 17 00:00:00 2001 From: Thomas White Date: Sat, 22 May 2010 18:59:58 +0200 Subject: [PATCH 1/8] 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 --- 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 305c590..7244cef 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 f7ba82e..30ce982 100644 --- a/drivers/gpu/drm/drm_bufs.c +++ b/drivers/gpu/drm/drm_bufs.c @@ -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); diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 4a66201..769d12b 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -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; 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 a0c365f..7e7eba6 100644 --- a/drivers/gpu/drm/drm_stub.c +++ b/drivers/gpu/drm/drm_stub.c @@ -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 diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c index 25bbd30..947e731 100644 --- a/drivers/gpu/drm/drm_sysfs.c +++ b/drivers/gpu/drm/drm_sysfs.c @@ -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; diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 2f3b3a0..43894ec 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -56,6 +56,7 @@ #include #include #include +#include #if defined(__alpha__) || defined(__powerpc__) #include /* 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); -- 1.7.1