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