1 /*
2  * Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20  * DEALINGS IN THE SOFTWARE.
21  */
22 #include "priv.h"
23 
24 #include <core/msgqueue.h>
25 #include <subdev/top.h>
26 #include <engine/falcon.h>
27 
28 static void *
29 nvkm_sec2_dtor(struct nvkm_engine *engine)
30 {
31 	struct nvkm_sec2 *sec2 = nvkm_sec2(engine);
32 	nvkm_msgqueue_del(&sec2->queue);
33 	nvkm_falcon_del(&sec2->falcon);
34 	return sec2;
35 }
36 
37 static void
38 nvkm_sec2_intr(struct nvkm_engine *engine)
39 {
40 	struct nvkm_sec2 *sec2 = nvkm_sec2(engine);
41 	struct nvkm_subdev *subdev = &engine->subdev;
42 	struct nvkm_device *device = subdev->device;
43 	u32 disp = nvkm_rd32(device, sec2->addr + 0x01c);
44 	u32 intr = nvkm_rd32(device, sec2->addr + 0x008) & disp & ~(disp >> 16);
45 
46 	if (intr & 0x00000040) {
47 		schedule_work(&sec2->work);
48 		nvkm_wr32(device, sec2->addr + 0x004, 0x00000040);
49 		intr &= ~0x00000040;
50 	}
51 
52 	if (intr) {
53 		nvkm_error(subdev, "unhandled intr %08x\n", intr);
54 		nvkm_wr32(device, sec2->addr + 0x004, intr);
55 
56 	}
57 }
58 
59 static void
60 nvkm_sec2_recv(struct work_struct *work)
61 {
62 	struct nvkm_sec2 *sec2 = container_of(work, typeof(*sec2), work);
63 
64 	if (!sec2->queue) {
65 		nvkm_warn(&sec2->engine.subdev,
66 			  "recv function called while no firmware set!\n");
67 		return;
68 	}
69 
70 	nvkm_msgqueue_recv(sec2->queue);
71 }
72 
73 
74 static int
75 nvkm_sec2_oneinit(struct nvkm_engine *engine)
76 {
77 	struct nvkm_sec2 *sec2 = nvkm_sec2(engine);
78 	struct nvkm_subdev *subdev = &sec2->engine.subdev;
79 
80 	if (!sec2->addr) {
81 		sec2->addr = nvkm_top_addr(subdev->device, subdev->index);
82 		if (WARN_ON(!sec2->addr))
83 			return -EINVAL;
84 	}
85 
86 	return nvkm_falcon_v1_new(subdev, "SEC2", sec2->addr, &sec2->falcon);
87 }
88 
89 static int
90 nvkm_sec2_fini(struct nvkm_engine *engine, bool suspend)
91 {
92 	struct nvkm_sec2 *sec2 = nvkm_sec2(engine);
93 	flush_work(&sec2->work);
94 	return 0;
95 }
96 
97 static const struct nvkm_engine_func
98 nvkm_sec2 = {
99 	.dtor = nvkm_sec2_dtor,
100 	.oneinit = nvkm_sec2_oneinit,
101 	.fini = nvkm_sec2_fini,
102 	.intr = nvkm_sec2_intr,
103 };
104 
105 int
106 nvkm_sec2_new_(struct nvkm_device *device, int index, u32 addr,
107 	       struct nvkm_sec2 **psec2)
108 {
109 	struct nvkm_sec2 *sec2;
110 
111 	if (!(sec2 = *psec2 = kzalloc(sizeof(*sec2), GFP_KERNEL)))
112 		return -ENOMEM;
113 	sec2->addr = addr;
114 	INIT_WORK(&sec2->work, nvkm_sec2_recv);
115 
116 	return nvkm_engine_ctor(&nvkm_sec2, device, index, true, &sec2->engine);
117 };
118