blob: f138a767f1e26b531906f3e71f9c09fd7b67c78f [file] [log] [blame]
/*
* drivers/amlogic/media/vout/cvbs/enc_clk_config.c
*
* Copyright (C) 2017 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.
*
*/
/* Linux Headers */
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/mutex.h>
/* Amlogic Headers */
#include <linux/amlogic/cpu_version.h>
#include <linux/amlogic/media/vout/vinfo.h>
#include <linux/amlogic/iomap.h>
/* Local Headers */
#include "cvbs_out.h"
#include "enc_clk_config.h"
#include "cvbs_out_reg.h"
static DEFINE_MUTEX(setclk_mutex);
static int pll_wait_lock(unsigned int reg, unsigned int lock_bit)
{
unsigned int pll_lock;
int wait_loop = 2000;
int ret = 0;
do {
udelay(50);
pll_lock = cvbs_out_hiu_getb(reg, lock_bit, 1);
wait_loop--;
} while ((pll_lock == 0) && (wait_loop > 0));
if (wait_loop == 0)
ret = -1;
return ret;
}
static void disable_vid1_clk_out(void)
{
/* close cts_enci_clk & cts_vdac_clk */
cvbs_out_hiu_setb(HHI_VID_CLK_CNTL2, 0, 4, 1);
cvbs_out_hiu_setb(HHI_VID_CLK_CNTL2, 0, 0, 1);
/* close vclk_div gate */
cvbs_out_hiu_setb(HHI_VID_CLK_CNTL, 0, VCLK_DIV1_EN, 1);
cvbs_out_hiu_setb(HHI_VID_CLK_CNTL, 0, VCLK_EN0, 1);
/* close pll_div gate */
cvbs_out_hiu_setb(HHI_VID_PLL_CLK_DIV, 0, 19, 1);
}
static void disable_vid2_clk_out(void)
{
/* close cts_enci_clk & cts_vdac_clk */
cvbs_out_hiu_setb(HHI_VID_CLK_CNTL2, 0, 4, 1);
cvbs_out_hiu_setb(HHI_VID_CLK_CNTL2, 0, 0, 1);
/* close vclk2_div gate */
cvbs_out_hiu_setb(HHI_VIID_CLK_CNTL, 0, VCLK2_DIV1_EN, 1);
cvbs_out_hiu_setb(HHI_VIID_CLK_CNTL, 0, VCLK2_EN, 1);
}
static void cvbs_set_vid1_clk(unsigned int src_pll)
{
int sel = 0;
pr_info("%s\n", __func__);
if (src_pll == 0) { /* hpll */
/* divider: 1 */
/* Disable the div output clock */
cvbs_out_hiu_setb(HHI_VID_PLL_CLK_DIV, 0, 19, 1);
cvbs_out_hiu_setb(HHI_VID_PLL_CLK_DIV, 0, 15, 1);
cvbs_out_hiu_setb(HHI_VID_PLL_CLK_DIV, 1, 18, 1);
/* Enable the final output clock */
cvbs_out_hiu_setb(HHI_VID_PLL_CLK_DIV, 1, 19, 1);
sel = 0;
} else { /* gp0_pll */
sel = 1;
}
/* xd: 55 */
/* setup the XD divider value */
cvbs_out_hiu_setb(HHI_VID_CLK_DIV, (55 - 1), VCLK_XD0, 8);
udelay(5);
cvbs_out_hiu_setb(HHI_VID_CLK_CNTL, sel, VCLK_CLK_IN_SEL, 1);
cvbs_out_hiu_setb(HHI_VID_CLK_CNTL, 1, VCLK_EN0, 1);
udelay(2);
/* vclk: 27M */
/* [31:28]=0 enci_clk_sel, select vclk_div1 */
cvbs_out_hiu_setb(HHI_VID_CLK_DIV, 0, 28, 4);
cvbs_out_hiu_setb(HHI_VIID_CLK_DIV, 0, 28, 4);
/* release vclk_div_reset and enable vclk_div */
cvbs_out_hiu_setb(HHI_VID_CLK_DIV, 1, VCLK_XD_EN, 2);
udelay(5);
cvbs_out_hiu_setb(HHI_VID_CLK_CNTL, 1, VCLK_DIV1_EN, 1);
cvbs_out_hiu_setb(HHI_VID_CLK_CNTL, 1, VCLK_SOFT_RST, 1);
udelay(10);
cvbs_out_hiu_setb(HHI_VID_CLK_CNTL, 0, VCLK_SOFT_RST, 1);
udelay(5);
}
static void cvbs_set_vid2_clk(unsigned int src_pll)
{
int sel = 0;
pr_info("%s\n", __func__);
if (src_pll == 0) { /* hpll */
/* divider: 1 */
/* Disable the div output clock */
cvbs_out_hiu_setb(HHI_VID_PLL_CLK_DIV, 0, 19, 1);
cvbs_out_hiu_setb(HHI_VID_PLL_CLK_DIV, 0, 15, 1);
cvbs_out_hiu_setb(HHI_VID_PLL_CLK_DIV, 1, 18, 1);
/* Enable the final output clock */
cvbs_out_hiu_setb(HHI_VID_PLL_CLK_DIV, 1, 19, 1);
sel = 0;
} else { /* gp0_pll */
sel = 1;
}
/* xd: 55 */
/* setup the XD divider value */
cvbs_out_hiu_setb(HHI_VIID_CLK_DIV, (55 - 1), VCLK2_XD, 8);
udelay(5);
/* Bit[18:16] - v2_cntl_clk_in_sel */
cvbs_out_hiu_setb(HHI_VIID_CLK_CNTL, sel, VCLK2_CLK_IN_SEL, 3);
cvbs_out_hiu_setb(HHI_VIID_CLK_CNTL, 1, VCLK2_EN, 1);
udelay(2);
/* vclk: 27M */
/* [31:28]=8 enci_clk_sel, select vclk2_div1 */
cvbs_out_hiu_setb(HHI_VID_CLK_DIV, 8, 28, 4);
cvbs_out_hiu_setb(HHI_VIID_CLK_DIV, 8, 28, 4);
/* release vclk2_div_reset and enable vclk2_div */
cvbs_out_hiu_setb(HHI_VIID_CLK_DIV, 1, VCLK2_XD_EN, 2);
udelay(5);
cvbs_out_hiu_setb(HHI_VIID_CLK_CNTL, 1, VCLK2_DIV1_EN, 1);
cvbs_out_hiu_setb(HHI_VIID_CLK_CNTL, 1, VCLK2_SOFT_RST, 1);
udelay(10);
cvbs_out_hiu_setb(HHI_VIID_CLK_CNTL, 0, VCLK2_SOFT_RST, 1);
udelay(5);
}
void set_vmode_clk(void)
{
int ret;
pr_info("set_vmode_clk start\n");
mutex_lock(&setclk_mutex);
if (cvbs_cpu_type() == CVBS_CPU_TYPE_GXTVBB) {
pr_info("config gxtvbb hdmi pll\n");
cvbs_out_hiu_write(HHI_HDMI_PLL_CNTL, 0x5800023d);
cvbs_out_hiu_write(HHI_HDMI_PLL_CNTL2, 0x00404380);
cvbs_out_hiu_write(HHI_HDMI_PLL_CNTL3, 0x0d5c5091);
cvbs_out_hiu_write(HHI_HDMI_PLL_CNTL4, 0x801da72c);
cvbs_out_hiu_write(HHI_HDMI_PLL_CNTL5, 0x71486980);
cvbs_out_hiu_write(HHI_HDMI_PLL_CNTL6, 0x00000e55);
cvbs_out_hiu_write(HHI_HDMI_PLL_CNTL, 0x4800023d);
ret = pll_wait_lock(HHI_HDMI_PLL_CNTL, 31);
if (ret)
pr_info("[error]: hdmi_pll lock failed\n");
cvbs_out_hiu_setb(HHI_VIID_CLK_CNTL, 0, VCLK2_EN, 1);
udelay(5);
} else if (cvbs_cpu_type() == CVBS_CPU_TYPE_G12A ||
cvbs_cpu_type() == CVBS_CPU_TYPE_G12B ||
cvbs_cpu_type() == CVBS_CPU_TYPE_SM1) {
if (cvbs_clk_path & 0x1) {
pr_info("config g12a gp0_pll\n");
cvbs_out_hiu_write(HHI_GP0_PLL_CNTL0, 0x180204f7);
cvbs_out_hiu_write(HHI_GP0_PLL_CNTL1, 0x00010000);
cvbs_out_hiu_write(HHI_GP0_PLL_CNTL2, 0x00000000);
cvbs_out_hiu_write(HHI_GP0_PLL_CNTL3, 0x6a28dc00);
cvbs_out_hiu_write(HHI_GP0_PLL_CNTL4, 0x65771290);
cvbs_out_hiu_write(HHI_GP0_PLL_CNTL5, 0x39272000);
cvbs_out_hiu_write(HHI_GP0_PLL_CNTL6, 0x56540000);
cvbs_out_hiu_write(HHI_GP0_PLL_CNTL0, 0x380204f7);
udelay(100);
cvbs_out_hiu_write(HHI_GP0_PLL_CNTL0, 0x180204f7);
ret = pll_wait_lock(HHI_GP0_PLL_CNTL0, 31);
} else {
pr_info("config g12a hdmi_pll\n");
cvbs_out_hiu_write(HHI_HDMI_PLL_CNTL, 0x1a0504f7);
cvbs_out_hiu_write(HHI_HDMI_PLL_CNTL2, 0x00010000);
cvbs_out_hiu_write(HHI_HDMI_PLL_CNTL3, 0x00000000);
cvbs_out_hiu_write(HHI_HDMI_PLL_CNTL4, 0x6a28dc00);
cvbs_out_hiu_write(HHI_HDMI_PLL_CNTL5, 0x65771290);
cvbs_out_hiu_write(HHI_HDMI_PLL_CNTL6, 0x39272000);
cvbs_out_hiu_write(HHI_HDMI_PLL_CNTL7, 0x56540000);
cvbs_out_hiu_write(HHI_HDMI_PLL_CNTL, 0x3a0504f7);
udelay(100);
cvbs_out_hiu_write(HHI_HDMI_PLL_CNTL, 0x1a0504f7);
ret = pll_wait_lock(HHI_HDMI_PLL_CNTL, 31);
}
if (ret)
pr_info("[error]:hdmi_pll lock failed\n");
} else if (cvbs_cpu_type() == CVBS_CPU_TYPE_TL1) {
cvbs_out_hiu_write(HHI_TCON_PLL_CNTL0, 0x202f04f7);
udelay(100);
cvbs_out_hiu_write(HHI_TCON_PLL_CNTL0, 0x302f04f7);
udelay(100);
cvbs_out_hiu_write(HHI_TCON_PLL_CNTL1, 0x10110000);
cvbs_out_hiu_write(HHI_TCON_PLL_CNTL2, 0x00001108);
cvbs_out_hiu_write(HHI_TCON_PLL_CNTL3, 0x10051400);
cvbs_out_hiu_write(HHI_TCON_PLL_CNTL4, 0x010100c0);
udelay(100);
cvbs_out_hiu_write(HHI_TCON_PLL_CNTL4, 0x038300c0);
udelay(100);
cvbs_out_hiu_write(HHI_TCON_PLL_CNTL0, 0x342f04f7);
udelay(100);
cvbs_out_hiu_write(HHI_TCON_PLL_CNTL0, 0x142f04f7);
udelay(100);
cvbs_out_hiu_write(HHI_TCON_PLL_CNTL2, 0x00003008);
udelay(100);
ret = pll_wait_lock(HHI_TCON_PLL_CNTL0, 31);
if (ret)
pr_info("[error]:tl1 tcon_pll lock failed\n");
} else {
pr_info("config eqafter gxl hdmi pll\n");
cvbs_out_hiu_write(HHI_HDMI_PLL_CNTL, 0x4000027b);
cvbs_out_hiu_write(HHI_HDMI_PLL_CNTL2, 0x800cb300);
cvbs_out_hiu_write(HHI_HDMI_PLL_CNTL3, 0xa6212844);
cvbs_out_hiu_write(HHI_HDMI_PLL_CNTL4, 0x0c4d000c);
cvbs_out_hiu_write(HHI_HDMI_PLL_CNTL5, 0x001fa729);
cvbs_out_hiu_write(HHI_HDMI_PLL_CNTL6, 0x01a31500);
cvbs_out_hiu_setb(HHI_HDMI_PLL_CNTL, 0x1, 28, 1);
cvbs_out_hiu_setb(HHI_HDMI_PLL_CNTL, 0x0, 28, 1);
ret = pll_wait_lock(HHI_HDMI_PLL_CNTL, 31);
if (ret)
pr_info("[error]: hdmi_pll lock failed\n");
}
if (cvbs_cpu_type() == CVBS_CPU_TYPE_G12A ||
cvbs_cpu_type() == CVBS_CPU_TYPE_G12B ||
cvbs_cpu_type() == CVBS_CPU_TYPE_SM1) {
if (cvbs_clk_path & 0x2)
cvbs_set_vid1_clk(cvbs_clk_path & 0x1);
else
cvbs_set_vid2_clk(cvbs_clk_path & 0x1);
} else if (cvbs_cpu_type() == CVBS_CPU_TYPE_TL1) {
if (cvbs_clk_path & 0x2)
cvbs_set_vid1_clk(0);
else
cvbs_set_vid2_clk(0);
} else {
cvbs_set_vid2_clk(0);
}
cvbs_out_hiu_setb(HHI_VID_CLK_CNTL2, 1, 0, 1);
cvbs_out_hiu_setb(HHI_VID_CLK_CNTL2, 1, 4, 1);
mutex_unlock(&setclk_mutex);
pr_info("set_vmode_clk DONE\n");
}
void disable_vmode_clk(void)
{
if (cvbs_cpu_type() == CVBS_CPU_TYPE_G12A ||
cvbs_cpu_type() == CVBS_CPU_TYPE_G12B ||
cvbs_cpu_type() == CVBS_CPU_TYPE_SM1) {
if (cvbs_clk_path & 0x2)
disable_vid1_clk_out();
else
disable_vid2_clk_out();
/* disable pll */
if (cvbs_clk_path & 0x1)
cvbs_out_hiu_setb(HHI_GP0_PLL_CNTL0, 0, 28, 1);
else
cvbs_out_hiu_setb(HHI_HDMI_PLL_CNTL, 0, 28, 1);
} else {
disable_vid2_clk_out();
/* disable pll */
cvbs_out_hiu_setb(HHI_HDMI_PLL_CNTL, 0, 30, 1);
}
}