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