Commit 74cfa1ef authored by Jocelyn Falempe's avatar Jocelyn Falempe
Browse files

drm/nouveau/disp: Move tiling functions to dispnv50/tile.h



Refactor, and move the tiling geometry functions to dispnv50/tile.h,
so they can be re-used by drm_panic.
No functional impact.

Signed-off-by: default avatarJocelyn Falempe <jfalempe@redhat.com>
Reviewed-by: default avatarLyude Paul <lyude@redhat.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20241022185553.1103384-3-jfalempe@redhat.com
parent 04596969
Loading
Loading
Loading
Loading
+63 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: MIT */
#ifndef __NV50_TILE_H__
#define __NV50_TILE_H__

#include <linux/types.h>
#include <linux/math.h>

/*
 * Tiling parameters for NV50+.
 * GOB = Group of bytes, the main unit for tiling blocks.
 * Tiling blocks are a power of 2 number of GOB.
 * All GOBs and blocks have the same width: 64 bytes (so 16 pixels in 32bits).
 * tile_mode is the log2 of the number of GOB per block.
 */

#define NV_TILE_GOB_HEIGHT_TESLA 4	/* 4 x 64 bytes = 256 bytes for a GOB on Tesla*/
#define NV_TILE_GOB_HEIGHT 8		/* 8 x 64 bytes = 512 bytes for a GOB on Fermi and later */
#define NV_TILE_GOB_WIDTH_BYTES 64

/* Number of blocks to cover the width of the framebuffer */
static inline u32 nouveau_get_width_in_blocks(u32 stride)
{
	return DIV_ROUND_UP(stride, NV_TILE_GOB_WIDTH_BYTES);
}

/* Return the height in pixel of one GOB */
static inline u32 nouveau_get_gob_height(u16 family)
{
	if (family == NV_DEVICE_INFO_V0_TESLA)
		return NV_TILE_GOB_HEIGHT_TESLA;
	else
		return NV_TILE_GOB_HEIGHT;
}

/* Number of blocks to cover the heigth of the framebuffer */
static inline u32 nouveau_get_height_in_blocks(u32 height, u32 gobs_in_block, u16 family)
{
	return DIV_ROUND_UP(height, nouveau_get_gob_height(family) * gobs_in_block);
}

/* Return the GOB size in bytes */
static inline u32 nouveau_get_gob_size(u16 family)
{
	return nouveau_get_gob_height(family) * NV_TILE_GOB_WIDTH_BYTES;
}

/* Return the number of GOB in a block */
static inline int nouveau_get_gobs_in_block(u32 tile_mode, u16 chipset)
{
	if (chipset >= 0xc0)
		return 1 << (tile_mode >> 4);
	return 1 << tile_mode;
}

/* Return true if tile_mode is invalid */
static inline bool nouveau_check_tile_mode(u32 tile_mode, u16 chipset)
{
	if (chipset >= 0xc0)
		return (tile_mode & 0xfffff0f);
	return (tile_mode & 0xfffffff0);
}

#endif
+10 −49
Original line number Diff line number Diff line
@@ -44,6 +44,7 @@
#include <nvif/if0011.h>
#include <nvif/if0013.h>
#include <dispnv50/crc.h>
#include <dispnv50/tile.h>

int
nouveau_display_vblank_enable(struct drm_crtc *crtc)
@@ -220,69 +221,29 @@ nouveau_validate_decode_mod(struct nouveau_drm *drm,
	return 0;
}

static inline uint32_t
nouveau_get_width_in_blocks(uint32_t stride)
{
	/* GOBs per block in the x direction is always one, and GOBs are
	 * 64 bytes wide
	 */
	static const uint32_t log_block_width = 6;

	return (stride + (1 << log_block_width) - 1) >> log_block_width;
}

static inline uint32_t
nouveau_get_height_in_blocks(struct nouveau_drm *drm,
			     uint32_t height,
			     uint32_t log_block_height_in_gobs)
{
	uint32_t log_gob_height;
	uint32_t log_block_height;

	BUG_ON(drm->client.device.info.family < NV_DEVICE_INFO_V0_TESLA);

	if (drm->client.device.info.family < NV_DEVICE_INFO_V0_FERMI)
		log_gob_height = 2;
	else
		log_gob_height = 3;

	log_block_height = log_block_height_in_gobs + log_gob_height;

	return (height + (1 << log_block_height) - 1) >> log_block_height;
}

static int
nouveau_check_bl_size(struct nouveau_drm *drm, struct nouveau_bo *nvbo,
		      uint32_t offset, uint32_t stride, uint32_t h,
		      uint32_t tile_mode)
{
	uint32_t gob_size, bw, bh;
	uint32_t gob_size, bw, bh, gobs_in_block;
	uint64_t bl_size;

	BUG_ON(drm->client.device.info.family < NV_DEVICE_INFO_V0_TESLA);

	if (drm->client.device.info.chipset >= 0xc0) {
		if (tile_mode & 0xF)
	if (nouveau_check_tile_mode(tile_mode, drm->client.device.info.chipset))
		return -EINVAL;
		tile_mode >>= 4;
	}

	if (tile_mode & 0xFFFFFFF0)
		return -EINVAL;

	if (drm->client.device.info.family < NV_DEVICE_INFO_V0_FERMI)
		gob_size = 256;
	else
		gob_size = 512;

	gobs_in_block = nouveau_get_gobs_in_block(tile_mode, drm->client.device.info.chipset);
	bw = nouveau_get_width_in_blocks(stride);
	bh = nouveau_get_height_in_blocks(drm, h, tile_mode);
	bh = nouveau_get_height_in_blocks(h, gobs_in_block, drm->client.device.info.family);
	gob_size = nouveau_get_gob_size(drm->client.device.info.family);

	bl_size = bw * bh * (1 << tile_mode) * gob_size;
	bl_size = bw * bh * gobs_in_block * gob_size;

	DRM_DEBUG_KMS("offset=%u stride=%u h=%u tile_mode=0x%02x bw=%u bh=%u gob_size=%u bl_size=%llu size=%zu\n",
		      offset, stride, h, tile_mode, bw, bh, gob_size, bl_size,
		      nvbo->bo.base.size);
	DRM_DEBUG_KMS("offset=%u stride=%u h=%u gobs_in_block=%u bw=%u bh=%u gob_size=%u bl_size=%llu size=%zu\n",
		      offset, stride, h, gobs_in_block, bw, bh, gob_size,
		      bl_size, nvbo->bo.base.size);

	if (bl_size + offset > nvbo->bo.base.size)
		return -ERANGE;