brintos

brintos / linux-shallow public Read only

0
0
Text · 15.9 KiB · 464000a Raw
631 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * Copyright (C) 2019-2022 Bootlin4 * Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com>5 */6 7#include <linux/of.h>8#include <linux/types.h>9 10#include <drm/drm_atomic.h>11#include <drm/drm_atomic_helper.h>12#include <drm/drm_blend.h>13#include <drm/drm_fb_dma_helper.h>14#include <drm/drm_fourcc.h>15#include <drm/drm_framebuffer.h>16#include <drm/drm_plane.h>17#include <drm/drm_print.h>18 19#include "logicvc_crtc.h"20#include "logicvc_drm.h"21#include "logicvc_layer.h"22#include "logicvc_of.h"23#include "logicvc_regs.h"24 25#define logicvc_layer(p) \26	container_of(p, struct logicvc_layer, drm_plane)27 28static uint32_t logicvc_layer_formats_rgb16[] = {29	DRM_FORMAT_RGB565,30	DRM_FORMAT_BGR565,31	DRM_FORMAT_INVALID,32};33 34static uint32_t logicvc_layer_formats_rgb24[] = {35	DRM_FORMAT_XRGB8888,36	DRM_FORMAT_XBGR8888,37	DRM_FORMAT_INVALID,38};39 40/*41 * What we call depth in this driver only counts color components, not alpha.42 * This allows us to stay compatible with the LogiCVC bistream definitions.43 */44static uint32_t logicvc_layer_formats_rgb24_alpha[] = {45	DRM_FORMAT_ARGB8888,46	DRM_FORMAT_ABGR8888,47	DRM_FORMAT_INVALID,48};49 50static struct logicvc_layer_formats logicvc_layer_formats[] = {51	{52		.colorspace	= LOGICVC_LAYER_COLORSPACE_RGB,53		.depth		= 16,54		.formats	= logicvc_layer_formats_rgb16,55	},56	{57		.colorspace	= LOGICVC_LAYER_COLORSPACE_RGB,58		.depth		= 24,59		.formats	= logicvc_layer_formats_rgb24,60	},61	{62		.colorspace	= LOGICVC_LAYER_COLORSPACE_RGB,63		.depth		= 24,64		.alpha		= true,65		.formats	= logicvc_layer_formats_rgb24_alpha,66	},67	{ }68};69 70static bool logicvc_layer_format_inverted(uint32_t format)71{72	switch (format) {73	case DRM_FORMAT_BGR565:74	case DRM_FORMAT_BGR888:75	case DRM_FORMAT_XBGR8888:76	case DRM_FORMAT_ABGR8888:77		return true;78	default:79		return false;80	}81}82 83static int logicvc_plane_atomic_check(struct drm_plane *drm_plane,84				      struct drm_atomic_state *state)85{86	struct drm_device *drm_dev = drm_plane->dev;87	struct logicvc_layer *layer = logicvc_layer(drm_plane);88	struct logicvc_drm *logicvc = logicvc_drm(drm_dev);89	struct drm_plane_state *new_state =90		drm_atomic_get_new_plane_state(state, drm_plane);91	struct drm_crtc_state *crtc_state;92	int min_scale, max_scale;93	bool can_position;94	int ret;95 96	if (!new_state->crtc)97		return 0;98 99	crtc_state = drm_atomic_get_existing_crtc_state(new_state->state,100							new_state->crtc);101	if (WARN_ON(!crtc_state))102		return -EINVAL;103 104	if (new_state->crtc_x < 0 || new_state->crtc_y < 0) {105		drm_err(drm_dev,106			"Negative on-CRTC positions are not supported.\n");107		return -EINVAL;108	}109 110	if (!logicvc->caps->layer_address) {111		ret = logicvc_layer_buffer_find_setup(logicvc, layer, new_state,112						      NULL);113		if (ret) {114			drm_err(drm_dev, "No viable setup for buffer found.\n");115			return ret;116		}117	}118 119	min_scale = DRM_PLANE_NO_SCALING;120	max_scale = DRM_PLANE_NO_SCALING;121 122	can_position = (drm_plane->type == DRM_PLANE_TYPE_OVERLAY &&123			layer->index != (logicvc->config.layers_count - 1) &&124			logicvc->config.layers_configurable);125 126	ret = drm_atomic_helper_check_plane_state(new_state, crtc_state,127						  min_scale, max_scale,128						  can_position, true);129	if (ret) {130		drm_err(drm_dev, "Invalid plane state\n\n");131		return ret;132	}133 134	return 0;135}136 137static void logicvc_plane_atomic_update(struct drm_plane *drm_plane,138					struct drm_atomic_state *state)139{140	struct logicvc_layer *layer = logicvc_layer(drm_plane);141	struct logicvc_drm *logicvc = logicvc_drm(drm_plane->dev);142	struct drm_device *drm_dev = &logicvc->drm_dev;143	struct drm_plane_state *new_state =144		drm_atomic_get_new_plane_state(state, drm_plane);145	struct drm_crtc *drm_crtc = &logicvc->crtc->drm_crtc;146	struct drm_display_mode *mode = &drm_crtc->state->adjusted_mode;147	struct drm_framebuffer *fb = new_state->fb;148	struct logicvc_layer_buffer_setup setup = {};149	u32 index = layer->index;150	u32 reg;151 152	/* Layer dimensions */153 154	regmap_write(logicvc->regmap, LOGICVC_LAYER_WIDTH_REG(index),155		     new_state->crtc_w - 1);156	regmap_write(logicvc->regmap, LOGICVC_LAYER_HEIGHT_REG(index),157		     new_state->crtc_h - 1);158 159	if (logicvc->caps->layer_address) {160		phys_addr_t fb_addr = drm_fb_dma_get_gem_addr(fb, new_state, 0);161 162		regmap_write(logicvc->regmap, LOGICVC_LAYER_ADDRESS_REG(index),163			     fb_addr);164	} else {165		/* Rely on offsets to configure the address. */166 167		logicvc_layer_buffer_find_setup(logicvc, layer, new_state,168						&setup);169 170		/* Layer memory offsets */171 172		regmap_write(logicvc->regmap, LOGICVC_BUFFER_SEL_REG,173			     LOGICVC_BUFFER_SEL_VALUE(index, setup.buffer_sel));174		regmap_write(logicvc->regmap, LOGICVC_LAYER_HOFFSET_REG(index),175			     setup.hoffset);176		regmap_write(logicvc->regmap, LOGICVC_LAYER_VOFFSET_REG(index),177			     setup.voffset);178	}179 180	/* Layer position */181 182	regmap_write(logicvc->regmap, LOGICVC_LAYER_HPOSITION_REG(index),183		     mode->hdisplay - 1 - new_state->crtc_x);184 185	/* Vertical position must be set last to sync layer register changes. */186	regmap_write(logicvc->regmap, LOGICVC_LAYER_VPOSITION_REG(index),187		     mode->vdisplay - 1 - new_state->crtc_y);188 189	/* Layer alpha */190 191	if (layer->config.alpha_mode == LOGICVC_LAYER_ALPHA_LAYER) {192		u32 alpha_bits;193		u32 alpha_max;194		u32 alpha;195 196		switch (layer->config.depth) {197		case 8:198			alpha_bits = 3;199			break;200		case 16:201			if (layer->config.colorspace ==202			    LOGICVC_LAYER_COLORSPACE_YUV)203				alpha_bits = 8;204			else205				alpha_bits = 6;206			break;207		default:208			alpha_bits = 8;209			break;210		}211 212		alpha_max = BIT(alpha_bits) - 1;213		alpha = new_state->alpha * alpha_max / DRM_BLEND_ALPHA_OPAQUE;214 215		drm_dbg_kms(drm_dev, "Setting layer %d alpha to %d/%d\n", index,216			    alpha, alpha_max);217 218		regmap_write(logicvc->regmap, LOGICVC_LAYER_ALPHA_REG(index),219			     alpha);220	}221 222	/* Layer control */223 224	reg = LOGICVC_LAYER_CTRL_ENABLE;225 226	if (logicvc_layer_format_inverted(fb->format->format))227		reg |= LOGICVC_LAYER_CTRL_PIXEL_FORMAT_INVERT;228 229	reg |= LOGICVC_LAYER_CTRL_COLOR_KEY_DISABLE;230 231	regmap_write(logicvc->regmap, LOGICVC_LAYER_CTRL_REG(index), reg);232}233 234static void logicvc_plane_atomic_disable(struct drm_plane *drm_plane,235					 struct drm_atomic_state *state)236{237	struct logicvc_layer *layer = logicvc_layer(drm_plane);238	struct logicvc_drm *logicvc = logicvc_drm(drm_plane->dev);239	u32 index = layer->index;240 241	regmap_write(logicvc->regmap, LOGICVC_LAYER_CTRL_REG(index), 0);242}243 244static struct drm_plane_helper_funcs logicvc_plane_helper_funcs = {245	.atomic_check		= logicvc_plane_atomic_check,246	.atomic_update		= logicvc_plane_atomic_update,247	.atomic_disable		= logicvc_plane_atomic_disable,248};249 250static const struct drm_plane_funcs logicvc_plane_funcs = {251	.update_plane		= drm_atomic_helper_update_plane,252	.disable_plane		= drm_atomic_helper_disable_plane,253	.destroy		= drm_plane_cleanup,254	.reset			= drm_atomic_helper_plane_reset,255	.atomic_duplicate_state	= drm_atomic_helper_plane_duplicate_state,256	.atomic_destroy_state	= drm_atomic_helper_plane_destroy_state,257};258 259int logicvc_layer_buffer_find_setup(struct logicvc_drm *logicvc,260				    struct logicvc_layer *layer,261				    struct drm_plane_state *state,262				    struct logicvc_layer_buffer_setup *setup)263{264	struct drm_device *drm_dev = &logicvc->drm_dev;265	struct drm_framebuffer *fb = state->fb;266	/* All the supported formats have a single data plane. */267	u32 layer_bytespp = fb->format->cpp[0];268	u32 layer_stride = layer_bytespp * logicvc->config.row_stride;269	u32 base_offset = layer->config.base_offset * layer_stride;270	u32 buffer_offset = layer->config.buffer_offset * layer_stride;271	u8 buffer_sel = 0;272	u16 voffset = 0;273	u16 hoffset = 0;274	phys_addr_t fb_addr;275	u32 fb_offset;276	u32 gap;277 278	if (!logicvc->reserved_mem_base) {279		drm_err(drm_dev, "No reserved memory base was registered!\n");280		return -ENOMEM;281	}282 283	fb_addr = drm_fb_dma_get_gem_addr(fb, state, 0);284	if (fb_addr < logicvc->reserved_mem_base) {285		drm_err(drm_dev,286			"Framebuffer memory below reserved memory base!\n");287		return -EINVAL;288	}289 290	fb_offset = (u32) (fb_addr - logicvc->reserved_mem_base);291 292	if (fb_offset < base_offset) {293		drm_err(drm_dev,294			"Framebuffer offset below layer base offset!\n");295		return -EINVAL;296	}297 298	gap = fb_offset - base_offset;299 300	/* Use the possible video buffers selection. */301	if (gap && buffer_offset) {302		buffer_sel = gap / buffer_offset;303		if (buffer_sel > LOGICVC_BUFFER_SEL_MAX)304			buffer_sel = LOGICVC_BUFFER_SEL_MAX;305 306		gap -= buffer_sel * buffer_offset;307	}308 309	/* Use the vertical offset. */310	if (gap && layer_stride && logicvc->config.layers_configurable) {311		voffset = gap / layer_stride;312		if (voffset > LOGICVC_LAYER_VOFFSET_MAX)313			voffset = LOGICVC_LAYER_VOFFSET_MAX;314 315		gap -= voffset * layer_stride;316	}317 318	/* Use the horizontal offset. */319	if (gap && layer_bytespp && logicvc->config.layers_configurable) {320		hoffset = gap / layer_bytespp;321		if (hoffset > LOGICVC_DIMENSIONS_MAX)322			hoffset = LOGICVC_DIMENSIONS_MAX;323 324		gap -= hoffset * layer_bytespp;325	}326 327	if (gap) {328		drm_err(drm_dev,329			"Unable to find layer %d buffer setup for 0x%x byte gap\n",330			layer->index, fb_offset - base_offset);331		return -EINVAL;332	}333 334	drm_dbg_kms(drm_dev, "Found layer %d buffer setup for 0x%x byte gap:\n",335		    layer->index, fb_offset - base_offset);336 337	drm_dbg_kms(drm_dev, "- buffer_sel = 0x%x chunks of 0x%x bytes\n",338		    buffer_sel, buffer_offset);339	drm_dbg_kms(drm_dev, "- voffset = 0x%x chunks of 0x%x bytes\n", voffset,340		    layer_stride);341	drm_dbg_kms(drm_dev, "- hoffset = 0x%x chunks of 0x%x bytes\n", hoffset,342		    layer_bytespp);343 344	if (setup) {345		setup->buffer_sel = buffer_sel;346		setup->voffset = voffset;347		setup->hoffset = hoffset;348	}349 350	return 0;351}352 353static struct logicvc_layer_formats *logicvc_layer_formats_lookup(struct logicvc_layer *layer)354{355	bool alpha;356	unsigned int i = 0;357 358	alpha = (layer->config.alpha_mode == LOGICVC_LAYER_ALPHA_PIXEL);359 360	while (logicvc_layer_formats[i].formats) {361		if (logicvc_layer_formats[i].colorspace == layer->config.colorspace &&362		    logicvc_layer_formats[i].depth == layer->config.depth &&363		    logicvc_layer_formats[i].alpha == alpha)364			return &logicvc_layer_formats[i];365 366		i++;367	}368 369	return NULL;370}371 372static unsigned int logicvc_layer_formats_count(struct logicvc_layer_formats *formats)373{374	unsigned int count = 0;375 376	while (formats->formats[count] != DRM_FORMAT_INVALID)377		count++;378 379	return count;380}381 382static int logicvc_layer_config_parse(struct logicvc_drm *logicvc,383				      struct logicvc_layer *layer)384{385	struct device_node *of_node = layer->of_node;386	struct logicvc_layer_config *config = &layer->config;387	int ret;388 389	logicvc_of_property_parse_bool(of_node,390				       LOGICVC_OF_PROPERTY_LAYER_PRIMARY,391				       &config->primary);392 393	ret = logicvc_of_property_parse_u32(of_node,394					    LOGICVC_OF_PROPERTY_LAYER_COLORSPACE,395					    &config->colorspace);396	if (ret)397		return ret;398 399	ret = logicvc_of_property_parse_u32(of_node,400					    LOGICVC_OF_PROPERTY_LAYER_DEPTH,401					    &config->depth);402	if (ret)403		return ret;404 405	ret = logicvc_of_property_parse_u32(of_node,406					    LOGICVC_OF_PROPERTY_LAYER_ALPHA_MODE,407					    &config->alpha_mode);408	if (ret)409		return ret;410 411	/*412	 * Memory offset is only relevant without layer address configuration.413	 */414	if (logicvc->caps->layer_address)415		return 0;416 417	ret = logicvc_of_property_parse_u32(of_node,418					    LOGICVC_OF_PROPERTY_LAYER_BASE_OFFSET,419					    &config->base_offset);420	if (ret)421		return ret;422 423	ret = logicvc_of_property_parse_u32(of_node,424					    LOGICVC_OF_PROPERTY_LAYER_BUFFER_OFFSET,425					    &config->buffer_offset);426	if (ret)427		return ret;428 429	return 0;430}431 432struct logicvc_layer *logicvc_layer_get_from_index(struct logicvc_drm *logicvc,433						   u32 index)434{435	struct logicvc_layer *layer;436 437	list_for_each_entry(layer, &logicvc->layers_list, list)438		if (layer->index == index)439			return layer;440 441	return NULL;442}443 444struct logicvc_layer *logicvc_layer_get_from_type(struct logicvc_drm *logicvc,445						  enum drm_plane_type type)446{447	struct logicvc_layer *layer;448 449	list_for_each_entry(layer, &logicvc->layers_list, list)450		if (layer->drm_plane.type == type)451			return layer;452 453	return NULL;454}455 456struct logicvc_layer *logicvc_layer_get_primary(struct logicvc_drm *logicvc)457{458	return logicvc_layer_get_from_type(logicvc, DRM_PLANE_TYPE_PRIMARY);459}460 461static int logicvc_layer_init(struct logicvc_drm *logicvc,462			      struct device_node *of_node, u32 index)463{464	struct drm_device *drm_dev = &logicvc->drm_dev;465	struct device *dev = drm_dev->dev;466	struct logicvc_layer *layer = NULL;467	struct logicvc_layer_formats *formats;468	unsigned int formats_count;469	enum drm_plane_type type;470	unsigned int zpos;471	int ret;472 473	layer = devm_kzalloc(dev, sizeof(*layer), GFP_KERNEL);474	if (!layer) {475		ret = -ENOMEM;476		goto error;477	}478 479	layer->of_node = of_node;480	layer->index = index;481 482	ret = logicvc_layer_config_parse(logicvc, layer);483	if (ret) {484		drm_err(drm_dev, "Failed to parse config for layer #%d\n",485			index);486		goto error;487	}488 489	formats = logicvc_layer_formats_lookup(layer);490	if (!formats) {491		drm_err(drm_dev, "Failed to lookup formats for layer #%d\n",492			index);493		ret = -EINVAL;494		goto error;495	}496 497	formats_count = logicvc_layer_formats_count(formats);498 499	/* The final layer can be configured as a background layer. */500	if (logicvc->config.background_layer &&501	    index == (logicvc->config.layers_count - 1)) {502		/*503		 * A zero value for black is only valid for RGB, not for YUV,504		 * so this will need to take the format in account for YUV.505		 */506		u32 background = 0;507 508		drm_dbg_kms(drm_dev, "Using layer #%d as background layer\n",509			    index);510 511		regmap_write(logicvc->regmap, LOGICVC_BACKGROUND_COLOR_REG,512			     background);513 514		devm_kfree(dev, layer);515 516		return 0;517	}518 519	if (layer->config.primary)520		type = DRM_PLANE_TYPE_PRIMARY;521	else522		type = DRM_PLANE_TYPE_OVERLAY;523 524	ret = drm_universal_plane_init(drm_dev, &layer->drm_plane, 0,525				       &logicvc_plane_funcs, formats->formats,526				       formats_count, NULL, type, NULL);527	if (ret) {528		drm_err(drm_dev, "Failed to initialize layer plane\n");529		return ret;530	}531 532	drm_plane_helper_add(&layer->drm_plane, &logicvc_plane_helper_funcs);533 534	zpos = logicvc->config.layers_count - index - 1;535	drm_dbg_kms(drm_dev, "Giving layer #%d zpos %d\n", index, zpos);536 537	if (layer->config.alpha_mode == LOGICVC_LAYER_ALPHA_LAYER)538		drm_plane_create_alpha_property(&layer->drm_plane);539 540	drm_plane_create_zpos_immutable_property(&layer->drm_plane, zpos);541 542	drm_dbg_kms(drm_dev, "Registering layer #%d\n", index);543 544	layer->formats = formats;545 546	list_add_tail(&layer->list, &logicvc->layers_list);547 548	return 0;549 550error:551	if (layer)552		devm_kfree(dev, layer);553 554	return ret;555}556 557static void logicvc_layer_fini(struct logicvc_drm *logicvc,558			       struct logicvc_layer *layer)559{560	struct device *dev = logicvc->drm_dev.dev;561 562	list_del(&layer->list);563	devm_kfree(dev, layer);564}565 566void logicvc_layers_attach_crtc(struct logicvc_drm *logicvc)567{568	uint32_t possible_crtcs = drm_crtc_mask(&logicvc->crtc->drm_crtc);569	struct logicvc_layer *layer;570 571	list_for_each_entry(layer, &logicvc->layers_list, list) {572		if (layer->drm_plane.type != DRM_PLANE_TYPE_OVERLAY)573			continue;574 575		layer->drm_plane.possible_crtcs = possible_crtcs;576	}577}578 579int logicvc_layers_init(struct logicvc_drm *logicvc)580{581	struct drm_device *drm_dev = &logicvc->drm_dev;582	struct device *dev = drm_dev->dev;583	struct device_node *of_node = dev->of_node;584	struct device_node *layer_node = NULL;585	struct device_node *layers_node;586	struct logicvc_layer *layer;587	struct logicvc_layer *next;588	int ret = 0;589 590	layers_node = of_get_child_by_name(of_node, "layers");591	if (!layers_node) {592		drm_err(drm_dev, "No layers node found in the description\n");593		ret = -ENODEV;594		goto error;595	}596 597	for_each_child_of_node(layers_node, layer_node) {598		u32 index = 0;599 600		if (!logicvc_of_node_is_layer(layer_node))601			continue;602 603		ret = of_property_read_u32(layer_node, "reg", &index);604		if (ret)605			continue;606 607		layer = logicvc_layer_get_from_index(logicvc, index);608		if (layer) {609			drm_err(drm_dev, "Duplicated entry for layer #%d\n",610				index);611			continue;612		}613 614		ret = logicvc_layer_init(logicvc, layer_node, index);615		if (ret) {616			of_node_put(layers_node);617			goto error;618		}619	}620 621	of_node_put(layers_node);622 623	return 0;624 625error:626	list_for_each_entry_safe(layer, next, &logicvc->layers_list, list)627		logicvc_layer_fini(logicvc, layer);628 629	return ret;630}631