162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Copyright 2019 Advanced Micro Devices, Inc.
362306a36Sopenharmony_ci * All Rights Reserved.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
662306a36Sopenharmony_ci * copy of this software and associated documentation files (the
762306a36Sopenharmony_ci * "Software"), to deal in the Software without restriction, including
862306a36Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish,
962306a36Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to
1062306a36Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to
1162306a36Sopenharmony_ci * the following conditions:
1262306a36Sopenharmony_ci *
1362306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1462306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1562306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
1662306a36Sopenharmony_ci * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
1762306a36Sopenharmony_ci * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
1862306a36Sopenharmony_ci * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
1962306a36Sopenharmony_ci * USE OR OTHER DEALINGS IN THE SOFTWARE.
2062306a36Sopenharmony_ci *
2162306a36Sopenharmony_ci * The above copyright notice and this permission notice (including the
2262306a36Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions
2362306a36Sopenharmony_ci * of the Software.
2462306a36Sopenharmony_ci *
2562306a36Sopenharmony_ci */
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#include "amdgpu.h"
2862306a36Sopenharmony_ci#include "amdgpu_jpeg.h"
2962306a36Sopenharmony_ci#include "amdgpu_pm.h"
3062306a36Sopenharmony_ci#include "soc15d.h"
3162306a36Sopenharmony_ci#include "soc15_common.h"
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#define JPEG_IDLE_TIMEOUT	msecs_to_jiffies(1000)
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_cistatic void amdgpu_jpeg_idle_work_handler(struct work_struct *work);
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ciint amdgpu_jpeg_sw_init(struct amdgpu_device *adev)
3862306a36Sopenharmony_ci{
3962306a36Sopenharmony_ci	INIT_DELAYED_WORK(&adev->jpeg.idle_work, amdgpu_jpeg_idle_work_handler);
4062306a36Sopenharmony_ci	mutex_init(&adev->jpeg.jpeg_pg_lock);
4162306a36Sopenharmony_ci	atomic_set(&adev->jpeg.total_submission_cnt, 0);
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	return 0;
4462306a36Sopenharmony_ci}
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ciint amdgpu_jpeg_sw_fini(struct amdgpu_device *adev)
4762306a36Sopenharmony_ci{
4862306a36Sopenharmony_ci	int i, j;
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	for (i = 0; i < adev->jpeg.num_jpeg_inst; ++i) {
5162306a36Sopenharmony_ci		if (adev->jpeg.harvest_config & (1 << i))
5262306a36Sopenharmony_ci			continue;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci		for (j = 0; j < adev->jpeg.num_jpeg_rings; ++j)
5562306a36Sopenharmony_ci			amdgpu_ring_fini(&adev->jpeg.inst[i].ring_dec[j]);
5662306a36Sopenharmony_ci	}
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	mutex_destroy(&adev->jpeg.jpeg_pg_lock);
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	return 0;
6162306a36Sopenharmony_ci}
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ciint amdgpu_jpeg_suspend(struct amdgpu_device *adev)
6462306a36Sopenharmony_ci{
6562306a36Sopenharmony_ci	cancel_delayed_work_sync(&adev->jpeg.idle_work);
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	return 0;
6862306a36Sopenharmony_ci}
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ciint amdgpu_jpeg_resume(struct amdgpu_device *adev)
7162306a36Sopenharmony_ci{
7262306a36Sopenharmony_ci	return 0;
7362306a36Sopenharmony_ci}
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_cistatic void amdgpu_jpeg_idle_work_handler(struct work_struct *work)
7662306a36Sopenharmony_ci{
7762306a36Sopenharmony_ci	struct amdgpu_device *adev =
7862306a36Sopenharmony_ci		container_of(work, struct amdgpu_device, jpeg.idle_work.work);
7962306a36Sopenharmony_ci	unsigned int fences = 0;
8062306a36Sopenharmony_ci	unsigned int i, j;
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	for (i = 0; i < adev->jpeg.num_jpeg_inst; ++i) {
8362306a36Sopenharmony_ci		if (adev->jpeg.harvest_config & (1 << i))
8462306a36Sopenharmony_ci			continue;
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci		for (j = 0; j < adev->jpeg.num_jpeg_rings; ++j)
8762306a36Sopenharmony_ci			fences += amdgpu_fence_count_emitted(&adev->jpeg.inst[i].ring_dec[j]);
8862306a36Sopenharmony_ci	}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	if (!fences && !atomic_read(&adev->jpeg.total_submission_cnt))
9162306a36Sopenharmony_ci		amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_JPEG,
9262306a36Sopenharmony_ci						       AMD_PG_STATE_GATE);
9362306a36Sopenharmony_ci	else
9462306a36Sopenharmony_ci		schedule_delayed_work(&adev->jpeg.idle_work, JPEG_IDLE_TIMEOUT);
9562306a36Sopenharmony_ci}
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_civoid amdgpu_jpeg_ring_begin_use(struct amdgpu_ring *ring)
9862306a36Sopenharmony_ci{
9962306a36Sopenharmony_ci	struct amdgpu_device *adev = ring->adev;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	atomic_inc(&adev->jpeg.total_submission_cnt);
10262306a36Sopenharmony_ci	cancel_delayed_work_sync(&adev->jpeg.idle_work);
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	mutex_lock(&adev->jpeg.jpeg_pg_lock);
10562306a36Sopenharmony_ci	amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_JPEG,
10662306a36Sopenharmony_ci						       AMD_PG_STATE_UNGATE);
10762306a36Sopenharmony_ci	mutex_unlock(&adev->jpeg.jpeg_pg_lock);
10862306a36Sopenharmony_ci}
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_civoid amdgpu_jpeg_ring_end_use(struct amdgpu_ring *ring)
11162306a36Sopenharmony_ci{
11262306a36Sopenharmony_ci	atomic_dec(&ring->adev->jpeg.total_submission_cnt);
11362306a36Sopenharmony_ci	schedule_delayed_work(&ring->adev->jpeg.idle_work, JPEG_IDLE_TIMEOUT);
11462306a36Sopenharmony_ci}
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ciint amdgpu_jpeg_dec_ring_test_ring(struct amdgpu_ring *ring)
11762306a36Sopenharmony_ci{
11862306a36Sopenharmony_ci	struct amdgpu_device *adev = ring->adev;
11962306a36Sopenharmony_ci	uint32_t tmp = 0;
12062306a36Sopenharmony_ci	unsigned i;
12162306a36Sopenharmony_ci	int r;
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	/* JPEG in SRIOV does not support direct register read/write */
12462306a36Sopenharmony_ci	if (amdgpu_sriov_vf(adev))
12562306a36Sopenharmony_ci		return 0;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	r = amdgpu_ring_alloc(ring, 3);
12862306a36Sopenharmony_ci	if (r)
12962306a36Sopenharmony_ci		return r;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	WREG32(adev->jpeg.inst[ring->me].external.jpeg_pitch[ring->pipe], 0xCAFEDEAD);
13262306a36Sopenharmony_ci	/* Add a read register to make sure the write register is executed. */
13362306a36Sopenharmony_ci	RREG32(adev->jpeg.inst[ring->me].external.jpeg_pitch[ring->pipe]);
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	amdgpu_ring_write(ring, PACKET0(adev->jpeg.internal.jpeg_pitch[ring->pipe], 0));
13662306a36Sopenharmony_ci	amdgpu_ring_write(ring, 0xABADCAFE);
13762306a36Sopenharmony_ci	amdgpu_ring_commit(ring);
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	for (i = 0; i < adev->usec_timeout; i++) {
14062306a36Sopenharmony_ci		tmp = RREG32(adev->jpeg.inst[ring->me].external.jpeg_pitch[ring->pipe]);
14162306a36Sopenharmony_ci		if (tmp == 0xABADCAFE)
14262306a36Sopenharmony_ci			break;
14362306a36Sopenharmony_ci		udelay(1);
14462306a36Sopenharmony_ci	}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	if (i >= adev->usec_timeout)
14762306a36Sopenharmony_ci		r = -ETIMEDOUT;
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	return r;
15062306a36Sopenharmony_ci}
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_cistatic int amdgpu_jpeg_dec_set_reg(struct amdgpu_ring *ring, uint32_t handle,
15362306a36Sopenharmony_ci		struct dma_fence **fence)
15462306a36Sopenharmony_ci{
15562306a36Sopenharmony_ci	struct amdgpu_device *adev = ring->adev;
15662306a36Sopenharmony_ci	struct amdgpu_job *job;
15762306a36Sopenharmony_ci	struct amdgpu_ib *ib;
15862306a36Sopenharmony_ci	struct dma_fence *f = NULL;
15962306a36Sopenharmony_ci	const unsigned ib_size_dw = 16;
16062306a36Sopenharmony_ci	int i, r;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	r = amdgpu_job_alloc_with_ib(ring->adev, NULL, NULL, ib_size_dw * 4,
16362306a36Sopenharmony_ci				     AMDGPU_IB_POOL_DIRECT, &job);
16462306a36Sopenharmony_ci	if (r)
16562306a36Sopenharmony_ci		return r;
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	ib = &job->ibs[0];
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	ib->ptr[0] = PACKETJ(adev->jpeg.internal.jpeg_pitch[ring->pipe], 0, 0, PACKETJ_TYPE0);
17062306a36Sopenharmony_ci	ib->ptr[1] = 0xDEADBEEF;
17162306a36Sopenharmony_ci	for (i = 2; i < 16; i += 2) {
17262306a36Sopenharmony_ci		ib->ptr[i] = PACKETJ(0, 0, 0, PACKETJ_TYPE6);
17362306a36Sopenharmony_ci		ib->ptr[i+1] = 0;
17462306a36Sopenharmony_ci	}
17562306a36Sopenharmony_ci	ib->length_dw = 16;
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	r = amdgpu_job_submit_direct(job, ring, &f);
17862306a36Sopenharmony_ci	if (r)
17962306a36Sopenharmony_ci		goto err;
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	if (fence)
18262306a36Sopenharmony_ci		*fence = dma_fence_get(f);
18362306a36Sopenharmony_ci	dma_fence_put(f);
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	return 0;
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_cierr:
18862306a36Sopenharmony_ci	amdgpu_job_free(job);
18962306a36Sopenharmony_ci	return r;
19062306a36Sopenharmony_ci}
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ciint amdgpu_jpeg_dec_ring_test_ib(struct amdgpu_ring *ring, long timeout)
19362306a36Sopenharmony_ci{
19462306a36Sopenharmony_ci	struct amdgpu_device *adev = ring->adev;
19562306a36Sopenharmony_ci	uint32_t tmp = 0;
19662306a36Sopenharmony_ci	unsigned i;
19762306a36Sopenharmony_ci	struct dma_fence *fence = NULL;
19862306a36Sopenharmony_ci	long r = 0;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	r = amdgpu_jpeg_dec_set_reg(ring, 1, &fence);
20162306a36Sopenharmony_ci	if (r)
20262306a36Sopenharmony_ci		goto error;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	r = dma_fence_wait_timeout(fence, false, timeout);
20562306a36Sopenharmony_ci	if (r == 0) {
20662306a36Sopenharmony_ci		r = -ETIMEDOUT;
20762306a36Sopenharmony_ci		goto error;
20862306a36Sopenharmony_ci	} else if (r < 0) {
20962306a36Sopenharmony_ci		goto error;
21062306a36Sopenharmony_ci	} else {
21162306a36Sopenharmony_ci		r = 0;
21262306a36Sopenharmony_ci	}
21362306a36Sopenharmony_ci	if (!amdgpu_sriov_vf(adev)) {
21462306a36Sopenharmony_ci		for (i = 0; i < adev->usec_timeout; i++) {
21562306a36Sopenharmony_ci			tmp = RREG32(adev->jpeg.inst[ring->me].external.jpeg_pitch[ring->pipe]);
21662306a36Sopenharmony_ci			if (tmp == 0xDEADBEEF)
21762306a36Sopenharmony_ci				break;
21862306a36Sopenharmony_ci			udelay(1);
21962306a36Sopenharmony_ci		}
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci		if (i >= adev->usec_timeout)
22262306a36Sopenharmony_ci			r = -ETIMEDOUT;
22362306a36Sopenharmony_ci	}
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	dma_fence_put(fence);
22662306a36Sopenharmony_cierror:
22762306a36Sopenharmony_ci	return r;
22862306a36Sopenharmony_ci}
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ciint amdgpu_jpeg_process_poison_irq(struct amdgpu_device *adev,
23162306a36Sopenharmony_ci				struct amdgpu_irq_src *source,
23262306a36Sopenharmony_ci				struct amdgpu_iv_entry *entry)
23362306a36Sopenharmony_ci{
23462306a36Sopenharmony_ci	struct ras_common_if *ras_if = adev->jpeg.ras_if;
23562306a36Sopenharmony_ci	struct ras_dispatch_if ih_data = {
23662306a36Sopenharmony_ci		.entry = entry,
23762306a36Sopenharmony_ci	};
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	if (!ras_if)
24062306a36Sopenharmony_ci		return 0;
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	ih_data.head = *ras_if;
24362306a36Sopenharmony_ci	amdgpu_ras_interrupt_dispatch(adev, &ih_data);
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	return 0;
24662306a36Sopenharmony_ci}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ciint amdgpu_jpeg_ras_late_init(struct amdgpu_device *adev, struct ras_common_if *ras_block)
24962306a36Sopenharmony_ci{
25062306a36Sopenharmony_ci	int r, i;
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	r = amdgpu_ras_block_late_init(adev, ras_block);
25362306a36Sopenharmony_ci	if (r)
25462306a36Sopenharmony_ci		return r;
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	if (amdgpu_ras_is_supported(adev, ras_block->block)) {
25762306a36Sopenharmony_ci		for (i = 0; i < adev->jpeg.num_jpeg_inst; ++i) {
25862306a36Sopenharmony_ci			if (adev->jpeg.harvest_config & (1 << i) ||
25962306a36Sopenharmony_ci			    !adev->jpeg.inst[i].ras_poison_irq.funcs)
26062306a36Sopenharmony_ci				continue;
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci			r = amdgpu_irq_get(adev, &adev->jpeg.inst[i].ras_poison_irq, 0);
26362306a36Sopenharmony_ci			if (r)
26462306a36Sopenharmony_ci				goto late_fini;
26562306a36Sopenharmony_ci		}
26662306a36Sopenharmony_ci	}
26762306a36Sopenharmony_ci	return 0;
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_cilate_fini:
27062306a36Sopenharmony_ci	amdgpu_ras_block_late_fini(adev, ras_block);
27162306a36Sopenharmony_ci	return r;
27262306a36Sopenharmony_ci}
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ciint amdgpu_jpeg_ras_sw_init(struct amdgpu_device *adev)
27562306a36Sopenharmony_ci{
27662306a36Sopenharmony_ci	int err;
27762306a36Sopenharmony_ci	struct amdgpu_jpeg_ras *ras;
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	if (!adev->jpeg.ras)
28062306a36Sopenharmony_ci		return 0;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	ras = adev->jpeg.ras;
28362306a36Sopenharmony_ci	err = amdgpu_ras_register_ras_block(adev, &ras->ras_block);
28462306a36Sopenharmony_ci	if (err) {
28562306a36Sopenharmony_ci		dev_err(adev->dev, "Failed to register jpeg ras block!\n");
28662306a36Sopenharmony_ci		return err;
28762306a36Sopenharmony_ci	}
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	strcpy(ras->ras_block.ras_comm.name, "jpeg");
29062306a36Sopenharmony_ci	ras->ras_block.ras_comm.block = AMDGPU_RAS_BLOCK__JPEG;
29162306a36Sopenharmony_ci	ras->ras_block.ras_comm.type = AMDGPU_RAS_ERROR__POISON;
29262306a36Sopenharmony_ci	adev->jpeg.ras_if = &ras->ras_block.ras_comm;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	if (!ras->ras_block.ras_late_init)
29562306a36Sopenharmony_ci		ras->ras_block.ras_late_init = amdgpu_jpeg_ras_late_init;
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	return 0;
29862306a36Sopenharmony_ci}
299