xref: /linux/drivers/gpu/drm/nouveau/nvkm/falcon/gm200.c (revision 0e44c21708761977dcbea9b846b51a6fb684907a)
1 /*
2  * Copyright 2022 Red Hat Inc.
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 COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20  * OTHER DEALINGS IN THE SOFTWARE.
21  */
22 #include "priv.h"
23 
24 #include <subdev/mc.h>
25 #include <subdev/timer.h>
26 
27 static void
28 gm200_flcn_pio_dmem_wr(struct nvkm_falcon *falcon, u8 port, const u8 *img, int len, u16 tag)
29 {
30 	while (len >= 4) {
31 		nvkm_falcon_wr32(falcon, 0x1c4 + (port * 8), *(u32 *)img);
32 		img += 4;
33 		len -= 4;
34 	}
35 }
36 
37 static void
38 gm200_flcn_pio_dmem_wr_init(struct nvkm_falcon *falcon, u8 port, bool sec, u32 dmem_base)
39 {
40 	nvkm_falcon_wr32(falcon, 0x1c0 + (port * 8), BIT(24) | dmem_base);
41 }
42 
43 const struct nvkm_falcon_func_pio
44 gm200_flcn_dmem_pio = {
45 	.min = 4,
46 	.max = 0x100,
47 	.wr_init = gm200_flcn_pio_dmem_wr_init,
48 	.wr = gm200_flcn_pio_dmem_wr,
49 };
50 
51 static void
52 gm200_flcn_pio_imem_wr_init(struct nvkm_falcon *falcon, u8 port, bool sec, u32 imem_base)
53 {
54 	nvkm_falcon_wr32(falcon, 0x180 + (port * 0x10), (sec ? BIT(28) : 0) | BIT(24) | imem_base);
55 }
56 
57 static void
58 gm200_flcn_pio_imem_wr(struct nvkm_falcon *falcon, u8 port, const u8 *img, int len, u16 tag)
59 {
60 	nvkm_falcon_wr32(falcon, 0x188 + (port * 0x10), tag++);
61 	while (len >= 4) {
62 		nvkm_falcon_wr32(falcon, 0x184 + (port * 0x10), *(u32 *)img);
63 		img += 4;
64 		len -= 4;
65 	}
66 }
67 
68 const struct nvkm_falcon_func_pio
69 gm200_flcn_imem_pio = {
70 	.min = 0x100,
71 	.max = 0x100,
72 	.wr_init = gm200_flcn_pio_imem_wr_init,
73 	.wr = gm200_flcn_pio_imem_wr,
74 };
75 
76 int
77 gm200_flcn_reset_wait_mem_scrubbing(struct nvkm_falcon *falcon)
78 {
79 	nvkm_falcon_mask(falcon, 0x040, 0x00000000, 0x00000000);
80 
81 	if (nvkm_msec(falcon->owner->device, 10,
82 		if (!(nvkm_falcon_rd32(falcon, 0x10c) & 0x00000006))
83 			break;
84 	) < 0)
85 		return -ETIMEDOUT;
86 
87 	return 0;
88 }
89 
90 int
91 gm200_flcn_enable(struct nvkm_falcon *falcon)
92 {
93 	struct nvkm_device *device = falcon->owner->device;
94 	int ret;
95 
96 	if (falcon->func->reset_eng) {
97 		ret = falcon->func->reset_eng(falcon);
98 		if (ret)
99 			return ret;
100 	}
101 
102 	if (falcon->func->reset_pmc)
103 		nvkm_mc_enable(device, falcon->owner->type, falcon->owner->inst);
104 
105 	ret = falcon->func->reset_wait_mem_scrubbing(falcon);
106 	if (ret)
107 		return ret;
108 
109 	nvkm_falcon_wr32(falcon, 0x084, nvkm_rd32(device, 0x000000));
110 	return 0;
111 }
112 
113 int
114 gm200_flcn_disable(struct nvkm_falcon *falcon)
115 {
116 	struct nvkm_device *device = falcon->owner->device;
117 	int ret;
118 
119 	nvkm_falcon_mask(falcon, 0x048, 0x00000003, 0x00000000);
120 	nvkm_falcon_wr32(falcon, 0x014, 0xffffffff);
121 
122 	if (falcon->func->reset_pmc)
123 		nvkm_mc_disable(device, falcon->owner->type, falcon->owner->inst);
124 
125 	if (falcon->func->reset_eng) {
126 		ret = falcon->func->reset_eng(falcon);
127 		if (ret)
128 			return ret;
129 	}
130 
131 	return 0;
132 }
133 
134 int
135 gm200_flcn_fw_boot(struct nvkm_falcon_fw *fw, u32 *pmbox0, u32 *pmbox1, u32 mbox0_ok, u32 irqsclr)
136 {
137 	struct nvkm_falcon *falcon = fw->falcon;
138 	u32 mbox0, mbox1;
139 	int ret = 0;
140 
141 	nvkm_falcon_wr32(falcon, 0x040, pmbox0 ? *pmbox0 : 0xcafebeef);
142 	if (pmbox1)
143 		nvkm_falcon_wr32(falcon, 0x044, *pmbox1);
144 
145 	nvkm_falcon_wr32(falcon, 0x104, fw->boot_addr);
146 	nvkm_falcon_wr32(falcon, 0x100, 0x00000002);
147 
148 	if (nvkm_msec(falcon->owner->device, 2000,
149 		if (nvkm_falcon_rd32(falcon, 0x100) & 0x00000010)
150 			break;
151 	) < 0)
152 		ret = -ETIMEDOUT;
153 
154 	mbox0 = nvkm_falcon_rd32(falcon, 0x040);
155 	mbox1 = nvkm_falcon_rd32(falcon, 0x044);
156 	if (FLCN_ERRON(falcon, ret || mbox0 != mbox0_ok, "mbox %08x %08x", mbox0, mbox1))
157 		ret = ret ?: -EIO;
158 
159 	if (irqsclr)
160 		nvkm_falcon_mask(falcon, 0x004, 0xffffffff, irqsclr);
161 
162 	return ret;
163 }
164 
165 int
166 gm200_flcn_fw_load(struct nvkm_falcon_fw *fw)
167 {
168 	struct nvkm_falcon *falcon = fw->falcon;
169 	int ret;
170 
171 	if (1) {
172 		nvkm_falcon_mask(falcon, 0x624, 0x00000080, 0x00000080);
173 		nvkm_falcon_wr32(falcon, 0x10c, 0x00000000);
174 	}
175 
176 	ret = nvkm_falcon_pio_wr(falcon, fw->fw.img + fw->nmem_base_img, fw->nmem_base_img, 0,
177 				 IMEM, fw->nmem_base, fw->nmem_size, fw->nmem_base >> 8, false);
178 	if (ret)
179 		return ret;
180 
181 	ret = nvkm_falcon_pio_wr(falcon, fw->fw.img + fw->imem_base_img, fw->imem_base_img, 0,
182 				 IMEM, fw->imem_base, fw->imem_size, fw->imem_base >> 8, true);
183 	if (ret)
184 		return ret;
185 
186 	ret = nvkm_falcon_pio_wr(falcon, fw->fw.img + fw->dmem_base_img, fw->dmem_base_img, 0,
187 				 DMEM, fw->dmem_base, fw->dmem_size, 0, false);
188 	if (ret)
189 		return ret;
190 
191 	return 0;
192 }
193 
194 int
195 gm200_flcn_fw_reset(struct nvkm_falcon_fw *fw)
196 {
197 	return nvkm_falcon_reset(fw->falcon);
198 }
199 
200 int
201 gm200_flcn_fw_signature(struct nvkm_falcon_fw *fw, u32 *sig_base_src)
202 {
203 	struct nvkm_falcon *falcon = fw->falcon;
204 	u32 addr = falcon->func->debug;
205 	int ret = 0;
206 
207 	if (addr) {
208 		ret = nvkm_falcon_enable(falcon);
209 		if (ret)
210 			return ret;
211 
212 		if (nvkm_falcon_rd32(falcon, addr) & 0x00100000) {
213 			*sig_base_src = fw->sig_base_dbg;
214 			return 1;
215 		}
216 	}
217 
218 	return ret;
219 }
220 
221 const struct nvkm_falcon_fw_func
222 gm200_flcn_fw = {
223 	.signature = gm200_flcn_fw_signature,
224 	.reset = gm200_flcn_fw_reset,
225 	.load = gm200_flcn_fw_load,
226 	.boot = gm200_flcn_fw_boot,
227 };
228