10a34fb31SBen Skeggs /*
20a34fb31SBen Skeggs * Copyright 2015 Red Hat Inc.
30a34fb31SBen Skeggs *
40a34fb31SBen Skeggs * Permission is hereby granted, free of charge, to any person obtaining a
50a34fb31SBen Skeggs * copy of this software and associated documentation files (the "Software"),
60a34fb31SBen Skeggs * to deal in the Software without restriction, including without limitation
70a34fb31SBen Skeggs * the rights to use, copy, modify, merge, publish, distribute, sublicense,
80a34fb31SBen Skeggs * and/or sell copies of the Software, and to permit persons to whom the
90a34fb31SBen Skeggs * Software is furnished to do so, subject to the following conditions:
100a34fb31SBen Skeggs *
110a34fb31SBen Skeggs * The above copyright notice and this permission notice shall be included in
120a34fb31SBen Skeggs * all copies or substantial portions of the Software.
130a34fb31SBen Skeggs *
140a34fb31SBen Skeggs * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
150a34fb31SBen Skeggs * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
160a34fb31SBen Skeggs * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
170a34fb31SBen Skeggs * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
180a34fb31SBen Skeggs * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
190a34fb31SBen Skeggs * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
200a34fb31SBen Skeggs * OTHER DEALINGS IN THE SOFTWARE.
210a34fb31SBen Skeggs *
220a34fb31SBen Skeggs * Authors: Ben Skeggs <bskeggs@redhat.com>
230a34fb31SBen Skeggs */
240a34fb31SBen Skeggs #include "priv.h"
25340b0e7cSBen Skeggs #include "agp.h"
260a34fb31SBen Skeggs
272b700825SBen Skeggs #include <core/option.h>
282b700825SBen Skeggs #include <core/pci.h>
29*727fd72fSBen Skeggs
30*727fd72fSBen Skeggs void
nvkm_pci_msi_rearm(struct nvkm_device * device)31*727fd72fSBen Skeggs nvkm_pci_msi_rearm(struct nvkm_device *device)
32*727fd72fSBen Skeggs {
33*727fd72fSBen Skeggs struct nvkm_pci *pci = device->pci;
34*727fd72fSBen Skeggs
35*727fd72fSBen Skeggs if (pci && pci->msi)
36*727fd72fSBen Skeggs pci->func->msi_rearm(pci);
37*727fd72fSBen Skeggs }
382b700825SBen Skeggs
390a34fb31SBen Skeggs u32
nvkm_pci_rd32(struct nvkm_pci * pci,u16 addr)400a34fb31SBen Skeggs nvkm_pci_rd32(struct nvkm_pci *pci, u16 addr)
410a34fb31SBen Skeggs {
420a34fb31SBen Skeggs return pci->func->rd32(pci, addr);
430a34fb31SBen Skeggs }
440a34fb31SBen Skeggs
450a34fb31SBen Skeggs void
nvkm_pci_wr08(struct nvkm_pci * pci,u16 addr,u8 data)460a34fb31SBen Skeggs nvkm_pci_wr08(struct nvkm_pci *pci, u16 addr, u8 data)
470a34fb31SBen Skeggs {
480a34fb31SBen Skeggs pci->func->wr08(pci, addr, data);
490a34fb31SBen Skeggs }
500a34fb31SBen Skeggs
510a34fb31SBen Skeggs void
nvkm_pci_wr32(struct nvkm_pci * pci,u16 addr,u32 data)520a34fb31SBen Skeggs nvkm_pci_wr32(struct nvkm_pci *pci, u16 addr, u32 data)
530a34fb31SBen Skeggs {
540a34fb31SBen Skeggs pci->func->wr32(pci, addr, data);
550a34fb31SBen Skeggs }
560a34fb31SBen Skeggs
575d5b43f5SPierre Moreau u32
nvkm_pci_mask(struct nvkm_pci * pci,u16 addr,u32 mask,u32 value)585d5b43f5SPierre Moreau nvkm_pci_mask(struct nvkm_pci *pci, u16 addr, u32 mask, u32 value)
595d5b43f5SPierre Moreau {
605d5b43f5SPierre Moreau u32 data = pci->func->rd32(pci, addr);
615d5b43f5SPierre Moreau pci->func->wr32(pci, addr, (data & ~mask) | value);
625d5b43f5SPierre Moreau return data;
635d5b43f5SPierre Moreau }
645d5b43f5SPierre Moreau
650a34fb31SBen Skeggs void
nvkm_pci_rom_shadow(struct nvkm_pci * pci,bool shadow)660a34fb31SBen Skeggs nvkm_pci_rom_shadow(struct nvkm_pci *pci, bool shadow)
670a34fb31SBen Skeggs {
680a34fb31SBen Skeggs u32 data = nvkm_pci_rd32(pci, 0x0050);
690a34fb31SBen Skeggs if (shadow)
700a34fb31SBen Skeggs data |= 0x00000001;
710a34fb31SBen Skeggs else
720a34fb31SBen Skeggs data &= ~0x00000001;
730a34fb31SBen Skeggs nvkm_pci_wr32(pci, 0x0050, data);
740a34fb31SBen Skeggs }
750a34fb31SBen Skeggs
762b700825SBen Skeggs static int
nvkm_pci_fini(struct nvkm_subdev * subdev,bool suspend)772b700825SBen Skeggs nvkm_pci_fini(struct nvkm_subdev *subdev, bool suspend)
782b700825SBen Skeggs {
792b700825SBen Skeggs struct nvkm_pci *pci = nvkm_pci(subdev);
80340b0e7cSBen Skeggs
81340b0e7cSBen Skeggs if (pci->agp.bridge)
82340b0e7cSBen Skeggs nvkm_agp_fini(pci);
83340b0e7cSBen Skeggs
84340b0e7cSBen Skeggs return 0;
85340b0e7cSBen Skeggs }
86340b0e7cSBen Skeggs
87340b0e7cSBen Skeggs static int
nvkm_pci_preinit(struct nvkm_subdev * subdev)88340b0e7cSBen Skeggs nvkm_pci_preinit(struct nvkm_subdev *subdev)
89340b0e7cSBen Skeggs {
90340b0e7cSBen Skeggs struct nvkm_pci *pci = nvkm_pci(subdev);
91340b0e7cSBen Skeggs if (pci->agp.bridge)
92340b0e7cSBen Skeggs nvkm_agp_preinit(pci);
932b700825SBen Skeggs return 0;
942b700825SBen Skeggs }
952b700825SBen Skeggs
962b700825SBen Skeggs static int
nvkm_pci_oneinit(struct nvkm_subdev * subdev)97bcc19d9bSKarol Herbst nvkm_pci_oneinit(struct nvkm_subdev *subdev)
98bcc19d9bSKarol Herbst {
99bcc19d9bSKarol Herbst struct nvkm_pci *pci = nvkm_pci(subdev);
1000fd189a9SLyude Paul int ret;
1010fd189a9SLyude Paul
1020fd189a9SLyude Paul if (pci_is_pcie(pci->pdev)) {
1030fd189a9SLyude Paul ret = nvkm_pcie_oneinit(pci);
1040fd189a9SLyude Paul if (ret)
1050fd189a9SLyude Paul return ret;
1060fd189a9SLyude Paul }
1070fd189a9SLyude Paul
108bcc19d9bSKarol Herbst return 0;
109bcc19d9bSKarol Herbst }
110bcc19d9bSKarol Herbst
111bcc19d9bSKarol Herbst static int
nvkm_pci_init(struct nvkm_subdev * subdev)1122b700825SBen Skeggs nvkm_pci_init(struct nvkm_subdev *subdev)
1132b700825SBen Skeggs {
1142b700825SBen Skeggs struct nvkm_pci *pci = nvkm_pci(subdev);
1152b700825SBen Skeggs int ret;
1162b700825SBen Skeggs
117340b0e7cSBen Skeggs if (pci->agp.bridge) {
118340b0e7cSBen Skeggs ret = nvkm_agp_init(pci);
119340b0e7cSBen Skeggs if (ret)
120340b0e7cSBen Skeggs return ret;
121bcc19d9bSKarol Herbst } else if (pci_is_pcie(pci->pdev)) {
122bcc19d9bSKarol Herbst nvkm_pcie_init(pci);
123340b0e7cSBen Skeggs }
124340b0e7cSBen Skeggs
125779d16aaSBen Skeggs if (pci->func->init)
126779d16aaSBen Skeggs pci->func->init(pci);
127779d16aaSBen Skeggs
128a121027dSKarol Herbst /* Ensure MSI interrupts are armed, for the case where there are
129a121027dSKarol Herbst * already interrupts pending (for whatever reason) at load time.
130a121027dSKarol Herbst */
131a121027dSKarol Herbst if (pci->msi)
132a121027dSKarol Herbst pci->func->msi_rearm(pci);
133a121027dSKarol Herbst
1340fd189a9SLyude Paul return 0;
1350a34fb31SBen Skeggs }
1360a34fb31SBen Skeggs
1370a34fb31SBen Skeggs static void *
nvkm_pci_dtor(struct nvkm_subdev * subdev)1380a34fb31SBen Skeggs nvkm_pci_dtor(struct nvkm_subdev *subdev)
1390a34fb31SBen Skeggs {
1402b700825SBen Skeggs struct nvkm_pci *pci = nvkm_pci(subdev);
1410fd189a9SLyude Paul
142340b0e7cSBen Skeggs nvkm_agp_dtor(pci);
1430fd189a9SLyude Paul
1442b700825SBen Skeggs if (pci->msi)
1452b700825SBen Skeggs pci_disable_msi(pci->pdev);
1460fd189a9SLyude Paul
1470a34fb31SBen Skeggs return nvkm_pci(subdev);
1480a34fb31SBen Skeggs }
1490a34fb31SBen Skeggs
1500a34fb31SBen Skeggs static const struct nvkm_subdev_func
1510a34fb31SBen Skeggs nvkm_pci_func = {
1520a34fb31SBen Skeggs .dtor = nvkm_pci_dtor,
153bcc19d9bSKarol Herbst .oneinit = nvkm_pci_oneinit,
154340b0e7cSBen Skeggs .preinit = nvkm_pci_preinit,
1552b700825SBen Skeggs .init = nvkm_pci_init,
1562b700825SBen Skeggs .fini = nvkm_pci_fini,
1570a34fb31SBen Skeggs };
1580a34fb31SBen Skeggs
1590a34fb31SBen Skeggs int
nvkm_pci_new_(const struct nvkm_pci_func * func,struct nvkm_device * device,enum nvkm_subdev_type type,int inst,struct nvkm_pci ** ppci)1600a34fb31SBen Skeggs nvkm_pci_new_(const struct nvkm_pci_func *func, struct nvkm_device *device,
1619b70cd54SBen Skeggs enum nvkm_subdev_type type, int inst, struct nvkm_pci **ppci)
1620a34fb31SBen Skeggs {
1630a34fb31SBen Skeggs struct nvkm_pci *pci;
1642b700825SBen Skeggs
1650a34fb31SBen Skeggs if (!(pci = *ppci = kzalloc(sizeof(**ppci), GFP_KERNEL)))
1660a34fb31SBen Skeggs return -ENOMEM;
1679b70cd54SBen Skeggs nvkm_subdev_ctor(&nvkm_pci_func, device, type, inst, &pci->subdev);
1680a34fb31SBen Skeggs pci->func = func;
1692b700825SBen Skeggs pci->pdev = device->func->pci(device)->pdev;
170bcc19d9bSKarol Herbst pci->pcie.speed = -1;
171bcc19d9bSKarol Herbst pci->pcie.width = -1;
1722b700825SBen Skeggs
173340b0e7cSBen Skeggs if (device->type == NVKM_DEVICE_AGP)
174340b0e7cSBen Skeggs nvkm_agp_ctor(pci);
175340b0e7cSBen Skeggs
1762b700825SBen Skeggs switch (pci->pdev->device & 0x0ff0) {
1772b700825SBen Skeggs case 0x00f0:
1782b700825SBen Skeggs case 0x02e0:
1792b700825SBen Skeggs /* BR02? NFI how these would be handled yet exactly */
1802b700825SBen Skeggs break;
1812b700825SBen Skeggs default:
1822b700825SBen Skeggs switch (device->chipset) {
1832b700825SBen Skeggs case 0xaa:
1842b700825SBen Skeggs /* reported broken, nv also disable it */
1852b700825SBen Skeggs break;
1862b700825SBen Skeggs default:
1872b700825SBen Skeggs pci->msi = true;
1882b700825SBen Skeggs break;
1892b700825SBen Skeggs }
1902b700825SBen Skeggs }
1912b700825SBen Skeggs
192bc60c90fSIlia Mirkin #ifdef __BIG_ENDIAN
193bc60c90fSIlia Mirkin pci->msi = false;
194bc60c90fSIlia Mirkin #endif
195bc60c90fSIlia Mirkin
1962b700825SBen Skeggs pci->msi = nvkm_boolopt(device->cfgopt, "NvMSI", pci->msi);
1972b700825SBen Skeggs if (pci->msi && func->msi_rearm) {
1982b700825SBen Skeggs pci->msi = pci_enable_msi(pci->pdev) == 0;
1992b700825SBen Skeggs if (pci->msi)
2002b700825SBen Skeggs nvkm_debug(&pci->subdev, "MSI enabled\n");
2012b700825SBen Skeggs } else {
2022b700825SBen Skeggs pci->msi = false;
2032b700825SBen Skeggs }
2042b700825SBen Skeggs
2050a34fb31SBen Skeggs return 0;
2060a34fb31SBen Skeggs }
207