0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022 #include "curs.h"
0023 #include "core.h"
0024 #include "head.h"
0025
0026 #include <nvif/if0014.h>
0027 #include <nvif/timer.h>
0028
0029 #include <nvhw/class/cl507a.h>
0030
0031 #include <drm/drm_atomic_helper.h>
0032 #include <drm/drm_plane_helper.h>
0033
0034 bool
0035 curs507a_space(struct nv50_wndw *wndw)
0036 {
0037 nvif_msec(&nouveau_drm(wndw->plane.dev)->client.device, 100,
0038 if (NVIF_TV32(&wndw->wimm.base.user, NV507A, FREE, COUNT, >=, 4))
0039 return true;
0040 );
0041
0042 WARN_ON(1);
0043 return false;
0044 }
0045
0046 static int
0047 curs507a_update(struct nv50_wndw *wndw, u32 *interlock)
0048 {
0049 struct nvif_object *user = &wndw->wimm.base.user;
0050 int ret = nvif_chan_wait(&wndw->wimm, 1);
0051 if (ret == 0) {
0052 NVIF_WR32(user, NV507A, UPDATE,
0053 NVDEF(NV507A, UPDATE, INTERLOCK_WITH_CORE, DISABLE));
0054 }
0055 return ret;
0056 }
0057
0058 static int
0059 curs507a_point(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
0060 {
0061 struct nvif_object *user = &wndw->wimm.base.user;
0062 int ret = nvif_chan_wait(&wndw->wimm, 1);
0063 if (ret == 0) {
0064 NVIF_WR32(user, NV507A, SET_CURSOR_HOT_SPOT_POINT_OUT,
0065 NVVAL(NV507A, SET_CURSOR_HOT_SPOT_POINT_OUT, X, asyw->point.x) |
0066 NVVAL(NV507A, SET_CURSOR_HOT_SPOT_POINT_OUT, Y, asyw->point.y));
0067 }
0068 return ret;
0069 }
0070
0071 const struct nv50_wimm_func
0072 curs507a = {
0073 .point = curs507a_point,
0074 .update = curs507a_update,
0075 };
0076
0077 static void
0078 curs507a_prepare(struct nv50_wndw *wndw, struct nv50_head_atom *asyh,
0079 struct nv50_wndw_atom *asyw)
0080 {
0081 u32 handle = nv50_disp(wndw->plane.dev)->core->chan.vram.handle;
0082 u32 offset = asyw->image.offset[0];
0083 if (asyh->curs.handle != handle || asyh->curs.offset != offset) {
0084 asyh->curs.handle = handle;
0085 asyh->curs.offset = offset;
0086 asyh->set.curs = asyh->curs.visible;
0087 }
0088 }
0089
0090 static void
0091 curs507a_release(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw,
0092 struct nv50_head_atom *asyh)
0093 {
0094 asyh->curs.visible = false;
0095 }
0096
0097 static int
0098 curs507a_acquire(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw,
0099 struct nv50_head_atom *asyh)
0100 {
0101 struct nouveau_drm *drm = nouveau_drm(wndw->plane.dev);
0102 struct nv50_head *head = nv50_head(asyw->state.crtc);
0103 int ret;
0104
0105 ret = drm_atomic_helper_check_plane_state(&asyw->state, &asyh->state,
0106 DRM_PLANE_HELPER_NO_SCALING,
0107 DRM_PLANE_HELPER_NO_SCALING,
0108 true, true);
0109 asyh->curs.visible = asyw->state.visible;
0110 if (ret || !asyh->curs.visible)
0111 return ret;
0112
0113 if (asyw->state.crtc_w != asyw->state.crtc_h) {
0114 NV_ATOMIC(drm, "Plane width/height must be equal for cursors\n");
0115 return -EINVAL;
0116 }
0117
0118 if (asyw->image.w != asyw->state.crtc_w) {
0119 NV_ATOMIC(drm, "Plane width must be equal to fb width for cursors (height can be larger though)\n");
0120 return -EINVAL;
0121 }
0122
0123 if (asyw->state.src_x || asyw->state.src_y) {
0124 NV_ATOMIC(drm, "Cursor planes do not support framebuffer offsets\n");
0125 return -EINVAL;
0126 }
0127
0128 ret = head->func->curs_layout(head, asyw, asyh);
0129 if (ret)
0130 return ret;
0131
0132 return head->func->curs_format(head, asyw, asyh);
0133 }
0134
0135 static const u32
0136 curs507a_format[] = {
0137 DRM_FORMAT_ARGB8888,
0138 0
0139 };
0140
0141 static const struct nv50_wndw_func
0142 curs507a_wndw = {
0143 .acquire = curs507a_acquire,
0144 .release = curs507a_release,
0145 .prepare = curs507a_prepare,
0146 };
0147
0148 int
0149 curs507a_new_(const struct nv50_wimm_func *func, struct nouveau_drm *drm,
0150 int head, s32 oclass, u32 interlock_data,
0151 struct nv50_wndw **pwndw)
0152 {
0153 struct nvif_disp_chan_v0 args = {
0154 .id = head,
0155 };
0156 struct nv50_disp *disp = nv50_disp(drm->dev);
0157 struct nv50_wndw *wndw;
0158 int ret;
0159
0160 ret = nv50_wndw_new_(&curs507a_wndw, drm->dev, DRM_PLANE_TYPE_CURSOR,
0161 "curs", head, curs507a_format, BIT(head),
0162 NV50_DISP_INTERLOCK_CURS, interlock_data, &wndw);
0163 if (*pwndw = wndw, ret)
0164 return ret;
0165
0166 ret = nvif_object_ctor(&disp->disp->object, "kmsCurs", 0, oclass,
0167 &args, sizeof(args), &wndw->wimm.base.user);
0168 if (ret) {
0169 NV_ERROR(drm, "curs%04x allocation failed: %d\n", oclass, ret);
0170 return ret;
0171 }
0172
0173 nvif_object_map(&wndw->wimm.base.user, NULL, 0);
0174 wndw->immd = func;
0175 wndw->ctxdma.parent = NULL;
0176 return 0;
0177 }
0178
0179 int
0180 curs507a_new(struct nouveau_drm *drm, int head, s32 oclass,
0181 struct nv50_wndw **pwndw)
0182 {
0183 return curs507a_new_(&curs507a, drm, head, oclass,
0184 0x00000001 << (head * 8), pwndw);
0185 }