794 lines · 17.8 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-only/* * Copyright (C) 2017 NVIDIA CORPORATION.  All rights reserved. */ #include <linux/dma-mapping.h>#include <linux/iommu.h>#include <linux/interconnect.h> #include <drm/drm_atomic.h>#include <drm/drm_atomic_helper.h>#include <drm/drm_fourcc.h>#include <drm/drm_framebuffer.h>#include <drm/drm_gem_atomic_helper.h> #include "dc.h"#include "plane.h" static void tegra_plane_destroy(struct drm_plane *plane){	struct tegra_plane *p = to_tegra_plane(plane); 	drm_plane_cleanup(plane);	kfree(p);} static void tegra_plane_reset(struct drm_plane *plane){	struct tegra_plane *p = to_tegra_plane(plane);	struct tegra_plane_state *state;	unsigned int i; 	if (plane->state)		__drm_atomic_helper_plane_destroy_state(plane->state); 	kfree(plane->state);	plane->state = NULL; 	state = kzalloc_obj(*state);	if (state) {		plane->state = &state->base;		plane->state->plane = plane;		plane->state->zpos = p->index;		plane->state->normalized_zpos = p->index; 		for (i = 0; i < 3; i++)			state->iova[i] = DMA_MAPPING_ERROR;	}} static struct drm_plane_state *tegra_plane_atomic_duplicate_state(struct drm_plane *plane){	struct tegra_plane_state *state = to_tegra_plane_state(plane->state);	struct tegra_plane_state *copy;	unsigned int i; 	copy = kmalloc_obj(*copy);	if (!copy)		return NULL; 	__drm_atomic_helper_plane_duplicate_state(plane, &copy->base);	copy->tiling = state->tiling;	copy->format = state->format;	copy->swap = state->swap;	copy->reflect_x = state->reflect_x;	copy->reflect_y = state->reflect_y;	copy->opaque = state->opaque;	copy->total_peak_memory_bandwidth = state->total_peak_memory_bandwidth;	copy->peak_memory_bandwidth = state->peak_memory_bandwidth;	copy->avg_memory_bandwidth = state->avg_memory_bandwidth; 	for (i = 0; i < 2; i++)		copy->blending[i] = state->blending[i]; 	for (i = 0; i < 3; i++) {		copy->iova[i] = DMA_MAPPING_ERROR;		copy->map[i] = NULL;	} 	return &copy->base;} static void tegra_plane_atomic_destroy_state(struct drm_plane *plane,					     struct drm_plane_state *state){	__drm_atomic_helper_plane_destroy_state(state);	kfree(state);} static bool tegra_plane_supports_sector_layout(struct drm_plane *plane){	struct drm_crtc *crtc; 	drm_for_each_crtc(crtc, plane->dev) {		if (plane->possible_crtcs & drm_crtc_mask(crtc)) {			struct tegra_dc *dc = to_tegra_dc(crtc); 			if (!dc->soc->supports_sector_layout)				return false;		}	} 	return true;} static bool tegra_plane_format_mod_supported(struct drm_plane *plane,					     uint32_t format,					     uint64_t modifier){	const struct drm_format_info *info = drm_format_info(format); 	if (modifier == DRM_FORMAT_MOD_LINEAR)		return true; 	/* check for the sector layout bit */	if (fourcc_mod_is_vendor(modifier, NVIDIA)) {		if (modifier & DRM_FORMAT_MOD_NVIDIA_SECTOR_LAYOUT) {			if (!tegra_plane_supports_sector_layout(plane))				return false;		}	} 	if (info->num_planes == 1)		return true; 	return false;} const struct drm_plane_funcs tegra_plane_funcs = {	.update_plane = drm_atomic_helper_update_plane,	.disable_plane = drm_atomic_helper_disable_plane,	.destroy = tegra_plane_destroy,	.reset = tegra_plane_reset,	.atomic_duplicate_state = tegra_plane_atomic_duplicate_state,	.atomic_destroy_state = tegra_plane_atomic_destroy_state,	.format_mod_supported = tegra_plane_format_mod_supported,}; static int tegra_dc_pin(struct tegra_dc *dc, struct tegra_plane_state *state){	unsigned int i;	int err; 	for (i = 0; i < state->base.fb->format->num_planes; i++) {		struct tegra_bo *bo = tegra_fb_get_plane(state->base.fb, i);		struct host1x_bo_mapping *map; 		map = host1x_bo_pin(dc->dev, &bo->base, DMA_TO_DEVICE, &dc->client.cache);		if (IS_ERR(map)) {			err = PTR_ERR(map);			goto unpin;		} 		if (!dc->client.group) {			/*			 * The display controller needs contiguous memory, so			 * fail if the buffer is discontiguous and we fail to			 * map its SG table to a single contiguous chunk of			 * I/O virtual memory.			 */			if (map->chunks > 1) {				err = -EINVAL;				goto unpin;			} 			state->iova[i] = map->phys;		} else {			state->iova[i] = bo->iova;		} 		state->map[i] = map;	} 	return 0; unpin:	dev_err(dc->dev, "failed to map plane %u: %d\n", i, err); 	while (i--) {		host1x_bo_unpin(state->map[i]);		state->iova[i] = DMA_MAPPING_ERROR;		state->map[i] = NULL;	} 	return err;} static void tegra_dc_unpin(struct tegra_dc *dc, struct tegra_plane_state *state){	unsigned int i; 	for (i = 0; i < state->base.fb->format->num_planes; i++) {		host1x_bo_unpin(state->map[i]);		state->iova[i] = DMA_MAPPING_ERROR;		state->map[i] = NULL;	}} int tegra_plane_prepare_fb(struct drm_plane *plane,			   struct drm_plane_state *state){	struct tegra_dc *dc = to_tegra_dc(state->crtc);	int err; 	if (!state->fb)		return 0; 	err = drm_gem_plane_helper_prepare_fb(plane, state);	if (err < 0)		return err; 	return tegra_dc_pin(dc, to_tegra_plane_state(state));} void tegra_plane_cleanup_fb(struct drm_plane *plane,			    struct drm_plane_state *state){	struct tegra_dc *dc = to_tegra_dc(state->crtc); 	if (dc)		tegra_dc_unpin(dc, to_tegra_plane_state(state));} static int tegra_plane_calculate_memory_bandwidth(struct drm_plane_state *state){	struct tegra_plane_state *tegra_state = to_tegra_plane_state(state);	unsigned int i, bpp, dst_w, dst_h, src_w, src_h, mul;	const struct tegra_dc_soc_info *soc;	const struct drm_format_info *fmt;	struct drm_crtc_state *crtc_state;	u64 avg_bandwidth, peak_bandwidth; 	if (!state->visible)		return 0; 	crtc_state = drm_atomic_get_new_crtc_state(state->state, state->crtc);	if (!crtc_state)		return -EINVAL; 	src_w = drm_rect_width(&state->src) >> 16;	src_h = drm_rect_height(&state->src) >> 16;	dst_w = drm_rect_width(&state->dst);	dst_h = drm_rect_height(&state->dst); 	fmt = state->fb->format;	soc = to_tegra_dc(state->crtc)->soc; 	/*	 * Note that real memory bandwidth vary depending on format and	 * memory layout, we are not taking that into account because small	 * estimation error isn't important since bandwidth is rounded up	 * anyway.	 */	for (i = 0, bpp = 0; i < fmt->num_planes; i++) {		unsigned int bpp_plane = fmt->cpp[i] * 8; 		/*		 * Sub-sampling is relevant for chroma planes only and vertical		 * readouts are not cached, hence only horizontal sub-sampling		 * matters.		 */		if (i > 0)			bpp_plane /= fmt->hsub; 		bpp += bpp_plane;	} 	/* average bandwidth in kbytes/sec */	avg_bandwidth  = min(src_w, dst_w) * min(src_h, dst_h);	avg_bandwidth *= drm_mode_vrefresh(&crtc_state->adjusted_mode);	avg_bandwidth  = DIV_ROUND_UP(avg_bandwidth * bpp, 8) + 999;	do_div(avg_bandwidth, 1000); 	/* mode.clock in kHz, peak bandwidth in kbytes/sec */	peak_bandwidth = DIV_ROUND_UP(crtc_state->adjusted_mode.clock * bpp, 8); 	/*	 * Tegra30/114 Memory Controller can't interleave DC memory requests	 * for the tiled windows because DC uses 16-bytes atom, while DDR3	 * uses 32-bytes atom.  Hence there is x2 memory overfetch for tiled	 * framebuffer and DDR3 on these SoCs.	 */	if (soc->plane_tiled_memory_bandwidth_x2 &&	    tegra_state->tiling.mode == TEGRA_BO_TILING_MODE_TILED)		mul = 2;	else		mul = 1; 	/* ICC bandwidth in kbytes/sec */	tegra_state->peak_memory_bandwidth = kBps_to_icc(peak_bandwidth) * mul;	tegra_state->avg_memory_bandwidth  = kBps_to_icc(avg_bandwidth)  * mul; 	return 0;} int tegra_plane_state_add(struct tegra_plane *plane,			  struct drm_plane_state *state){	struct drm_crtc_state *crtc_state;	struct tegra_dc_state *tegra;	int err; 	/* Propagate errors from allocation or locking failures. */	crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc);	if (IS_ERR(crtc_state))		return PTR_ERR(crtc_state); 	/* Check plane state for visibility and calculate clipping bounds */	err = drm_atomic_helper_check_plane_state(state, crtc_state,						  0, INT_MAX, true, true);	if (err < 0)		return err; 	err = tegra_plane_calculate_memory_bandwidth(state);	if (err < 0)		return err; 	tegra = to_dc_state(crtc_state); 	tegra->planes |= WIN_A_ACT_REQ << plane->index; 	return 0;} int tegra_plane_format(u32 fourcc, u32 *format, u32 *swap){	/* assume no swapping of fetched data */	if (swap)		*swap = BYTE_SWAP_NOSWAP; 	switch (fourcc) {	case DRM_FORMAT_ARGB4444:		*format = WIN_COLOR_DEPTH_B4G4R4A4;		break; 	case DRM_FORMAT_ARGB1555:		*format = WIN_COLOR_DEPTH_B5G5R5A1;		break; 	case DRM_FORMAT_RGB565:		*format = WIN_COLOR_DEPTH_B5G6R5;		break; 	case DRM_FORMAT_RGBA5551:		*format = WIN_COLOR_DEPTH_A1B5G5R5;		break; 	case DRM_FORMAT_ARGB8888:		*format = WIN_COLOR_DEPTH_B8G8R8A8;		break; 	case DRM_FORMAT_ABGR8888:		*format = WIN_COLOR_DEPTH_R8G8B8A8;		break; 	case DRM_FORMAT_ABGR4444:		*format = WIN_COLOR_DEPTH_R4G4B4A4;		break; 	case DRM_FORMAT_ABGR1555:		*format = WIN_COLOR_DEPTH_R5G5B5A;		break; 	case DRM_FORMAT_BGRA5551:		*format = WIN_COLOR_DEPTH_AR5G5B5;		break; 	case DRM_FORMAT_XRGB1555:		*format = WIN_COLOR_DEPTH_B5G5R5X1;		break; 	case DRM_FORMAT_RGBX5551:		*format = WIN_COLOR_DEPTH_X1B5G5R5;		break; 	case DRM_FORMAT_XBGR1555:		*format = WIN_COLOR_DEPTH_R5G5B5X1;		break; 	case DRM_FORMAT_BGRX5551:		*format = WIN_COLOR_DEPTH_X1R5G5B5;		break; 	case DRM_FORMAT_BGR565:		*format = WIN_COLOR_DEPTH_R5G6B5;		break; 	case DRM_FORMAT_BGRA8888:		*format = WIN_COLOR_DEPTH_A8R8G8B8;		break; 	case DRM_FORMAT_RGBA8888:		*format = WIN_COLOR_DEPTH_A8B8G8R8;		break; 	case DRM_FORMAT_XRGB8888:		*format = WIN_COLOR_DEPTH_B8G8R8X8;		break; 	case DRM_FORMAT_XBGR8888:		*format = WIN_COLOR_DEPTH_R8G8B8X8;		break; 	case DRM_FORMAT_UYVY:		*format = WIN_COLOR_DEPTH_YCbCr422;		break; 	case DRM_FORMAT_YUYV:		if (!swap)			return -EINVAL; 		*format = WIN_COLOR_DEPTH_YCbCr422;		*swap = BYTE_SWAP_SWAP2;		break; 	case DRM_FORMAT_YVYU:		if (!swap)			return -EINVAL; 		*format = WIN_COLOR_DEPTH_YCbCr422;		*swap = BYTE_SWAP_SWAP4;		break; 	case DRM_FORMAT_VYUY:		if (!swap)			return -EINVAL; 		*format = WIN_COLOR_DEPTH_YCbCr422;		*swap = BYTE_SWAP_SWAP4HW;		break; 	case DRM_FORMAT_YUV420:		*format = WIN_COLOR_DEPTH_YCbCr420P;		break; 	case DRM_FORMAT_YUV422:		*format = WIN_COLOR_DEPTH_YCbCr422P;		break; 	case DRM_FORMAT_YUV444:		*format = WIN_COLOR_DEPTH_YCbCr444P;		break; 	case DRM_FORMAT_NV12:		*format = WIN_COLOR_DEPTH_YCbCr420SP;		break; 	case DRM_FORMAT_NV21:		*format = WIN_COLOR_DEPTH_YCrCb420SP;		break; 	case DRM_FORMAT_NV16:		*format = WIN_COLOR_DEPTH_YCbCr422SP;		break; 	case DRM_FORMAT_NV61:		*format = WIN_COLOR_DEPTH_YCrCb422SP;		break; 	case DRM_FORMAT_NV24:		*format = WIN_COLOR_DEPTH_YCbCr444SP;		break; 	case DRM_FORMAT_NV42:		*format = WIN_COLOR_DEPTH_YCrCb444SP;		break; 	default:		return -EINVAL;	} 	return 0;} bool tegra_plane_format_is_indexed(unsigned int format){	switch (format) {	case WIN_COLOR_DEPTH_P1:	case WIN_COLOR_DEPTH_P2:	case WIN_COLOR_DEPTH_P4:	case WIN_COLOR_DEPTH_P8:		return true;	} 	return false;} bool tegra_plane_format_is_yuv(unsigned int format, unsigned int *planes, unsigned int *bpc){	switch (format) {	case WIN_COLOR_DEPTH_YCbCr422:	case WIN_COLOR_DEPTH_YUV422:		if (planes)			*planes = 1; 		if (bpc)			*bpc = 8; 		return true;

Lines 1–500 of 794.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t