blob: 972bcc131b8f7f5f338a492d41084e5290c9f226 [file] [log] [blame]
/*
* drivers/amlogic/media/common/arch/clk/clk.c
*
* Copyright (C) 2016 Amlogic, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/vmalloc.h>
#include <linux/mm.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>
#include <linux/amlogic/media/utils/vformat.h>
#include <linux/amlogic/cpu_version.h>
#include "../../../stream_input/amports/amports_priv.h"
#include "../../../frame_provider/decoder/utils/vdec.h"
#include "../../chips/chips.h"
#include "clk_priv.h"
#include <linux/amlogic/media/utils/log.h>
#include "../../chips/decoder_cpu_ver_info.h"
#define p_vdec() (get_current_vdec_chip()->clk_mgr[VDEC_1])
#define p_vdec2() (get_current_vdec_chip()->clk_mgr[VDEC_2])
#define p_vdec_hcodec() (get_current_vdec_chip()->clk_mgr[VDEC_HCODEC])
#define p_vdec_hevc() (get_current_vdec_chip()->clk_mgr[VDEC_HEVC])
#define p_vdec_hevc_back() (get_current_vdec_chip()->clk_mgr[VDEC_HEVCB])
static int clock_source_wxhxfps_saved[VDEC_MAX + 1];
#define IF_HAVE_RUN(p, fn)\
do {\
if (p && p->fn)\
p->fn();\
} while (0)
/*
*#define IF_HAVE_RUN_P1_RET(p, fn, p1)\
* do {\
* pr_debug("%s-----%d\n", __func__, clk);\
* if (p && p->fn)\
* return p->fn(p1);\
* else\
* return -1;\
* } while (0)
*
*#define IF_HAVE_RUN_RET(p, fn)\
* do {\
* if (p && p->fn)\
* return p->fn();\
* else\
* return 0;\
* } while (0)
*/
int vdec_clock_init(void)
{
if (p_vdec() && p_vdec()->clock_init)
return p_vdec()->clock_init();
else
return 0;
}
EXPORT_SYMBOL(vdec_clock_init);
/*
*clk ==0 :
* to be release.
* released shared clk,
*clk ==1 :default low clk
*clk ==2 :default high clk
*/
int vdec_clock_set(int clk)
{
pr_debug("%s-----%d\n", __func__, clk);
if (p_vdec() && p_vdec()->clock_set)
return p_vdec()->clock_set(clk);
else
return -1;
}
EXPORT_SYMBOL(vdec_clock_set);
void vdec_clock_enable(void)
{
vdec_clock_set(1);
}
EXPORT_SYMBOL(vdec_clock_enable);
void vdec_clock_hi_enable(void)
{
vdec_clock_set(2);
}
EXPORT_SYMBOL(vdec_clock_hi_enable);
void vdec_clock_on(void)
{
IF_HAVE_RUN(p_vdec(), clock_on);
}
EXPORT_SYMBOL(vdec_clock_on);
void vdec_clock_off(void)
{
IF_HAVE_RUN(p_vdec(), clock_off);
clock_source_wxhxfps_saved[VDEC_1] = 0;
}
EXPORT_SYMBOL(vdec_clock_off);
int vdec2_clock_set(int clk)
{
pr_debug("%s-----%d\n", __func__, clk);
if (p_vdec2() && p_vdec2()->clock_set)
return p_vdec2()->clock_set(clk);
else
return -1;
}
EXPORT_SYMBOL(vdec2_clock_set);
void vdec2_clock_enable(void)
{
vdec2_clock_set(1);
}
EXPORT_SYMBOL(vdec2_clock_enable);
void vdec2_clock_hi_enable(void)
{
vdec2_clock_set(2);
}
EXPORT_SYMBOL(vdec2_clock_hi_enable);
void vdec2_clock_on(void)
{
IF_HAVE_RUN(p_vdec2(), clock_on);
}
EXPORT_SYMBOL(vdec2_clock_on);
void vdec2_clock_off(void)
{
IF_HAVE_RUN(p_vdec2(), clock_off);
clock_source_wxhxfps_saved[VDEC_2] = 0;
}
EXPORT_SYMBOL(vdec2_clock_off);
int hcodec_clock_set(int clk)
{
pr_debug("%s-----%d\n", __func__, clk);
if (p_vdec_hcodec() && p_vdec_hcodec()->clock_set)
return p_vdec_hcodec()->clock_set(clk);
else
return -1;
}
EXPORT_SYMBOL(hcodec_clock_set);
void hcodec_clock_enable(void)
{
hcodec_clock_set(1);
}
EXPORT_SYMBOL(hcodec_clock_enable);
void hcodec_clock_hi_enable(void)
{
hcodec_clock_set(2);
}
EXPORT_SYMBOL(hcodec_clock_hi_enable);
void hcodec_clock_on(void)
{
IF_HAVE_RUN(p_vdec_hcodec(), clock_on);
}
EXPORT_SYMBOL(hcodec_clock_on);
void hcodec_clock_off(void)
{
IF_HAVE_RUN(p_vdec_hcodec(), clock_off);
clock_source_wxhxfps_saved[VDEC_HCODEC] = 0;
}
EXPORT_SYMBOL(hcodec_clock_off);
int hevc_back_clock_init(void)
{
if (p_vdec_hevc_back() && p_vdec_hevc_back()->clock_init)
return p_vdec_hevc_back()->clock_init();
else
return 0;
}
EXPORT_SYMBOL(hevc_back_clock_init);
int hevc_back_clock_set(int clk)
{
pr_debug("%s-----%d\n", __func__, clk);
if (p_vdec_hevc_back() && p_vdec_hevc_back()->clock_set)
return p_vdec_hevc_back()->clock_set(clk);
else
return -1;
}
EXPORT_SYMBOL(hevc_back_clock_set);
void hevc_back_clock_enable(void)
{
hevc_back_clock_set(1);
}
EXPORT_SYMBOL(hevc_back_clock_enable);
void hevc_back_clock_hi_enable(void)
{
hevc_back_clock_set(2);
}
EXPORT_SYMBOL(hevc_back_clock_hi_enable);
int hevc_clock_init(void)
{
if (p_vdec_hevc() && p_vdec_hevc()->clock_init)
return p_vdec_hevc()->clock_init();
else
return 0;
}
EXPORT_SYMBOL(hevc_clock_init);
int hevc_clock_set(int clk)
{
pr_debug("%s-----%d\n", __func__, clk);
if (p_vdec_hevc() && p_vdec_hevc()->clock_set)
return p_vdec_hevc()->clock_set(clk);
else
return -1;
}
EXPORT_SYMBOL(hevc_clock_set);
void hevc_clock_enable(void)
{
hevc_clock_set(1);
}
EXPORT_SYMBOL(hevc_clock_enable);
void hevc_clock_hi_enable(void)
{
hevc_clock_set(2);
}
EXPORT_SYMBOL(hevc_clock_hi_enable);
void hevc_back_clock_on(void)
{
IF_HAVE_RUN(p_vdec_hevc_back(), clock_on);
}
EXPORT_SYMBOL(hevc_back_clock_on);
void hevc_back_clock_off(void)
{
IF_HAVE_RUN(p_vdec_hevc_back(), clock_off);
clock_source_wxhxfps_saved[VDEC_HEVCB] = 0;
}
EXPORT_SYMBOL(hevc_back_clock_off);
void hevc_clock_on(void)
{
IF_HAVE_RUN(p_vdec_hevc(), clock_on);
}
EXPORT_SYMBOL(hevc_clock_on);
void hevc_clock_off(void)
{
IF_HAVE_RUN(p_vdec_hevc(), clock_off);
clock_source_wxhxfps_saved[VDEC_HEVC] = 0;
}
EXPORT_SYMBOL(hevc_clock_off);
int vdec_source_get(enum vdec_type_e core)
{
return clock_source_wxhxfps_saved[core];
}
EXPORT_SYMBOL(vdec_source_get);
int vdec_clk_get(enum vdec_type_e core)
{
return get_current_vdec_chip()->clk_mgr[core]->clock_get(core);
}
EXPORT_SYMBOL(vdec_clk_get);
int get_clk_with_source(int format, int w_x_h_fps)
{
struct clk_set_setting *p_setting;
int i;
int clk = -2;
p_setting = get_current_vdec_chip()->clk_setting_array;
if (!p_setting || format < 0 || format > VFORMAT_MAX) {
pr_info("error on get_clk_with_source ,%p,%d\n",
p_setting, format);
return -1; /*no setting found. */
}
p_setting = &p_setting[format];
for (i = 0; i < MAX_CLK_SET; i++) {
if (p_setting->set[i].wh_X_fps > w_x_h_fps) {
clk = p_setting->set[i].clk_Mhz;
break;
}
}
return clk;
}
EXPORT_SYMBOL(get_clk_with_source);
int vdec_source_changed_for_clk_set(int format, int width, int height, int fps)
{
int clk = get_clk_with_source(format, width * height * fps);
int ret_clk;
if (clk < 0) {
pr_info("can't get valid clk for source ,%d,%d,%d\n",
width, height, fps);
if (format >= 1920 && width >= 1080 && fps >= 30)
clk = 2; /*default high clk */
else
clk = 0; /*default clk. */
}
if (width * height * fps == 0)
clk = 0;
/*
*clk == 0
*is used for set default clk;
*if used supper clk.
*changed to default min clk.
*/
if (format == VFORMAT_HEVC || format == VFORMAT_VP9
|| format == VFORMAT_AVS2
|| format == VFORMAT_AV1) {
ret_clk = hevc_clock_set(clk);
clock_source_wxhxfps_saved[VDEC_HEVC] = width * height * fps;
if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) {
ret_clk = hevc_back_clock_set(clk);
clock_source_wxhxfps_saved[VDEC_HEVCB] = width * height * fps;
}
} else if (format == VFORMAT_H264_ENC || format == VFORMAT_JPEG_ENC) {
ret_clk = hcodec_clock_set(clk);
clock_source_wxhxfps_saved[VDEC_HCODEC] = width * height * fps;
} else if (format == VFORMAT_H264_4K2K &&
get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_M8) {
ret_clk = vdec2_clock_set(clk);
clock_source_wxhxfps_saved[VDEC_2] = width * height * fps;
ret_clk = vdec_clock_set(clk);
clock_source_wxhxfps_saved[VDEC_1] = width * height * fps;
} else {
ret_clk = vdec_clock_set(clk);
clock_source_wxhxfps_saved[VDEC_1] = width * height * fps;
}
return ret_clk;
}
EXPORT_SYMBOL(vdec_source_changed_for_clk_set);
static int register_vdec_clk_mgr_per_cpu(int cputype,
enum vdec_type_e vdec_type, struct chip_vdec_clk_s *t_mgr)
{
struct chip_vdec_clk_s *mgr;
if (cputype != get_cpu_major_id() || vdec_type >= VDEC_MAX) {
/*
*pr_info("ignore vdec clk mgr for vdec[%d] cpu=%d\n",
*vdec_type, cputype);
*/
return 0; /* ignore don't needed firmare. */
}
mgr = vzalloc(sizeof(struct chip_vdec_clk_s));
if (!mgr)
return -ENOMEM;
*mgr = *t_mgr;
/*
*pr_info("register vdec clk mgr for vdec[%d]\n", vdec_type);
*/
if (mgr->clock_init) {
if (mgr->clock_init()) {
vfree(mgr);
return -ENOMEM;
}
}
get_current_vdec_chip()->clk_mgr[vdec_type] = mgr;
return 0;
}
int register_vdec_clk_mgr(int cputype[], enum vdec_type_e vdec_type,
struct chip_vdec_clk_s *t_mgr)
{
int i = 0;
while (cputype[i] > 0) {
register_vdec_clk_mgr_per_cpu(cputype[i], vdec_type, t_mgr);
i++;
}
return 0;
}
EXPORT_SYMBOL(register_vdec_clk_mgr);
int unregister_vdec_clk_mgr(enum vdec_type_e vdec_type)
{
vfree(get_current_vdec_chip()->clk_mgr[vdec_type]);
return 0;
}
EXPORT_SYMBOL(unregister_vdec_clk_mgr);
static int register_vdec_clk_setting_per_cpu(int cputype,
struct clk_set_setting *setting, int size)
{
struct clk_set_setting *p_setting;
if (cputype != get_cpu_major_id()) {
/*
*pr_info("ignore clk_set_setting for cpu=%d\n",
*cputype);
*/
return 0; /* ignore don't needed this setting . */
}
p_setting = vzalloc(size);
if (!p_setting)
return -ENOMEM;
memcpy(p_setting, setting, size);
pr_info("register clk_set_setting cpu[%d]\n", cputype);
get_current_vdec_chip()->clk_setting_array = p_setting;
return 0;
}
int register_vdec_clk_setting(int cputype[],
struct clk_set_setting *p_seting, int size)
{
int i = 0;
while (cputype[i] > 0) {
register_vdec_clk_setting_per_cpu(cputype[i], p_seting, size);
i++;
}
return 0;
}
EXPORT_SYMBOL(register_vdec_clk_setting);
int unregister_vdec_clk_setting(void)
{
vfree(get_current_vdec_chip()->clk_setting_array);
return 0;
}
EXPORT_SYMBOL(unregister_vdec_clk_setting);