blob: 144006c158194a952bfe321d1b1e2d2f09dbe3da
1 | /* |
2 | * drivers/amlogic/media/common/arch/clk/clk.c |
3 | * |
4 | * Copyright (C) 2016 Amlogic, Inc. All rights reserved. |
5 | * |
6 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License as published by |
8 | * the Free Software Foundation; either version 2 of the License, or |
9 | * (at your option) any later version. |
10 | * |
11 | * This program is distributed in the hope that it will be useful, but WITHOUT |
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
14 | * more details. |
15 | * |
16 | */ |
17 | |
18 | #include <linux/kernel.h> |
19 | #include <linux/module.h> |
20 | #include <linux/types.h> |
21 | #include <linux/fs.h> |
22 | #include <linux/init.h> |
23 | #include <linux/device.h> |
24 | #include <linux/vmalloc.h> |
25 | #include <linux/mm.h> |
26 | #include <linux/vmalloc.h> |
27 | #include <linux/slab.h> |
28 | |
29 | #include <linux/amlogic/media/utils/vformat.h> |
30 | #include <linux/amlogic/cpu_version.h> |
31 | #include "../../../stream_input/amports/amports_priv.h" |
32 | #include "../../../frame_provider/decoder/utils/vdec.h" |
33 | #include "../../chips/chips.h" |
34 | #include "clk_priv.h" |
35 | #include <linux/amlogic/media/utils/log.h> |
36 | #include "../../chips/decoder_cpu_ver_info.h" |
37 | |
38 | #define p_vdec() (get_current_vdec_chip()->clk_mgr[VDEC_1]) |
39 | #define p_vdec2() (get_current_vdec_chip()->clk_mgr[VDEC_2]) |
40 | #define p_vdec_hcodec() (get_current_vdec_chip()->clk_mgr[VDEC_HCODEC]) |
41 | #define p_vdec_hevc() (get_current_vdec_chip()->clk_mgr[VDEC_HEVC]) |
42 | #define p_vdec_hevc_back() (get_current_vdec_chip()->clk_mgr[VDEC_HEVCB]) |
43 | |
44 | static int clock_source_wxhxfps_saved[VDEC_MAX + 1]; |
45 | |
46 | #define IF_HAVE_RUN(p, fn)\ |
47 | do {\ |
48 | if (p && p->fn)\ |
49 | p->fn();\ |
50 | } while (0) |
51 | /* |
52 | *#define IF_HAVE_RUN_P1_RET(p, fn, p1)\ |
53 | * do {\ |
54 | * pr_debug("%s-----%d\n", __func__, clk);\ |
55 | * if (p && p->fn)\ |
56 | * return p->fn(p1);\ |
57 | * else\ |
58 | * return -1;\ |
59 | * } while (0) |
60 | * |
61 | *#define IF_HAVE_RUN_RET(p, fn)\ |
62 | * do {\ |
63 | * if (p && p->fn)\ |
64 | * return p->fn();\ |
65 | * else\ |
66 | * return 0;\ |
67 | * } while (0) |
68 | */ |
69 | |
70 | int vdec_clock_init(void) |
71 | { |
72 | if (p_vdec() && p_vdec()->clock_init) |
73 | return p_vdec()->clock_init(); |
74 | else |
75 | return 0; |
76 | } |
77 | EXPORT_SYMBOL(vdec_clock_init); |
78 | |
79 | /* |
80 | *clk ==0 : |
81 | * to be release. |
82 | * released shared clk, |
83 | *clk ==1 :default low clk |
84 | *clk ==2 :default high clk |
85 | */ |
86 | int vdec_clock_set(int clk) |
87 | { |
88 | pr_debug("%s-----%d\n", __func__, clk); |
89 | if (p_vdec() && p_vdec()->clock_set) |
90 | return p_vdec()->clock_set(clk); |
91 | else |
92 | return -1; |
93 | } |
94 | EXPORT_SYMBOL(vdec_clock_set); |
95 | |
96 | void vdec_clock_enable(void) |
97 | { |
98 | vdec_clock_set(1); |
99 | } |
100 | EXPORT_SYMBOL(vdec_clock_enable); |
101 | |
102 | void vdec_clock_hi_enable(void) |
103 | { |
104 | vdec_clock_set(2); |
105 | } |
106 | EXPORT_SYMBOL(vdec_clock_hi_enable); |
107 | |
108 | void vdec_clock_on(void) |
109 | { |
110 | IF_HAVE_RUN(p_vdec(), clock_on); |
111 | } |
112 | EXPORT_SYMBOL(vdec_clock_on); |
113 | |
114 | void vdec_clock_off(void) |
115 | { |
116 | IF_HAVE_RUN(p_vdec(), clock_off); |
117 | clock_source_wxhxfps_saved[VDEC_1] = 0; |
118 | } |
119 | EXPORT_SYMBOL(vdec_clock_off); |
120 | |
121 | int vdec2_clock_set(int clk) |
122 | { |
123 | pr_debug("%s-----%d\n", __func__, clk); |
124 | if (p_vdec2() && p_vdec2()->clock_set) |
125 | return p_vdec2()->clock_set(clk); |
126 | else |
127 | return -1; |
128 | } |
129 | EXPORT_SYMBOL(vdec2_clock_set); |
130 | |
131 | void vdec2_clock_enable(void) |
132 | { |
133 | vdec2_clock_set(1); |
134 | } |
135 | EXPORT_SYMBOL(vdec2_clock_enable); |
136 | |
137 | void vdec2_clock_hi_enable(void) |
138 | { |
139 | vdec2_clock_set(2); |
140 | } |
141 | EXPORT_SYMBOL(vdec2_clock_hi_enable); |
142 | |
143 | void vdec2_clock_on(void) |
144 | { |
145 | IF_HAVE_RUN(p_vdec2(), clock_on); |
146 | } |
147 | EXPORT_SYMBOL(vdec2_clock_on); |
148 | |
149 | void vdec2_clock_off(void) |
150 | { |
151 | IF_HAVE_RUN(p_vdec2(), clock_off); |
152 | clock_source_wxhxfps_saved[VDEC_2] = 0; |
153 | } |
154 | EXPORT_SYMBOL(vdec2_clock_off); |
155 | |
156 | int hcodec_clock_set(int clk) |
157 | { |
158 | pr_debug("%s-----%d\n", __func__, clk); |
159 | if (p_vdec_hcodec() && p_vdec_hcodec()->clock_set) |
160 | return p_vdec_hcodec()->clock_set(clk); |
161 | else |
162 | return -1; |
163 | } |
164 | EXPORT_SYMBOL(hcodec_clock_set); |
165 | |
166 | void hcodec_clock_enable(void) |
167 | { |
168 | hcodec_clock_set(1); |
169 | } |
170 | EXPORT_SYMBOL(hcodec_clock_enable); |
171 | |
172 | void hcodec_clock_hi_enable(void) |
173 | { |
174 | hcodec_clock_set(2); |
175 | } |
176 | EXPORT_SYMBOL(hcodec_clock_hi_enable); |
177 | |
178 | void hcodec_clock_on(void) |
179 | { |
180 | IF_HAVE_RUN(p_vdec_hcodec(), clock_on); |
181 | } |
182 | EXPORT_SYMBOL(hcodec_clock_on); |
183 | |
184 | void hcodec_clock_off(void) |
185 | { |
186 | IF_HAVE_RUN(p_vdec_hcodec(), clock_off); |
187 | clock_source_wxhxfps_saved[VDEC_HCODEC] = 0; |
188 | } |
189 | EXPORT_SYMBOL(hcodec_clock_off); |
190 | |
191 | int hevc_back_clock_init(void) |
192 | { |
193 | if (p_vdec_hevc_back() && p_vdec_hevc_back()->clock_init) |
194 | return p_vdec_hevc_back()->clock_init(); |
195 | else |
196 | return 0; |
197 | } |
198 | EXPORT_SYMBOL(hevc_back_clock_init); |
199 | |
200 | int hevc_back_clock_set(int clk) |
201 | { |
202 | pr_debug("%s-----%d\n", __func__, clk); |
203 | if (p_vdec_hevc_back() && p_vdec_hevc_back()->clock_set) |
204 | return p_vdec_hevc_back()->clock_set(clk); |
205 | else |
206 | return -1; |
207 | } |
208 | EXPORT_SYMBOL(hevc_back_clock_set); |
209 | |
210 | void hevc_back_clock_enable(void) |
211 | { |
212 | hevc_back_clock_set(1); |
213 | } |
214 | EXPORT_SYMBOL(hevc_back_clock_enable); |
215 | |
216 | void hevc_back_clock_hi_enable(void) |
217 | { |
218 | hevc_back_clock_set(2); |
219 | } |
220 | EXPORT_SYMBOL(hevc_back_clock_hi_enable); |
221 | |
222 | int hevc_clock_init(void) |
223 | { |
224 | if (p_vdec_hevc() && p_vdec_hevc()->clock_init) |
225 | return p_vdec_hevc()->clock_init(); |
226 | else |
227 | return 0; |
228 | } |
229 | EXPORT_SYMBOL(hevc_clock_init); |
230 | |
231 | int hevc_clock_set(int clk) |
232 | { |
233 | pr_debug("%s-----%d\n", __func__, clk); |
234 | if (p_vdec_hevc() && p_vdec_hevc()->clock_set) |
235 | return p_vdec_hevc()->clock_set(clk); |
236 | else |
237 | return -1; |
238 | } |
239 | EXPORT_SYMBOL(hevc_clock_set); |
240 | |
241 | void hevc_clock_enable(void) |
242 | { |
243 | hevc_clock_set(1); |
244 | } |
245 | EXPORT_SYMBOL(hevc_clock_enable); |
246 | |
247 | void hevc_clock_hi_enable(void) |
248 | { |
249 | hevc_clock_set(2); |
250 | } |
251 | EXPORT_SYMBOL(hevc_clock_hi_enable); |
252 | |
253 | void hevc_back_clock_on(void) |
254 | { |
255 | IF_HAVE_RUN(p_vdec_hevc_back(), clock_on); |
256 | } |
257 | EXPORT_SYMBOL(hevc_back_clock_on); |
258 | |
259 | void hevc_back_clock_off(void) |
260 | { |
261 | IF_HAVE_RUN(p_vdec_hevc_back(), clock_off); |
262 | clock_source_wxhxfps_saved[VDEC_HEVCB] = 0; |
263 | } |
264 | EXPORT_SYMBOL(hevc_back_clock_off); |
265 | |
266 | void hevc_clock_on(void) |
267 | { |
268 | IF_HAVE_RUN(p_vdec_hevc(), clock_on); |
269 | } |
270 | EXPORT_SYMBOL(hevc_clock_on); |
271 | |
272 | void hevc_clock_off(void) |
273 | { |
274 | IF_HAVE_RUN(p_vdec_hevc(), clock_off); |
275 | clock_source_wxhxfps_saved[VDEC_HEVC] = 0; |
276 | } |
277 | EXPORT_SYMBOL(hevc_clock_off); |
278 | |
279 | int vdec_source_get(enum vdec_type_e core) |
280 | { |
281 | return clock_source_wxhxfps_saved[core]; |
282 | } |
283 | EXPORT_SYMBOL(vdec_source_get); |
284 | |
285 | int vdec_clk_get(enum vdec_type_e core) |
286 | { |
287 | return get_current_vdec_chip()->clk_mgr[core]->clock_get(core); |
288 | } |
289 | EXPORT_SYMBOL(vdec_clk_get); |
290 | |
291 | int get_clk_with_source(int format, int w_x_h_fps) |
292 | { |
293 | struct clk_set_setting *p_setting; |
294 | int i; |
295 | int clk = -2; |
296 | |
297 | p_setting = get_current_vdec_chip()->clk_setting_array; |
298 | if (!p_setting || format < 0 || format > VFORMAT_MAX) { |
299 | pr_info("error on get_clk_with_source ,%p,%d\n", |
300 | p_setting, format); |
301 | return -1; /*no setting found. */ |
302 | } |
303 | p_setting = &p_setting[format]; |
304 | for (i = 0; i < MAX_CLK_SET; i++) { |
305 | if (p_setting->set[i].wh_X_fps > w_x_h_fps) { |
306 | clk = p_setting->set[i].clk_Mhz; |
307 | break; |
308 | } |
309 | } |
310 | return clk; |
311 | } |
312 | EXPORT_SYMBOL(get_clk_with_source); |
313 | |
314 | int vdec_source_changed_for_clk_set(int format, int width, int height, int fps) |
315 | { |
316 | int clk = get_clk_with_source(format, width * height * fps); |
317 | int ret_clk; |
318 | |
319 | if (clk < 0) { |
320 | pr_info("can't get valid clk for source ,%d,%d,%d\n", |
321 | width, height, fps); |
322 | if (format >= 1920 && width >= 1080 && fps >= 30) |
323 | clk = 2; /*default high clk */ |
324 | else |
325 | clk = 0; /*default clk. */ |
326 | } |
327 | if (width * height * fps == 0) |
328 | clk = 0; |
329 | /* |
330 | *clk == 0 |
331 | *is used for set default clk; |
332 | *if used supper clk. |
333 | *changed to default min clk. |
334 | */ |
335 | |
336 | if (format == VFORMAT_HEVC || format == VFORMAT_VP9 |
337 | || format == VFORMAT_AVS2 |
338 | || format == VFORMAT_AV1) { |
339 | ret_clk = hevc_clock_set(clk); |
340 | clock_source_wxhxfps_saved[VDEC_HEVC] = width * height * fps; |
341 | if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) { |
342 | ret_clk = hevc_back_clock_set(clk); |
343 | clock_source_wxhxfps_saved[VDEC_HEVCB] = width * height * fps; |
344 | } |
345 | } else if (format == VFORMAT_H264_ENC || format == VFORMAT_JPEG_ENC) { |
346 | ret_clk = hcodec_clock_set(clk); |
347 | clock_source_wxhxfps_saved[VDEC_HCODEC] = width * height * fps; |
348 | } else if (format == VFORMAT_H264_4K2K && |
349 | get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_M8) { |
350 | ret_clk = vdec2_clock_set(clk); |
351 | clock_source_wxhxfps_saved[VDEC_2] = width * height * fps; |
352 | ret_clk = vdec_clock_set(clk); |
353 | clock_source_wxhxfps_saved[VDEC_1] = width * height * fps; |
354 | } else { |
355 | ret_clk = vdec_clock_set(clk); |
356 | clock_source_wxhxfps_saved[VDEC_1] = width * height * fps; |
357 | } |
358 | return ret_clk; |
359 | } |
360 | EXPORT_SYMBOL(vdec_source_changed_for_clk_set); |
361 | |
362 | static int register_vdec_clk_mgr_per_cpu(int cputype, |
363 | enum vdec_type_e vdec_type, struct chip_vdec_clk_s *t_mgr) |
364 | { |
365 | |
366 | struct chip_vdec_clk_s *mgr; |
367 | |
368 | if (cputype != get_cpu_major_id() || vdec_type >= VDEC_MAX) { |
369 | /* |
370 | *pr_info("ignore vdec clk mgr for vdec[%d] cpu=%d\n", |
371 | *vdec_type, cputype); |
372 | */ |
373 | return 0; /* ignore don't needed firmare. */ |
374 | } |
375 | mgr = kmalloc(sizeof(struct chip_vdec_clk_s), GFP_KERNEL); |
376 | if (!mgr) |
377 | return -ENOMEM; |
378 | *mgr = *t_mgr; |
379 | /* |
380 | *pr_info("register vdec clk mgr for vdec[%d]\n", vdec_type); |
381 | */ |
382 | if (mgr->clock_init) { |
383 | if (mgr->clock_init()) { |
384 | kfree(mgr); |
385 | return -ENOMEM; |
386 | } |
387 | } |
388 | get_current_vdec_chip()->clk_mgr[vdec_type] = mgr; |
389 | return 0; |
390 | } |
391 | |
392 | int register_vdec_clk_mgr(int cputype[], enum vdec_type_e vdec_type, |
393 | struct chip_vdec_clk_s *t_mgr) |
394 | { |
395 | int i = 0; |
396 | |
397 | while (cputype[i] > 0) { |
398 | register_vdec_clk_mgr_per_cpu(cputype[i], vdec_type, t_mgr); |
399 | i++; |
400 | } |
401 | return 0; |
402 | } |
403 | EXPORT_SYMBOL(register_vdec_clk_mgr); |
404 | |
405 | int unregister_vdec_clk_mgr(enum vdec_type_e vdec_type) |
406 | { |
407 | kfree(get_current_vdec_chip()->clk_mgr[vdec_type]); |
408 | |
409 | return 0; |
410 | } |
411 | EXPORT_SYMBOL(unregister_vdec_clk_mgr); |
412 | |
413 | static int register_vdec_clk_setting_per_cpu(int cputype, |
414 | struct clk_set_setting *setting, int size) |
415 | { |
416 | |
417 | struct clk_set_setting *p_setting; |
418 | |
419 | if (cputype != get_cpu_major_id()) { |
420 | /* |
421 | *pr_info("ignore clk_set_setting for cpu=%d\n", |
422 | *cputype); |
423 | */ |
424 | return 0; /* ignore don't needed this setting . */ |
425 | } |
426 | p_setting = kmalloc(size, GFP_KERNEL); |
427 | if (!p_setting) |
428 | return -ENOMEM; |
429 | memcpy(p_setting, setting, size); |
430 | |
431 | pr_info("register clk_set_setting cpu[%d]\n", cputype); |
432 | |
433 | get_current_vdec_chip()->clk_setting_array = p_setting; |
434 | return 0; |
435 | } |
436 | |
437 | int register_vdec_clk_setting(int cputype[], |
438 | struct clk_set_setting *p_seting, int size) |
439 | { |
440 | int i = 0; |
441 | |
442 | while (cputype[i] > 0) { |
443 | register_vdec_clk_setting_per_cpu(cputype[i], p_seting, size); |
444 | i++; |
445 | } |
446 | return 0; |
447 | } |
448 | EXPORT_SYMBOL(register_vdec_clk_setting); |
449 | |
450 | int unregister_vdec_clk_setting(void) |
451 | { |
452 | kfree(get_current_vdec_chip()->clk_setting_array); |
453 | |
454 | return 0; |
455 | } |
456 | EXPORT_SYMBOL(unregister_vdec_clk_setting); |
457 | |
458 |