Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 420b9469 authored by Alexandre Courbot's avatar Alexandre Courbot Committed by Ben Skeggs
Browse files

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: default avatarAlexandre Courbot <acourbot@nvidia.com>
Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent 0b681687
Loading
Loading
Loading
Loading
+78 −5
Original line number Diff line number Diff line
@@ -131,8 +131,8 @@ nouveau_devobj_ctor(struct nouveau_object *parent,
	if (ret)
		return ret;

	mmio_base = pci_resource_start(device->pdev, 0);
	mmio_size = pci_resource_len(device->pdev, 0);
	mmio_base = nv_device_resource_start(device, 0);
	mmio_size = nv_device_resource_len(device, 0);

	/* translate api disable mask into internal mapping */
	disable = args->debug0;
@@ -448,6 +448,72 @@ nouveau_device_dtor(struct nouveau_object *object)
	nouveau_engine_destroy(&device->base);
}

resource_size_t
nv_device_resource_start(struct nouveau_device *device, unsigned int bar)
{
	if (nv_device_is_pci(device)) {
		return pci_resource_start(device->pdev, bar);
	} else {
		struct resource *res;
		res = platform_get_resource(device->platformdev,
					    IORESOURCE_MEM, bar);
		if (!res)
			return 0;
		return res->start;
	}
}

resource_size_t
nv_device_resource_len(struct nouveau_device *device, unsigned int bar)
{
	if (nv_device_is_pci(device)) {
		return pci_resource_len(device->pdev, bar);
	} else {
		struct resource *res;
		res = platform_get_resource(device->platformdev,
					    IORESOURCE_MEM, bar);
		if (!res)
			return 0;
		return resource_size(res);
	}
}

dma_addr_t
nv_device_map_page(struct nouveau_device *device, struct page *page)
{
	dma_addr_t ret;

	if (nv_device_is_pci(device)) {
		ret = pci_map_page(device->pdev, page, 0, PAGE_SIZE,
				   PCI_DMA_BIDIRECTIONAL);
		if (pci_dma_mapping_error(device->pdev, ret))
			ret = 0;
	} else {
		ret = page_to_phys(page);
	}

	return ret;
}

void
nv_device_unmap_page(struct nouveau_device *device, dma_addr_t addr)
{
	if (nv_device_is_pci(device))
		pci_unmap_page(device->pdev, addr, PAGE_SIZE,
			       PCI_DMA_BIDIRECTIONAL);
}

int
nv_device_get_irq(struct nouveau_device *device, bool stall)
{
	if (nv_device_is_pci(device)) {
		return device->pdev->irq;
	} else {
		return platform_get_irq_byname(device->platformdev,
					       stall ? "stall" : "nonstall");
	}
}

static struct nouveau_oclass
nouveau_device_oclass = {
	.handle = NV_ENGINE(DEVICE, 0x00),
@@ -459,8 +525,8 @@ nouveau_device_oclass = {
};

int
nouveau_device_create_(struct pci_dev *pdev, u64 name, const char *sname,
		       const char *cfg, const char *dbg,
nouveau_device_create_(void *dev, enum nv_bus_type type, u64 name,
		       const char *sname, const char *cfg, const char *dbg,
		       int length, void **pobject)
{
	struct nouveau_device *device;
@@ -478,7 +544,14 @@ nouveau_device_create_(struct pci_dev *pdev, u64 name, const char *sname,
	if (ret)
		goto done;

	device->pdev = pdev;
	switch (type) {
	case NOUVEAU_BUS_PCI:
		device->pdev = dev;
		break;
	case NOUVEAU_BUS_PLATFORM:
		device->platformdev = dev;
		break;
	}
	device->handle = name;
	device->cfgopt = cfg;
	device->dbgopt = dbg;
+3 −3
Original line number Diff line number Diff line
@@ -119,7 +119,7 @@ _nouveau_falcon_init(struct nouveau_object *object)
		snprintf(name, sizeof(name), "nouveau/nv%02x_fuc%03x",
			 device->chipset, falcon->addr >> 12);

		ret = request_firmware(&fw, name, &device->pdev->dev);
		ret = request_firmware(&fw, name, nv_device_base(device));
		if (ret == 0) {
			falcon->code.data = vmemdup(fw->data, fw->size);
			falcon->code.size = fw->size;
@@ -138,7 +138,7 @@ _nouveau_falcon_init(struct nouveau_object *object)
		snprintf(name, sizeof(name), "nouveau/nv%02x_fuc%03xd",
			 device->chipset, falcon->addr >> 12);

		ret = request_firmware(&fw, name, &device->pdev->dev);
		ret = request_firmware(&fw, name, nv_device_base(device));
		if (ret) {
			nv_error(falcon, "unable to load firmware data\n");
			return ret;
@@ -153,7 +153,7 @@ _nouveau_falcon_init(struct nouveau_object *object)
		snprintf(name, sizeof(name), "nouveau/nv%02x_fuc%03xc",
			 device->chipset, falcon->addr >> 12);

		ret = request_firmware(&fw, name, &device->pdev->dev);
		ret = request_firmware(&fw, name, nv_device_base(device));
		if (ret) {
			nv_error(falcon, "unable to load firmware code\n");
			return ret;
+1 −1
Original line number Diff line number Diff line
@@ -86,7 +86,7 @@ nouveau_fifo_channel_create_(struct nouveau_object *parent,
	}

	/* map fifo control registers */
	chan->user = ioremap(pci_resource_start(device->pdev, bar) + addr +
	chan->user = ioremap(nv_device_resource_start(device, bar) + addr +
			     (chan->chid * size), size);
	if (!chan->user)
		return -EFAULT;
+1 −1
Original line number Diff line number Diff line
@@ -349,7 +349,7 @@ nv20_graph_init(struct nouveau_object *object)
	nv_wr32(priv, NV10_PGRAPH_SURFACE, tmp);

	/* begin RAM config */
	vramsz = pci_resource_len(nv_device(priv)->pdev, 0) - 1;
	vramsz = nv_device_resource_len(nv_device(priv), 0) - 1;
	nv_wr32(priv, 0x4009A4, nv_rd32(priv, 0x100200));
	nv_wr32(priv, 0x4009A8, nv_rd32(priv, 0x100204));
	nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0000);
+1 −1
Original line number Diff line number Diff line
@@ -484,7 +484,7 @@ nv40_graph_init(struct nouveau_object *object)
		engine->tile_prog(engine, i);

	/* begin RAM config */
	vramsz = pci_resource_len(nv_device(priv)->pdev, 0) - 1;
	vramsz = nv_device_resource_len(nv_device(priv), 0) - 1;
	switch (nv_device(priv)->chipset) {
	case 0x40:
		nv_wr32(priv, 0x4009A4, nv_rd32(priv, 0x100200));
Loading