summaryrefslogtreecommitdiff
path: root/drivers/media/platform/qcom/iris/iris_hfi_queue.c
blob: 494ef205133de4f13a592916489bef7236ec9fc6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
 */

#include "iris_core.h"
#include "iris_hfi_queue.h"

static void iris_hfi_queue_set_header(struct iris_core *core, u32 queue_id,
				      struct iris_iface_q_info *iface_q)
{
	iface_q->qhdr->status = 0x1;
	iface_q->qhdr->start_addr = iface_q->device_addr;
	iface_q->qhdr->header_type = IFACEQ_DFLT_QHDR;
	iface_q->qhdr->queue_type = queue_id;
	iface_q->qhdr->q_size = IFACEQ_QUEUE_SIZE / sizeof(u32);
	iface_q->qhdr->pkt_size = 0; /* variable packet size */
	iface_q->qhdr->rx_wm = 0x1;
	iface_q->qhdr->tx_wm = 0x1;
	iface_q->qhdr->rx_req = 0x1;
	iface_q->qhdr->tx_req = 0x0;
	iface_q->qhdr->rx_irq_status = 0x0;
	iface_q->qhdr->tx_irq_status = 0x0;
	iface_q->qhdr->read_idx = 0x0;
	iface_q->qhdr->write_idx = 0x0;

	/*
	 * Set receive request to zero on debug queue as there is no
	 * need of interrupt from video hardware for debug messages
	 */
	if (queue_id == IFACEQ_DBGQ_ID)
		iface_q->qhdr->rx_req = 0;
}

static void
iris_hfi_queue_init(struct iris_core *core, u32 queue_id, struct iris_iface_q_info *iface_q)
{
	struct iris_hfi_queue_table_header *q_tbl_hdr = core->iface_q_table_vaddr;
	u32 offset = sizeof(*q_tbl_hdr) + (queue_id * IFACEQ_QUEUE_SIZE);

	iface_q->device_addr = core->iface_q_table_daddr + offset;
	iface_q->kernel_vaddr =
			(void *)((char *)core->iface_q_table_vaddr + offset);
	iface_q->qhdr = &q_tbl_hdr->q_hdr[queue_id];

	iris_hfi_queue_set_header(core, queue_id, iface_q);
}

static void iris_hfi_queue_deinit(struct iris_iface_q_info *iface_q)
{
	iface_q->qhdr = NULL;
	iface_q->kernel_vaddr = NULL;
	iface_q->device_addr = 0;
}

int iris_hfi_queues_init(struct iris_core *core)
{
	struct iris_hfi_queue_table_header *q_tbl_hdr;
	u32 queue_size;

	/* Iris hardware requires 4K queue alignment */
	queue_size = ALIGN((sizeof(*q_tbl_hdr) + (IFACEQ_QUEUE_SIZE * IFACEQ_NUMQ)), SZ_4K);
	core->iface_q_table_vaddr = dma_alloc_attrs(core->dev, queue_size,
						    &core->iface_q_table_daddr,
						    GFP_KERNEL, DMA_ATTR_WRITE_COMBINE);
	if (!core->iface_q_table_vaddr) {
		dev_err(core->dev, "queues alloc and map failed\n");
		return -ENOMEM;
	}

	core->sfr_vaddr = dma_alloc_attrs(core->dev, SFR_SIZE,
					  &core->sfr_daddr,
					  GFP_KERNEL, DMA_ATTR_WRITE_COMBINE);
	if (!core->sfr_vaddr) {
		dev_err(core->dev, "sfr alloc and map failed\n");
		dma_free_attrs(core->dev, sizeof(*q_tbl_hdr), core->iface_q_table_vaddr,
			       core->iface_q_table_daddr, DMA_ATTR_WRITE_COMBINE);
		return -ENOMEM;
	}

	iris_hfi_queue_init(core, IFACEQ_CMDQ_ID, &core->command_queue);
	iris_hfi_queue_init(core, IFACEQ_MSGQ_ID, &core->message_queue);
	iris_hfi_queue_init(core, IFACEQ_DBGQ_ID, &core->debug_queue);

	q_tbl_hdr = (struct iris_hfi_queue_table_header *)core->iface_q_table_vaddr;
	q_tbl_hdr->version = 0;
	q_tbl_hdr->device_addr = (void *)core;
	strscpy(q_tbl_hdr->name, "iris-hfi-queues", sizeof(q_tbl_hdr->name));
	q_tbl_hdr->size = sizeof(*q_tbl_hdr);
	q_tbl_hdr->qhdr0_offset = sizeof(*q_tbl_hdr) -
		(IFACEQ_NUMQ * sizeof(struct iris_hfi_queue_header));
	q_tbl_hdr->qhdr_size = sizeof(q_tbl_hdr->q_hdr[0]);
	q_tbl_hdr->num_q = IFACEQ_NUMQ;
	q_tbl_hdr->num_active_q = IFACEQ_NUMQ;

	 /* Write sfr size in first word to be used by firmware */
	*((u32 *)core->sfr_vaddr) = SFR_SIZE;

	return 0;
}

void iris_hfi_queues_deinit(struct iris_core *core)
{
	u32 queue_size;

	if (!core->iface_q_table_vaddr)
		return;

	iris_hfi_queue_deinit(&core->debug_queue);
	iris_hfi_queue_deinit(&core->message_queue);
	iris_hfi_queue_deinit(&core->command_queue);

	dma_free_attrs(core->dev, SFR_SIZE, core->sfr_vaddr,
		       core->sfr_daddr, DMA_ATTR_WRITE_COMBINE);

	core->sfr_vaddr = NULL;
	core->sfr_daddr = 0;

	queue_size = ALIGN(sizeof(struct iris_hfi_queue_table_header) +
		(IFACEQ_QUEUE_SIZE * IFACEQ_NUMQ), SZ_4K);

	dma_free_attrs(core->dev, queue_size, core->iface_q_table_vaddr,
		       core->iface_q_table_daddr, DMA_ATTR_WRITE_COMBINE);

	core->iface_q_table_vaddr = NULL;
	core->iface_q_table_daddr = 0;
}