1c39f472eSBen Skeggs /*
2c39f472eSBen Skeggs * Copyright 2012 Red Hat Inc.
3c39f472eSBen Skeggs *
4c39f472eSBen Skeggs * Permission is hereby granted, free of charge, to any person obtaining a
5c39f472eSBen Skeggs * copy of this software and associated documentation files (the "Software"),
6c39f472eSBen Skeggs * to deal in the Software without restriction, including without limitation
7c39f472eSBen Skeggs * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8c39f472eSBen Skeggs * and/or sell copies of the Software, and to permit persons to whom the
9c39f472eSBen Skeggs * Software is furnished to do so, subject to the following conditions:
10c39f472eSBen Skeggs *
11c39f472eSBen Skeggs * The above copyright notice and this permission notice shall be included in
12c39f472eSBen Skeggs * all copies or substantial portions of the Software.
13c39f472eSBen Skeggs *
14c39f472eSBen Skeggs * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15c39f472eSBen Skeggs * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16c39f472eSBen Skeggs * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17c39f472eSBen Skeggs * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18c39f472eSBen Skeggs * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19c39f472eSBen Skeggs * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20c39f472eSBen Skeggs * OTHER DEALINGS IN THE SOFTWARE.
21c39f472eSBen Skeggs *
22c39f472eSBen Skeggs */
23c39f472eSBen Skeggs #include "priv.h"
24c39f472eSBen Skeggs
2526c9e8efSBen Skeggs #include <core/pci.h>
2626c9e8efSBen Skeggs
27c39f472eSBen Skeggs struct priv {
28c39f472eSBen Skeggs struct pci_dev *pdev;
29c39f472eSBen Skeggs void __iomem *rom;
30c39f472eSBen Skeggs size_t size;
31c39f472eSBen Skeggs };
32c39f472eSBen Skeggs
33c39f472eSBen Skeggs static u32
pcirom_read(void * data,u32 offset,u32 length,struct nvkm_bios * bios)34d390b480SBen Skeggs pcirom_read(void *data, u32 offset, u32 length, struct nvkm_bios *bios)
35c39f472eSBen Skeggs {
36c39f472eSBen Skeggs struct priv *priv = data;
37c39f472eSBen Skeggs if (offset + length <= priv->size) {
38c39f472eSBen Skeggs memcpy_fromio(bios->data + offset, priv->rom + offset, length);
39c39f472eSBen Skeggs return length;
40c39f472eSBen Skeggs }
41c39f472eSBen Skeggs return 0;
42c39f472eSBen Skeggs }
43c39f472eSBen Skeggs
44c39f472eSBen Skeggs static void
pcirom_fini(void * data)45c39f472eSBen Skeggs pcirom_fini(void *data)
46c39f472eSBen Skeggs {
47c39f472eSBen Skeggs struct priv *priv = data;
48c39f472eSBen Skeggs pci_unmap_rom(priv->pdev, priv->rom);
49c39f472eSBen Skeggs pci_disable_rom(priv->pdev);
50c39f472eSBen Skeggs kfree(priv);
51c39f472eSBen Skeggs }
52c39f472eSBen Skeggs
53c39f472eSBen Skeggs static void *
pcirom_init(struct nvkm_bios * bios,const char * name)54d390b480SBen Skeggs pcirom_init(struct nvkm_bios *bios, const char *name)
55c39f472eSBen Skeggs {
5626c9e8efSBen Skeggs struct nvkm_device *device = bios->subdev.device;
57c39f472eSBen Skeggs struct priv *priv = NULL;
5826c9e8efSBen Skeggs struct pci_dev *pdev;
59c39f472eSBen Skeggs int ret;
60c39f472eSBen Skeggs
6126c9e8efSBen Skeggs if (device->func->pci)
6226c9e8efSBen Skeggs pdev = device->func->pci(device)->pdev;
6326c9e8efSBen Skeggs else
6426c9e8efSBen Skeggs return ERR_PTR(-ENODEV);
6526c9e8efSBen Skeggs
66c39f472eSBen Skeggs if (!(ret = pci_enable_rom(pdev))) {
67c39f472eSBen Skeggs if (ret = -ENOMEM,
68c39f472eSBen Skeggs (priv = kmalloc(sizeof(*priv), GFP_KERNEL))) {
69c39f472eSBen Skeggs if (ret = -EFAULT,
70c39f472eSBen Skeggs (priv->rom = pci_map_rom(pdev, &priv->size))) {
71c39f472eSBen Skeggs priv->pdev = pdev;
72c39f472eSBen Skeggs return priv;
73c39f472eSBen Skeggs }
74c39f472eSBen Skeggs kfree(priv);
75c39f472eSBen Skeggs }
76c39f472eSBen Skeggs pci_disable_rom(pdev);
77c39f472eSBen Skeggs }
78c39f472eSBen Skeggs
79c39f472eSBen Skeggs return ERR_PTR(ret);
80c39f472eSBen Skeggs }
81c39f472eSBen Skeggs
82c39f472eSBen Skeggs const struct nvbios_source
83c39f472eSBen Skeggs nvbios_pcirom = {
84c39f472eSBen Skeggs .name = "PCIROM",
85c39f472eSBen Skeggs .init = pcirom_init,
86c39f472eSBen Skeggs .fini = pcirom_fini,
87c39f472eSBen Skeggs .read = pcirom_read,
88c39f472eSBen Skeggs .rw = true,
89c39f472eSBen Skeggs };
90c39f472eSBen Skeggs
91c39f472eSBen Skeggs static void *
platform_init(struct nvkm_bios * bios,const char * name)92d390b480SBen Skeggs platform_init(struct nvkm_bios *bios, const char *name)
93c39f472eSBen Skeggs {
9426c9e8efSBen Skeggs struct nvkm_device *device = bios->subdev.device;
9526c9e8efSBen Skeggs struct pci_dev *pdev;
96c39f472eSBen Skeggs struct priv *priv;
97c39f472eSBen Skeggs int ret = -ENOMEM;
98c39f472eSBen Skeggs
9926c9e8efSBen Skeggs if (device->func->pci)
10026c9e8efSBen Skeggs pdev = device->func->pci(device)->pdev;
10126c9e8efSBen Skeggs else
10226c9e8efSBen Skeggs return ERR_PTR(-ENODEV);
10326c9e8efSBen Skeggs
10472e0ef0eSMikel Rychliski if (!pdev->rom || pdev->romlen == 0)
10572e0ef0eSMikel Rychliski return ERR_PTR(-ENODEV);
10672e0ef0eSMikel Rychliski
107c39f472eSBen Skeggs if ((priv = kmalloc(sizeof(*priv), GFP_KERNEL))) {
10872e0ef0eSMikel Rychliski priv->size = pdev->romlen;
109c39f472eSBen Skeggs if (ret = -ENODEV,
11072e0ef0eSMikel Rychliski (priv->rom = ioremap(pdev->rom, pdev->romlen)))
111c39f472eSBen Skeggs return priv;
112c39f472eSBen Skeggs kfree(priv);
113c39f472eSBen Skeggs }
114c39f472eSBen Skeggs
115c39f472eSBen Skeggs return ERR_PTR(ret);
116c39f472eSBen Skeggs }
117c39f472eSBen Skeggs
11872e0ef0eSMikel Rychliski static void
platform_fini(void * data)11972e0ef0eSMikel Rychliski platform_fini(void *data)
12072e0ef0eSMikel Rychliski {
12172e0ef0eSMikel Rychliski struct priv *priv = data;
12272e0ef0eSMikel Rychliski
12372e0ef0eSMikel Rychliski iounmap(priv->rom);
12472e0ef0eSMikel Rychliski kfree(priv);
12572e0ef0eSMikel Rychliski }
12672e0ef0eSMikel Rychliski
127c39f472eSBen Skeggs const struct nvbios_source
128c39f472eSBen Skeggs nvbios_platform = {
129c39f472eSBen Skeggs .name = "PLATFORM",
130c39f472eSBen Skeggs .init = platform_init,
13172e0ef0eSMikel Rychliski .fini = platform_fini,
132c39f472eSBen Skeggs .read = pcirom_read,
133c39f472eSBen Skeggs .rw = true,
134c39f472eSBen Skeggs };
135