1
0
Fork 0
mirror of synced 2025-03-06 20:59:54 +01:00
linux/drivers/gpu/drm/nouveau/dispnv50/crc.h
Lyude Paul 57cbdbe65e drm/nouveau/kms/nv140-: Use hard-coded wndws or core channel for CRC channel
Originally it was assumed based on Nvidia's open-gpu-docs and testing that
NVDisplay required that at least one wndw which belongs to a given head to
be used as the controlling channel
(NVC37D_HEAD_SET_CRC_CONTROL_CONTROLLING_CHANNEL) in order for CRC capture
to function. While this is the case on Volta, Turing actually adds the
ability to instead use the core channel as the controlling channel. For
Turing this is quite useful, as it means that we can always default to the
core channel as the controlling channel and we don't need to be concerned
about ensuring we have at least one wndw channel owned by a head with CRC
output enabled. While Volta lacks this ability, Volta conveniently also
lacks flexible wndw mapping - meaning that we can always rely on each head
having four wndw channels mapped to it regardless of the atomic state.

So, simply use the hard-coded wndw mappings we're guaranteed to have on
Volta as the controlling channel, and use the core channel as the
controlling channel for Turing+. As a result this also renders the plane
ownership logic in nv50_crc_atomic_check() unnessecary, which gives us one
less thing to implement when we get support for flexible wndw mapping. We
also can entirely drop the wndw parameter from our set_src callbacks, and
the atomic state.

v2 (Karol): put prackets around complex macro definition
            removed spaces before :32 in structs

Cc: Martin Peres <martin.peres@free.fr>
Cc: Jeremy Cline <jcline@redhat.com>
Cc: Simon Ser <contact@emersion.fr>
Signed-off-by: Lyude Paul <lyude@redhat.com>
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Reviewed-by: Karol Herbst <kherbst@redhat.com>
Signed-off-by: Karol Herbst <kherbst@redhat.com>
Link: https://gitlab.freedesktop.org/drm/nouveau/-/merge_requests/10
2021-11-12 23:46:03 +01:00

131 lines
3.8 KiB
C

/* SPDX-License-Identifier: MIT */
#ifndef __NV50_CRC_H__
#define __NV50_CRC_H__
#include <linux/mutex.h>
#include <drm/drm_crtc.h>
#include <drm/drm_vblank_work.h>
#include <nvif/mem.h>
#include <nvkm/subdev/bios.h>
#include "nouveau_encoder.h"
struct nv50_atom;
struct nv50_disp;
struct nv50_head;
#if IS_ENABLED(CONFIG_DEBUG_FS)
enum nv50_crc_source {
NV50_CRC_SOURCE_NONE = 0,
NV50_CRC_SOURCE_AUTO,
NV50_CRC_SOURCE_RG,
NV50_CRC_SOURCE_OUTP_ACTIVE,
NV50_CRC_SOURCE_OUTP_COMPLETE,
NV50_CRC_SOURCE_OUTP_INACTIVE,
};
/* RG -> SF (DP only)
* -> SOR
* -> PIOR
* -> DAC
*/
enum nv50_crc_source_type {
NV50_CRC_SOURCE_TYPE_NONE = 0,
NV50_CRC_SOURCE_TYPE_SOR,
NV50_CRC_SOURCE_TYPE_PIOR,
NV50_CRC_SOURCE_TYPE_DAC,
NV50_CRC_SOURCE_TYPE_RG,
NV50_CRC_SOURCE_TYPE_SF,
};
struct nv50_crc_notifier_ctx {
struct nvif_mem mem;
struct nvif_object ntfy;
};
struct nv50_crc_atom {
enum nv50_crc_source src;
};
struct nv50_crc_func {
int (*set_src)(struct nv50_head *, int or, enum nv50_crc_source_type type,
struct nv50_crc_notifier_ctx *ctx);
int (*set_ctx)(struct nv50_head *, struct nv50_crc_notifier_ctx *);
u32 (*get_entry)(struct nv50_head *, struct nv50_crc_notifier_ctx *,
enum nv50_crc_source, int idx);
bool (*ctx_finished)(struct nv50_head *,
struct nv50_crc_notifier_ctx *);
short flip_threshold;
short num_entries;
size_t notifier_len;
};
struct nv50_crc {
spinlock_t lock;
struct nv50_crc_notifier_ctx ctx[2];
struct drm_vblank_work flip_work;
enum nv50_crc_source src;
u64 frame;
short entry_idx;
short flip_threshold;
u8 ctx_idx : 1;
bool ctx_changed : 1;
};
void nv50_crc_init(struct drm_device *dev);
int nv50_head_crc_late_register(struct nv50_head *);
void nv50_crc_handle_vblank(struct nv50_head *head);
int nv50_crc_verify_source(struct drm_crtc *, const char *, size_t *);
const char *const *nv50_crc_get_sources(struct drm_crtc *, size_t *);
int nv50_crc_set_source(struct drm_crtc *, const char *);
int nv50_crc_atomic_check_head(struct nv50_head *, struct nv50_head_atom *,
struct nv50_head_atom *);
void nv50_crc_atomic_check_outp(struct nv50_atom *atom);
void nv50_crc_atomic_stop_reporting(struct drm_atomic_state *);
void nv50_crc_atomic_init_notifier_contexts(struct drm_atomic_state *);
void nv50_crc_atomic_release_notifier_contexts(struct drm_atomic_state *);
void nv50_crc_atomic_start_reporting(struct drm_atomic_state *);
void nv50_crc_atomic_set(struct nv50_head *, struct nv50_head_atom *);
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;
#else /* IS_ENABLED(CONFIG_DEBUG_FS) */
struct nv50_crc {};
struct nv50_crc_func {};
struct nv50_crc_atom {};
#define nv50_crc_verify_source NULL
#define nv50_crc_get_sources NULL
#define nv50_crc_set_source NULL
static inline void nv50_crc_init(struct drm_device *dev) {}
static inline int
nv50_head_crc_late_register(struct nv50_head *head) { return 0; }
static inline void nv50_crc_handle_vblank(struct nv50_head *head) {}
static inline int
nv50_crc_atomic_check_head(struct nv50_head *head,
struct nv50_head_atom *asyh,
struct nv50_head_atom *armh) { return 0; }
static inline void nv50_crc_atomic_check_outp(struct nv50_atom *atom) {}
static inline void
nv50_crc_atomic_stop_reporting(struct drm_atomic_state *state) {}
static inline void
nv50_crc_atomic_init_notifier_contexts(struct drm_atomic_state *state) {}
static inline void
nv50_crc_atomic_release_notifier_contexts(struct drm_atomic_state *state) {}
static inline void
nv50_crc_atomic_start_reporting(struct drm_atomic_state *state) {}
static inline void
nv50_crc_atomic_set(struct nv50_head *head, struct nv50_head_atom *state) {}
static inline void
nv50_crc_atomic_clr(struct nv50_head *head) {}
#endif /* IS_ENABLED(CONFIG_DEBUG_FS) */
#endif /* !__NV50_CRC_H__ */