diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/dispnv50')
21 files changed, 799 insertions, 38 deletions
diff --git a/drivers/gpu/drm/nouveau/dispnv50/Kbuild b/drivers/gpu/drm/nouveau/dispnv50/Kbuild index 28be2912ff74..d5049dee4b8c 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/Kbuild +++ b/drivers/gpu/drm/nouveau/dispnv50/Kbuild @@ -9,11 +9,13 @@ nouveau-y += dispnv50/core907d.o nouveau-y += dispnv50/core917d.o nouveau-y += dispnv50/corec37d.o nouveau-y += dispnv50/corec57d.o +nouveau-y += dispnv50/coreca7d.o nouveau-$(CONFIG_DEBUG_FS) += dispnv50/crc.o nouveau-$(CONFIG_DEBUG_FS) += dispnv50/crc907d.o nouveau-$(CONFIG_DEBUG_FS) += dispnv50/crcc37d.o nouveau-$(CONFIG_DEBUG_FS) += dispnv50/crcc57d.o +nouveau-$(CONFIG_DEBUG_FS) += dispnv50/crcca7d.o nouveau-y += dispnv50/dac507d.o nouveau-y += dispnv50/dac907d.o @@ -31,6 +33,7 @@ nouveau-y += dispnv50/head907d.o nouveau-y += dispnv50/head917d.o nouveau-y += dispnv50/headc37d.o nouveau-y += dispnv50/headc57d.o +nouveau-y += dispnv50/headca7d.o nouveau-y += dispnv50/wimm.o nouveau-y += dispnv50/wimmc37b.o @@ -39,6 +42,7 @@ nouveau-y += dispnv50/wndw.o nouveau-y += dispnv50/wndwc37e.o nouveau-y += dispnv50/wndwc57e.o nouveau-y += dispnv50/wndwc67e.o +nouveau-y += dispnv50/wndwca7e.o nouveau-y += dispnv50/base.o nouveau-y += dispnv50/base507c.o diff --git a/drivers/gpu/drm/nouveau/dispnv50/core.c b/drivers/gpu/drm/nouveau/dispnv50/core.c index f045515696cb..c6331bf97582 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/core.c +++ b/drivers/gpu/drm/nouveau/dispnv50/core.c @@ -42,6 +42,7 @@ nv50_core_new(struct nouveau_drm *drm, struct nv50_core **pcore) int version; int (*new)(struct nouveau_drm *, s32, struct nv50_core **); } cores[] = { + { GB202_DISP_CORE_CHANNEL_DMA, 0, coreca7d_new }, { AD102_DISP_CORE_CHANNEL_DMA, 0, corec57d_new }, { GA102_DISP_CORE_CHANNEL_DMA, 0, corec57d_new }, { TU102_DISP_CORE_CHANNEL_DMA, 0, corec57d_new }, diff --git a/drivers/gpu/drm/nouveau/dispnv50/core.h b/drivers/gpu/drm/nouveau/dispnv50/core.h index f75088186fba..aa07a3ad5dfd 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/core.h +++ b/drivers/gpu/drm/nouveau/dispnv50/core.h @@ -7,7 +7,10 @@ struct nv50_core { const struct nv50_core_func *func; + struct nv50_disp *disp; + struct nv50_dmac chan; + bool assign_windows; }; @@ -18,6 +21,7 @@ struct nv50_core_func { int (*init)(struct nv50_core *); void (*ntfy_init)(struct nouveau_bo *, u32 offset); int (*caps_init)(struct nouveau_drm *, struct nv50_disp *); + u32 caps_class; int (*ntfy_wait_done)(struct nouveau_bo *, u32 offset, struct nvif_device *); int (*update)(struct nv50_core *, u32 *interlock, bool ntfy); @@ -70,4 +74,6 @@ int corec37d_wndw_owner(struct nv50_core *); extern const struct nv50_outp_func sorc37d; int corec57d_new(struct nouveau_drm *, s32, struct nv50_core **); + +int coreca7d_new(struct nouveau_drm *, s32, struct nv50_core **); #endif diff --git a/drivers/gpu/drm/nouveau/dispnv50/core507d.c b/drivers/gpu/drm/nouveau/dispnv50/core507d.c index ce2cb78bbdd3..4b947b67a844 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/core507d.c +++ b/drivers/gpu/drm/nouveau/dispnv50/core507d.c @@ -165,6 +165,7 @@ core507d_new_(const struct nv50_core_func *func, struct nouveau_drm *drm, if (!(core = *pcore = kzalloc(sizeof(*core), GFP_KERNEL))) return -ENOMEM; core->func = func; + core->disp = disp; ret = nv50_dmac_create(drm, &oclass, 0, &args, sizeof(args), diff --git a/drivers/gpu/drm/nouveau/dispnv50/corec37d.c b/drivers/gpu/drm/nouveau/dispnv50/corec37d.c index 7f637b8830be..83eec2f091f0 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/corec37d.c +++ b/drivers/gpu/drm/nouveau/dispnv50/corec37d.c @@ -105,7 +105,7 @@ int corec37d_caps_init(struct nouveau_drm *drm, struct nv50_disp *disp) int ret; ret = nvif_object_ctor(&disp->disp->object, "dispCaps", 0, - GV100_DISP_CAPS, NULL, 0, &disp->caps); + disp->core->func->caps_class, NULL, 0, &disp->caps); if (ret) { NV_ERROR(drm, "Failed to init notifier caps region: %d\n", @@ -162,6 +162,7 @@ corec37d = { .init = corec37d_init, .ntfy_init = corec37d_ntfy_init, .caps_init = corec37d_caps_init, + .caps_class = GV100_DISP_CAPS, .ntfy_wait_done = corec37d_ntfy_wait_done, .update = corec37d_update, .wndw.owner = corec37d_wndw_owner, diff --git a/drivers/gpu/drm/nouveau/dispnv50/corec57d.c b/drivers/gpu/drm/nouveau/dispnv50/corec57d.c index 421d0d57e1d8..39be576eadcb 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/corec57d.c +++ b/drivers/gpu/drm/nouveau/dispnv50/corec57d.c @@ -22,6 +22,7 @@ #include "core.h" #include "head.h" +#include <nvif/class.h> #include <nvif/pushc37b.h> #include <nvhw/class/clc57d.h> @@ -63,6 +64,7 @@ corec57d = { .init = corec57d_init, .ntfy_init = corec37d_ntfy_init, .caps_init = corec37d_caps_init, + .caps_class = GV100_DISP_CAPS, .ntfy_wait_done = corec37d_ntfy_wait_done, .update = corec37d_update, .wndw.owner = corec37d_wndw_owner, diff --git a/drivers/gpu/drm/nouveau/dispnv50/coreca7d.c b/drivers/gpu/drm/nouveau/dispnv50/coreca7d.c new file mode 100644 index 000000000000..171727be400e --- /dev/null +++ b/drivers/gpu/drm/nouveau/dispnv50/coreca7d.c @@ -0,0 +1,122 @@ +/* SPDX-License-Identifier: MIT + * + * Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved. + */ +#include "core.h" +#include "head.h" + +#include <nvif/class.h> +#include <nvif/pushc97b.h> + +#include <nvhw/class/clca7d.h> + +#include <nouveau_bo.h> + +static int +coreca7d_update(struct nv50_core *core, u32 *interlock, bool ntfy) +{ + const u64 ntfy_addr = core->disp->sync->offset + NV50_DISP_CORE_NTFY; + const u32 ntfy_hi = upper_32_bits(ntfy_addr); + const u32 ntfy_lo = lower_32_bits(ntfy_addr); + struct nvif_push *push = &core->chan.push; + int ret; + + ret = PUSH_WAIT(push, 5 + (ntfy ? 5 + 2 : 0)); + if (ret) + return ret; + + if (ntfy) { + PUSH_MTHD(push, NVCA7D, SET_SURFACE_ADDRESS_HI_NOTIFIER, ntfy_hi, + + SET_SURFACE_ADDRESS_LO_NOTIFIER, + NVVAL(NVCA7D, SET_SURFACE_ADDRESS_LO_NOTIFIER, ADDRESS_LO, ntfy_lo >> 4) | + NVDEF(NVCA7D, SET_SURFACE_ADDRESS_LO_NOTIFIER, TARGET, PHYSICAL_NVM) | + NVDEF(NVCA7D, SET_SURFACE_ADDRESS_LO_NOTIFIER, ENABLE, ENABLE)); + + PUSH_MTHD(push, NVCA7D, SET_NOTIFIER_CONTROL, + NVDEF(NVCA7D, SET_NOTIFIER_CONTROL, MODE, WRITE) | + NVDEF(NVCA7D, SET_NOTIFIER_CONTROL, NOTIFY, ENABLE)); + } + + PUSH_MTHD(push, NVCA7D, SET_INTERLOCK_FLAGS, interlock[NV50_DISP_INTERLOCK_CURS], + SET_WINDOW_INTERLOCK_FLAGS, interlock[NV50_DISP_INTERLOCK_WNDW]); + + PUSH_MTHD(push, NVCA7D, UPDATE, + NVDEF(NVCA7D, UPDATE, RELEASE_ELV, TRUE) | + NVDEF(NVCA7D, UPDATE, SPECIAL_HANDLING, NONE) | + NVDEF(NVCA7D, UPDATE, INHIBIT_INTERRUPTS, FALSE)); + + if (ntfy) { + PUSH_MTHD(push, NVCA7D, SET_NOTIFIER_CONTROL, + NVDEF(NVCA7D, SET_NOTIFIER_CONTROL, NOTIFY, DISABLE)); + } + + return PUSH_KICK(push); +} + +static int +coreca7d_init(struct nv50_core *core) +{ + struct nvif_push *push = &core->chan.push; + const u32 windows = 8, heads = 4; + int ret, i; + + ret = PUSH_WAIT(push, windows * 6 + heads * 6); + if (ret) + return ret; + + for (i = 0; i < windows; i++) { + PUSH_MTHD(push, NVCA7D, WINDOW_SET_WINDOW_FORMAT_USAGE_BOUNDS(i), + NVDEF(NVCA7D, WINDOW_SET_WINDOW_FORMAT_USAGE_BOUNDS, RGB_PACKED1BPP, TRUE) | + NVDEF(NVCA7D, WINDOW_SET_WINDOW_FORMAT_USAGE_BOUNDS, RGB_PACKED2BPP, TRUE) | + NVDEF(NVCA7D, WINDOW_SET_WINDOW_FORMAT_USAGE_BOUNDS, RGB_PACKED4BPP, TRUE) | + NVDEF(NVCA7D, WINDOW_SET_WINDOW_FORMAT_USAGE_BOUNDS, RGB_PACKED8BPP, TRUE), + + WINDOW_SET_WINDOW_ROTATED_FORMAT_USAGE_BOUNDS(i), 0x00000000); + + PUSH_MTHD(push, NVCA7D, WINDOW_SET_WINDOW_USAGE_BOUNDS(i), + NVVAL(NVCA7D, WINDOW_SET_WINDOW_USAGE_BOUNDS, MAX_PIXELS_FETCHED_PER_LINE, 0x7fff) | + NVDEF(NVCA7D, WINDOW_SET_WINDOW_USAGE_BOUNDS, ILUT_ALLOWED, TRUE) | + NVDEF(NVCA7D, WINDOW_SET_WINDOW_USAGE_BOUNDS, INPUT_SCALER_TAPS, TAPS_2) | + NVDEF(NVCA7D, WINDOW_SET_WINDOW_USAGE_BOUNDS, UPSCALING_ALLOWED, FALSE), + + WINDOW_SET_PHYSICAL(i), BIT(i)); + } + + for (i = 0; i < heads; i++) { + PUSH_MTHD(push, NVCA7D, HEAD_SET_HEAD_USAGE_BOUNDS(i), + NVDEF(NVCA7D, HEAD_SET_HEAD_USAGE_BOUNDS, CURSOR, USAGE_W256_H256) | + NVDEF(NVCA7D, HEAD_SET_HEAD_USAGE_BOUNDS, OLUT_ALLOWED, TRUE) | + NVDEF(NVCA7D, HEAD_SET_HEAD_USAGE_BOUNDS, OUTPUT_SCALER_TAPS, TAPS_2) | + NVDEF(NVCA7D, HEAD_SET_HEAD_USAGE_BOUNDS, UPSCALING_ALLOWED, TRUE)); + + PUSH_MTHD(push, NVCA7D, HEAD_SET_TILE_MASK(i), BIT(i)); + + PUSH_MTHD(push, NVCA7D, TILE_SET_TILE_SIZE(i), 0); + } + + core->assign_windows = true; + return PUSH_KICK(push); +} + +static const struct nv50_core_func +coreca7d = { + .init = coreca7d_init, + .ntfy_init = corec37d_ntfy_init, + .caps_init = corec37d_caps_init, + .caps_class = GB202_DISP_CAPS, + .ntfy_wait_done = corec37d_ntfy_wait_done, + .update = coreca7d_update, + .wndw.owner = corec37d_wndw_owner, + .head = &headca7d, + .sor = &sorc37d, +#if IS_ENABLED(CONFIG_DEBUG_FS) + .crc = &crcca7d, +#endif +}; + +int +coreca7d_new(struct nouveau_drm *drm, s32 oclass, struct nv50_core **pcore) +{ + return core507d_new_(&coreca7d, drm, oclass, pcore); +} diff --git a/drivers/gpu/drm/nouveau/dispnv50/crc.c b/drivers/gpu/drm/nouveau/dispnv50/crc.c index 5936b6b3b15d..deb6af40ef32 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/crc.c +++ b/drivers/gpu/drm/nouveau/dispnv50/crc.c @@ -509,6 +509,10 @@ nv50_crc_ctx_init(struct nv50_head *head, struct nvif_mmu *mmu, if (ret) return ret; + /* No CTXDMAs on Blackwell. */ + if (core->chan.base.user.oclass >= GB202_DISP_CORE_CHANNEL_DMA) + return 0; + ret = nvif_object_ctor(&core->chan.base.user, "kmsCrcNtfyCtxDma", NV50_DISP_HANDLE_CRC_CTX(head, idx), NV_DMA_IN_MEMORY, diff --git a/drivers/gpu/drm/nouveau/dispnv50/crc.h b/drivers/gpu/drm/nouveau/dispnv50/crc.h index 4823f1fde2dd..75a2009e8193 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/crc.h +++ b/drivers/gpu/drm/nouveau/dispnv50/crc.h @@ -94,6 +94,7 @@ void nv50_crc_atomic_clr(struct nv50_head *); extern const struct nv50_crc_func crc907d; extern const struct nv50_crc_func crcc37d; extern const struct nv50_crc_func crcc57d; +extern const struct nv50_crc_func crcca7d; #else /* IS_ENABLED(CONFIG_DEBUG_FS) */ struct nv50_crc {}; diff --git a/drivers/gpu/drm/nouveau/dispnv50/crcca7d.c b/drivers/gpu/drm/nouveau/dispnv50/crcca7d.c new file mode 100644 index 000000000000..912f59aebe87 --- /dev/null +++ b/drivers/gpu/drm/nouveau/dispnv50/crcca7d.c @@ -0,0 +1,98 @@ +/* SPDX-License-Identifier: MIT + * + * Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved. + */ +#include "crcc37d.h" +#include "core.h" +#include "head.h" + +#include <nvif/pushc97b.h> + +#include <nvhw/class/clca7d.h> + +static int +crcca7d_set_ctx(struct nv50_head *head, struct nv50_crc_notifier_ctx *ctx) +{ + struct nvif_push *push = &head->disp->core->chan.push; + const int i = head->base.index; + int ret; + + ret = PUSH_WAIT(push, ctx ? 3 : 2); + if (ret) + return ret; + + if (ctx) { + const u32 crc_hi = upper_32_bits(ctx->mem.addr); + const u32 crc_lo = lower_32_bits(ctx->mem.addr); + + PUSH_MTHD(push, NVCA7D, HEAD_SET_SURFACE_ADDRESS_HI_CRC(i), crc_hi, + + HEAD_SET_SURFACE_ADDRESS_LO_CRC(i), + NVVAL(NVCA7D, HEAD_SET_SURFACE_ADDRESS_LO_CRC, ADDRESS_LO, crc_lo >> 4) | + NVDEF(NVCA7D, HEAD_SET_SURFACE_ADDRESS_LO_CRC, TARGET, PHYSICAL_NVM) | + NVDEF(NVCA7D, HEAD_SET_SURFACE_ADDRESS_LO_CRC, ENABLE, ENABLE)); + } else { + PUSH_MTHD(push, NVCA7D, HEAD_SET_SURFACE_ADDRESS_LO_CRC(i), + NVDEF(NVCA7D, HEAD_SET_SURFACE_ADDRESS_LO_CRC, ENABLE, DISABLE)); + } + + return 0; +} + +static int +crcca7d_set_src(struct nv50_head *head, int or, enum nv50_crc_source_type source, + struct nv50_crc_notifier_ctx *ctx) +{ + struct nvif_push *push = &head->disp->core->chan.push; + const int i = head->base.index; + int primary_crc, ret; + + if (!source) { + ret = PUSH_WAIT(push, 1); + if (ret) + return ret; + + PUSH_MTHD(push, NVCA7D, HEAD_SET_CRC_CONTROL(i), 0); + + return crcca7d_set_ctx(head, NULL); + } + + switch (source) { + case NV50_CRC_SOURCE_TYPE_SOR: + primary_crc = NVCA7D_HEAD_SET_CRC_CONTROL_PRIMARY_CRC_SOR(or); + break; + case NV50_CRC_SOURCE_TYPE_SF: + primary_crc = NVCA7D_HEAD_SET_CRC_CONTROL_PRIMARY_CRC_SF; + break; + default: + break; + } + + ret = crcca7d_set_ctx(head, ctx); + if (ret) + return ret; + + ret = PUSH_WAIT(push, 2); + if (ret) + return ret; + + PUSH_MTHD(push, NVCA7D, HEAD_SET_CRC_CONTROL(i), + NVDEF(NVCA7D, HEAD_SET_CRC_CONTROL, CONTROLLING_CHANNEL, CORE) | + NVDEF(NVCA7D, HEAD_SET_CRC_CONTROL, EXPECT_BUFFER_COLLAPSE, FALSE) | + NVVAL(NVCA7D, HEAD_SET_CRC_CONTROL, PRIMARY_CRC, primary_crc) | + NVDEF(NVCA7D, HEAD_SET_CRC_CONTROL, SECONDARY_CRC, NONE) | + NVDEF(NVCA7D, HEAD_SET_CRC_CONTROL, CRC_DURING_SNOOZE, DISABLE)); + + return 0; +} + +const struct nv50_crc_func +crcca7d = { + .set_src = crcca7d_set_src, + .set_ctx = crcca7d_set_ctx, + .get_entry = crcc37d_get_entry, + .ctx_finished = crcc37d_ctx_finished, + .flip_threshold = CRCC37D_FLIP_THRESHOLD, + .num_entries = CRCC37D_MAX_ENTRIES, + .notifier_len = sizeof(struct crcc37d_notifier), +}; diff --git a/drivers/gpu/drm/nouveau/dispnv50/curs.c b/drivers/gpu/drm/nouveau/dispnv50/curs.c index 31d8b2e4791d..557bd05240fa 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/curs.c +++ b/drivers/gpu/drm/nouveau/dispnv50/curs.c @@ -31,6 +31,7 @@ nv50_curs_new(struct nouveau_drm *drm, int head, struct nv50_wndw **pwndw) int version; int (*new)(struct nouveau_drm *, int, s32, struct nv50_wndw **); } curses[] = { + { GB202_DISP_CURSOR, 0, cursc37a_new }, { GA102_DISP_CURSOR, 0, cursc37a_new }, { TU102_DISP_CURSOR, 0, cursc37a_new }, { GV100_DISP_CURSOR, 0, cursc37a_new }, diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index 504cb3f2054b..e5d37eee4301 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -279,6 +279,16 @@ nv50_dmac_create(struct nouveau_drm *drm, if (syncbuf < 0) return 0; + /* No CTXDMAs on Blackwell. */ + if (disp->oclass >= GB202_DISP) { + /* "handle != NULL_HANDLE" is used to determine enable status + * in a number of places, so fill in some fake object handles. + */ + dmac->sync.handle = NV50_DISP_HANDLE_SYNCBUF; + dmac->vram.handle = NV50_DISP_HANDLE_VRAM; + return 0; + } + ret = nvif_object_ctor(&dmac->base.user, "kmsSyncCtxDma", NV50_DISP_HANDLE_SYNCBUF, NV_DMA_IN_MEMORY, &(struct nv_dma_v0) { @@ -775,10 +785,8 @@ nv50_hdmi_enable(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc, union hdmi_infoframe infoframe = { 0 }; const u8 rekey = 56; /* binary driver, and tegra, constant */ u32 max_ac_packet; - struct { - struct nvif_outp_infoframe_v0 infoframe; - u8 data[17]; - } args = { 0 }; + DEFINE_RAW_FLEX(struct nvif_outp_infoframe_v0, args, data, 17); + const u8 data_len = __member_size(args->data); int ret, size; max_ac_packet = mode->htotal - mode->hdisplay; @@ -815,29 +823,29 @@ nv50_hdmi_enable(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc, return; /* AVI InfoFrame. */ - args.infoframe.version = 0; - args.infoframe.head = nv_crtc->index; + args->version = 0; + args->head = nv_crtc->index; if (!drm_hdmi_avi_infoframe_from_display_mode(&infoframe.avi, &nv_connector->base, mode)) { drm_hdmi_avi_infoframe_quant_range(&infoframe.avi, &nv_connector->base, mode, HDMI_QUANTIZATION_RANGE_FULL); - size = hdmi_infoframe_pack(&infoframe, args.data, ARRAY_SIZE(args.data)); + size = hdmi_infoframe_pack(&infoframe, args->data, data_len); } else { size = 0; } - nvif_outp_infoframe(&nv_encoder->outp, NVIF_OUTP_INFOFRAME_V0_AVI, &args.infoframe, size); + nvif_outp_infoframe(&nv_encoder->outp, NVIF_OUTP_INFOFRAME_V0_AVI, args, size); /* Vendor InfoFrame. */ - memset(&args.data, 0, sizeof(args.data)); + memset(args->data, 0, data_len); if (!drm_hdmi_vendor_infoframe_from_display_mode(&infoframe.vendor.hdmi, &nv_connector->base, mode)) - size = hdmi_infoframe_pack(&infoframe, args.data, ARRAY_SIZE(args.data)); + size = hdmi_infoframe_pack(&infoframe, args->data, data_len); else size = 0; - nvif_outp_infoframe(&nv_encoder->outp, NVIF_OUTP_INFOFRAME_V0_VSI, &args.infoframe, size); + nvif_outp_infoframe(&nv_encoder->outp, NVIF_OUTP_INFOFRAME_V0_VSI, args, size); nv_encoder->hdmi.enabled = true; } @@ -2810,10 +2818,7 @@ nv50_display_destroy(struct drm_device *dev) nvif_object_dtor(&disp->caps); nv50_core_del(&disp->core); - nouveau_bo_unmap(disp->sync); - if (disp->sync) - nouveau_bo_unpin(disp->sync); - nouveau_bo_fini(disp->sync); + nouveau_bo_unpin_del(&disp->sync); nouveau_display(dev)->priv = NULL; kfree(disp); @@ -2845,20 +2850,7 @@ nv50_display_create(struct drm_device *dev) dev->mode_config.normalize_zpos = true; /* small shared memory area we use for notifiers and semaphores */ - ret = nouveau_bo_new(&drm->client, 4096, 0x1000, - NOUVEAU_GEM_DOMAIN_VRAM, - 0, 0x0000, NULL, NULL, &disp->sync); - if (!ret) { - ret = nouveau_bo_pin(disp->sync, NOUVEAU_GEM_DOMAIN_VRAM, true); - if (!ret) { - ret = nouveau_bo_map(disp->sync); - if (ret) - nouveau_bo_unpin(disp->sync); - } - if (ret) - nouveau_bo_fini(disp->sync); - } - + ret = nouveau_bo_new_map(&drm->client, NOUVEAU_GEM_DOMAIN_VRAM, PAGE_SIZE, &disp->sync); if (ret) goto out; diff --git a/drivers/gpu/drm/nouveau/dispnv50/head.c b/drivers/gpu/drm/nouveau/dispnv50/head.c index d7c74cc43ba5..3dd742b4f823 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/head.c +++ b/drivers/gpu/drm/nouveau/dispnv50/head.c @@ -577,6 +577,7 @@ nv50_head_create(struct drm_device *dev, int index) return ERR_PTR(-ENOMEM); head->func = disp->core->func->head; + head->disp = disp; head->base.index = index; if (disp->disp->object.oclass < GF110_DISP) diff --git a/drivers/gpu/drm/nouveau/dispnv50/head.h b/drivers/gpu/drm/nouveau/dispnv50/head.h index e9d17037ffcf..8bd2fcb1eff5 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/head.h +++ b/drivers/gpu/drm/nouveau/dispnv50/head.h @@ -13,6 +13,8 @@ struct nv50_head { const struct nv50_head_func *func; + struct nv50_disp *disp; + struct nouveau_crtc base; struct nv50_crc crc; struct nv50_lut olut; @@ -98,4 +100,7 @@ int headc37d_dither(struct nv50_head *, struct nv50_head_atom *); void headc37d_static_wndw_map(struct nv50_head *, struct nv50_head_atom *); extern const struct nv50_head_func headc57d; +bool headc57d_olut(struct nv50_head *, struct nv50_head_atom *, int size); + +extern const struct nv50_head_func headca7d; #endif diff --git a/drivers/gpu/drm/nouveau/dispnv50/headc57d.c b/drivers/gpu/drm/nouveau/dispnv50/headc57d.c index fde4087e7691..3f8ba495de8f 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/headc57d.c +++ b/drivers/gpu/drm/nouveau/dispnv50/headc57d.c @@ -182,7 +182,7 @@ headc57d_olut_load(struct drm_color_lut *in, int size, void __iomem *mem) writew(readw(mem - 4), mem + 4); } -static bool +bool headc57d_olut(struct nv50_head *head, struct nv50_head_atom *asyh, int size) { if (size != 0 && size != 256 && size != 1024) diff --git a/drivers/gpu/drm/nouveau/dispnv50/headca7d.c b/drivers/gpu/drm/nouveau/dispnv50/headca7d.c new file mode 100644 index 000000000000..eeaeb15aa664 --- /dev/null +++ b/drivers/gpu/drm/nouveau/dispnv50/headca7d.c @@ -0,0 +1,297 @@ +/* SPDX-License-Identifier: MIT + * + * Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved. + */ +#include "head.h" +#include "atom.h" +#include "core.h" + +#include <nvif/pushc97b.h> + +#include <nvhw/class/clca7d.h> + +static int +headca7d_display_id(struct nv50_head *head, u32 display_id) +{ + struct nvif_push *push = &head->disp->core->chan.push; + const int i = head->base.index; + int ret; + + ret = PUSH_WAIT(push, 2); + if (ret) + return ret; + + PUSH_MTHD(push, NVCA7D, HEAD_SET_DISPLAY_ID(i, 0), display_id); + + return 0; +} + +static int +headca7d_or(struct nv50_head *head, struct nv50_head_atom *asyh) +{ + struct nvif_push *push = &head->disp->core->chan.push; + const int i = head->base.index; + u8 depth; + int ret; + + switch (asyh->or.depth) { + case 6: + depth = NVCA7D_HEAD_SET_CONTROL_OUTPUT_RESOURCE_PIXEL_DEPTH_BPP_30_444; + break; + case 5: + depth = NVCA7D_HEAD_SET_CONTROL_OUTPUT_RESOURCE_PIXEL_DEPTH_BPP_24_444; + break; + case 2: + depth = NVCA7D_HEAD_SET_CONTROL_OUTPUT_RESOURCE_PIXEL_DEPTH_BPP_18_444; + break; + case 0: + depth = NVCA7D_HEAD_SET_CONTROL_OUTPUT_RESOURCE_PIXEL_DEPTH_BPP_24_444; + break; + default: + WARN_ON(1); + return -EINVAL; + } + + ret = PUSH_WAIT(push, 2); + if (ret) + return ret; + + PUSH_MTHD(push, NVCA7D, HEAD_SET_CONTROL_OUTPUT_RESOURCE(i), + NVVAL(NVCA7D, HEAD_SET_CONTROL_OUTPUT_RESOURCE, CRC_MODE, asyh->or.crc_raster) | + NVVAL(NVCA7D, HEAD_SET_CONTROL_OUTPUT_RESOURCE, HSYNC_POLARITY, asyh->or.nhsync) | + NVVAL(NVCA7D, HEAD_SET_CONTROL_OUTPUT_RESOURCE, VSYNC_POLARITY, asyh->or.nvsync) | + NVVAL(NVCA7D, HEAD_SET_CONTROL_OUTPUT_RESOURCE, PIXEL_DEPTH, depth) | + NVDEF(NVCA7D, HEAD_SET_CONTROL_OUTPUT_RESOURCE, COLOR_SPACE_OVERRIDE, DISABLE) | + NVDEF(NVCA7D, HEAD_SET_CONTROL_OUTPUT_RESOURCE, EXT_PACKET_WIN, NONE)); + + return 0; +} + +static int +headca7d_procamp(struct nv50_head *head, struct nv50_head_atom *asyh) +{ + struct nvif_push *push = &head->disp->core->chan.push; + const int i = head->base.index; + int ret; + + ret = PUSH_WAIT(push, 2); + if (ret) + return ret; + + PUSH_MTHD(push, NVCA7D, HEAD_SET_PROCAMP(i), + NVDEF(NVCA7D, HEAD_SET_PROCAMP, COLOR_SPACE, RGB) | + NVDEF(NVCA7D, HEAD_SET_PROCAMP, CHROMA_LPF, DISABLE) | + NVDEF(NVCA7D, HEAD_SET_PROCAMP, DYNAMIC_RANGE, VESA)); + + return 0; +} + +static int +headca7d_dither(struct nv50_head *head, struct nv50_head_atom *asyh) +{ + struct nvif_push *push = &head->disp->core->chan.push; + const int i = head->base.index; + int ret; + + ret = PUSH_WAIT(push, 2); + if (ret) + return ret; + + PUSH_MTHD(push, NVCA7D, HEAD_SET_DITHER_CONTROL(i), + NVVAL(NVCA7D, HEAD_SET_DITHER_CONTROL, ENABLE, asyh->dither.enable) | + NVVAL(NVCA7D, HEAD_SET_DITHER_CONTROL, BITS, asyh->dither.bits) | + NVDEF(NVCA7D, HEAD_SET_DITHER_CONTROL, OFFSET_ENABLE, DISABLE) | + NVVAL(NVCA7D, HEAD_SET_DITHER_CONTROL, MODE, asyh->dither.mode) | + NVVAL(NVCA7D, HEAD_SET_DITHER_CONTROL, PHASE, 0)); + + return 0; +} + +static int +headca7d_curs_clr(struct nv50_head *head) +{ + struct nvif_push *push = &head->disp->core->chan.push; + const int i = head->base.index; + int ret; + + ret = PUSH_WAIT(push, 4); + if (ret) + return ret; + + PUSH_MTHD(push, NVCA7D, HEAD_SET_CONTROL_CURSOR(i), + NVDEF(NVCA7D, HEAD_SET_CONTROL_CURSOR, ENABLE, DISABLE) | + NVDEF(NVCA7D, HEAD_SET_CONTROL_CURSOR, FORMAT, A8R8G8B8)); + + PUSH_MTHD(push, NVCA7D, HEAD_SET_SURFACE_ADDRESS_LO_CURSOR(i, 0), + NVDEF(NVCA7D, HEAD_SET_SURFACE_ADDRESS_LO_CURSOR, ENABLE, DISABLE)); + + return 0; +} + +static int +headca7d_curs_set(struct nv50_head *head, struct nv50_head_atom *asyh) +{ + struct nvif_push *push = &head->disp->core->chan.push; + const u32 curs_hi = upper_32_bits(asyh->curs.offset); + const u32 curs_lo = lower_32_bits(asyh->curs.offset); + const int i = head->base.index; + int ret; + + ret = PUSH_WAIT(push, 7); + if (ret) + return ret; + + PUSH_MTHD(push, NVCA7D, HEAD_SET_SURFACE_ADDRESS_HI_CURSOR(i, 0), curs_hi); + + PUSH_MTHD(push, NVCA7D, HEAD_SET_SURFACE_ADDRESS_LO_CURSOR(i, 0), + NVVAL(NVCA7D, HEAD_SET_SURFACE_ADDRESS_LO_CURSOR, ADDRESS_LO, curs_lo >> 4) | + NVDEF(NVCA7D, HEAD_SET_SURFACE_ADDRESS_LO_CURSOR, TARGET, PHYSICAL_NVM) | + NVDEF(NVCA7D, HEAD_SET_SURFACE_ADDRESS_LO_CURSOR, ENABLE, ENABLE)); + + PUSH_MTHD(push, NVCA7D, HEAD_SET_CONTROL_CURSOR(i), + NVDEF(NVCA7D, HEAD_SET_CONTROL_CURSOR, ENABLE, ENABLE) | + NVVAL(NVCA7D, HEAD_SET_CONTROL_CURSOR, FORMAT, asyh->curs.format) | + NVVAL(NVCA7D, HEAD_SET_CONTROL_CURSOR, SIZE, asyh->curs.layout) | + NVVAL(NVCA7D, HEAD_SET_CONTROL_CURSOR, HOT_SPOT_X, 0) | + NVVAL(NVCA7D, HEAD_SET_CONTROL_CURSOR, HOT_SPOT_Y, 0), + + HEAD_SET_CONTROL_CURSOR_COMPOSITION(i), + NVVAL(NVCA7D, HEAD_SET_CONTROL_CURSOR_COMPOSITION, K1, 0xff) | + NVDEF(NVCA7D, HEAD_SET_CONTROL_CURSOR_COMPOSITION, CURSOR_COLOR_FACTOR_SELECT, + K1) | + NVDEF(NVCA7D, HEAD_SET_CONTROL_CURSOR_COMPOSITION, VIEWPORT_COLOR_FACTOR_SELECT, + NEG_K1_TIMES_SRC) | + NVDEF(NVCA7D, HEAD_SET_CONTROL_CURSOR_COMPOSITION, MODE, BLEND)); + + return 0; +} + +static int +headca7d_olut_clr(struct nv50_head *head) +{ + struct nvif_push *push = &head->disp->core->chan.push; + const int i = head->base.index; + int ret; + + ret = PUSH_WAIT(push, 2); + if (ret) + return ret; + + PUSH_MTHD(push, NVCA7D, HEAD_SET_SURFACE_ADDRESS_LO_OLUT(i), + NVDEF(NVCA7D, HEAD_SET_SURFACE_ADDRESS_LO_OLUT, ENABLE, DISABLE)); + + return 0; +} + +static int +headca7d_olut_set(struct nv50_head *head, struct nv50_head_atom *asyh) +{ + struct nvif_push *push = &head->disp->core->chan.push; + const u32 olut_hi = upper_32_bits(asyh->olut.offset); + const u32 olut_lo = lower_32_bits(asyh->olut.offset); + const int i = head->base.index; + int ret; + + ret = PUSH_WAIT(push, 6); + if (ret) + return ret; + + PUSH_MTHD(push, NVCA7D, HEAD_SET_SURFACE_ADDRESS_HI_OLUT(i), olut_hi, + + HEAD_SET_SURFACE_ADDRESS_LO_OLUT(i), + NVVAL(NVCA7D, HEAD_SET_SURFACE_ADDRESS_LO_OLUT, ADDRESS_LO, olut_lo >> 4) | + NVDEF(NVCA7D, HEAD_SET_SURFACE_ADDRESS_LO_OLUT, TARGET, PHYSICAL_NVM) | + NVDEF(NVCA7D, HEAD_SET_SURFACE_ADDRESS_LO_OLUT, ENABLE, ENABLE)); + + PUSH_MTHD(push, NVCA7D, HEAD_SET_OLUT_CONTROL(i), + NVVAL(NVCA7D, HEAD_SET_OLUT_CONTROL, INTERPOLATE, asyh->olut.output_mode) | + NVDEF(NVCA7D, HEAD_SET_OLUT_CONTROL, MIRROR, DISABLE) | + NVVAL(NVCA7D, HEAD_SET_OLUT_CONTROL, MODE, asyh->olut.mode) | + NVVAL(NVCA7D, HEAD_SET_OLUT_CONTROL, SIZE, asyh->olut.size), + + HEAD_SET_OLUT_FP_NORM_SCALE(i), 0xffffffff); + + return 0; +} + +static int +headca7d_mode(struct nv50_head *head, struct nv50_head_atom *asyh) +{ + struct nvif_push *push = &head->disp->core->chan.push; + struct nv50_head_mode *m = &asyh->mode; + const int i = head->base.index; + int ret; + + ret = PUSH_WAIT(push, 11); + if (ret) + return ret; + + PUSH_MTHD(push, NVCA7D, HEAD_SET_RASTER_SIZE(i), + NVVAL(NVCA7D, HEAD_SET_RASTER_SIZE, WIDTH, m->h.active) | + NVVAL(NVCA7D, HEAD_SET_RASTER_SIZE, HEIGHT, m->v.active), + + HEAD_SET_RASTER_SYNC_END(i), + NVVAL(NVCA7D, HEAD_SET_RASTER_SYNC_END, X, m->h.synce) | + NVVAL(NVCA7D, HEAD_SET_RASTER_SYNC_END, Y, m->v.synce), + + HEAD_SET_RASTER_BLANK_END(i), + NVVAL(NVCA7D, HEAD_SET_RASTER_BLANK_END, X, m->h.blanke) | + NVVAL(NVCA7D, HEAD_SET_RASTER_BLANK_END, Y, m->v.blanke), + + HEAD_SET_RASTER_BLANK_START(i), + NVVAL(NVCA7D, HEAD_SET_RASTER_BLANK_START, X, m->h.blanks) | + NVVAL(NVCA7D, HEAD_SET_RASTER_BLANK_START, Y, m->v.blanks)); + + PUSH_MTHD(push, NVCA7D, HEAD_SET_CONTROL(i), + NVDEF(NVCA7D, HEAD_SET_CONTROL, STRUCTURE, PROGRESSIVE)); + + PUSH_MTHD(push, NVCA7D, HEAD_SET_PIXEL_CLOCK_FREQUENCY(i), + NVVAL(NVCA7D, HEAD_SET_PIXEL_CLOCK_FREQUENCY, HERTZ, m->clock * 1000)); + + PUSH_MTHD(push, NVCA7D, HEAD_SET_PIXEL_CLOCK_FREQUENCY_MAX(i), + NVVAL(NVCA7D, HEAD_SET_PIXEL_CLOCK_FREQUENCY_MAX, HERTZ, m->clock * 1000)); + + return 0; +} + +static int +headca7d_view(struct nv50_head *head, struct nv50_head_atom *asyh) +{ + struct nvif_push *push = &head->disp->core->chan.push; + const int i = head->base.index; + int ret; + + ret = PUSH_WAIT(push, 4); + if (ret) + return ret; + + PUSH_MTHD(push, NVCA7D, HEAD_SET_VIEWPORT_SIZE_IN(i), + NVVAL(NVCA7D, HEAD_SET_VIEWPORT_SIZE_IN, WIDTH, asyh->view.iW) | + NVVAL(NVCA7D, HEAD_SET_VIEWPORT_SIZE_IN, HEIGHT, asyh->view.iH)); + + PUSH_MTHD(push, NVCA7D, HEAD_SET_VIEWPORT_SIZE_OUT(i), + NVVAL(NVCA7D, HEAD_SET_VIEWPORT_SIZE_OUT, WIDTH, asyh->view.oW) | + NVVAL(NVCA7D, HEAD_SET_VIEWPORT_SIZE_OUT, HEIGHT, asyh->view.oH)); + return 0; +} + +const struct nv50_head_func +headca7d = { + .view = headca7d_view, + .mode = headca7d_mode, + .olut = headc57d_olut, + .ilut_check = head907d_ilut_check, + .olut_identity = true, + .olut_size = 1024, + .olut_set = headca7d_olut_set, + .olut_clr = headca7d_olut_clr, + .curs_layout = head917d_curs_layout, + .curs_format = headc37d_curs_format, + .curs_set = headca7d_curs_set, + .curs_clr = headca7d_curs_clr, + .dither = headca7d_dither, + .procamp = headca7d_procamp, + .or = headca7d_or, + .static_wndw_map = headc37d_static_wndw_map, + .display_id = headca7d_display_id, +}; diff --git a/drivers/gpu/drm/nouveau/dispnv50/wimm.c b/drivers/gpu/drm/nouveau/dispnv50/wimm.c index 566fbddfc8d7..53c9ab6c138b 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/wimm.c +++ b/drivers/gpu/drm/nouveau/dispnv50/wimm.c @@ -31,6 +31,7 @@ nv50_wimm_init(struct nouveau_drm *drm, struct nv50_wndw *wndw) int version; int (*init)(struct nouveau_drm *, s32, struct nv50_wndw *); } wimms[] = { + { GB202_DISP_WINDOW_IMM_CHANNEL_DMA, 0, wimmc37b_init }, { GA102_DISP_WINDOW_IMM_CHANNEL_DMA, 0, wimmc37b_init }, { TU102_DISP_WINDOW_IMM_CHANNEL_DMA, 0, wimmc37b_init }, { GV100_DISP_WINDOW_IMM_CHANNEL_DMA, 0, wimmc37b_init }, diff --git a/drivers/gpu/drm/nouveau/dispnv50/wndw.c b/drivers/gpu/drm/nouveau/dispnv50/wndw.c index f6be426dd525..11d5b923d6e7 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/wndw.c +++ b/drivers/gpu/drm/nouveau/dispnv50/wndw.c @@ -556,14 +556,24 @@ nv50_wndw_prepare_fb(struct drm_plane *plane, struct drm_plane_state *state) return ret; if (wndw->ctxdma.parent) { - ctxdma = nv50_wndw_ctxdma_new(wndw, fb); - if (IS_ERR(ctxdma)) { - nouveau_bo_unpin(nvbo); - return PTR_ERR(ctxdma); + if (wndw->wndw.base.user.oclass < GB202_DISP_WINDOW_CHANNEL_DMA) { + ctxdma = nv50_wndw_ctxdma_new(wndw, fb); + if (IS_ERR(ctxdma)) { + nouveau_bo_unpin(nvbo); + return PTR_ERR(ctxdma); + } + + if (asyw->visible) + asyw->image.handle[0] = ctxdma->object.handle; + } else { + /* No CTXDMAs on Blackwell. */ + if (asyw->visible) { + /* "handle != NULL_HANDLE" is used to determine enable status + * in a number of places, so fill in a fake object handle. + */ + asyw->image.handle[0] = NV50_DISP_HANDLE_WNDW_CTX(0); + } } - - if (asyw->visible) - asyw->image.handle[0] = ctxdma->object.handle; } ret = drm_gem_plane_helper_prepare_fb(plane, state); @@ -901,6 +911,7 @@ nv50_wndw_new(struct nouveau_drm *drm, enum drm_plane_type type, int index, int (*new)(struct nouveau_drm *, enum drm_plane_type, int, s32, struct nv50_wndw **); } wndws[] = { + { GB202_DISP_WINDOW_CHANNEL_DMA, 0, wndwca7e_new }, { GA102_DISP_WINDOW_CHANNEL_DMA, 0, wndwc67e_new }, { TU102_DISP_WINDOW_CHANNEL_DMA, 0, wndwc57e_new }, { GV100_DISP_WINDOW_CHANNEL_DMA, 0, wndwc37e_new }, diff --git a/drivers/gpu/drm/nouveau/dispnv50/wndw.h b/drivers/gpu/drm/nouveau/dispnv50/wndw.h index 76a6ae5d5652..90d100514bef 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/wndw.h +++ b/drivers/gpu/drm/nouveau/dispnv50/wndw.h @@ -134,6 +134,9 @@ int wndwc57e_csc_clr(struct nv50_wndw *); int wndwc67e_new(struct nouveau_drm *, enum drm_plane_type, int, s32, struct nv50_wndw **); +int wndwca7e_new(struct nouveau_drm *, enum drm_plane_type, int, s32, + struct nv50_wndw **); + int nv50_wndw_new(struct nouveau_drm *, enum drm_plane_type, int index, struct nv50_wndw **); #endif diff --git a/drivers/gpu/drm/nouveau/dispnv50/wndwc37e.c b/drivers/gpu/drm/nouveau/dispnv50/wndwc37e.c index 50a7b97d37a2..554c4f91f8be 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/wndwc37e.c +++ b/drivers/gpu/drm/nouveau/dispnv50/wndwc37e.c @@ -25,6 +25,7 @@ #include <drm/drm_atomic_helper.h> #include <nouveau_bo.h> +#include <nvif/class.h> #include <nvif/if0014.h> #include <nvif/pushc37b.h> diff --git a/drivers/gpu/drm/nouveau/dispnv50/wndwca7e.c b/drivers/gpu/drm/nouveau/dispnv50/wndwca7e.c new file mode 100644 index 000000000000..0d8e9a9d1a57 --- /dev/null +++ b/drivers/gpu/drm/nouveau/dispnv50/wndwca7e.c @@ -0,0 +1,209 @@ +/* SPDX-License-Identifier: MIT + * + * Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved. + */ +#include "wndw.h" +#include "atom.h" + +#include <nvif/pushc97b.h> + +#include <nvhw/class/clca7e.h> + +#include <nouveau_bo.h> + +static int +wndwca7e_image_clr(struct nv50_wndw *wndw) +{ + struct nvif_push *push = &wndw->wndw.push; + int ret; + + ret = PUSH_WAIT(push, 4); + if (ret) + return ret; + + PUSH_MTHD(push, NVCA7E, SET_PRESENT_CONTROL, + NVVAL(NVCA7E, SET_PRESENT_CONTROL, MIN_PRESENT_INTERVAL, 0) | + NVDEF(NVCA7E, SET_PRESENT_CONTROL, BEGIN_MODE, NON_TEARING)); + + PUSH_MTHD(push, NVCA7E, SET_SURFACE_ADDRESS_LO_ISO(0), + NVDEF(NVCA7E, SET_SURFACE_ADDRESS_LO_ISO, ENABLE, DISABLE)); + + return 0; +} + +static int +wndwca7e_image_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw) +{ + const u32 iso0_hi = upper_32_bits(asyw->image.offset[0]); + const u32 iso0_lo = lower_32_bits(asyw->image.offset[0]); + struct nvif_push *push = &wndw->wndw.push; + int ret, kind; + + if (asyw->image.kind) + kind = NVCA7E_SET_SURFACE_ADDRESS_LO_ISO_KIND_BLOCKLINEAR; + else + kind = NVCA7E_SET_SURFACE_ADDRESS_LO_ISO_KIND_PITCH; + + ret = PUSH_WAIT(push, 17); + if (ret) + return ret; + + PUSH_MTHD(push, NVCA7E, SET_SURFACE_ADDRESS_HI_ISO(0), iso0_hi); + + PUSH_MTHD(push, NVCA7E, SET_SURFACE_ADDRESS_LO_ISO(0), + NVVAL(NVCA7E, SET_SURFACE_ADDRESS_LO_ISO, ADDRESS_LO, iso0_lo >> 4) | + NVDEF(NVCA7E, SET_SURFACE_ADDRESS_LO_ISO, TARGET, PHYSICAL_NVM) | + NVVAL(NVCA7E, SET_SURFACE_ADDRESS_LO_ISO, KIND, kind) | + NVDEF(NVCA7E, SET_SURFACE_ADDRESS_LO_ISO, ENABLE, ENABLE)); + + PUSH_MTHD(push, NVCA7E, SET_PRESENT_CONTROL, + NVVAL(NVCA7E, SET_PRESENT_CONTROL, MIN_PRESENT_INTERVAL, asyw->image.interval) | + NVVAL(NVCA7E, SET_PRESENT_CONTROL, BEGIN_MODE, asyw->image.mode) | + NVDEF(NVCA7E, SET_PRESENT_CONTROL, TIMESTAMP_MODE, DISABLE)); + + PUSH_MTHD(push, NVCA7E, SET_SIZE, + NVVAL(NVCA7E, SET_SIZE, WIDTH, asyw->image.w) | + NVVAL(NVCA7E, SET_SIZE, HEIGHT, asyw->image.h), + + SET_STORAGE, + NVVAL(NVCA7E, SET_STORAGE, BLOCK_HEIGHT, asyw->image.blockh), + + SET_PARAMS, + NVVAL(NVCA7E, SET_PARAMS, FORMAT, asyw->image.format) | + NVDEF(NVCA7E, SET_PARAMS, CLAMP_BEFORE_BLEND, DISABLE) | + NVDEF(NVCA7E, SET_PARAMS, SWAP_UV, DISABLE) | + NVDEF(NVCA7E, SET_PARAMS, FMT_ROUNDING_MODE, ROUND_TO_NEAREST), + + SET_PLANAR_STORAGE(0), + NVVAL(NVCA7E, SET_PLANAR_STORAGE, PITCH, asyw->image.blocks[0]) | + NVVAL(NVCA7E, SET_PLANAR_STORAGE, PITCH, asyw->image.pitch[0] >> 6)); + + PUSH_MTHD(push, NVCA7E, SET_POINT_IN(0), + NVVAL(NVCA7E, SET_POINT_IN, X, asyw->state.src_x >> 16) | + NVVAL(NVCA7E, SET_POINT_IN, Y, asyw->state.src_y >> 16)); + + PUSH_MTHD(push, NVCA7E, SET_SIZE_IN, + NVVAL(NVCA7E, SET_SIZE_IN, WIDTH, asyw->state.src_w >> 16) | + NVVAL(NVCA7E, SET_SIZE_IN, HEIGHT, asyw->state.src_h >> 16)); + + PUSH_MTHD(push, NVCA7E, SET_SIZE_OUT, + NVVAL(NVCA7E, SET_SIZE_OUT, WIDTH, asyw->state.crtc_w) | + NVVAL(NVCA7E, SET_SIZE_OUT, HEIGHT, asyw->state.crtc_h)); + + return 0; +} + +static int +wndwca7e_ilut_clr(struct nv50_wndw *wndw) +{ + struct nvif_push *push = &wndw->wndw.push; + int ret; + + ret = PUSH_WAIT(push, 2); + if (ret) + return ret; + + PUSH_MTHD(push, NVCA7E, SET_SURFACE_ADDRESS_LO_ILUT, + NVDEF(NVCA7E, SET_SURFACE_ADDRESS_LO_ILUT, ENABLE, DISABLE)); + + return 0; +} + +static int +wndwca7e_ilut_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw) +{ + const u32 ilut_hi = upper_32_bits(asyw->xlut.i.offset); + const u32 ilut_lo = lower_32_bits(asyw->xlut.i.offset); + struct nvif_push *push = &wndw->wndw.push; + int ret; + + ret = PUSH_WAIT(push, 5); + if (ret) + return ret; + + PUSH_MTHD(push, NVCA7E, SET_SURFACE_ADDRESS_HI_ILUT, ilut_hi, + + SET_SURFACE_ADDRESS_LO_ILUT, + NVVAL(NVCA7E, SET_SURFACE_ADDRESS_LO_ILUT, ADDRESS_LO, ilut_lo >> 4) | + NVDEF(NVCA7E, SET_SURFACE_ADDRESS_LO_ILUT, TARGET, PHYSICAL_NVM) | + NVDEF(NVCA7E, SET_SURFACE_ADDRESS_LO_ILUT, ENABLE, ENABLE)); + + PUSH_MTHD(push, NVCA7E, SET_ILUT_CONTROL, + NVVAL(NVCA7E, SET_ILUT_CONTROL, SIZE, asyw->xlut.i.size) | + NVVAL(NVCA7E, SET_ILUT_CONTROL, MODE, asyw->xlut.i.mode) | + NVVAL(NVCA7E, SET_ILUT_CONTROL, INTERPOLATE, asyw->xlut.i.output_mode)); + + return 0; +} + +static int +wndwca7e_ntfy_clr(struct nv50_wndw *wndw) +{ + struct nvif_push *push = &wndw->wndw.push; + int ret; + + ret = PUSH_WAIT(push, 2); + if (ret) + return ret; + + PUSH_MTHD(push, NVCA7E, SET_SURFACE_ADDRESS_LO_NOTIFIER, + NVDEF(NVCA7E, SET_SURFACE_ADDRESS_LO_NOTIFIER, ENABLE, DISABLE)); + + return 0; +} + +static int +wndwca7e_ntfy_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw) +{ + struct nv50_disp *disp = nv50_disp(wndw->plane.dev); + const u64 ntfy_addr = disp->sync->offset + asyw->ntfy.offset; + const u32 ntfy_hi = upper_32_bits(ntfy_addr); + const u32 ntfy_lo = lower_32_bits(ntfy_addr); + struct nvif_push *push = &wndw->wndw.push; + int ret; + + ret = PUSH_WAIT(push, 5); + if (ret) + return ret; + + PUSH_MTHD(push, NVCA7E, SET_SURFACE_ADDRESS_HI_NOTIFIER, ntfy_hi, + + SET_SURFACE_ADDRESS_LO_NOTIFIER, + NVVAL(NVCA7E, SET_SURFACE_ADDRESS_LO_NOTIFIER, ADDRESS_LO, ntfy_lo >> 4) | + NVDEF(NVCA7E, SET_SURFACE_ADDRESS_LO_NOTIFIER, TARGET, PHYSICAL_NVM) | + NVDEF(NVCA7E, SET_SURFACE_ADDRESS_LO_NOTIFIER, ENABLE, ENABLE)); + + PUSH_MTHD(push, NVCA7E, SET_NOTIFIER_CONTROL, + NVVAL(NVCA7E, SET_NOTIFIER_CONTROL, MODE, asyw->ntfy.awaken)); + + return 0; +} + +static const struct nv50_wndw_func +wndwca7e = { + .acquire = wndwc37e_acquire, + .release = wndwc37e_release, + .ntfy_set = wndwca7e_ntfy_set, + .ntfy_clr = wndwca7e_ntfy_clr, + .ntfy_reset = corec37d_ntfy_init, + .ntfy_wait_begun = base507c_ntfy_wait_begun, + .ilut = wndwc57e_ilut, + .ilut_identity = true, + .ilut_size = 1024, + .xlut_set = wndwca7e_ilut_set, + .xlut_clr = wndwca7e_ilut_clr, + .csc = base907c_csc, + .csc_set = wndwc57e_csc_set, + .csc_clr = wndwc57e_csc_clr, + .image_set = wndwca7e_image_set, + .image_clr = wndwca7e_image_clr, + .blend_set = wndwc37e_blend_set, + .update = wndwc37e_update, +}; + +int +wndwca7e_new(struct nouveau_drm *drm, enum drm_plane_type type, int index, + s32 oclass, struct nv50_wndw **pwndw) +{ + return wndwc37e_new_(&wndwca7e, drm, type, index, oclass, BIT(index >> 1), pwndw); +} |