brintos

brintos / linux-shallow public Read only

0
0
Text · 33.0 KiB · cee5eaf Raw
1263 lines · c
1// SPDX-License-Identifier: MIT2/*3 * Copyright 2018 Noralf Trønnes4 * Copyright (c) 2006-2009 Red Hat Inc.5 * Copyright (c) 2006-2008 Intel Corporation6 *   Jesse Barnes <jesse.barnes@intel.com>7 * Copyright (c) 2007 Dave Airlie <airlied@linux.ie>8 */9 10#include "drm/drm_modeset_lock.h"11#include <linux/module.h>12#include <linux/mutex.h>13#include <linux/slab.h>14#include <linux/string_helpers.h>15 16#include <drm/drm_atomic.h>17#include <drm/drm_client.h>18#include <drm/drm_connector.h>19#include <drm/drm_crtc.h>20#include <drm/drm_device.h>21#include <drm/drm_drv.h>22#include <drm/drm_edid.h>23#include <drm/drm_encoder.h>24#include <drm/drm_print.h>25 26#include "drm_crtc_internal.h"27#include "drm_internal.h"28 29#define DRM_CLIENT_MAX_CLONED_CONNECTORS	830 31struct drm_client_offset {32	int x, y;33};34 35int drm_client_modeset_create(struct drm_client_dev *client)36{37	struct drm_device *dev = client->dev;38	unsigned int num_crtc = dev->mode_config.num_crtc;39	unsigned int max_connector_count = 1;40	struct drm_mode_set *modeset;41	struct drm_crtc *crtc;42	unsigned int i = 0;43 44	/* Add terminating zero entry to enable index less iteration */45	client->modesets = kcalloc(num_crtc + 1, sizeof(*client->modesets), GFP_KERNEL);46	if (!client->modesets)47		return -ENOMEM;48 49	mutex_init(&client->modeset_mutex);50 51	drm_for_each_crtc(crtc, dev)52		client->modesets[i++].crtc = crtc;53 54	/* Cloning is only supported in the single crtc case. */55	if (num_crtc == 1)56		max_connector_count = DRM_CLIENT_MAX_CLONED_CONNECTORS;57 58	for (modeset = client->modesets; modeset->crtc; modeset++) {59		modeset->connectors = kcalloc(max_connector_count,60					      sizeof(*modeset->connectors), GFP_KERNEL);61		if (!modeset->connectors)62			goto err_free;63	}64 65	return 0;66 67err_free:68	drm_client_modeset_free(client);69 70	return -ENOMEM;71}72 73static void drm_client_modeset_release(struct drm_client_dev *client)74{75	struct drm_mode_set *modeset;76	unsigned int i;77 78	drm_client_for_each_modeset(modeset, client) {79		drm_mode_destroy(client->dev, modeset->mode);80		modeset->mode = NULL;81		modeset->fb = NULL;82 83		for (i = 0; i < modeset->num_connectors; i++) {84			drm_connector_put(modeset->connectors[i]);85			modeset->connectors[i] = NULL;86		}87		modeset->num_connectors = 0;88	}89}90 91void drm_client_modeset_free(struct drm_client_dev *client)92{93	struct drm_mode_set *modeset;94 95	mutex_lock(&client->modeset_mutex);96 97	drm_client_modeset_release(client);98 99	drm_client_for_each_modeset(modeset, client)100		kfree(modeset->connectors);101 102	mutex_unlock(&client->modeset_mutex);103 104	mutex_destroy(&client->modeset_mutex);105	kfree(client->modesets);106}107 108static struct drm_mode_set *109drm_client_find_modeset(struct drm_client_dev *client, struct drm_crtc *crtc)110{111	struct drm_mode_set *modeset;112 113	drm_client_for_each_modeset(modeset, client)114		if (modeset->crtc == crtc)115			return modeset;116 117	return NULL;118}119 120static struct drm_display_mode *121drm_connector_get_tiled_mode(struct drm_connector *connector)122{123	struct drm_display_mode *mode;124 125	list_for_each_entry(mode, &connector->modes, head) {126		if (mode->hdisplay == connector->tile_h_size &&127		    mode->vdisplay == connector->tile_v_size)128			return mode;129	}130	return NULL;131}132 133static struct drm_display_mode *134drm_connector_fallback_non_tiled_mode(struct drm_connector *connector)135{136	struct drm_display_mode *mode;137 138	list_for_each_entry(mode, &connector->modes, head) {139		if (mode->hdisplay == connector->tile_h_size &&140		    mode->vdisplay == connector->tile_v_size)141			continue;142		return mode;143	}144	return NULL;145}146 147static struct drm_display_mode *148drm_connector_has_preferred_mode(struct drm_connector *connector, int width, int height)149{150	struct drm_display_mode *mode;151 152	list_for_each_entry(mode, &connector->modes, head) {153		if (mode->hdisplay > width ||154		    mode->vdisplay > height)155			continue;156		if (mode->type & DRM_MODE_TYPE_PREFERRED)157			return mode;158	}159	return NULL;160}161 162static struct drm_display_mode *drm_connector_pick_cmdline_mode(struct drm_connector *connector)163{164	struct drm_cmdline_mode *cmdline_mode;165	struct drm_display_mode *mode;166	bool prefer_non_interlace;167 168	/*169	 * Find a user-defined mode. If the user gave us a valid170	 * mode on the kernel command line, it will show up in this171	 * list.172	 */173 174	list_for_each_entry(mode, &connector->modes, head) {175		if (mode->type & DRM_MODE_TYPE_USERDEF)176			return mode;177	}178 179	cmdline_mode = &connector->cmdline_mode;180	if (cmdline_mode->specified == false)181		return NULL;182 183	/*184	 * Attempt to find a matching mode in the list of modes we185	 * have gotten so far.186	 */187 188	prefer_non_interlace = !cmdline_mode->interlace;189again:190	list_for_each_entry(mode, &connector->modes, head) {191		/* check width/height */192		if (mode->hdisplay != cmdline_mode->xres ||193		    mode->vdisplay != cmdline_mode->yres)194			continue;195 196		if (cmdline_mode->refresh_specified) {197			if (drm_mode_vrefresh(mode) != cmdline_mode->refresh)198				continue;199		}200 201		if (cmdline_mode->interlace) {202			if (!(mode->flags & DRM_MODE_FLAG_INTERLACE))203				continue;204		} else if (prefer_non_interlace) {205			if (mode->flags & DRM_MODE_FLAG_INTERLACE)206				continue;207		}208		return mode;209	}210 211	if (prefer_non_interlace) {212		prefer_non_interlace = false;213		goto again;214	}215 216	return NULL;217}218 219static bool drm_connector_enabled(struct drm_connector *connector, bool strict)220{221	bool enable;222 223	if (connector->display_info.non_desktop)224		return false;225 226	if (strict)227		enable = connector->status == connector_status_connected;228	else229		enable = connector->status != connector_status_disconnected;230 231	return enable;232}233 234static void drm_client_connectors_enabled(struct drm_connector **connectors,235					  unsigned int connector_count,236					  bool *enabled)237{238	bool any_enabled = false;239	struct drm_connector *connector;240	int i = 0;241 242	for (i = 0; i < connector_count; i++) {243		connector = connectors[i];244		enabled[i] = drm_connector_enabled(connector, true);245		drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] enabled? %s\n",246			    connector->base.id, connector->name,247			    connector->display_info.non_desktop ?248			    "non desktop" : str_yes_no(enabled[i]));249 250		any_enabled |= enabled[i];251	}252 253	if (any_enabled)254		return;255 256	for (i = 0; i < connector_count; i++)257		enabled[i] = drm_connector_enabled(connectors[i], false);258}259 260static bool drm_client_target_cloned(struct drm_device *dev,261				     struct drm_connector **connectors,262				     unsigned int connector_count,263				     struct drm_display_mode **modes,264				     struct drm_client_offset *offsets,265				     bool *enabled, int width, int height)266{267	int count, i, j;268	bool can_clone = false;269	struct drm_display_mode *dmt_mode, *mode;270 271	/* only contemplate cloning in the single crtc case */272	if (dev->mode_config.num_crtc > 1)273		return false;274 275	count = 0;276	for (i = 0; i < connector_count; i++) {277		if (enabled[i])278			count++;279	}280 281	/* only contemplate cloning if more than one connector is enabled */282	if (count <= 1)283		return false;284 285	/* check the command line or if nothing common pick 1024x768 */286	can_clone = true;287	for (i = 0; i < connector_count; i++) {288		if (!enabled[i])289			continue;290		modes[i] = drm_connector_pick_cmdline_mode(connectors[i]);291		if (!modes[i]) {292			can_clone = false;293			break;294		}295		for (j = 0; j < i; j++) {296			if (!enabled[j])297				continue;298			if (!drm_mode_match(modes[j], modes[i],299					    DRM_MODE_MATCH_TIMINGS |300					    DRM_MODE_MATCH_CLOCK |301					    DRM_MODE_MATCH_FLAGS |302					    DRM_MODE_MATCH_3D_FLAGS))303				can_clone = false;304		}305	}306 307	if (can_clone) {308		drm_dbg_kms(dev, "can clone using command line\n");309		return true;310	}311 312	/* try and find a 1024x768 mode on each connector */313	can_clone = true;314	dmt_mode = drm_mode_find_dmt(dev, 1024, 768, 60, false);315 316	if (!dmt_mode)317		goto fail;318 319	for (i = 0; i < connector_count; i++) {320		if (!enabled[i])321			continue;322 323		list_for_each_entry(mode, &connectors[i]->modes, head) {324			if (drm_mode_match(mode, dmt_mode,325					   DRM_MODE_MATCH_TIMINGS |326					   DRM_MODE_MATCH_CLOCK |327					   DRM_MODE_MATCH_FLAGS |328					   DRM_MODE_MATCH_3D_FLAGS))329				modes[i] = mode;330		}331		if (!modes[i])332			can_clone = false;333	}334	kfree(dmt_mode);335 336	if (can_clone) {337		drm_dbg_kms(dev, "can clone using 1024x768\n");338		return true;339	}340fail:341	drm_info(dev, "kms: can't enable cloning when we probably wanted to.\n");342	return false;343}344 345static int drm_client_get_tile_offsets(struct drm_device *dev,346				       struct drm_connector **connectors,347				       unsigned int connector_count,348				       struct drm_display_mode **modes,349				       struct drm_client_offset *offsets,350				       int idx,351				       int h_idx, int v_idx)352{353	struct drm_connector *connector;354	int i;355	int hoffset = 0, voffset = 0;356 357	for (i = 0; i < connector_count; i++) {358		connector = connectors[i];359		if (!connector->has_tile)360			continue;361 362		if (!modes[i] && (h_idx || v_idx)) {363			drm_dbg_kms(dev,364				    "[CONNECTOR:%d:%s] no modes for connector tiled %d\n",365				    connector->base.id, connector->name, i);366			continue;367		}368		if (connector->tile_h_loc < h_idx)369			hoffset += modes[i]->hdisplay;370 371		if (connector->tile_v_loc < v_idx)372			voffset += modes[i]->vdisplay;373	}374	offsets[idx].x = hoffset;375	offsets[idx].y = voffset;376	drm_dbg_kms(dev, "returned %d %d for %d %d\n", hoffset, voffset, h_idx, v_idx);377	return 0;378}379 380static bool drm_client_target_preferred(struct drm_device *dev,381					struct drm_connector **connectors,382					unsigned int connector_count,383					struct drm_display_mode **modes,384					struct drm_client_offset *offsets,385					bool *enabled, int width, int height)386{387	const u64 mask = BIT_ULL(connector_count) - 1;388	struct drm_connector *connector;389	u64 conn_configured = 0;390	int tile_pass = 0;391	int num_tiled_conns = 0;392	int i;393 394	for (i = 0; i < connector_count; i++) {395		if (connectors[i]->has_tile &&396		    connectors[i]->status == connector_status_connected)397			num_tiled_conns++;398	}399 400retry:401	for (i = 0; i < connector_count; i++) {402		connector = connectors[i];403 404		if (conn_configured & BIT_ULL(i))405			continue;406 407		if (enabled[i] == false) {408			conn_configured |= BIT_ULL(i);409			continue;410		}411 412		/* first pass over all the untiled connectors */413		if (tile_pass == 0 && connector->has_tile)414			continue;415 416		if (tile_pass == 1) {417			if (connector->tile_h_loc != 0 ||418			    connector->tile_v_loc != 0)419				continue;420 421		} else {422			if (connector->tile_h_loc != tile_pass - 1 &&423			    connector->tile_v_loc != tile_pass - 1)424			/* if this tile_pass doesn't cover any of the tiles - keep going */425				continue;426 427			/*428			 * find the tile offsets for this pass - need to find429			 * all tiles left and above430			 */431			drm_client_get_tile_offsets(dev, connectors, connector_count,432						    modes, offsets, i,433						    connector->tile_h_loc, connector->tile_v_loc);434		}435		drm_dbg_kms(dev, "[CONNECTOR:%d:%s] looking for cmdline mode\n",436			    connector->base.id, connector->name);437 438		/* got for command line mode first */439		modes[i] = drm_connector_pick_cmdline_mode(connector);440		if (!modes[i]) {441			drm_dbg_kms(dev, "[CONNECTOR:%d:%s] looking for preferred mode, tile %d\n",442				    connector->base.id, connector->name,443				    connector->tile_group ? connector->tile_group->id : 0);444			modes[i] = drm_connector_has_preferred_mode(connector, width, height);445		}446		/* No preferred modes, pick one off the list */447		if (!modes[i] && !list_empty(&connector->modes)) {448			list_for_each_entry(modes[i], &connector->modes, head)449				break;450		}451		/*452		 * In case of tiled mode if all tiles not present fallback to453		 * first available non tiled mode.454		 * After all tiles are present, try to find the tiled mode455		 * for all and if tiled mode not present due to fbcon size456		 * limitations, use first non tiled mode only for457		 * tile 0,0 and set to no mode for all other tiles.458		 */459		if (connector->has_tile) {460			if (num_tiled_conns <461			    connector->num_h_tile * connector->num_v_tile ||462			    (connector->tile_h_loc == 0 &&463			     connector->tile_v_loc == 0 &&464			     !drm_connector_get_tiled_mode(connector))) {465				drm_dbg_kms(dev,466					    "[CONNECTOR:%d:%s] Falling back to non-tiled mode\n",467					    connector->base.id, connector->name);468				modes[i] = drm_connector_fallback_non_tiled_mode(connector);469			} else {470				modes[i] = drm_connector_get_tiled_mode(connector);471			}472		}473 474		drm_dbg_kms(dev, "[CONNECTOR:%d:%s] Found mode %s\n",475			    connector->base.id, connector->name,476			    modes[i] ? modes[i]->name : "none");477		conn_configured |= BIT_ULL(i);478	}479 480	if ((conn_configured & mask) != mask) {481		tile_pass++;482		goto retry;483	}484	return true;485}486 487static bool connector_has_possible_crtc(struct drm_connector *connector,488					struct drm_crtc *crtc)489{490	struct drm_encoder *encoder;491 492	drm_connector_for_each_possible_encoder(connector, encoder) {493		if (encoder->possible_crtcs & drm_crtc_mask(crtc))494			return true;495	}496 497	return false;498}499 500static int drm_client_pick_crtcs(struct drm_client_dev *client,501				 struct drm_connector **connectors,502				 unsigned int connector_count,503				 struct drm_crtc **best_crtcs,504				 struct drm_display_mode **modes,505				 int n, int width, int height)506{507	struct drm_device *dev = client->dev;508	struct drm_connector *connector;509	int my_score, best_score, score;510	struct drm_crtc **crtcs, *crtc;511	struct drm_mode_set *modeset;512	int o;513 514	if (n == connector_count)515		return 0;516 517	connector = connectors[n];518 519	best_crtcs[n] = NULL;520	best_score = drm_client_pick_crtcs(client, connectors, connector_count,521					   best_crtcs, modes, n + 1, width, height);522	if (modes[n] == NULL)523		return best_score;524 525	crtcs = kcalloc(connector_count, sizeof(*crtcs), GFP_KERNEL);526	if (!crtcs)527		return best_score;528 529	my_score = 1;530	if (connector->status == connector_status_connected)531		my_score++;532	if (connector->cmdline_mode.specified)533		my_score++;534	if (drm_connector_has_preferred_mode(connector, width, height))535		my_score++;536 537	/*538	 * select a crtc for this connector and then attempt to configure539	 * remaining connectors540	 */541	drm_client_for_each_modeset(modeset, client) {542		crtc = modeset->crtc;543 544		if (!connector_has_possible_crtc(connector, crtc))545			continue;546 547		for (o = 0; o < n; o++)548			if (best_crtcs[o] == crtc)549				break;550 551		if (o < n) {552			/* ignore cloning unless only a single crtc */553			if (dev->mode_config.num_crtc > 1)554				continue;555 556			if (!drm_mode_equal(modes[o], modes[n]))557				continue;558		}559 560		crtcs[n] = crtc;561		memcpy(crtcs, best_crtcs, n * sizeof(*crtcs));562		score = my_score + drm_client_pick_crtcs(client, connectors, connector_count,563							 crtcs, modes, n + 1, width, height);564		if (score > best_score) {565			best_score = score;566			memcpy(best_crtcs, crtcs, connector_count * sizeof(*crtcs));567		}568	}569 570	kfree(crtcs);571	return best_score;572}573 574/* Try to read the BIOS display configuration and use it for the initial config */575static bool drm_client_firmware_config(struct drm_client_dev *client,576				       struct drm_connector **connectors,577				       unsigned int connector_count,578				       struct drm_crtc **crtcs,579				       struct drm_display_mode **modes,580				       struct drm_client_offset *offsets,581				       bool *enabled, int width, int height)582{583	const int count = min_t(unsigned int, connector_count, BITS_PER_LONG);584	unsigned long conn_configured, conn_seq, mask;585	struct drm_device *dev = client->dev;586	int i, j;587	bool *save_enabled;588	bool fallback = true, ret = true;589	int num_connectors_enabled = 0;590	int num_connectors_detected = 0;591	int num_tiled_conns = 0;592	struct drm_modeset_acquire_ctx ctx;593 594	if (!drm_drv_uses_atomic_modeset(dev))595		return false;596 597	if (drm_WARN_ON(dev, count <= 0))598		return false;599 600	save_enabled = kcalloc(count, sizeof(bool), GFP_KERNEL);601	if (!save_enabled)602		return false;603 604	drm_modeset_acquire_init(&ctx, 0);605 606	while (drm_modeset_lock_all_ctx(dev, &ctx) != 0)607		drm_modeset_backoff(&ctx);608 609	memcpy(save_enabled, enabled, count);610	mask = GENMASK(count - 1, 0);611	conn_configured = 0;612	for (i = 0; i < count; i++) {613		if (connectors[i]->has_tile &&614		    connectors[i]->status == connector_status_connected)615			num_tiled_conns++;616	}617retry:618	conn_seq = conn_configured;619	for (i = 0; i < count; i++) {620		struct drm_connector *connector;621		struct drm_encoder *encoder;622		struct drm_crtc *new_crtc;623 624		connector = connectors[i];625 626		if (conn_configured & BIT(i))627			continue;628 629		if (conn_seq == 0 && !connector->has_tile)630			continue;631 632		if (connector->status == connector_status_connected)633			num_connectors_detected++;634 635		if (!enabled[i]) {636			drm_dbg_kms(dev, "[CONNECTOR:%d:%s] not enabled, skipping\n",637				    connector->base.id, connector->name);638			conn_configured |= BIT(i);639			continue;640		}641 642		if (connector->force == DRM_FORCE_OFF) {643			drm_dbg_kms(dev, "[CONNECTOR:%d:%s] disabled by user, skipping\n",644				    connector->base.id, connector->name);645			enabled[i] = false;646			continue;647		}648 649		encoder = connector->state->best_encoder;650		if (!encoder || drm_WARN_ON(dev, !connector->state->crtc)) {651			if (connector->force > DRM_FORCE_OFF)652				goto bail;653 654			drm_dbg_kms(dev, "[CONNECTOR:%d:%s] has no encoder or crtc, skipping\n",655				    connector->base.id, connector->name);656			enabled[i] = false;657			conn_configured |= BIT(i);658			continue;659		}660 661		num_connectors_enabled++;662 663		new_crtc = connector->state->crtc;664 665		/*666		 * Make sure we're not trying to drive multiple connectors667		 * with a single CRTC, since our cloning support may not668		 * match the BIOS.669		 */670		for (j = 0; j < count; j++) {671			if (crtcs[j] == new_crtc) {672				drm_dbg_kms(dev, "fallback: cloned configuration\n");673				goto bail;674			}675		}676 677		drm_dbg_kms(dev, "[CONNECTOR:%d:%s] looking for cmdline mode\n",678			    connector->base.id, connector->name);679 680		/* go for command line mode first */681		modes[i] = drm_connector_pick_cmdline_mode(connector);682 683		/* try for preferred next */684		if (!modes[i]) {685			drm_dbg_kms(dev,686				    "[CONNECTOR:%d:%s] looking for preferred mode, has tile: %s\n",687				    connector->base.id, connector->name,688				    str_yes_no(connector->has_tile));689			modes[i] = drm_connector_has_preferred_mode(connector, width, height);690		}691 692		/* No preferred mode marked by the EDID? Are there any modes? */693		if (!modes[i] && !list_empty(&connector->modes)) {694			drm_dbg_kms(dev, "[CONNECTOR:%d:%s] using first listed mode\n",695				    connector->base.id, connector->name);696			modes[i] = list_first_entry(&connector->modes,697						    struct drm_display_mode,698						    head);699		}700 701		/* last resort: use current mode */702		if (!modes[i]) {703			/*704			 * IMPORTANT: We want to use the adjusted mode (i.e.705			 * after the panel fitter upscaling) as the initial706			 * config, not the input mode, which is what crtc->mode707			 * usually contains. But since our current708			 * code puts a mode derived from the post-pfit timings709			 * into crtc->mode this works out correctly.710			 *711			 * This is crtc->mode and not crtc->state->mode for the712			 * fastboot check to work correctly.713			 */714			drm_dbg_kms(dev, "[CONNECTOR:%d:%s] looking for current mode\n",715				    connector->base.id, connector->name);716			modes[i] = &connector->state->crtc->mode;717		}718		/*719		 * In case of tiled modes, if all tiles are not present720		 * then fallback to a non tiled mode.721		 */722		if (connector->has_tile &&723		    num_tiled_conns < connector->num_h_tile * connector->num_v_tile) {724			drm_dbg_kms(dev, "[CONNECTOR:%d:%s] Falling back to non-tiled mode\n",725				    connector->base.id, connector->name);726			modes[i] = drm_connector_fallback_non_tiled_mode(connector);727		}728		crtcs[i] = new_crtc;729 730		drm_dbg_kms(dev, "[CONNECTOR:%d:%s] on [CRTC:%d:%s]: %dx%d%s\n",731			    connector->base.id, connector->name,732			    connector->state->crtc->base.id,733			    connector->state->crtc->name,734			    modes[i]->hdisplay, modes[i]->vdisplay,735			    modes[i]->flags & DRM_MODE_FLAG_INTERLACE ? "i" : "");736 737		fallback = false;738		conn_configured |= BIT(i);739	}740 741	if ((conn_configured & mask) != mask && conn_configured != conn_seq)742		goto retry;743 744	/*745	 * If the BIOS didn't enable everything it could, fall back to have the746	 * same user experiencing of lighting up as much as possible like the747	 * fbdev helper library.748	 */749	if (num_connectors_enabled != num_connectors_detected &&750	    num_connectors_enabled < dev->mode_config.num_crtc) {751		drm_dbg_kms(dev, "fallback: Not all outputs enabled\n");752		drm_dbg_kms(dev, "Enabled: %i, detected: %i\n",753			    num_connectors_enabled, num_connectors_detected);754		fallback = true;755	}756 757	if (fallback) {758bail:759		drm_dbg_kms(dev, "Not using firmware configuration\n");760		memcpy(enabled, save_enabled, count);761		ret = false;762	}763 764	drm_modeset_drop_locks(&ctx);765	drm_modeset_acquire_fini(&ctx);766 767	kfree(save_enabled);768	return ret;769}770 771/**772 * drm_client_modeset_probe() - Probe for displays773 * @client: DRM client774 * @width: Maximum display mode width (optional)775 * @height: Maximum display mode height (optional)776 *777 * This function sets up display pipelines for enabled connectors and stores the778 * config in the client's modeset array.779 *780 * Returns:781 * Zero on success or negative error code on failure.782 */783int drm_client_modeset_probe(struct drm_client_dev *client, unsigned int width, unsigned int height)784{785	struct drm_connector *connector, **connectors = NULL;786	struct drm_connector_list_iter conn_iter;787	struct drm_device *dev = client->dev;788	unsigned int total_modes_count = 0;789	struct drm_client_offset *offsets;790	unsigned int connector_count = 0;791	/* points to modes protected by mode_config.mutex */792	struct drm_display_mode **modes;793	struct drm_crtc **crtcs;794	int i, ret = 0;795	bool *enabled;796 797	drm_dbg_kms(dev, "\n");798 799	if (!width)800		width = dev->mode_config.max_width;801	if (!height)802		height = dev->mode_config.max_height;803 804	drm_connector_list_iter_begin(dev, &conn_iter);805	drm_client_for_each_connector_iter(connector, &conn_iter) {806		struct drm_connector **tmp;807 808		tmp = krealloc(connectors, (connector_count + 1) * sizeof(*connectors), GFP_KERNEL);809		if (!tmp) {810			ret = -ENOMEM;811			goto free_connectors;812		}813 814		connectors = tmp;815		drm_connector_get(connector);816		connectors[connector_count++] = connector;817	}818	drm_connector_list_iter_end(&conn_iter);819 820	if (!connector_count)821		return 0;822 823	crtcs = kcalloc(connector_count, sizeof(*crtcs), GFP_KERNEL);824	modes = kcalloc(connector_count, sizeof(*modes), GFP_KERNEL);825	offsets = kcalloc(connector_count, sizeof(*offsets), GFP_KERNEL);826	enabled = kcalloc(connector_count, sizeof(bool), GFP_KERNEL);827	if (!crtcs || !modes || !enabled || !offsets) {828		ret = -ENOMEM;829		goto out;830	}831 832	mutex_lock(&client->modeset_mutex);833 834	mutex_lock(&dev->mode_config.mutex);835	for (i = 0; i < connector_count; i++)836		total_modes_count += connectors[i]->funcs->fill_modes(connectors[i], width, height);837	if (!total_modes_count)838		drm_dbg_kms(dev, "No connectors reported connected with modes\n");839	drm_client_connectors_enabled(connectors, connector_count, enabled);840 841	if (!drm_client_firmware_config(client, connectors, connector_count, crtcs,842					modes, offsets, enabled, width, height)) {843		memset(modes, 0, connector_count * sizeof(*modes));844		memset(crtcs, 0, connector_count * sizeof(*crtcs));845		memset(offsets, 0, connector_count * sizeof(*offsets));846 847		if (!drm_client_target_cloned(dev, connectors, connector_count, modes,848					      offsets, enabled, width, height) &&849		    !drm_client_target_preferred(dev, connectors, connector_count, modes,850						 offsets, enabled, width, height))851			drm_err(dev, "Unable to find initial modes\n");852 853		drm_dbg_kms(dev, "picking CRTCs for %dx%d config\n",854			    width, height);855 856		drm_client_pick_crtcs(client, connectors, connector_count,857				      crtcs, modes, 0, width, height);858	}859 860	drm_client_modeset_release(client);861 862	for (i = 0; i < connector_count; i++) {863		struct drm_display_mode *mode = modes[i];864		struct drm_crtc *crtc = crtcs[i];865		struct drm_client_offset *offset = &offsets[i];866 867		if (mode && crtc) {868			struct drm_mode_set *modeset = drm_client_find_modeset(client, crtc);869			struct drm_connector *connector = connectors[i];870 871			drm_dbg_kms(dev, "[CRTC:%d:%s] desired mode %s set (%d,%d)\n",872				    crtc->base.id, crtc->name,873				    mode->name, offset->x, offset->y);874 875			if (drm_WARN_ON_ONCE(dev, modeset->num_connectors == DRM_CLIENT_MAX_CLONED_CONNECTORS ||876					     (dev->mode_config.num_crtc > 1 && modeset->num_connectors == 1))) {877				ret = -EINVAL;878				break;879			}880 881			kfree(modeset->mode);882			modeset->mode = drm_mode_duplicate(dev, mode);883			if (!modeset->mode) {884				ret = -ENOMEM;885				break;886			}887 888			drm_connector_get(connector);889			modeset->connectors[modeset->num_connectors++] = connector;890			modeset->x = offset->x;891			modeset->y = offset->y;892		}893	}894	mutex_unlock(&dev->mode_config.mutex);895 896	mutex_unlock(&client->modeset_mutex);897out:898	kfree(crtcs);899	kfree(modes);900	kfree(offsets);901	kfree(enabled);902free_connectors:903	for (i = 0; i < connector_count; i++)904		drm_connector_put(connectors[i]);905	kfree(connectors);906 907	return ret;908}909EXPORT_SYMBOL(drm_client_modeset_probe);910 911/**912 * drm_client_rotation() - Check the initial rotation value913 * @modeset: DRM modeset914 * @rotation: Returned rotation value915 *916 * This function checks if the primary plane in @modeset can hw rotate917 * to match the rotation needed on its connector.918 *919 * Note: Currently only 0 and 180 degrees are supported.920 *921 * Return:922 * True if the plane can do the rotation, false otherwise.923 */924bool drm_client_rotation(struct drm_mode_set *modeset, unsigned int *rotation)925{926	struct drm_connector *connector = modeset->connectors[0];927	struct drm_plane *plane = modeset->crtc->primary;928	struct drm_cmdline_mode *cmdline;929	u64 valid_mask = 0;930	unsigned int i;931 932	if (!modeset->num_connectors)933		return false;934 935	switch (connector->display_info.panel_orientation) {936	case DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP:937		*rotation = DRM_MODE_ROTATE_180;938		break;939	case DRM_MODE_PANEL_ORIENTATION_LEFT_UP:940		*rotation = DRM_MODE_ROTATE_90;941		break;942	case DRM_MODE_PANEL_ORIENTATION_RIGHT_UP:943		*rotation = DRM_MODE_ROTATE_270;944		break;945	default:946		*rotation = DRM_MODE_ROTATE_0;947	}948 949	/**950	 * The panel already defined the default rotation951	 * through its orientation. Whatever has been provided952	 * on the command line needs to be added to that.953	 *954	 * Unfortunately, the rotations are at different bit955	 * indices, so the math to add them up are not as956	 * trivial as they could.957	 *958	 * Reflections on the other hand are pretty trivial to deal with, a959	 * simple XOR between the two handle the addition nicely.960	 */961	cmdline = &connector->cmdline_mode;962	if (cmdline->specified && cmdline->rotation_reflection) {963		unsigned int cmdline_rest, panel_rest;964		unsigned int cmdline_rot, panel_rot;965		unsigned int sum_rot, sum_rest;966 967		panel_rot = ilog2(*rotation & DRM_MODE_ROTATE_MASK);968		cmdline_rot = ilog2(cmdline->rotation_reflection & DRM_MODE_ROTATE_MASK);969		sum_rot = (panel_rot + cmdline_rot) % 4;970 971		panel_rest = *rotation & ~DRM_MODE_ROTATE_MASK;972		cmdline_rest = cmdline->rotation_reflection & ~DRM_MODE_ROTATE_MASK;973		sum_rest = panel_rest ^ cmdline_rest;974 975		*rotation = (1 << sum_rot) | sum_rest;976	}977 978	/*979	 * TODO: support 90 / 270 degree hardware rotation,980	 * depending on the hardware this may require the framebuffer981	 * to be in a specific tiling format.982	 */983	if (((*rotation & DRM_MODE_ROTATE_MASK) != DRM_MODE_ROTATE_0 &&984	     (*rotation & DRM_MODE_ROTATE_MASK) != DRM_MODE_ROTATE_180) ||985	    !plane->rotation_property)986		return false;987 988	for (i = 0; i < plane->rotation_property->num_values; i++)989		valid_mask |= (1ULL << plane->rotation_property->values[i]);990 991	if (!(*rotation & valid_mask))992		return false;993 994	return true;995}996EXPORT_SYMBOL(drm_client_rotation);997 998static int drm_client_modeset_commit_atomic(struct drm_client_dev *client, bool active, bool check)999{1000	struct drm_device *dev = client->dev;1001	struct drm_plane *plane;1002	struct drm_atomic_state *state;1003	struct drm_modeset_acquire_ctx ctx;1004	struct drm_mode_set *mode_set;1005	int ret;1006 1007	drm_modeset_acquire_init(&ctx, 0);1008 1009	state = drm_atomic_state_alloc(dev);1010	if (!state) {1011		ret = -ENOMEM;1012		goto out_ctx;1013	}1014 1015	state->acquire_ctx = &ctx;1016retry:1017	drm_for_each_plane(plane, dev) {1018		struct drm_plane_state *plane_state;1019 1020		plane_state = drm_atomic_get_plane_state(state, plane);1021		if (IS_ERR(plane_state)) {1022			ret = PTR_ERR(plane_state);1023			goto out_state;1024		}1025 1026		plane_state->rotation = DRM_MODE_ROTATE_0;1027 1028		/* disable non-primary: */1029		if (plane->type == DRM_PLANE_TYPE_PRIMARY)1030			continue;1031 1032		ret = __drm_atomic_helper_disable_plane(plane, plane_state);1033		if (ret != 0)1034			goto out_state;1035	}1036 1037	drm_client_for_each_modeset(mode_set, client) {1038		struct drm_plane *primary = mode_set->crtc->primary;1039		unsigned int rotation;1040 1041		if (drm_client_rotation(mode_set, &rotation)) {1042			struct drm_plane_state *plane_state;1043 1044			/* Cannot fail as we've already gotten the plane state above */1045			plane_state = drm_atomic_get_new_plane_state(state, primary);1046			plane_state->rotation = rotation;1047		}1048 1049		ret = __drm_atomic_helper_set_config(mode_set, state);1050		if (ret != 0)1051			goto out_state;1052 1053		/*1054		 * __drm_atomic_helper_set_config() sets active when a1055		 * mode is set, unconditionally clear it if we force DPMS off1056		 */1057		if (!active) {1058			struct drm_crtc *crtc = mode_set->crtc;1059			struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);1060 1061			crtc_state->active = false;1062		}1063	}1064 1065	if (check)1066		ret = drm_atomic_check_only(state);1067	else1068		ret = drm_atomic_commit(state);1069 1070out_state:1071	if (ret == -EDEADLK)1072		goto backoff;1073 1074	drm_atomic_state_put(state);1075out_ctx:1076	drm_modeset_drop_locks(&ctx);1077	drm_modeset_acquire_fini(&ctx);1078 1079	return ret;1080 1081backoff:1082	drm_atomic_state_clear(state);1083	drm_modeset_backoff(&ctx);1084 1085	goto retry;1086}1087 1088static int drm_client_modeset_commit_legacy(struct drm_client_dev *client)1089{1090	struct drm_device *dev = client->dev;1091	struct drm_mode_set *mode_set;1092	struct drm_plane *plane;1093	int ret = 0;1094 1095	drm_modeset_lock_all(dev);1096	drm_for_each_plane(plane, dev) {1097		if (plane->type != DRM_PLANE_TYPE_PRIMARY)1098			drm_plane_force_disable(plane);1099 1100		if (plane->rotation_property)1101			drm_mode_plane_set_obj_prop(plane,1102						    plane->rotation_property,1103						    DRM_MODE_ROTATE_0);1104	}1105 1106	drm_client_for_each_modeset(mode_set, client) {1107		struct drm_crtc *crtc = mode_set->crtc;1108 1109		if (crtc->funcs->cursor_set2) {1110			ret = crtc->funcs->cursor_set2(crtc, NULL, 0, 0, 0, 0, 0);1111			if (ret)1112				goto out;1113		} else if (crtc->funcs->cursor_set) {1114			ret = crtc->funcs->cursor_set(crtc, NULL, 0, 0, 0);1115			if (ret)1116				goto out;1117		}1118 1119		ret = drm_mode_set_config_internal(mode_set);1120		if (ret)1121			goto out;1122	}1123out:1124	drm_modeset_unlock_all(dev);1125 1126	return ret;1127}1128 1129/**1130 * drm_client_modeset_check() - Check modeset configuration1131 * @client: DRM client1132 *1133 * Check modeset configuration.1134 *1135 * Returns:1136 * Zero on success or negative error code on failure.1137 */1138int drm_client_modeset_check(struct drm_client_dev *client)1139{1140	int ret;1141 1142	if (!drm_drv_uses_atomic_modeset(client->dev))1143		return 0;1144 1145	mutex_lock(&client->modeset_mutex);1146	ret = drm_client_modeset_commit_atomic(client, true, true);1147	mutex_unlock(&client->modeset_mutex);1148 1149	return ret;1150}1151EXPORT_SYMBOL(drm_client_modeset_check);1152 1153/**1154 * drm_client_modeset_commit_locked() - Force commit CRTC configuration1155 * @client: DRM client1156 *1157 * Commit modeset configuration to crtcs without checking if there is a DRM1158 * master. The assumption is that the caller already holds an internal DRM1159 * master reference acquired with drm_master_internal_acquire().1160 *1161 * Returns:1162 * Zero on success or negative error code on failure.1163 */1164int drm_client_modeset_commit_locked(struct drm_client_dev *client)1165{1166	struct drm_device *dev = client->dev;1167	int ret;1168 1169	mutex_lock(&client->modeset_mutex);1170	if (drm_drv_uses_atomic_modeset(dev))1171		ret = drm_client_modeset_commit_atomic(client, true, false);1172	else1173		ret = drm_client_modeset_commit_legacy(client);1174	mutex_unlock(&client->modeset_mutex);1175 1176	return ret;1177}1178EXPORT_SYMBOL(drm_client_modeset_commit_locked);1179 1180/**1181 * drm_client_modeset_commit() - Commit CRTC configuration1182 * @client: DRM client1183 *1184 * Commit modeset configuration to crtcs.1185 *1186 * Returns:1187 * Zero on success or negative error code on failure.1188 */1189int drm_client_modeset_commit(struct drm_client_dev *client)1190{1191	struct drm_device *dev = client->dev;1192	int ret;1193 1194	if (!drm_master_internal_acquire(dev))1195		return -EBUSY;1196 1197	ret = drm_client_modeset_commit_locked(client);1198 1199	drm_master_internal_release(dev);1200 1201	return ret;1202}1203EXPORT_SYMBOL(drm_client_modeset_commit);1204 1205static void drm_client_modeset_dpms_legacy(struct drm_client_dev *client, int dpms_mode)1206{1207	struct drm_device *dev = client->dev;1208	struct drm_connector *connector;1209	struct drm_mode_set *modeset;1210	struct drm_modeset_acquire_ctx ctx;1211	int j;1212	int ret;1213 1214	DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret);1215	drm_client_for_each_modeset(modeset, client) {1216		if (!modeset->crtc->enabled)1217			continue;1218 1219		for (j = 0; j < modeset->num_connectors; j++) {1220			connector = modeset->connectors[j];1221			connector->funcs->dpms(connector, dpms_mode);1222			drm_object_property_set_value(&connector->base,1223				dev->mode_config.dpms_property, dpms_mode);1224		}1225	}1226	DRM_MODESET_LOCK_ALL_END(dev, ctx, ret);1227}1228 1229/**1230 * drm_client_modeset_dpms() - Set DPMS mode1231 * @client: DRM client1232 * @mode: DPMS mode1233 *1234 * Note: For atomic drivers @mode is reduced to on/off.1235 *1236 * Returns:1237 * Zero on success or negative error code on failure.1238 */1239int drm_client_modeset_dpms(struct drm_client_dev *client, int mode)1240{1241	struct drm_device *dev = client->dev;1242	int ret = 0;1243 1244	if (!drm_master_internal_acquire(dev))1245		return -EBUSY;1246 1247	mutex_lock(&client->modeset_mutex);1248	if (drm_drv_uses_atomic_modeset(dev))1249		ret = drm_client_modeset_commit_atomic(client, mode == DRM_MODE_DPMS_ON, false);1250	else1251		drm_client_modeset_dpms_legacy(client, mode);1252	mutex_unlock(&client->modeset_mutex);1253 1254	drm_master_internal_release(dev);1255 1256	return ret;1257}1258EXPORT_SYMBOL(drm_client_modeset_dpms);1259 1260#ifdef CONFIG_DRM_KUNIT_TEST1261#include "tests/drm_client_modeset_test.c"1262#endif1263