File Index
Files and directories
Sign in
FILE

vdec_hevc.c

File preview with syntax highlighting.

linux-6.19.14/drivers/staging/media/meson/vdec/vdec_hevc.c C
  1// SPDX-License-Identifier: GPL-2.0+
  2/*
  3 * Copyright (C) 2018 Maxime Jourdan <maxi.jourdan@wanadoo.fr>
  4 *
  5 * VDEC_HEVC is a video decoding block that allows decoding of
  6 * HEVC, VP9
  7 */
  8
  9#include <linux/firmware.h>
 10#include <linux/clk.h>
 11
 12#include "vdec_1.h"
 13#include "vdec_helpers.h"
 14#include "vdec_hevc.h"
 15#include "hevc_regs.h"
 16#include "dos_regs.h"
 17
 18/* AO Registers */
 19#define AO_RTI_GEN_PWR_SLEEP0	0xe8
 20#define AO_RTI_GEN_PWR_ISO0	0xec
 21	#define GEN_PWR_VDEC_HEVC (BIT(7) | BIT(6))
 22	#define GEN_PWR_VDEC_HEVC_SM1 (BIT(2))
 23
 24#define MC_SIZE	(4096 * 4)
 25
 26static int vdec_hevc_load_firmware(struct amvdec_session *sess,
 27				   const char *fwname)
 28{
 29	struct amvdec_core *core = sess->core;
 30	struct device *dev = core->dev_dec;
 31	const struct firmware *fw;
 32	static void *mc_addr;
 33	static dma_addr_t mc_addr_map;
 34	int ret;
 35	u32 i = 100;
 36
 37	ret = request_firmware(&fw, fwname, dev);
 38	if (ret < 0)  {
 39		dev_err(dev, "Unable to request firmware %s\n", fwname);
 40		return ret;
 41	}
 42
 43	if (fw->size < MC_SIZE) {
 44		dev_err(dev, "Firmware size %zu is too small. Expected %u.\n",
 45			fw->size, MC_SIZE);
 46		ret = -EINVAL;
 47		goto release_firmware;
 48	}
 49
 50	mc_addr = dma_alloc_coherent(core->dev, MC_SIZE, &mc_addr_map,
 51				     GFP_KERNEL);
 52	if (!mc_addr) {
 53		ret = -ENOMEM;
 54		goto release_firmware;
 55	}
 56
 57	memcpy(mc_addr, fw->data, MC_SIZE);
 58
 59	amvdec_write_dos(core, HEVC_MPSR, 0);
 60	amvdec_write_dos(core, HEVC_CPSR, 0);
 61
 62	amvdec_write_dos(core, HEVC_IMEM_DMA_ADR, mc_addr_map);
 63	amvdec_write_dos(core, HEVC_IMEM_DMA_COUNT, MC_SIZE / 4);
 64	amvdec_write_dos(core, HEVC_IMEM_DMA_CTRL, (0x8000 | (7 << 16)));
 65
 66	while (i && (readl(core->dos_base + HEVC_IMEM_DMA_CTRL) & 0x8000))
 67		i--;
 68
 69	if (i == 0) {
 70		dev_err(dev, "Firmware load fail (DMA hang?)\n");
 71		ret = -ENODEV;
 72	}
 73
 74	dma_free_coherent(core->dev, MC_SIZE, mc_addr, mc_addr_map);
 75release_firmware:
 76	release_firmware(fw);
 77	return ret;
 78}
 79
 80static void vdec_hevc_stbuf_init(struct amvdec_session *sess)
 81{
 82	struct amvdec_core *core = sess->core;
 83
 84	amvdec_write_dos(core, HEVC_STREAM_CONTROL,
 85			 amvdec_read_dos(core, HEVC_STREAM_CONTROL) & ~1);
 86	amvdec_write_dos(core, HEVC_STREAM_START_ADDR, sess->vififo_paddr);
 87	amvdec_write_dos(core, HEVC_STREAM_END_ADDR,
 88			 sess->vififo_paddr + sess->vififo_size);
 89	amvdec_write_dos(core, HEVC_STREAM_RD_PTR, sess->vififo_paddr);
 90	amvdec_write_dos(core, HEVC_STREAM_WR_PTR, sess->vififo_paddr);
 91}
 92
 93/* VDEC_HEVC specific ESPARSER configuration */
 94static void vdec_hevc_conf_esparser(struct amvdec_session *sess)
 95{
 96	struct amvdec_core *core = sess->core;
 97
 98	/* set vififo_vbuf_rp_sel=>vdec_hevc */
 99	amvdec_write_dos(core, DOS_GEN_CTRL0, 3 << 1);
100	amvdec_write_dos(core, HEVC_STREAM_CONTROL,
101			 amvdec_read_dos(core, HEVC_STREAM_CONTROL) | BIT(3));
102	amvdec_write_dos(core, HEVC_STREAM_CONTROL,
103			 amvdec_read_dos(core, HEVC_STREAM_CONTROL) | 1);
104	amvdec_write_dos(core, HEVC_STREAM_FIFO_CTL,
105			 amvdec_read_dos(core, HEVC_STREAM_FIFO_CTL) | BIT(29));
106}
107
108static u32 vdec_hevc_vififo_level(struct amvdec_session *sess)
109{
110	return readl_relaxed(sess->core->dos_base + HEVC_STREAM_LEVEL);
111}
112
113static void __vdec_hevc_stop(struct amvdec_session *sess)
114{
115	struct amvdec_core *core = sess->core;
116	struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops;
117
118	/* Disable interrupt */
119	amvdec_write_dos(core, HEVC_ASSIST_MBOX1_MASK, 0);
120	/* Disable firmware processor */
121	amvdec_write_dos(core, HEVC_MPSR, 0);
122
123	if (sess->priv)
124		codec_ops->stop(sess);
125
126	/* Enable VDEC_HEVC Isolation */
127	if (core->platform->revision == VDEC_REVISION_SM1)
128		regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_ISO0,
129				   GEN_PWR_VDEC_HEVC_SM1,
130				   GEN_PWR_VDEC_HEVC_SM1);
131	else
132		regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_ISO0,
133				   0xc00, 0xc00);
134
135	/* VDEC_HEVC Memories */
136	amvdec_write_dos(core, DOS_MEM_PD_HEVC, 0xffffffffUL);
137
138	if (core->platform->revision == VDEC_REVISION_SM1)
139		regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
140				   GEN_PWR_VDEC_HEVC_SM1,
141				   GEN_PWR_VDEC_HEVC_SM1);
142	else
143		regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
144				   GEN_PWR_VDEC_HEVC, GEN_PWR_VDEC_HEVC);
145}
146
147static int vdec_hevc_stop(struct amvdec_session *sess)
148{
149	struct amvdec_core *core = sess->core;
150
151	__vdec_hevc_stop(sess);
152
153	clk_disable_unprepare(core->vdec_hevc_clk);
154	if (core->platform->revision == VDEC_REVISION_G12A ||
155	    core->platform->revision == VDEC_REVISION_SM1)
156		clk_disable_unprepare(core->vdec_hevcf_clk);
157
158	return 0;
159}
160
161static int __vdec_hevc_start(struct amvdec_session *sess)
162{
163	int ret;
164	struct amvdec_core *core = sess->core;
165	struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops;
166
167	clk_set_rate(core->vdec_hevc_clk, 666666666);
168	ret = clk_prepare_enable(core->vdec_hevc_clk);
169	if (ret) {
170		if (core->platform->revision == VDEC_REVISION_G12A ||
171		    core->platform->revision == VDEC_REVISION_SM1)
172			clk_disable_unprepare(core->vdec_hevcf_clk);
173		return ret;
174	}
175
176	if (core->platform->revision == VDEC_REVISION_SM1)
177		regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
178				   GEN_PWR_VDEC_HEVC_SM1, 0);
179	else
180		regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
181				   GEN_PWR_VDEC_HEVC, 0);
182	usleep_range(10, 20);
183
184	/* Reset VDEC_HEVC*/
185	amvdec_write_dos(core, DOS_SW_RESET3, 0xffffffff);
186	amvdec_write_dos(core, DOS_SW_RESET3, 0x00000000);
187
188	amvdec_write_dos(core, DOS_GCLK_EN3, 0xffffffff);
189
190	/* VDEC_HEVC Memories */
191	amvdec_write_dos(core, DOS_MEM_PD_HEVC, 0x00000000);
192
193	/* Remove VDEC_HEVC Isolation */
194	if (core->platform->revision == VDEC_REVISION_SM1)
195		regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_ISO0,
196				   GEN_PWR_VDEC_HEVC_SM1, 0);
197	else
198		regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_ISO0,
199				   0xc00, 0);
200
201	amvdec_write_dos(core, DOS_SW_RESET3, 0xffffffff);
202	amvdec_write_dos(core, DOS_SW_RESET3, 0x00000000);
203
204	vdec_hevc_stbuf_init(sess);
205
206	ret = vdec_hevc_load_firmware(sess, sess->fmt_out->firmware_path);
207	if (ret)
208		goto stop;
209
210	ret = codec_ops->start(sess);
211	if (ret)
212		goto stop;
213
214	amvdec_write_dos(core, DOS_SW_RESET3, BIT(12) | BIT(11));
215	amvdec_write_dos(core, DOS_SW_RESET3, 0);
216	amvdec_read_dos(core, DOS_SW_RESET3);
217
218	amvdec_write_dos(core, HEVC_MPSR, 1);
219	/* Let the firmware settle */
220	usleep_range(10, 20);
221
222	return 0;
223
224stop:
225	__vdec_hevc_stop(sess);
226	clk_disable_unprepare(core->vdec_hevc_clk);
227	return ret;
228}
229
230static int vdec_hevc_start(struct amvdec_session *sess)
231{
232	struct amvdec_core *core = sess->core;
233	int ret;
234
235	if (core->platform->revision == VDEC_REVISION_G12A ||
236	    core->platform->revision == VDEC_REVISION_SM1) {
237		clk_set_rate(core->vdec_hevcf_clk, 666666666);
238		ret = clk_prepare_enable(core->vdec_hevcf_clk);
239		if (ret)
240			return ret;
241
242		ret = __vdec_hevc_start(sess);
243		if (ret)
244			clk_disable_unprepare(core->vdec_hevcf_clk);
245		return ret;
246	}
247
248	return __vdec_hevc_start(sess);
249}
250
251struct amvdec_ops vdec_hevc_ops = {
252	.start = vdec_hevc_start,
253	.stop = vdec_hevc_stop,
254	.conf_esparser = vdec_hevc_conf_esparser,
255	.vififo_level = vdec_hevc_vififo_level,
256};
~/ Read-only file preview.