brintos

brintos / linux-shallow public Read only

0
0
Text · 17.2 KiB · d4c2afa Raw
684 lines · c
1// SPDX-License-Identifier: GPL-2.0+2 3#include <drm/drm_atomic_helper.h>4#include <drm/drm_edid.h>5#include <drm/drm_simple_kms_helper.h>6#include <drm/drm_gem_framebuffer_helper.h>7#include <drm/drm_vblank.h>8 9#include "amdgpu.h"10#ifdef CONFIG_DRM_AMDGPU_SI11#include "dce_v6_0.h"12#endif13#ifdef CONFIG_DRM_AMDGPU_CIK14#include "dce_v8_0.h"15#endif16#include "dce_v10_0.h"17#include "dce_v11_0.h"18#include "ivsrcid/ivsrcid_vislands30.h"19#include "amdgpu_vkms.h"20#include "amdgpu_display.h"21#include "atom.h"22#include "amdgpu_irq.h"23 24/**25 * DOC: amdgpu_vkms26 *27 * The amdgpu vkms interface provides a virtual KMS interface for several use28 * cases: devices without display hardware, platforms where the actual display29 * hardware is not useful (e.g., servers), SR-IOV virtual functions, device30 * emulation/simulation, and device bring up prior to display hardware being31 * usable. We previously emulated a legacy KMS interface, but there was a desire32 * to move to the atomic KMS interface. The vkms driver did everything we33 * needed, but we wanted KMS support natively in the driver without buffer34 * sharing and the ability to support an instance of VKMS per device. We first35 * looked at splitting vkms into a stub driver and a helper module that other36 * drivers could use to implement a virtual display, but this strategy ended up37 * being messy due to driver specific callbacks needed for buffer management.38 * Ultimately, it proved easier to import the vkms code as it mostly used core39 * drm helpers anyway.40 */41 42static const u32 amdgpu_vkms_formats[] = {43	DRM_FORMAT_XRGB8888,44};45 46static enum hrtimer_restart amdgpu_vkms_vblank_simulate(struct hrtimer *timer)47{48	struct amdgpu_crtc *amdgpu_crtc = container_of(timer, struct amdgpu_crtc, vblank_timer);49	struct drm_crtc *crtc = &amdgpu_crtc->base;50	struct amdgpu_vkms_output *output = drm_crtc_to_amdgpu_vkms_output(crtc);51	u64 ret_overrun;52	bool ret;53 54	ret_overrun = hrtimer_forward_now(&amdgpu_crtc->vblank_timer,55					  output->period_ns);56	if (ret_overrun != 1)57		DRM_WARN("%s: vblank timer overrun\n", __func__);58 59	ret = drm_crtc_handle_vblank(crtc);60	/* Don't queue timer again when vblank is disabled. */61	if (!ret)62		return HRTIMER_NORESTART;63 64	return HRTIMER_RESTART;65}66 67static int amdgpu_vkms_enable_vblank(struct drm_crtc *crtc)68{69	struct drm_vblank_crtc *vblank = drm_crtc_vblank_crtc(crtc);70	struct amdgpu_vkms_output *out = drm_crtc_to_amdgpu_vkms_output(crtc);71	struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);72 73	drm_calc_timestamping_constants(crtc, &crtc->mode);74 75	out->period_ns = ktime_set(0, vblank->framedur_ns);76	hrtimer_start(&amdgpu_crtc->vblank_timer, out->period_ns, HRTIMER_MODE_REL);77 78	return 0;79}80 81static void amdgpu_vkms_disable_vblank(struct drm_crtc *crtc)82{83	struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);84 85	hrtimer_try_to_cancel(&amdgpu_crtc->vblank_timer);86}87 88static bool amdgpu_vkms_get_vblank_timestamp(struct drm_crtc *crtc,89					     int *max_error,90					     ktime_t *vblank_time,91					     bool in_vblank_irq)92{93	struct amdgpu_vkms_output *output = drm_crtc_to_amdgpu_vkms_output(crtc);94	struct drm_vblank_crtc *vblank = drm_crtc_vblank_crtc(crtc);95	struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);96 97	if (!READ_ONCE(vblank->enabled)) {98		*vblank_time = ktime_get();99		return true;100	}101 102	*vblank_time = READ_ONCE(amdgpu_crtc->vblank_timer.node.expires);103 104	if (WARN_ON(*vblank_time == vblank->time))105		return true;106 107	/*108	 * To prevent races we roll the hrtimer forward before we do any109	 * interrupt processing - this is how real hw works (the interrupt is110	 * only generated after all the vblank registers are updated) and what111	 * the vblank core expects. Therefore we need to always correct the112	 * timestampe by one frame.113	 */114	*vblank_time -= output->period_ns;115 116	return true;117}118 119static const struct drm_crtc_funcs amdgpu_vkms_crtc_funcs = {120	.set_config             = drm_atomic_helper_set_config,121	.destroy                = drm_crtc_cleanup,122	.page_flip              = drm_atomic_helper_page_flip,123	.reset                  = drm_atomic_helper_crtc_reset,124	.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,125	.atomic_destroy_state   = drm_atomic_helper_crtc_destroy_state,126	.enable_vblank		= amdgpu_vkms_enable_vblank,127	.disable_vblank		= amdgpu_vkms_disable_vblank,128	.get_vblank_timestamp	= amdgpu_vkms_get_vblank_timestamp,129};130 131static void amdgpu_vkms_crtc_atomic_enable(struct drm_crtc *crtc,132					   struct drm_atomic_state *state)133{134	drm_crtc_vblank_on(crtc);135}136 137static void amdgpu_vkms_crtc_atomic_disable(struct drm_crtc *crtc,138					    struct drm_atomic_state *state)139{140	drm_crtc_vblank_off(crtc);141}142 143static void amdgpu_vkms_crtc_atomic_flush(struct drm_crtc *crtc,144					  struct drm_atomic_state *state)145{146	unsigned long flags;147	if (crtc->state->event) {148		spin_lock_irqsave(&crtc->dev->event_lock, flags);149 150		if (drm_crtc_vblank_get(crtc) != 0)151			drm_crtc_send_vblank_event(crtc, crtc->state->event);152		else153			drm_crtc_arm_vblank_event(crtc, crtc->state->event);154 155		spin_unlock_irqrestore(&crtc->dev->event_lock, flags);156 157		crtc->state->event = NULL;158	}159}160 161static const struct drm_crtc_helper_funcs amdgpu_vkms_crtc_helper_funcs = {162	.atomic_flush	= amdgpu_vkms_crtc_atomic_flush,163	.atomic_enable	= amdgpu_vkms_crtc_atomic_enable,164	.atomic_disable	= amdgpu_vkms_crtc_atomic_disable,165};166 167static int amdgpu_vkms_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,168			  struct drm_plane *primary, struct drm_plane *cursor)169{170	struct amdgpu_device *adev = drm_to_adev(dev);171	struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);172	int ret;173 174	ret = drm_crtc_init_with_planes(dev, crtc, primary, cursor,175					&amdgpu_vkms_crtc_funcs, NULL);176	if (ret) {177		DRM_ERROR("Failed to init CRTC\n");178		return ret;179	}180 181	drm_crtc_helper_add(crtc, &amdgpu_vkms_crtc_helper_funcs);182 183	amdgpu_crtc->crtc_id = drm_crtc_index(crtc);184	adev->mode_info.crtcs[drm_crtc_index(crtc)] = amdgpu_crtc;185 186	amdgpu_crtc->pll_id = ATOM_PPLL_INVALID;187	amdgpu_crtc->encoder = NULL;188	amdgpu_crtc->connector = NULL;189	amdgpu_crtc->vsync_timer_enabled = AMDGPU_IRQ_STATE_DISABLE;190 191	hrtimer_init(&amdgpu_crtc->vblank_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);192	amdgpu_crtc->vblank_timer.function = &amdgpu_vkms_vblank_simulate;193 194	return ret;195}196 197static const struct drm_connector_funcs amdgpu_vkms_connector_funcs = {198	.fill_modes = drm_helper_probe_single_connector_modes,199	.destroy = drm_connector_cleanup,200	.reset = drm_atomic_helper_connector_reset,201	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,202	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,203};204 205static int amdgpu_vkms_conn_get_modes(struct drm_connector *connector)206{207	struct drm_device *dev = connector->dev;208	struct drm_display_mode *mode = NULL;209	unsigned i;210	static const struct mode_size {211		int w;212		int h;213	} common_modes[] = {214		{ 640,  480},215		{ 720,  480},216		{ 800,  600},217		{ 848,  480},218		{1024,  768},219		{1152,  768},220		{1280,  720},221		{1280,  800},222		{1280,  854},223		{1280,  960},224		{1280, 1024},225		{1440,  900},226		{1400, 1050},227		{1680, 1050},228		{1600, 1200},229		{1920, 1080},230		{1920, 1200},231		{2560, 1440},232		{4096, 3112},233		{3656, 2664},234		{3840, 2160},235		{4096, 2160},236	};237 238	for (i = 0; i < ARRAY_SIZE(common_modes); i++) {239		mode = drm_cvt_mode(dev, common_modes[i].w, common_modes[i].h, 60, false, false, false);240		if (!mode)241			continue;242		drm_mode_probed_add(connector, mode);243	}244 245	drm_set_preferred_mode(connector, XRES_DEF, YRES_DEF);246 247	return ARRAY_SIZE(common_modes);248}249 250static const struct drm_connector_helper_funcs amdgpu_vkms_conn_helper_funcs = {251	.get_modes    = amdgpu_vkms_conn_get_modes,252};253 254static const struct drm_plane_funcs amdgpu_vkms_plane_funcs = {255	.update_plane		= drm_atomic_helper_update_plane,256	.disable_plane		= drm_atomic_helper_disable_plane,257	.destroy		= drm_plane_cleanup,258	.reset			= drm_atomic_helper_plane_reset,259	.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,260	.atomic_destroy_state	= drm_atomic_helper_plane_destroy_state,261};262 263static void amdgpu_vkms_plane_atomic_update(struct drm_plane *plane,264					    struct drm_atomic_state *old_state)265{266	return;267}268 269static int amdgpu_vkms_plane_atomic_check(struct drm_plane *plane,270					  struct drm_atomic_state *state)271{272	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,273										 plane);274	struct drm_crtc_state *crtc_state;275	int ret;276 277	if (!new_plane_state->fb || WARN_ON(!new_plane_state->crtc))278		return 0;279 280	crtc_state = drm_atomic_get_crtc_state(state,281					       new_plane_state->crtc);282	if (IS_ERR(crtc_state))283		return PTR_ERR(crtc_state);284 285	ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,286						  DRM_PLANE_NO_SCALING,287						  DRM_PLANE_NO_SCALING,288						  false, true);289	if (ret != 0)290		return ret;291 292	/* for now primary plane must be visible and full screen */293	if (!new_plane_state->visible)294		return -EINVAL;295 296	return 0;297}298 299static int amdgpu_vkms_prepare_fb(struct drm_plane *plane,300				  struct drm_plane_state *new_state)301{302	struct amdgpu_framebuffer *afb;303	struct drm_gem_object *obj;304	struct amdgpu_device *adev;305	struct amdgpu_bo *rbo;306	uint32_t domain;307	int r;308 309	if (!new_state->fb) {310		DRM_DEBUG_KMS("No FB bound\n");311		return 0;312	}313	afb = to_amdgpu_framebuffer(new_state->fb);314 315	obj = drm_gem_fb_get_obj(new_state->fb, 0);316	if (!obj) {317		DRM_ERROR("Failed to get obj from framebuffer\n");318		return -EINVAL;319	}320 321	rbo = gem_to_amdgpu_bo(obj);322	adev = amdgpu_ttm_adev(rbo->tbo.bdev);323 324	r = amdgpu_bo_reserve(rbo, true);325	if (r) {326		dev_err(adev->dev, "fail to reserve bo (%d)\n", r);327		return r;328	}329 330	r = dma_resv_reserve_fences(rbo->tbo.base.resv, 1);331	if (r) {332		dev_err(adev->dev, "allocating fence slot failed (%d)\n", r);333		goto error_unlock;334	}335 336	if (plane->type != DRM_PLANE_TYPE_CURSOR)337		domain = amdgpu_display_supported_domains(adev, rbo->flags);338	else339		domain = AMDGPU_GEM_DOMAIN_VRAM;340 341	rbo->flags |= AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS;342	r = amdgpu_bo_pin(rbo, domain);343	if (unlikely(r != 0)) {344		if (r != -ERESTARTSYS)345			DRM_ERROR("Failed to pin framebuffer with error %d\n", r);346		goto error_unlock;347	}348 349	r = amdgpu_ttm_alloc_gart(&rbo->tbo);350	if (unlikely(r != 0)) {351		DRM_ERROR("%p bind failed\n", rbo);352		goto error_unpin;353	}354 355	amdgpu_bo_unreserve(rbo);356 357	afb->address = amdgpu_bo_gpu_offset(rbo);358 359	amdgpu_bo_ref(rbo);360 361	return 0;362 363error_unpin:364	amdgpu_bo_unpin(rbo);365 366error_unlock:367	amdgpu_bo_unreserve(rbo);368	return r;369}370 371static void amdgpu_vkms_cleanup_fb(struct drm_plane *plane,372				   struct drm_plane_state *old_state)373{374	struct amdgpu_bo *rbo;375	struct drm_gem_object *obj;376	int r;377 378	if (!old_state->fb)379		return;380 381	obj = drm_gem_fb_get_obj(old_state->fb, 0);382	if (!obj) {383		DRM_ERROR("Failed to get obj from framebuffer\n");384		return;385	}386 387	rbo = gem_to_amdgpu_bo(obj);388	r = amdgpu_bo_reserve(rbo, false);389	if (unlikely(r)) {390		DRM_ERROR("failed to reserve rbo before unpin\n");391		return;392	}393 394	amdgpu_bo_unpin(rbo);395	amdgpu_bo_unreserve(rbo);396	amdgpu_bo_unref(&rbo);397}398 399static const struct drm_plane_helper_funcs amdgpu_vkms_primary_helper_funcs = {400	.atomic_update		= amdgpu_vkms_plane_atomic_update,401	.atomic_check		= amdgpu_vkms_plane_atomic_check,402	.prepare_fb		= amdgpu_vkms_prepare_fb,403	.cleanup_fb		= amdgpu_vkms_cleanup_fb,404};405 406static struct drm_plane *amdgpu_vkms_plane_init(struct drm_device *dev,407						enum drm_plane_type type,408						int index)409{410	struct drm_plane *plane;411	int ret;412 413	plane = kzalloc(sizeof(*plane), GFP_KERNEL);414	if (!plane)415		return ERR_PTR(-ENOMEM);416 417	ret = drm_universal_plane_init(dev, plane, 1 << index,418				       &amdgpu_vkms_plane_funcs,419				       amdgpu_vkms_formats,420				       ARRAY_SIZE(amdgpu_vkms_formats),421				       NULL, type, NULL);422	if (ret) {423		kfree(plane);424		return ERR_PTR(ret);425	}426 427	drm_plane_helper_add(plane, &amdgpu_vkms_primary_helper_funcs);428 429	return plane;430}431 432static int amdgpu_vkms_output_init(struct drm_device *dev, struct433				   amdgpu_vkms_output *output, int index)434{435	struct drm_connector *connector = &output->connector;436	struct drm_encoder *encoder = &output->encoder;437	struct drm_crtc *crtc = &output->crtc.base;438	struct drm_plane *primary, *cursor = NULL;439	int ret;440 441	primary = amdgpu_vkms_plane_init(dev, DRM_PLANE_TYPE_PRIMARY, index);442	if (IS_ERR(primary))443		return PTR_ERR(primary);444 445	ret = amdgpu_vkms_crtc_init(dev, crtc, primary, cursor);446	if (ret)447		goto err_crtc;448 449	ret = drm_connector_init(dev, connector, &amdgpu_vkms_connector_funcs,450				 DRM_MODE_CONNECTOR_VIRTUAL);451	if (ret) {452		DRM_ERROR("Failed to init connector\n");453		goto err_connector;454	}455 456	drm_connector_helper_add(connector, &amdgpu_vkms_conn_helper_funcs);457 458	ret = drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_VIRTUAL);459	if (ret) {460		DRM_ERROR("Failed to init encoder\n");461		goto err_encoder;462	}463	encoder->possible_crtcs = 1 << index;464 465	ret = drm_connector_attach_encoder(connector, encoder);466	if (ret) {467		DRM_ERROR("Failed to attach connector to encoder\n");468		goto err_attach;469	}470 471	drm_mode_config_reset(dev);472 473	return 0;474 475err_attach:476	drm_encoder_cleanup(encoder);477 478err_encoder:479	drm_connector_cleanup(connector);480 481err_connector:482	drm_crtc_cleanup(crtc);483 484err_crtc:485	drm_plane_cleanup(primary);486 487	return ret;488}489 490const struct drm_mode_config_funcs amdgpu_vkms_mode_funcs = {491	.fb_create = amdgpu_display_user_framebuffer_create,492	.atomic_check = drm_atomic_helper_check,493	.atomic_commit = drm_atomic_helper_commit,494};495 496static int amdgpu_vkms_sw_init(void *handle)497{498	int r, i;499	struct amdgpu_device *adev = (struct amdgpu_device *)handle;500 501	adev->amdgpu_vkms_output = kcalloc(adev->mode_info.num_crtc,502		sizeof(struct amdgpu_vkms_output), GFP_KERNEL);503	if (!adev->amdgpu_vkms_output)504		return -ENOMEM;505 506	adev_to_drm(adev)->max_vblank_count = 0;507 508	adev_to_drm(adev)->mode_config.funcs = &amdgpu_vkms_mode_funcs;509 510	adev_to_drm(adev)->mode_config.max_width = XRES_MAX;511	adev_to_drm(adev)->mode_config.max_height = YRES_MAX;512 513	adev_to_drm(adev)->mode_config.preferred_depth = 24;514	adev_to_drm(adev)->mode_config.prefer_shadow = 1;515 516	adev_to_drm(adev)->mode_config.fb_modifiers_not_supported = true;517 518	r = amdgpu_display_modeset_create_props(adev);519	if (r)520		return r;521 522	/* allocate crtcs, encoders, connectors */523	for (i = 0; i < adev->mode_info.num_crtc; i++) {524		r = amdgpu_vkms_output_init(adev_to_drm(adev), &adev->amdgpu_vkms_output[i], i);525		if (r)526			return r;527	}528 529	r = drm_vblank_init(adev_to_drm(adev), adev->mode_info.num_crtc);530	if (r)531		return r;532 533	drm_kms_helper_poll_init(adev_to_drm(adev));534 535	adev->mode_info.mode_config_initialized = true;536	return 0;537}538 539static int amdgpu_vkms_sw_fini(void *handle)540{541	struct amdgpu_device *adev = (struct amdgpu_device *)handle;542	int i = 0;543 544	for (i = 0; i < adev->mode_info.num_crtc; i++)545		if (adev->mode_info.crtcs[i])546			hrtimer_cancel(&adev->mode_info.crtcs[i]->vblank_timer);547 548	drm_kms_helper_poll_fini(adev_to_drm(adev));549	drm_mode_config_cleanup(adev_to_drm(adev));550 551	adev->mode_info.mode_config_initialized = false;552 553	drm_edid_free(adev->mode_info.bios_hardcoded_edid);554	kfree(adev->amdgpu_vkms_output);555	return 0;556}557 558static int amdgpu_vkms_hw_init(void *handle)559{560	struct amdgpu_device *adev = (struct amdgpu_device *)handle;561 562	switch (adev->asic_type) {563#ifdef CONFIG_DRM_AMDGPU_SI564	case CHIP_TAHITI:565	case CHIP_PITCAIRN:566	case CHIP_VERDE:567	case CHIP_OLAND:568		dce_v6_0_disable_dce(adev);569		break;570#endif571#ifdef CONFIG_DRM_AMDGPU_CIK572	case CHIP_BONAIRE:573	case CHIP_HAWAII:574	case CHIP_KAVERI:575	case CHIP_KABINI:576	case CHIP_MULLINS:577		dce_v8_0_disable_dce(adev);578		break;579#endif580	case CHIP_FIJI:581	case CHIP_TONGA:582		dce_v10_0_disable_dce(adev);583		break;584	case CHIP_CARRIZO:585	case CHIP_STONEY:586	case CHIP_POLARIS10:587	case CHIP_POLARIS11:588	case CHIP_VEGAM:589		dce_v11_0_disable_dce(adev);590		break;591	case CHIP_TOPAZ:592#ifdef CONFIG_DRM_AMDGPU_SI593	case CHIP_HAINAN:594#endif595		/* no DCE */596		break;597	default:598		break;599	}600	return 0;601}602 603static int amdgpu_vkms_hw_fini(void *handle)604{605	return 0;606}607 608static int amdgpu_vkms_suspend(void *handle)609{610	struct amdgpu_device *adev = (struct amdgpu_device *)handle;611	int r;612 613	r = drm_mode_config_helper_suspend(adev_to_drm(adev));614	if (r)615		return r;616	return amdgpu_vkms_hw_fini(handle);617}618 619static int amdgpu_vkms_resume(void *handle)620{621	struct amdgpu_device *adev = (struct amdgpu_device *)handle;622	int r;623 624	r = amdgpu_vkms_hw_init(handle);625	if (r)626		return r;627	return drm_mode_config_helper_resume(adev_to_drm(adev));628}629 630static bool amdgpu_vkms_is_idle(void *handle)631{632	return true;633}634 635static int amdgpu_vkms_wait_for_idle(void *handle)636{637	return 0;638}639 640static int amdgpu_vkms_soft_reset(void *handle)641{642	return 0;643}644 645static int amdgpu_vkms_set_clockgating_state(void *handle,646					  enum amd_clockgating_state state)647{648	return 0;649}650 651static int amdgpu_vkms_set_powergating_state(void *handle,652					  enum amd_powergating_state state)653{654	return 0;655}656 657static const struct amd_ip_funcs amdgpu_vkms_ip_funcs = {658	.name = "amdgpu_vkms",659	.early_init = NULL,660	.late_init = NULL,661	.sw_init = amdgpu_vkms_sw_init,662	.sw_fini = amdgpu_vkms_sw_fini,663	.hw_init = amdgpu_vkms_hw_init,664	.hw_fini = amdgpu_vkms_hw_fini,665	.suspend = amdgpu_vkms_suspend,666	.resume = amdgpu_vkms_resume,667	.is_idle = amdgpu_vkms_is_idle,668	.wait_for_idle = amdgpu_vkms_wait_for_idle,669	.soft_reset = amdgpu_vkms_soft_reset,670	.set_clockgating_state = amdgpu_vkms_set_clockgating_state,671	.set_powergating_state = amdgpu_vkms_set_powergating_state,672	.dump_ip_state = NULL,673	.print_ip_state = NULL,674};675 676const struct amdgpu_ip_block_version amdgpu_vkms_ip_block = {677	.type = AMD_IP_BLOCK_TYPE_DCE,678	.major = 1,679	.minor = 0,680	.rev = 0,681	.funcs = &amdgpu_vkms_ip_funcs,682};683 684