Commit 9e994444 authored by Ben Skeggs's avatar Ben Skeggs Committed by Dave Airlie
Browse files

drm/nouveau/disp/r535: initial support

parent 5bf02571
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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[] = {
		{ AD102_DISP_CORE_CHANNEL_DMA, 0, corec57d_new },
		{ GA102_DISP_CORE_CHANNEL_DMA, 0, corec57d_new },
		{ TU102_DISP_CORE_CHANNEL_DMA, 0, corec57d_new },
		{ GV100_DISP_CORE_CHANNEL_DMA, 0, corec37d_new },
+141 −0
Original line number Diff line number Diff line
@@ -1592,6 +1592,146 @@ nv50_sor_atomic_disable(struct drm_encoder *encoder, struct drm_atomic_state *st
	nv_encoder->crtc = NULL;
}

// common/inc/displayport/displayport.h
#define DP_CONFIG_WATERMARK_ADJUST                   2
#define DP_CONFIG_WATERMARK_LIMIT                   20
#define DP_CONFIG_INCREASED_WATERMARK_ADJUST         8
#define DP_CONFIG_INCREASED_WATERMARK_LIMIT         22

static bool
nv50_sor_dp_watermark_sst(struct nouveau_encoder *outp,
			  struct nv50_head *head, struct nv50_head_atom *asyh)
{
	bool enhancedFraming = outp->dp.dpcd[DP_MAX_LANE_COUNT] & DP_ENHANCED_FRAME_CAP;
	u64 minRate = outp->dp.link_bw * 1000;
	unsigned tuSize = 64;
	unsigned waterMark;
	unsigned hBlankSym;
	unsigned vBlankSym;
	unsigned watermarkAdjust = DP_CONFIG_WATERMARK_ADJUST;
	unsigned watermarkMinimum = DP_CONFIG_WATERMARK_LIMIT;
	// depth is multiplied by 16 in case of DSC enable
	s32 hblank_symbols;
	// number of link clocks per line.
	int vblank_symbols	  = 0;
	bool bEnableDsc = false;
	unsigned surfaceWidth = asyh->mode.h.blanks - asyh->mode.h.blanke;
	unsigned rasterWidth = asyh->mode.h.active;
	unsigned depth = asyh->or.bpc * 3;
	unsigned DSC_FACTOR = bEnableDsc ? 16 : 1;
	u64 pixelClockHz = asyh->mode.clock * 1000;
	u64 PrecisionFactor = 100000, ratioF, watermarkF;
	u32 numLanesPerLink = outp->dp.link_nr;
	u32 numSymbolsPerLine;
	u32 BlankingBits;
	u32 surfaceWidthPerLink;
	u32 PixelSteeringBits;
	u64 NumBlankingLinkClocks;
	u32 MinHBlank;

	if (outp->outp.info.dp.increased_wm) {
		watermarkAdjust = DP_CONFIG_INCREASED_WATERMARK_ADJUST;
		watermarkMinimum = DP_CONFIG_INCREASED_WATERMARK_LIMIT;
	}

	if ((pixelClockHz * depth) >= (8 * minRate * outp->dp.link_nr * DSC_FACTOR))
	{
		return false;
	}

	//
	// For DSC, if (pclk * bpp) < (1/64 * orclk * 8 * lanes) then some TU may end up with
	// 0 active symbols. This may cause HW hang. Bug 200379426
	//
	if ((bEnableDsc) &&
		((pixelClockHz * depth) < ((8 * minRate * outp->dp.link_nr * DSC_FACTOR) / 64)))
	{
		return false;
	}

	//
	//  Perform the SST calculation.
	//	For auto mode the watermark calculation does not need to track accumulated error the
	//	formulas for manual mode will not work.  So below calculation was extracted from the DTB.
	//
	ratioF = ((u64)pixelClockHz * depth * PrecisionFactor) / DSC_FACTOR;

	ratioF /= 8 * (u64) minRate * outp->dp.link_nr;

	if (PrecisionFactor < ratioF) // Assert if we will end up with a negative number in below
		return false;

	watermarkF = ratioF * tuSize * (PrecisionFactor - ratioF)  / PrecisionFactor;
	waterMark = (unsigned)(watermarkAdjust + ((2 * (depth * PrecisionFactor / (8 * numLanesPerLink * DSC_FACTOR)) + watermarkF) / PrecisionFactor));

	//
	//  Bounds check the watermark
	//
	numSymbolsPerLine = (surfaceWidth * depth) / (8 * outp->dp.link_nr * DSC_FACTOR);

	if (WARN_ON(waterMark > 39 || waterMark > numSymbolsPerLine))
		return false;

	//
	//  Clamp the low side
	//
	if (waterMark < watermarkMinimum)
		waterMark = watermarkMinimum;

	//Bits to send BS/BE/Extra symbols due to pixel padding
	//Also accounts for enhanced framing.
	BlankingBits = 3*8*numLanesPerLink + (enhancedFraming ? 3*8*numLanesPerLink : 0);

	//VBID/MVID/MAUD sent 4 times all the time
	BlankingBits += 3*8*4;

	surfaceWidthPerLink = surfaceWidth;

	//Extra bits sent due to pixel steering
	PixelSteeringBits = (surfaceWidthPerLink % numLanesPerLink) ? (((numLanesPerLink - surfaceWidthPerLink % numLanesPerLink) * depth) / DSC_FACTOR) : 0;

	BlankingBits += PixelSteeringBits;
	NumBlankingLinkClocks = (u64)BlankingBits * PrecisionFactor / (8 * numLanesPerLink);
	MinHBlank = (u32)(NumBlankingLinkClocks * pixelClockHz/ minRate / PrecisionFactor);
	MinHBlank += 12;

	if (WARN_ON(MinHBlank > rasterWidth - surfaceWidth))
		return false;

	// Bug 702290 - Active Width should be greater than 60
	if (WARN_ON(surfaceWidth <= 60))
		return false;


	hblank_symbols = (s32)(((u64)(rasterWidth - surfaceWidth - MinHBlank) * minRate) / pixelClockHz);

	//reduce HBlank Symbols to account for secondary data packet
	hblank_symbols -= 1; //Stuffer latency to send BS
	hblank_symbols -= 3; //SPKT latency to send data to stuffer

	hblank_symbols -= numLanesPerLink == 1 ? 9  : numLanesPerLink == 2 ? 6 : 3;

	hBlankSym = (hblank_symbols < 0) ? 0 : hblank_symbols;

	// Refer to dev_disp.ref for more information.
	// # symbols/vblank = ((SetRasterBlankEnd.X + SetRasterSize.Width - SetRasterBlankStart.X - 40) * link_clk / pclk) - Y - 1;
	// where Y = (# lanes == 4) 12 : (# lanes == 2) ? 21 : 39
	if (surfaceWidth < 40)
	{
		vblank_symbols = 0;
	}
	else
	{
		vblank_symbols = (s32)(((u64)(surfaceWidth - 40) * minRate) /  pixelClockHz) - 1;

		vblank_symbols -= numLanesPerLink == 1 ? 39  : numLanesPerLink == 2 ? 21 : 12;
	}

	vBlankSym = (vblank_symbols < 0) ? 0 : vblank_symbols;

	return nvif_outp_dp_sst(&outp->outp, head->base.index, waterMark, hBlankSym, vBlankSym);
}

static void
nv50_sor_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *state)
{
@@ -1679,6 +1819,7 @@ nv50_sor_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *sta
		break;
	case DCB_OUTPUT_DP:
		nouveau_dp_train(nv_encoder, false, mode->clock, asyh->or.bpc);
		nv50_sor_dp_watermark_sst(nv_encoder, head, asyh);
		depth = nv50_dp_bpc_to_depth(asyh->or.bpc);

		if (nv_encoder->outp.or.link & 1)
+2 −0
Original line number Diff line number Diff line
@@ -104,6 +104,7 @@
#define GV100_DISP                                    /* if0010.h */ 0x0000c370
#define TU102_DISP                                    /* if0010.h */ 0x0000c570
#define GA102_DISP                                    /* if0010.h */ 0x0000c670
#define AD102_DISP                                    /* if0010.h */ 0x0000c770

#define GV100_DISP_CAPS                                              0x0000c373

@@ -154,6 +155,7 @@
#define GV100_DISP_CORE_CHANNEL_DMA                   /* if0014.h */ 0x0000c37d
#define TU102_DISP_CORE_CHANNEL_DMA                   /* if0014.h */ 0x0000c57d
#define GA102_DISP_CORE_CHANNEL_DMA                   /* if0014.h */ 0x0000c67d
#define AD102_DISP_CORE_CHANNEL_DMA                   /* if0014.h */ 0x0000c77d

#define NV50_DISP_OVERLAY_CHANNEL_DMA                 /* if0014.h */ 0x0000507e
#define G82_DISP_OVERLAY_CHANNEL_DMA                  /* if0014.h */ 0x0000827e
+19 −0
Original line number Diff line number Diff line
@@ -5,11 +5,29 @@
#include <core/engine.h>
#include <core/object.h>
#include <core/event.h>
#include <subdev/gsp.h>

struct nvkm_disp {
	const struct nvkm_disp_func *func;
	struct nvkm_engine engine;

	struct {
		struct nvkm_gsp_client client;
		struct nvkm_gsp_device device;

		struct nvkm_gsp_object objcom;
		struct nvkm_gsp_object object;

#define NVKM_DPYID_PLUG   BIT(0)
#define NVKM_DPYID_UNPLUG BIT(1)
#define NVKM_DPYID_IRQ    BIT(2)
		struct nvkm_event event;
		struct nvkm_gsp_event hpd;
		struct nvkm_gsp_event irq;

		u32 assigned_sors;
	} rm;

	struct list_head heads;
	struct list_head iors;
	struct list_head outps;
@@ -69,4 +87,5 @@ int gp102_disp_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct
int gv100_disp_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_disp **);
int tu102_disp_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_disp **);
int ga102_disp_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_disp **);
int ad102_disp_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_disp **);
#endif
+35 −0
Original line number Diff line number Diff line
@@ -23,6 +23,9 @@ void nvkm_gsp_sg_free(struct nvkm_device *, struct sg_table *);

