1 /* 2 * Copyright 2016 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 * Authors: Ben Skeggs <bskeggs@redhat.com> 23 */ 24 #include "priv.h" 25 #include "chan.h" 26 #include "head.h" 27 #include "ior.h" 28 29 #include <subdev/timer.h> 30 31 #include <nvif/class.h> 32 33 static int 34 gp102_disp_dmac_init(struct nvkm_disp_chan *chan) 35 { 36 struct nvkm_subdev *subdev = &chan->disp->engine.subdev; 37 struct nvkm_device *device = subdev->device; 38 int ctrl = chan->chid.ctrl; 39 int user = chan->chid.user; 40 41 /* initialise channel for dma command submission */ 42 nvkm_wr32(device, 0x611494 + (ctrl * 0x0010), chan->push); 43 nvkm_wr32(device, 0x611498 + (ctrl * 0x0010), 0x00010000); 44 nvkm_wr32(device, 0x61149c + (ctrl * 0x0010), 0x00000001); 45 nvkm_mask(device, 0x610490 + (ctrl * 0x0010), 0x00000010, 0x00000010); 46 nvkm_wr32(device, 0x640000 + (ctrl * 0x1000), chan->suspend_put); 47 nvkm_wr32(device, 0x610490 + (ctrl * 0x0010), 0x00000013); 48 49 /* wait for it to go inactive */ 50 if (nvkm_msec(device, 2000, 51 if (!(nvkm_rd32(device, 0x610490 + (ctrl * 0x10)) & 0x80000000)) 52 break; 53 ) < 0) { 54 nvkm_error(subdev, "ch %d init: %08x\n", user, 55 nvkm_rd32(device, 0x610490 + (ctrl * 0x10))); 56 return -EBUSY; 57 } 58 59 return 0; 60 } 61 62 const struct nvkm_disp_chan_func 63 gp102_disp_dmac_func = { 64 .init = gp102_disp_dmac_init, 65 .fini = gf119_disp_dmac_fini, 66 .intr = gf119_disp_chan_intr, 67 .user = nv50_disp_chan_user, 68 .bind = gf119_disp_dmac_bind, 69 }; 70 71 int 72 gp102_disp_curs_new(const struct nvkm_oclass *oclass, void *argv, u32 argc, 73 struct nvkm_disp *disp, struct nvkm_object **pobject) 74 { 75 return nv50_disp_curs_new_(&gf119_disp_pioc_func, disp, 13, 17, 76 oclass, argv, argc, pobject); 77 } 78 79 int 80 gp102_disp_oimm_new(const struct nvkm_oclass *oclass, void *argv, u32 argc, 81 struct nvkm_disp *disp, struct nvkm_object **pobject) 82 { 83 return nv50_disp_oimm_new_(&gf119_disp_pioc_func, disp, 9, 13, 84 oclass, argv, argc, pobject); 85 } 86 87 int 88 gp102_disp_ovly_new(const struct nvkm_oclass *oclass, void *argv, u32 argc, 89 struct nvkm_disp *disp, struct nvkm_object **pobject) 90 { 91 return nv50_disp_ovly_new_(&gp102_disp_dmac_func, &gk104_disp_ovly_mthd, 92 disp, 5, oclass, argv, argc, pobject); 93 } 94 95 int 96 gp102_disp_base_new(const struct nvkm_oclass *oclass, void *argv, u32 argc, 97 struct nvkm_disp *disp, struct nvkm_object **pobject) 98 { 99 return nv50_disp_base_new_(&gp102_disp_dmac_func, &gf119_disp_base_mthd, 100 disp, 1, oclass, argv, argc, pobject); 101 } 102 103 static int 104 gp102_disp_core_init(struct nvkm_disp_chan *chan) 105 { 106 struct nvkm_subdev *subdev = &chan->disp->engine.subdev; 107 struct nvkm_device *device = subdev->device; 108 109 /* initialise channel for dma command submission */ 110 nvkm_wr32(device, 0x611494, chan->push); 111 nvkm_wr32(device, 0x611498, 0x00010000); 112 nvkm_wr32(device, 0x61149c, 0x00000001); 113 nvkm_mask(device, 0x610490, 0x00000010, 0x00000010); 114 nvkm_wr32(device, 0x640000, chan->suspend_put); 115 nvkm_wr32(device, 0x610490, 0x01000013); 116 117 /* wait for it to go inactive */ 118 if (nvkm_msec(device, 2000, 119 if (!(nvkm_rd32(device, 0x610490) & 0x80000000)) 120 break; 121 ) < 0) { 122 nvkm_error(subdev, "core init: %08x\n", 123 nvkm_rd32(device, 0x610490)); 124 return -EBUSY; 125 } 126 127 return 0; 128 } 129 130 static const struct nvkm_disp_chan_func 131 gp102_disp_core_func = { 132 .init = gp102_disp_core_init, 133 .fini = gf119_disp_core_fini, 134 .intr = gf119_disp_chan_intr, 135 .user = nv50_disp_chan_user, 136 .bind = gf119_disp_dmac_bind, 137 }; 138 139 int 140 gp102_disp_core_new(const struct nvkm_oclass *oclass, void *argv, u32 argc, 141 struct nvkm_disp *disp, struct nvkm_object **pobject) 142 { 143 return nv50_disp_core_new_(&gp102_disp_core_func, &gk104_disp_core_mthd, 144 disp, 0, oclass, argv, argc, pobject); 145 } 146 147 static void 148 gp102_disp_intr_error(struct nvkm_disp *disp, int chid) 149 { 150 struct nvkm_subdev *subdev = &disp->engine.subdev; 151 struct nvkm_device *device = subdev->device; 152 u32 mthd = nvkm_rd32(device, 0x6111f0 + (chid * 12)); 153 u32 data = nvkm_rd32(device, 0x6111f4 + (chid * 12)); 154 u32 unkn = nvkm_rd32(device, 0x6111f8 + (chid * 12)); 155 156 nvkm_error(subdev, "chid %d mthd %04x data %08x %08x %08x\n", 157 chid, (mthd & 0x0000ffc), data, mthd, unkn); 158 159 if (chid < ARRAY_SIZE(disp->chan)) { 160 switch (mthd & 0xffc) { 161 case 0x0080: 162 nv50_disp_chan_mthd(disp->chan[chid], NV_DBG_ERROR); 163 break; 164 default: 165 break; 166 } 167 } 168 169 nvkm_wr32(device, 0x61009c, (1 << chid)); 170 nvkm_wr32(device, 0x6111f0 + (chid * 12), 0x90000000); 171 } 172 173 static const struct nvkm_disp_func 174 gp102_disp = { 175 .dtor = nv50_disp_dtor, 176 .oneinit = nv50_disp_oneinit, 177 .init = gf119_disp_init, 178 .fini = gf119_disp_fini, 179 .intr = gf119_disp_intr, 180 .intr_error = gp102_disp_intr_error, 181 .super = gf119_disp_super, 182 .uevent = &gf119_disp_chan_uevent, 183 .head = { .cnt = gf119_head_cnt, .new = gf119_head_new }, 184 .sor = { .cnt = gf119_sor_cnt, .new = gp100_sor_new }, 185 .root = { 0,0,GP102_DISP }, 186 .user = { 187 {{0,0,GK104_DISP_CURSOR }, gp102_disp_curs_new }, 188 {{0,0,GK104_DISP_OVERLAY }, gp102_disp_oimm_new }, 189 {{0,0,GK110_DISP_BASE_CHANNEL_DMA }, gp102_disp_base_new }, 190 {{0,0,GP102_DISP_CORE_CHANNEL_DMA }, gp102_disp_core_new }, 191 {{0,0,GK104_DISP_OVERLAY_CONTROL_DMA}, gp102_disp_ovly_new }, 192 {} 193 }, 194 }; 195 196 int 197 gp102_disp_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, 198 struct nvkm_disp **pdisp) 199 { 200 return nv50_disp_new_(&gp102_disp, device, type, inst, pdisp); 201 } 202