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 * Authors: Ben Skeggs
23c39f472eSBen Skeggs */
24c39f472eSBen Skeggs #include "priv.h"
25d7e5fcd2SBen Skeggs
26c39f472eSBen Skeggs #include <core/option.h>
27583f8e4eSBen Skeggs #include <subdev/top.h>
28c39f472eSBen Skeggs
2954dcadd5SBen Skeggs void
nvkm_mc_unk260(struct nvkm_device * device,u32 data)30d3981190SBen Skeggs nvkm_mc_unk260(struct nvkm_device *device, u32 data)
31c39f472eSBen Skeggs {
32d3981190SBen Skeggs struct nvkm_mc *mc = device->mc;
33d3981190SBen Skeggs if (likely(mc) && mc->func->unk260)
3454dcadd5SBen Skeggs mc->func->unk260(mc, data);
35c39f472eSBen Skeggs }
36c39f472eSBen Skeggs
37d4c4cc83SBen Skeggs void
nvkm_mc_intr_mask(struct nvkm_device * device,enum nvkm_subdev_type type,int inst,bool en)38a35047baSBen Skeggs nvkm_mc_intr_mask(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, bool en)
3966adbfb0SBen Skeggs {
40fe76fe49SBen Skeggs struct nvkm_subdev *subdev = nvkm_device_subdev(device, type, inst);
4166adbfb0SBen Skeggs
42209ec1b8SBen Skeggs if (subdev) {
43fe76fe49SBen Skeggs if (en)
44fe76fe49SBen Skeggs nvkm_intr_allow(subdev, NVKM_INTR_SUBDEV);
45fe76fe49SBen Skeggs else
46fe76fe49SBen Skeggs nvkm_intr_block(subdev, NVKM_INTR_SUBDEV);
47209ec1b8SBen Skeggs }
48209ec1b8SBen Skeggs }
49c39f472eSBen Skeggs
503c2a536bSBen Skeggs static u32
nvkm_mc_reset_mask(struct nvkm_device * device,bool isauto,enum nvkm_subdev_type type,int inst)516997ea13SBen Skeggs nvkm_mc_reset_mask(struct nvkm_device *device, bool isauto, enum nvkm_subdev_type type, int inst)
526defde5aSBen Skeggs {
533c2a536bSBen Skeggs struct nvkm_mc *mc = device->mc;
5470b01f07SBen Skeggs const struct nvkm_mc_map *map;
553c2a536bSBen Skeggs u64 pmc_enable = 0;
563c2a536bSBen Skeggs if (likely(mc)) {
576997ea13SBen Skeggs if (!(pmc_enable = nvkm_top_reset(device, type, inst))) {
5870b01f07SBen Skeggs for (map = mc->func->reset; map && map->stat; map++) {
593c2a536bSBen Skeggs if (!isauto || !map->noauto) {
606997ea13SBen Skeggs if (map->type == type && map->inst == inst) {
6170b01f07SBen Skeggs pmc_enable = map->stat;
6270b01f07SBen Skeggs break;
6370b01f07SBen Skeggs }
6470b01f07SBen Skeggs }
65583f8e4eSBen Skeggs }
663c2a536bSBen Skeggs }
673c2a536bSBen Skeggs }
683c2a536bSBen Skeggs return pmc_enable;
693c2a536bSBen Skeggs }
7070b01f07SBen Skeggs
713c2a536bSBen Skeggs void
nvkm_mc_reset(struct nvkm_device * device,enum nvkm_subdev_type type,int inst)726997ea13SBen Skeggs nvkm_mc_reset(struct nvkm_device *device, enum nvkm_subdev_type type, int inst)
733c2a536bSBen Skeggs {
746997ea13SBen Skeggs u64 pmc_enable = nvkm_mc_reset_mask(device, true, type, inst);
756defde5aSBen Skeggs if (pmc_enable) {
76*ebb195dbSBen Skeggs device->mc->func->device->disable(device->mc, pmc_enable);
77*ebb195dbSBen Skeggs device->mc->func->device->enable(device->mc, pmc_enable);
786defde5aSBen Skeggs }
796defde5aSBen Skeggs }
806defde5aSBen Skeggs
816defde5aSBen Skeggs void
nvkm_mc_disable(struct nvkm_device * device,enum nvkm_subdev_type type,int inst)826997ea13SBen Skeggs nvkm_mc_disable(struct nvkm_device *device, enum nvkm_subdev_type type, int inst)
836defde5aSBen Skeggs {
846997ea13SBen Skeggs u64 pmc_enable = nvkm_mc_reset_mask(device, false, type, inst);
853c2a536bSBen Skeggs if (pmc_enable)
86*ebb195dbSBen Skeggs device->mc->func->device->disable(device->mc, pmc_enable);
873c2a536bSBen Skeggs }
883c2a536bSBen Skeggs
893c2a536bSBen Skeggs void
nvkm_mc_enable(struct nvkm_device * device,enum nvkm_subdev_type type,int inst)906997ea13SBen Skeggs nvkm_mc_enable(struct nvkm_device *device, enum nvkm_subdev_type type, int inst)
913c2a536bSBen Skeggs {
926997ea13SBen Skeggs u64 pmc_enable = nvkm_mc_reset_mask(device, false, type, inst);
93*ebb195dbSBen Skeggs if (pmc_enable)
94*ebb195dbSBen Skeggs device->mc->func->device->enable(device->mc, pmc_enable);
956defde5aSBen Skeggs }
966defde5aSBen Skeggs
97c599dd4bSAlexandre Courbot bool
nvkm_mc_enabled(struct nvkm_device * device,enum nvkm_subdev_type type,int inst)986997ea13SBen Skeggs nvkm_mc_enabled(struct nvkm_device *device, enum nvkm_subdev_type type, int inst)
99c599dd4bSAlexandre Courbot {
1006997ea13SBen Skeggs u64 pmc_enable = nvkm_mc_reset_mask(device, false, type, inst);
101c599dd4bSAlexandre Courbot
102*ebb195dbSBen Skeggs return (pmc_enable != 0) && device->mc->func->device->enabled(device->mc, pmc_enable);
103c599dd4bSAlexandre Courbot }
104c599dd4bSAlexandre Courbot
10554dcadd5SBen Skeggs static int
nvkm_mc_init(struct nvkm_subdev * subdev)10654dcadd5SBen Skeggs nvkm_mc_init(struct nvkm_subdev *subdev)
10754dcadd5SBen Skeggs {
10854dcadd5SBen Skeggs struct nvkm_mc *mc = nvkm_mc(subdev);
10954dcadd5SBen Skeggs if (mc->func->init)
11054dcadd5SBen Skeggs mc->func->init(mc);
111c39f472eSBen Skeggs return 0;
112c39f472eSBen Skeggs }
113c39f472eSBen Skeggs
11454dcadd5SBen Skeggs static void *
nvkm_mc_dtor(struct nvkm_subdev * subdev)11554dcadd5SBen Skeggs nvkm_mc_dtor(struct nvkm_subdev *subdev)
116c39f472eSBen Skeggs {
1172b700825SBen Skeggs return nvkm_mc(subdev);
118c39f472eSBen Skeggs }
119c39f472eSBen Skeggs
12054dcadd5SBen Skeggs static const struct nvkm_subdev_func
12154dcadd5SBen Skeggs nvkm_mc = {
12254dcadd5SBen Skeggs .dtor = nvkm_mc_dtor,
12354dcadd5SBen Skeggs .init = nvkm_mc_init,
12454dcadd5SBen Skeggs };
12554dcadd5SBen Skeggs
126c39f472eSBen Skeggs int
nvkm_mc_new_(const struct nvkm_mc_func * func,struct nvkm_device * device,enum nvkm_subdev_type type,int inst,struct nvkm_mc ** pmc)12754dcadd5SBen Skeggs nvkm_mc_new_(const struct nvkm_mc_func *func, struct nvkm_device *device,
1281fc2fddfSBen Skeggs enum nvkm_subdev_type type, int inst, struct nvkm_mc **pmc)
129c39f472eSBen Skeggs {
1302ca0ddbcSBen Skeggs struct nvkm_mc *mc;
131fe76fe49SBen Skeggs int ret;
132fe76fe49SBen Skeggs
13354dcadd5SBen Skeggs if (!(mc = *pmc = kzalloc(sizeof(*mc), GFP_KERNEL)))
13454dcadd5SBen Skeggs return -ENOMEM;
135fe76fe49SBen Skeggs
136fe76fe49SBen Skeggs nvkm_subdev_ctor(&nvkm_mc, device, type, inst, &mc->subdev);
137fe76fe49SBen Skeggs mc->func = func;
138fe76fe49SBen Skeggs
139fe76fe49SBen Skeggs if (mc->func->intr) {
140fe76fe49SBen Skeggs ret = nvkm_intr_add(mc->func->intr, mc->func->intrs, &mc->subdev,
141fe76fe49SBen Skeggs mc->func->intr_nonstall ? 2 : 1, &mc->intr);
142fe76fe49SBen Skeggs if (ret)
143fe76fe49SBen Skeggs return ret;
144fe76fe49SBen Skeggs }
145fe76fe49SBen Skeggs
146c39f472eSBen Skeggs return 0;
147c39f472eSBen Skeggs }
148