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 int 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	clk_disable_unprepare(core->vdec_hevc_clk);
147	if (core->platform->revision == VDEC_REVISION_G12A ||
148	    core->platform->revision == VDEC_REVISION_SM1)
149		clk_disable_unprepare(core->vdec_hevcf_clk);
150
151	return 0;
152}
153
154static int vdec_hevc_start(struct amvdec_session *sess)
155{
156	int ret;
157	struct amvdec_core *core = sess->core;
158	struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops;
159
160	if (core->platform->revision == VDEC_REVISION_G12A ||
161	    core->platform->revision == VDEC_REVISION_SM1) {
162		clk_set_rate(core->vdec_hevcf_clk, 666666666);
163		ret = clk_prepare_enable(core->vdec_hevcf_clk);
164		if (ret)
165			return ret;
166	}
167
168	clk_set_rate(core->vdec_hevc_clk, 666666666);
169	ret = clk_prepare_enable(core->vdec_hevc_clk);
170	if (ret) {
171		if (core->platform->revision == VDEC_REVISION_G12A ||
172		    core->platform->revision == VDEC_REVISION_SM1)
173			clk_disable_unprepare(core->vdec_hevcf_clk);
174		return ret;
175	}
176
177	if (core->platform->revision == VDEC_REVISION_SM1)
178		regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
179				   GEN_PWR_VDEC_HEVC_SM1, 0);
180	else
181		regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
182				   GEN_PWR_VDEC_HEVC, 0);
183	usleep_range(10, 20);
184
185	/* Reset VDEC_HEVC*/
186	amvdec_write_dos(core, DOS_SW_RESET3, 0xffffffff);
187	amvdec_write_dos(core, DOS_SW_RESET3, 0x00000000);
188
189	amvdec_write_dos(core, DOS_GCLK_EN3, 0xffffffff);
190
191	/* VDEC_HEVC Memories */
192	amvdec_write_dos(core, DOS_MEM_PD_HEVC, 0x00000000);
193
194	/* Remove VDEC_HEVC Isolation */
195	if (core->platform->revision == VDEC_REVISION_SM1)
196		regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_ISO0,
197				   GEN_PWR_VDEC_HEVC_SM1, 0);
198	else
199		regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_ISO0,
200				   0xc00, 0);
201
202	amvdec_write_dos(core, DOS_SW_RESET3, 0xffffffff);
203	amvdec_write_dos(core, DOS_SW_RESET3, 0x00000000);
204
205	vdec_hevc_stbuf_init(sess);
206
207	ret = vdec_hevc_load_firmware(sess, sess->fmt_out->firmware_path);
208	if (ret)
209		goto stop;
210
211	ret = codec_ops->start(sess);
212	if (ret)
213		goto stop;
214
215	amvdec_write_dos(core, DOS_SW_RESET3, BIT(12) | BIT(11));
216	amvdec_write_dos(core, DOS_SW_RESET3, 0);
217	amvdec_read_dos(core, DOS_SW_RESET3);
218
219	amvdec_write_dos(core, HEVC_MPSR, 1);
220	/* Let the firmware settle */
221	usleep_range(10, 20);
222
223	return 0;
224
225stop:
226	vdec_hevc_stop(sess);
227	return ret;
228}
229
230struct amvdec_ops vdec_hevc_ops = {
231	.start = vdec_hevc_start,
232	.stop = vdec_hevc_stop,
233	.conf_esparser = vdec_hevc_conf_esparser,
234	.vififo_level = vdec_hevc_vififo_level,
235};
236