1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Hantro VPU codec driver
4  *
5  * Copyright (C) 2018 Rockchip Electronics Co., Ltd.
6  *	Jeffy Chen <jeffy.chen@rock-chips.com>
7  */
8 
9 #include <linux/clk.h>
10 
11 #include "hantro.h"
12 #include "hantro_jpeg.h"
13 #include "hantro_g1_regs.h"
14 #include "hantro_h1_regs.h"
15 
16 #define RK3288_ACLK_MAX_FREQ (400 * 1000 * 1000)
17 
18 /*
19  * Supported formats.
20  */
21 
22 static const struct hantro_fmt rk3288_vpu_enc_fmts[] = {
23 	{
24 		.fourcc = V4L2_PIX_FMT_YUV420M,
25 		.codec_mode = HANTRO_MODE_NONE,
26 		.enc_fmt = RK3288_VPU_ENC_FMT_YUV420P,
27 	},
28 	{
29 		.fourcc = V4L2_PIX_FMT_NV12M,
30 		.codec_mode = HANTRO_MODE_NONE,
31 		.enc_fmt = RK3288_VPU_ENC_FMT_YUV420SP,
32 	},
33 	{
34 		.fourcc = V4L2_PIX_FMT_YUYV,
35 		.codec_mode = HANTRO_MODE_NONE,
36 		.enc_fmt = RK3288_VPU_ENC_FMT_YUYV422,
37 	},
38 	{
39 		.fourcc = V4L2_PIX_FMT_UYVY,
40 		.codec_mode = HANTRO_MODE_NONE,
41 		.enc_fmt = RK3288_VPU_ENC_FMT_UYVY422,
42 	},
43 	{
44 		.fourcc = V4L2_PIX_FMT_JPEG,
45 		.codec_mode = HANTRO_MODE_JPEG_ENC,
46 		.max_depth = 2,
47 		.header_size = JPEG_HEADER_SIZE,
48 		.frmsize = {
49 			.min_width = 96,
50 			.max_width = 8192,
51 			.step_width = JPEG_MB_DIM,
52 			.min_height = 32,
53 			.max_height = 8192,
54 			.step_height = JPEG_MB_DIM,
55 		},
56 	},
57 };
58 
59 static const struct hantro_fmt rk3288_vpu_dec_fmts[] = {
60 	{
61 		.fourcc = V4L2_PIX_FMT_NV12,
62 		.codec_mode = HANTRO_MODE_NONE,
63 	},
64 	{
65 		.fourcc = V4L2_PIX_FMT_H264_SLICE,
66 		.codec_mode = HANTRO_MODE_H264_DEC,
67 		.max_depth = 2,
68 		.frmsize = {
69 			.min_width = 48,
70 			.max_width = 3840,
71 			.step_width = H264_MB_DIM,
72 			.min_height = 48,
73 			.max_height = 2160,
74 			.step_height = H264_MB_DIM,
75 		},
76 	},
77 	{
78 		.fourcc = V4L2_PIX_FMT_MPEG2_SLICE,
79 		.codec_mode = HANTRO_MODE_MPEG2_DEC,
80 		.max_depth = 2,
81 		.frmsize = {
82 			.min_width = 48,
83 			.max_width = 1920,
84 			.step_width = MPEG2_MB_DIM,
85 			.min_height = 48,
86 			.max_height = 1088,
87 			.step_height = MPEG2_MB_DIM,
88 		},
89 	},
90 	{
91 		.fourcc = V4L2_PIX_FMT_VP8_FRAME,
92 		.codec_mode = HANTRO_MODE_VP8_DEC,
93 		.max_depth = 2,
94 		.frmsize = {
95 			.min_width = 48,
96 			.max_width = 3840,
97 			.step_width = VP8_MB_DIM,
98 			.min_height = 48,
99 			.max_height = 2160,
100 			.step_height = VP8_MB_DIM,
101 		},
102 	},
103 };
104 
rk3288_vepu_irq(int irq,void * dev_id)105 static irqreturn_t rk3288_vepu_irq(int irq, void *dev_id)
106 {
107 	struct hantro_dev *vpu = dev_id;
108 	enum vb2_buffer_state state;
109 	u32 status, bytesused;
110 
111 	status = vepu_read(vpu, H1_REG_INTERRUPT);
112 	bytesused = vepu_read(vpu, H1_REG_STR_BUF_LIMIT) / 8;
113 	state = (status & H1_REG_INTERRUPT_FRAME_RDY) ?
114 		VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR;
115 
116 	vepu_write(vpu, 0, H1_REG_INTERRUPT);
117 	vepu_write(vpu, 0, H1_REG_AXI_CTRL);
118 
119 	hantro_irq_done(vpu, bytesused, state);
120 
121 	return IRQ_HANDLED;
122 }
123 
rk3288_vdpu_irq(int irq,void * dev_id)124 static irqreturn_t rk3288_vdpu_irq(int irq, void *dev_id)
125 {
126 	struct hantro_dev *vpu = dev_id;
127 	enum vb2_buffer_state state;
128 	u32 status;
129 
130 	status = vdpu_read(vpu, G1_REG_INTERRUPT);
131 	state = (status & G1_REG_INTERRUPT_DEC_RDY_INT) ?
132 		VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR;
133 
134 	vdpu_write(vpu, 0, G1_REG_INTERRUPT);
135 	vdpu_write(vpu, G1_REG_CONFIG_DEC_CLK_GATE_E, G1_REG_CONFIG);
136 
137 	hantro_irq_done(vpu, 0, state);
138 
139 	return IRQ_HANDLED;
140 }
141 
rk3288_vpu_hw_init(struct hantro_dev * vpu)142 static int rk3288_vpu_hw_init(struct hantro_dev *vpu)
143 {
144 	/* Bump ACLK to max. possible freq. to improve performance. */
145 	clk_set_rate(vpu->clocks[0].clk, RK3288_ACLK_MAX_FREQ);
146 	return 0;
147 }
148 
rk3288_vpu_enc_reset(struct hantro_ctx * ctx)149 static void rk3288_vpu_enc_reset(struct hantro_ctx *ctx)
150 {
151 	struct hantro_dev *vpu = ctx->dev;
152 
153 	vepu_write(vpu, H1_REG_INTERRUPT_DIS_BIT, H1_REG_INTERRUPT);
154 	vepu_write(vpu, 0, H1_REG_ENC_CTRL);
155 	vepu_write(vpu, 0, H1_REG_AXI_CTRL);
156 }
157 
rk3288_vpu_dec_reset(struct hantro_ctx * ctx)158 static void rk3288_vpu_dec_reset(struct hantro_ctx *ctx)
159 {
160 	struct hantro_dev *vpu = ctx->dev;
161 
162 	vdpu_write(vpu, G1_REG_INTERRUPT_DEC_IRQ_DIS, G1_REG_INTERRUPT);
163 	vdpu_write(vpu, G1_REG_CONFIG_DEC_CLK_GATE_E, G1_REG_CONFIG);
164 	vdpu_write(vpu, 1, G1_REG_SOFT_RESET);
165 }
166 
167 /*
168  * Supported codec ops.
169  */
170 
171 static const struct hantro_codec_ops rk3288_vpu_codec_ops[] = {
172 	[HANTRO_MODE_JPEG_ENC] = {
173 		.run = hantro_h1_jpeg_enc_run,
174 		.reset = rk3288_vpu_enc_reset,
175 		.init = hantro_jpeg_enc_init,
176 		.exit = hantro_jpeg_enc_exit,
177 	},
178 	[HANTRO_MODE_H264_DEC] = {
179 		.run = hantro_g1_h264_dec_run,
180 		.reset = rk3288_vpu_dec_reset,
181 		.init = hantro_h264_dec_init,
182 		.exit = hantro_h264_dec_exit,
183 	},
184 	[HANTRO_MODE_MPEG2_DEC] = {
185 		.run = hantro_g1_mpeg2_dec_run,
186 		.reset = rk3288_vpu_dec_reset,
187 		.init = hantro_mpeg2_dec_init,
188 		.exit = hantro_mpeg2_dec_exit,
189 	},
190 	[HANTRO_MODE_VP8_DEC] = {
191 		.run = hantro_g1_vp8_dec_run,
192 		.reset = rk3288_vpu_dec_reset,
193 		.init = hantro_vp8_dec_init,
194 		.exit = hantro_vp8_dec_exit,
195 	},
196 };
197 
198 /*
199  * VPU variant.
200  */
201 
202 static const struct hantro_irq rk3288_irqs[] = {
203 	{ "vepu", rk3288_vepu_irq },
204 	{ "vdpu", rk3288_vdpu_irq },
205 };
206 
207 static const char * const rk3288_clk_names[] = {
208 	"aclk", "hclk"
209 };
210 
211 const struct hantro_variant rk3288_vpu_variant = {
212 	.enc_offset = 0x0,
213 	.enc_fmts = rk3288_vpu_enc_fmts,
214 	.num_enc_fmts = ARRAY_SIZE(rk3288_vpu_enc_fmts),
215 	.dec_offset = 0x400,
216 	.dec_fmts = rk3288_vpu_dec_fmts,
217 	.num_dec_fmts = ARRAY_SIZE(rk3288_vpu_dec_fmts),
218 	.codec = HANTRO_JPEG_ENCODER | HANTRO_MPEG2_DECODER |
219 		 HANTRO_VP8_DECODER | HANTRO_H264_DECODER,
220 	.codec_ops = rk3288_vpu_codec_ops,
221 	.irqs = rk3288_irqs,
222 	.num_irqs = ARRAY_SIZE(rk3288_irqs),
223 	.init = rk3288_vpu_hw_init,
224 	.clk_names = rk3288_clk_names,
225 	.num_clocks = ARRAY_SIZE(rk3288_clk_names)
226 };
227