typedef int (*nvkm_gsp_msg_ntfy_func)(void *priv, u32 fn, void *repv, u32 repc);

struct nvkm_gsp_event;
typedef void (*nvkm_gsp_event_func)(struct nvkm_gsp_event *, void *repv, u32 repc);

struct nvkm_gsp {
	const struct nvkm_gsp_func *func;
	struct nvkm_subdev subdev;
@@ -150,6 +153,8 @@ struct nvkm_gsp {
			} object;

			struct nvkm_gsp *gsp;

			struct list_head events;
		} client;

		struct nvkm_gsp_device {
@@ -191,6 +196,10 @@ struct nvkm_gsp {

		int (*device_ctor)(struct nvkm_gsp_client *, struct nvkm_gsp_device *);
		void (*device_dtor)(struct nvkm_gsp_device *);

		int (*event_ctor)(struct nvkm_gsp_device *, u32 handle, u32 id,
				  nvkm_gsp_event_func, struct nvkm_gsp_event *);
		void (*event_dtor)(struct nvkm_gsp_event *);
	} *rm;

	struct {
@@ -399,6 +408,32 @@ nvkm_gsp_client_device_ctor(struct nvkm_gsp *gsp,
	return ret;
}

struct nvkm_gsp_event {
	struct nvkm_gsp_device *device;
	u32 id;
	nvkm_gsp_event_func func;

	struct nvkm_gsp_object object;

	struct list_head head;
};

static inline int
nvkm_gsp_device_event_ctor(struct nvkm_gsp_device *device, u32 handle, u32 id,
			   nvkm_gsp_event_func func, struct nvkm_gsp_event *event)
{
	return device->object.client->gsp->rm->event_ctor(device, handle, id, func, event);
}

static inline void
nvkm_gsp_event_dtor(struct nvkm_gsp_event *event)
{
	struct nvkm_gsp_device *device = event->device;

	if (device)
		device->object.client->gsp->rm->event_dtor(event);
}

int nvkm_gsp_intr_stall(struct nvkm_gsp *, enum nvkm_subdev_type, int);
int nvkm_gsp_intr_nonstall(struct nvkm_gsp *, enum nvkm_subdev_type, int);

Loading