1 /* 2 * Copyright 2018 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 "base.h" 23 24 #include <nvif/cl507c.h> 25 #include <nvif/event.h> 26 27 #include <drm/drm_atomic_helper.h> 28 #include <drm/drm_plane_helper.h> 29 #include "nouveau_bo.h" 30 31 void 32 base507c_update(struct nv50_wndw *wndw, u32 *interlock) 33 { 34 u32 *push; 35 if ((push = evo_wait(&wndw->wndw, 2))) { 36 evo_mthd(push, 0x0080, 1); 37 evo_data(push, interlock[NV50_DISP_INTERLOCK_CORE]); 38 evo_kick(push, &wndw->wndw); 39 } 40 } 41 42 void 43 base507c_lut(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw) 44 { 45 u32 *push; 46 if ((push = evo_wait(&wndw->wndw, 2))) { 47 evo_mthd(push, 0x00e0, 1); 48 evo_data(push, asyw->lut.enable << 30); 49 evo_kick(push, &wndw->wndw); 50 } 51 } 52 53 void 54 base507c_image_clr(struct nv50_wndw *wndw) 55 { 56 u32 *push; 57 if ((push = evo_wait(&wndw->wndw, 4))) { 58 evo_mthd(push, 0x0084, 1); 59 evo_data(push, 0x00000000); 60 evo_mthd(push, 0x00c0, 1); 61 evo_data(push, 0x00000000); 62 evo_kick(push, &wndw->wndw); 63 } 64 } 65 66 static void 67 base507c_image_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw) 68 { 69 u32 *push; 70 if ((push = evo_wait(&wndw->wndw, 10))) { 71 evo_mthd(push, 0x0084, 1); 72 evo_data(push, asyw->image.mode << 8 | 73 asyw->image.interval << 4); 74 evo_mthd(push, 0x00c0, 1); 75 evo_data(push, asyw->image.handle[0]); 76 evo_mthd(push, 0x0800, 5); 77 evo_data(push, asyw->image.offset[0] >> 8); 78 evo_data(push, 0x00000000); 79 evo_data(push, asyw->image.h << 16 | asyw->image.w); 80 evo_data(push, asyw->image.layout << 20 | 81 asyw->image.pitch[0] | 82 asyw->image.block); 83 evo_data(push, asyw->image.kind << 16 | 84 asyw->image.format << 8); 85 evo_kick(push, &wndw->wndw); 86 } 87 } 88 89 int 90 base507c_ntfy_wait_begun(struct nouveau_bo *bo, u32 offset, 91 struct nvif_device *device) 92 { 93 s64 time = nvif_msec(device, 2000ULL, 94 u32 data = nouveau_bo_rd32(bo, offset / 4); 95 if ((data & 0xc0000000) == 0x40000000) 96 break; 97 usleep_range(1, 2); 98 ); 99 return time < 0 ? time : 0; 100 } 101 102 void 103 base507c_ntfy_clr(struct nv50_wndw *wndw) 104 { 105 u32 *push; 106 if ((push = evo_wait(&wndw->wndw, 2))) { 107 evo_mthd(push, 0x00a4, 1); 108 evo_data(push, 0x00000000); 109 evo_kick(push, &wndw->wndw); 110 } 111 } 112 113 void 114 base507c_ntfy_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw) 115 { 116 u32 *push; 117 if ((push = evo_wait(&wndw->wndw, 3))) { 118 evo_mthd(push, 0x00a0, 2); 119 evo_data(push, asyw->ntfy.awaken << 30 | asyw->ntfy.offset); 120 evo_data(push, asyw->ntfy.handle); 121 evo_kick(push, &wndw->wndw); 122 } 123 } 124 125 void 126 base507c_ntfy_reset(struct nouveau_bo *bo, u32 offset) 127 { 128 nouveau_bo_wr32(bo, offset / 4, 0x00000000); 129 } 130 131 void 132 base507c_sema_clr(struct nv50_wndw *wndw) 133 { 134 u32 *push; 135 if ((push = evo_wait(&wndw->wndw, 2))) { 136 evo_mthd(push, 0x0094, 1); 137 evo_data(push, 0x00000000); 138 evo_kick(push, &wndw->wndw); 139 } 140 } 141 142 void 143 base507c_sema_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw) 144 { 145 u32 *push; 146 if ((push = evo_wait(&wndw->wndw, 5))) { 147 evo_mthd(push, 0x0088, 4); 148 evo_data(push, asyw->sema.offset); 149 evo_data(push, asyw->sema.acquire); 150 evo_data(push, asyw->sema.release); 151 evo_data(push, asyw->sema.handle); 152 evo_kick(push, &wndw->wndw); 153 } 154 } 155 156 void 157 base507c_release(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw, 158 struct nv50_head_atom *asyh) 159 { 160 asyh->base.cpp = 0; 161 } 162 163 int 164 base507c_acquire(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw, 165 struct nv50_head_atom *asyh) 166 { 167 const struct drm_framebuffer *fb = asyw->state.fb; 168 int ret; 169 170 if (!fb->format->depth) 171 return -EINVAL; 172 173 ret = drm_atomic_helper_check_plane_state(&asyw->state, &asyh->state, 174 DRM_PLANE_HELPER_NO_SCALING, 175 DRM_PLANE_HELPER_NO_SCALING, 176 false, true); 177 if (ret) 178 return ret; 179 180 asyh->base.depth = fb->format->depth; 181 asyh->base.cpp = fb->format->cpp[0]; 182 asyh->base.x = asyw->state.src.x1 >> 16; 183 asyh->base.y = asyw->state.src.y1 >> 16; 184 asyh->base.w = asyw->state.fb->width; 185 asyh->base.h = asyw->state.fb->height; 186 187 asyw->lut.enable = 1; 188 asyw->set.image = true; 189 return 0; 190 } 191 192 const u32 193 base507c_format[] = { 194 DRM_FORMAT_C8, 195 DRM_FORMAT_RGB565, 196 DRM_FORMAT_XRGB1555, 197 DRM_FORMAT_ARGB1555, 198 DRM_FORMAT_XRGB8888, 199 DRM_FORMAT_ARGB8888, 200 DRM_FORMAT_XBGR2101010, 201 DRM_FORMAT_ABGR2101010, 202 DRM_FORMAT_XBGR8888, 203 DRM_FORMAT_ABGR8888, 204 0 205 }; 206 207 static const struct nv50_wndw_func 208 base507c = { 209 .acquire = base507c_acquire, 210 .release = base507c_release, 211 .sema_set = base507c_sema_set, 212 .sema_clr = base507c_sema_clr, 213 .ntfy_reset = base507c_ntfy_reset, 214 .ntfy_set = base507c_ntfy_set, 215 .ntfy_clr = base507c_ntfy_clr, 216 .ntfy_wait_begun = base507c_ntfy_wait_begun, 217 .image_set = base507c_image_set, 218 .image_clr = base507c_image_clr, 219 .lut = base507c_lut, 220 .update = base507c_update, 221 }; 222 223 int 224 base507c_new_(const struct nv50_wndw_func *func, const u32 *format, 225 struct nouveau_drm *drm, int head, s32 oclass, u32 interlock_data, 226 struct nv50_wndw **pwndw) 227 { 228 struct nv50_disp_base_channel_dma_v0 args = { 229 .head = head, 230 }; 231 struct nv50_disp *disp = nv50_disp(drm->dev); 232 struct nv50_wndw *wndw; 233 int ret; 234 235 ret = nv50_wndw_new_(func, drm->dev, DRM_PLANE_TYPE_PRIMARY, 236 "base", head, format, BIT(head), 237 NV50_DISP_INTERLOCK_BASE, interlock_data, &wndw); 238 if (*pwndw = wndw, ret) 239 return ret; 240 241 ret = nv50_dmac_create(&drm->client.device, &disp->disp->object, 242 &oclass, head, &args, sizeof(args), 243 disp->sync->bo.offset, &wndw->wndw); 244 if (ret) { 245 NV_ERROR(drm, "base%04x allocation failed: %d\n", oclass, ret); 246 return ret; 247 } 248 249 ret = nvif_notify_init(&wndw->wndw.base.user, wndw->notify.func, 250 false, NV50_DISP_BASE_CHANNEL_DMA_V0_NTFY_UEVENT, 251 &(struct nvif_notify_uevent_req) {}, 252 sizeof(struct nvif_notify_uevent_req), 253 sizeof(struct nvif_notify_uevent_rep), 254 &wndw->notify); 255 if (ret) 256 return ret; 257 258 wndw->ntfy = NV50_DISP_BASE_NTFY(wndw->id); 259 wndw->sema = NV50_DISP_BASE_SEM0(wndw->id); 260 wndw->data = 0x00000000; 261 return 0; 262 } 263 264 int 265 base507c_new(struct nouveau_drm *drm, int head, s32 oclass, 266 struct nv50_wndw **pwndw) 267 { 268 return base507c_new_(&base507c, base507c_format, drm, head, oclass, 269 0x00000002 << (head * 8), pwndw); 270 } 271