diff options
author | Alexandre Courbot <acourbot@nvidia.com> | 2014-02-17 10:17:26 +0400 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2014-03-26 08:08:04 +0400 |
commit | 420b94697722512a2c0732970dc1530197a49adb (patch) | |
tree | eb87f8b5ed60beac890dbe34ca884dc84dc6c765 /drivers/gpu/drm/nouveau/nouveau_drm.c | |
parent | 0b681687fe9eaa552059030a90897a78fea8f86a (diff) | |
download | linux-420b94697722512a2c0732970dc1530197a49adb.tar.xz |
support for platform devices
Upcoming mobile Kepler GPUs (such as GK20A) use the platform bus instead
of PCI to which Nouveau is tightly dependent. This patch allows Nouveau
to handle platform devices by:
- abstracting PCI-dependent functions that were typically used for
resource querying and page mapping,
- introducing a nv_device_is_pci() function that allows to make
PCI-dependent code conditional,
- providing a nouveau_drm_platform_probe() function that takes a GPU
platform device to be probed.
Core code as well as engine/subdev drivers are updated wherever possible
to make use of these functions. Some older drivers are too dependent on
PCI to be properly updated, but all newer code on which future chips may
depend should at least be runnable with platform devices.
Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau/nouveau_drm.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_drm.c | 59 |
1 files changed, 51 insertions, 8 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index eeadcac8e8f4..8f811a5f16e2 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -82,7 +82,7 @@ module_param_named(runpm, nouveau_runtime_pm, int, 0400); static struct drm_driver driver; static u64 -nouveau_name(struct pci_dev *pdev) +nouveau_pci_name(struct pci_dev *pdev) { u64 name = (u64)pci_domain_nr(pdev->bus) << 32; name |= pdev->bus->number << 16; @@ -90,15 +90,30 @@ nouveau_name(struct pci_dev *pdev) return name | PCI_FUNC(pdev->devfn); } +static u64 +nouveau_platform_name(struct platform_device *platformdev) +{ + return platformdev->id; +} + +static u64 +nouveau_name(struct drm_device *dev) +{ + if (dev->pdev) + return nouveau_pci_name(dev->pdev); + else + return nouveau_platform_name(dev->platformdev); +} + static int -nouveau_cli_create(struct pci_dev *pdev, const char *name, +nouveau_cli_create(u64 name, const char *sname, int size, void **pcli) { struct nouveau_cli *cli; int ret; *pcli = NULL; - ret = nouveau_client_create_(name, nouveau_name(pdev), nouveau_config, + ret = nouveau_client_create_(sname, name, nouveau_config, nouveau_debug, size, pcli); cli = *pcli; if (ret) { @@ -282,7 +297,8 @@ static int nouveau_drm_probe(struct pci_dev *pdev, remove_conflicting_framebuffers(aper, "nouveaufb", boot); kfree(aper); - ret = nouveau_device_create(pdev, nouveau_name(pdev), pci_name(pdev), + ret = nouveau_device_create(pdev, NOUVEAU_BUS_PCI, + nouveau_pci_name(pdev), pci_name(pdev), nouveau_config, nouveau_debug, &device); if (ret) return ret; @@ -305,6 +321,12 @@ nouveau_get_hdmi_dev(struct nouveau_drm *drm) { struct pci_dev *pdev = drm->dev->pdev; + if (!pdev) { + DRM_INFO("not a PCI device; no HDMI"); + drm->hdmi_device = NULL; + return; + } + /* subfunction one is a hdmi audio device? */ drm->hdmi_device = pci_get_bus_and_slot((unsigned int)pdev->bus->number, PCI_DEVFN(PCI_SLOT(pdev->devfn), 1)); @@ -330,7 +352,8 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags) struct nouveau_drm *drm; int ret; - ret = nouveau_cli_create(pdev, "DRM", sizeof(*drm), (void**)&drm); + ret = nouveau_cli_create(nouveau_name(dev), "DRM", sizeof(*drm), + (void **)&drm); if (ret) return ret; @@ -346,7 +369,7 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags) /* make sure AGP controller is in a consistent state before we * (possibly) execute vbios init tables (see nouveau_agp.h) */ - if (drm_pci_device_is_agp(dev) && dev->agp) { + if (pdev && drm_pci_device_is_agp(dev) && dev->agp) { /* dummy device object, doesn't init anything, but allows * agp code access to registers */ @@ -672,7 +695,6 @@ static int nouveau_pmops_thaw(struct device *dev) static int nouveau_drm_open(struct drm_device *dev, struct drm_file *fpriv) { - struct pci_dev *pdev = dev->pdev; struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_cli *cli; char name[32], tmpname[TASK_COMM_LEN]; @@ -686,7 +708,9 @@ nouveau_drm_open(struct drm_device *dev, struct drm_file *fpriv) get_task_comm(tmpname, current); snprintf(name, sizeof(name), "%s[%d]", tmpname, pid_nr(fpriv->pid)); - ret = nouveau_cli_create(pdev, name, sizeof(*cli), (void **)&cli); + ret = nouveau_cli_create(nouveau_name(dev), name, sizeof(*cli), + (void **)&cli); + if (ret) goto out_suspend; @@ -975,6 +999,25 @@ nouveau_drm_pci_driver = { .driver.pm = &nouveau_pm_ops, }; +int nouveau_drm_platform_probe(struct platform_device *pdev) +{ + struct nouveau_device *device; + int ret; + + ret = nouveau_device_create(pdev, NOUVEAU_BUS_PLATFORM, + nouveau_platform_name(pdev), + dev_name(&pdev->dev), nouveau_config, + nouveau_debug, &device); + + ret = drm_platform_init(&driver, pdev); + if (ret) { + nouveau_object_ref(NULL, (struct nouveau_object **)&device); + return ret; + } + + return ret; +} + static int __init nouveau_drm_init(void) { |