1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2018 Maxime Jourdan <mjourdan@baylibre.com>
4  */
5 
6 #include <media/v4l2-mem2mem.h>
7 #include <media/videobuf2-dma-contig.h>
8 
9 #include "codec_hevc_common.h"
10 #include "vdec_helpers.h"
11 #include "hevc_regs.h"
12 
13 #define MMU_COMPRESS_HEADER_SIZE 0x48000
14 #define MMU_MAP_SIZE 0x4800
15 
16 const u16 vdec_hevc_parser_cmd[] = {
17 	0x0401,	0x8401,	0x0800,	0x0402,
18 	0x9002,	0x1423,	0x8CC3,	0x1423,
19 	0x8804,	0x9825,	0x0800,	0x04FE,
20 	0x8406,	0x8411,	0x1800,	0x8408,
21 	0x8409,	0x8C2A,	0x9C2B,	0x1C00,
22 	0x840F,	0x8407,	0x8000,	0x8408,
23 	0x2000,	0xA800,	0x8410,	0x04DE,
24 	0x840C,	0x840D,	0xAC00,	0xA000,
25 	0x08C0,	0x08E0,	0xA40E,	0xFC00,
26 	0x7C00
27 };
28 
29 /* Configure decode head read mode */
codec_hevc_setup_decode_head(struct amvdec_session * sess,int is_10bit)30 void codec_hevc_setup_decode_head(struct amvdec_session *sess, int is_10bit)
31 {
32 	struct amvdec_core *core = sess->core;
33 	u32 body_size = amvdec_am21c_body_size(sess->width, sess->height);
34 	u32 head_size = amvdec_am21c_head_size(sess->width, sess->height);
35 
36 	if (!codec_hevc_use_fbc(sess->pixfmt_cap, is_10bit)) {
37 		/* Enable 2-plane reference read mode */
38 		amvdec_write_dos(core, HEVCD_MPP_DECOMP_CTL1, BIT(31));
39 		return;
40 	}
41 
42 	if (codec_hevc_use_mmu(core->platform->revision,
43 			       sess->pixfmt_cap, is_10bit))
44 		amvdec_write_dos(core, HEVCD_MPP_DECOMP_CTL1, BIT(4));
45 	else
46 		amvdec_write_dos(core, HEVCD_MPP_DECOMP_CTL1, 0);
47 
48 	if (core->platform->revision < VDEC_REVISION_SM1)
49 		amvdec_write_dos(core, HEVCD_MPP_DECOMP_CTL2, body_size / 32);
50 	amvdec_write_dos(core, HEVC_CM_BODY_LENGTH, body_size);
51 	amvdec_write_dos(core, HEVC_CM_HEADER_OFFSET, body_size);
52 	amvdec_write_dos(core, HEVC_CM_HEADER_LENGTH, head_size);
53 }
54 EXPORT_SYMBOL_GPL(codec_hevc_setup_decode_head);
55 
codec_hevc_setup_buffers_gxbb(struct amvdec_session * sess,struct codec_hevc_common * comm,int is_10bit)56 static void codec_hevc_setup_buffers_gxbb(struct amvdec_session *sess,
57 					  struct codec_hevc_common *comm,
58 					  int is_10bit)
59 {
60 	struct amvdec_core *core = sess->core;
61 	struct v4l2_m2m_buffer *buf;
62 	u32 buf_num = v4l2_m2m_num_dst_bufs_ready(sess->m2m_ctx);
63 	dma_addr_t buf_y_paddr = 0;
64 	dma_addr_t buf_uv_paddr = 0;
65 	u32 idx = 0;
66 	u32 val;
67 	int i;
68 
69 	amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 0);
70 
71 	v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) {
72 		struct vb2_buffer *vb = &buf->vb.vb2_buf;
73 
74 		idx = vb->index;
75 
76 		if (codec_hevc_use_downsample(sess->pixfmt_cap, is_10bit))
77 			buf_y_paddr = comm->fbc_buffer_paddr[idx];
78 		else
79 			buf_y_paddr = vb2_dma_contig_plane_dma_addr(vb, 0);
80 
81 		if (codec_hevc_use_fbc(sess->pixfmt_cap, is_10bit)) {
82 			val = buf_y_paddr | (idx << 8) | 1;
83 			amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR,
84 					 val);
85 		} else {
86 			buf_uv_paddr = vb2_dma_contig_plane_dma_addr(vb, 1);
87 			val = buf_y_paddr | ((idx * 2) << 8) | 1;
88 			amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR,
89 					 val);
90 			val = buf_uv_paddr | ((idx * 2 + 1) << 8) | 1;
91 			amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR,
92 					 val);
93 		}
94 	}
95 
96 	if (codec_hevc_use_fbc(sess->pixfmt_cap, is_10bit))
97 		val = buf_y_paddr | (idx << 8) | 1;
98 	else
99 		val = buf_y_paddr | ((idx * 2) << 8) | 1;
100 
101 	/* Fill the remaining unused slots with the last buffer's Y addr */
102 	for (i = buf_num; i < MAX_REF_PIC_NUM; ++i)
103 		amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR, val);
104 
105 	amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 1);
106 	amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, 1);
107 	for (i = 0; i < 32; ++i)
108 		amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_DATA_ADDR, 0);
109 }
110 
codec_hevc_setup_buffers_gxl(struct amvdec_session * sess,struct codec_hevc_common * comm,int is_10bit)111 static void codec_hevc_setup_buffers_gxl(struct amvdec_session *sess,
112 					 struct codec_hevc_common *comm,
113 					 int is_10bit)
114 {
115 	struct amvdec_core *core = sess->core;
116 	struct v4l2_m2m_buffer *buf;
117 	u32 revision = core->platform->revision;
118 	u32 pixfmt_cap = sess->pixfmt_cap;
119 	int i;
120 
121 	amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR,
122 			 BIT(2) | BIT(1));
123 
124 	v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) {
125 		struct vb2_buffer *vb = &buf->vb.vb2_buf;
126 		dma_addr_t buf_y_paddr = 0;
127 		dma_addr_t buf_uv_paddr = 0;
128 		u32 idx = vb->index;
129 
130 		if (codec_hevc_use_mmu(revision, pixfmt_cap, is_10bit))
131 			buf_y_paddr = comm->mmu_header_paddr[idx];
132 		else if (codec_hevc_use_downsample(pixfmt_cap, is_10bit))
133 			buf_y_paddr = comm->fbc_buffer_paddr[idx];
134 		else
135 			buf_y_paddr = vb2_dma_contig_plane_dma_addr(vb, 0);
136 
137 		amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_DATA,
138 				 buf_y_paddr >> 5);
139 
140 		if (!codec_hevc_use_fbc(pixfmt_cap, is_10bit)) {
141 			buf_uv_paddr = vb2_dma_contig_plane_dma_addr(vb, 1);
142 			amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_DATA,
143 					 buf_uv_paddr >> 5);
144 		}
145 	}
146 
147 	amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 1);
148 	amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, 1);
149 	for (i = 0; i < 32; ++i)
150 		amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_DATA_ADDR, 0);
151 }
152 
codec_hevc_free_fbc_buffers(struct amvdec_session * sess,struct codec_hevc_common * comm)153 void codec_hevc_free_fbc_buffers(struct amvdec_session *sess,
154 				 struct codec_hevc_common *comm)
155 {
156 	struct device *dev = sess->core->dev;
157 	u32 am21_size = amvdec_am21c_size(sess->width, sess->height);
158 	int i;
159 
160 	for (i = 0; i < MAX_REF_PIC_NUM; ++i) {
161 		if (comm->fbc_buffer_vaddr[i]) {
162 			dma_free_coherent(dev, am21_size,
163 					  comm->fbc_buffer_vaddr[i],
164 					  comm->fbc_buffer_paddr[i]);
165 			comm->fbc_buffer_vaddr[i] = NULL;
166 		}
167 	}
168 }
169 EXPORT_SYMBOL_GPL(codec_hevc_free_fbc_buffers);
170 
codec_hevc_alloc_fbc_buffers(struct amvdec_session * sess,struct codec_hevc_common * comm)171 static int codec_hevc_alloc_fbc_buffers(struct amvdec_session *sess,
172 					struct codec_hevc_common *comm)
173 {
174 	struct device *dev = sess->core->dev;
175 	struct v4l2_m2m_buffer *buf;
176 	u32 am21_size = amvdec_am21c_size(sess->width, sess->height);
177 
178 	v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) {
179 		u32 idx = buf->vb.vb2_buf.index;
180 		dma_addr_t paddr;
181 		void *vaddr = dma_alloc_coherent(dev, am21_size, &paddr,
182 						 GFP_KERNEL);
183 		if (!vaddr) {
184 			codec_hevc_free_fbc_buffers(sess, comm);
185 			return -ENOMEM;
186 		}
187 
188 		comm->fbc_buffer_vaddr[idx] = vaddr;
189 		comm->fbc_buffer_paddr[idx] = paddr;
190 	}
191 
192 	return 0;
193 }
194 
codec_hevc_free_mmu_headers(struct amvdec_session * sess,struct codec_hevc_common * comm)195 void codec_hevc_free_mmu_headers(struct amvdec_session *sess,
196 				 struct codec_hevc_common *comm)
197 {
198 	struct device *dev = sess->core->dev;
199 	int i;
200 
201 	for (i = 0; i < MAX_REF_PIC_NUM; ++i) {
202 		if (comm->mmu_header_vaddr[i]) {
203 			dma_free_coherent(dev, MMU_COMPRESS_HEADER_SIZE,
204 					  comm->mmu_header_vaddr[i],
205 					  comm->mmu_header_paddr[i]);
206 			comm->mmu_header_vaddr[i] = NULL;
207 		}
208 	}
209 
210 	if (comm->mmu_map_vaddr) {
211 		dma_free_coherent(dev, MMU_MAP_SIZE,
212 				  comm->mmu_map_vaddr,
213 				  comm->mmu_map_paddr);
214 		comm->mmu_map_vaddr = NULL;
215 	}
216 }
217 EXPORT_SYMBOL_GPL(codec_hevc_free_mmu_headers);
218 
codec_hevc_alloc_mmu_headers(struct amvdec_session * sess,struct codec_hevc_common * comm)219 static int codec_hevc_alloc_mmu_headers(struct amvdec_session *sess,
220 					struct codec_hevc_common *comm)
221 {
222 	struct device *dev = sess->core->dev;
223 	struct v4l2_m2m_buffer *buf;
224 
225 	comm->mmu_map_vaddr = dma_alloc_coherent(dev, MMU_MAP_SIZE,
226 						 &comm->mmu_map_paddr,
227 						 GFP_KERNEL);
228 	if (!comm->mmu_map_vaddr)
229 		return -ENOMEM;
230 
231 	v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) {
232 		u32 idx = buf->vb.vb2_buf.index;
233 		dma_addr_t paddr;
234 		void *vaddr = dma_alloc_coherent(dev, MMU_COMPRESS_HEADER_SIZE,
235 						 &paddr, GFP_KERNEL);
236 		if (!vaddr) {
237 			codec_hevc_free_mmu_headers(sess, comm);
238 			return -ENOMEM;
239 		}
240 
241 		comm->mmu_header_vaddr[idx] = vaddr;
242 		comm->mmu_header_paddr[idx] = paddr;
243 	}
244 
245 	return 0;
246 }
247 
codec_hevc_setup_buffers(struct amvdec_session * sess,struct codec_hevc_common * comm,int is_10bit)248 int codec_hevc_setup_buffers(struct amvdec_session *sess,
249 			     struct codec_hevc_common *comm,
250 			     int is_10bit)
251 {
252 	struct amvdec_core *core = sess->core;
253 	int ret;
254 
255 	if (codec_hevc_use_downsample(sess->pixfmt_cap, is_10bit)) {
256 		ret = codec_hevc_alloc_fbc_buffers(sess, comm);
257 		if (ret)
258 			return ret;
259 	}
260 
261 	if (codec_hevc_use_mmu(core->platform->revision,
262 			       sess->pixfmt_cap, is_10bit)) {
263 		ret = codec_hevc_alloc_mmu_headers(sess, comm);
264 		if (ret) {
265 			codec_hevc_free_fbc_buffers(sess, comm);
266 			return ret;
267 		}
268 	}
269 
270 	if (core->platform->revision == VDEC_REVISION_GXBB)
271 		codec_hevc_setup_buffers_gxbb(sess, comm, is_10bit);
272 	else
273 		codec_hevc_setup_buffers_gxl(sess, comm, is_10bit);
274 
275 	return 0;
276 }
277 EXPORT_SYMBOL_GPL(codec_hevc_setup_buffers);
278 
codec_hevc_fill_mmu_map(struct amvdec_session * sess,struct codec_hevc_common * comm,struct vb2_buffer * vb)279 void codec_hevc_fill_mmu_map(struct amvdec_session *sess,
280 			     struct codec_hevc_common *comm,
281 			     struct vb2_buffer *vb)
282 {
283 	u32 size = amvdec_am21c_size(sess->width, sess->height);
284 	u32 nb_pages = size / PAGE_SIZE;
285 	u32 *mmu_map = comm->mmu_map_vaddr;
286 	u32 first_page;
287 	u32 i;
288 
289 	if (sess->pixfmt_cap == V4L2_PIX_FMT_NV12M)
290 		first_page = comm->fbc_buffer_paddr[vb->index] >> PAGE_SHIFT;
291 	else
292 		first_page = vb2_dma_contig_plane_dma_addr(vb, 0) >> PAGE_SHIFT;
293 
294 	for (i = 0; i < nb_pages; ++i)
295 		mmu_map[i] = first_page + i;
296 }
297 EXPORT_SYMBOL_GPL(codec_hevc_fill_mmu_map);
298