blob: 0993d5bdc4f4271f173911bd39284efc6cc50485 [file] [log] [blame]
/*
* Copyright (C) 2020 MediaTek Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* 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/delay.h>
#include <linux/of_address.h>
#include "clkdbg.h"
#include "clk-fmeter.h"
static DEFINE_SPINLOCK(meter_lock);
#define fmeter_lock(flags) spin_lock_irqsave(&meter_lock, flags)
#define fmeter_unlock(flags) spin_unlock_irqrestore(&meter_lock, flags)
/*
* clkdbg fmeter
*/
#define clk_readl(addr) readl(addr)
#define clk_writel(addr, val) \
do { writel(val, addr); wmb(); } while (0) /* sync write */
#define FMCLK(_t, _i, _n) { .type = _t, .id = _i, .name = _n }
static const struct fmeter_clk fclks[] = {
FMCLK(CKGEN, 1, "axi_sel"),
FMCLK(CKGEN, 2, "spm_sel"),
FMCLK(CKGEN, 3, "scp_sel"),
FMCLK(CKGEN, 4, "bus_aximem_sel"),
FMCLK(CKGEN, 5, "mm_sel"),
FMCLK(CKGEN, 6, "mdp_sel"),
FMCLK(CKGEN, 7, "img1_sel"),
FMCLK(CKGEN, 8, "img2_sel"),
FMCLK(CKGEN, 9, "ipe_sel"),
FMCLK(CKGEN, 10, "dpe_sel"),
FMCLK(CKGEN, 11, "cam_sel"),
FMCLK(CKGEN, 12, "ccu_sel"),
FMCLK(CKGEN, 13, "dsp_sel"),
FMCLK(CKGEN, 14, "dsp1_sel"),
FMCLK(CKGEN, 15, "dsp2_sel"),
FMCLK(CKGEN, 16, "dsp3_sel"),
FMCLK(CKGEN, 17, "dsp4_sel"),
FMCLK(CKGEN, 18, "dsp5_sel"),
FMCLK(CKGEN, 19, "dsp6_sel"),
FMCLK(CKGEN, 20, "dsp7_sel"),
FMCLK(CKGEN, 21, "ipu_if_sel"),
FMCLK(CKGEN, 22, "mfg_sel"),
FMCLK(CKGEN, 23, "camtg_sel"),
FMCLK(CKGEN, 24, "camtg2_sel"),
FMCLK(CKGEN, 25, "camtg3_sel"),
FMCLK(CKGEN, 26, "camtg4_sel"),
FMCLK(CKGEN, 27, "uart_sel"),
FMCLK(CKGEN, 28, "spi_sel"),
FMCLK(CKGEN, 29, "msdc50_0_hclk_sel"),
FMCLK(CKGEN, 30, "msdc50_0_sel"),
FMCLK(CKGEN, 31, "msdc30_1_sel"),
FMCLK(CKGEN, 32, "audio_sel"),
FMCLK(CKGEN, 33, "aud_intbus_sel"),
FMCLK(CKGEN, 34, "pwrap_ulposc_sel"),
FMCLK(CKGEN, 35, "atb_sel"),
FMCLK(CKGEN, 36, "p_w_r_mcu_sel"),
FMCLK(CKGEN, 37, "dp_sel"),
FMCLK(CKGEN, 38, "scam_sel"),
FMCLK(CKGEN, 39, "disp_pwm_sel"),
FMCLK(CKGEN, 40, "usb_top_sel"),
FMCLK(CKGEN, 41, "ssusb_xhci_sel"),
FMCLK(CKGEN, 42, "i2c_sel"),
FMCLK(CKGEN, 43, "seninf_sel"),
FMCLK(CKGEN, 44, "sspm_sel"),
FMCLK(CKGEN, 45, "spmi_mst_sel"),
FMCLK(CKGEN, 46, "dvfsrc_sel"),
FMCLK(CKGEN, 47, "dxcc_sel"),
FMCLK(CKGEN, 48, "aud_engen1_sel"),
FMCLK(CKGEN, 49, "aud_engen2_sel"),
FMCLK(CKGEN, 50, "aes_ufsfde_sel"),
FMCLK(CKGEN, 51, "ufs_sel"),
FMCLK(CKGEN, 52, "aud_1_sel"),
FMCLK(CKGEN, 53, "aud_2_sel"),
FMCLK(CKGEN, 54, "adsp_sel"),
FMCLK(CKGEN, 55, "dpmaif_main_sel"),
FMCLK(CKGEN, 56, "venc_sel"),
FMCLK(CKGEN, 57, "vdec_sel"),
FMCLK(CKGEN, 58, "vdec_lat_sel"),
FMCLK(CKGEN, 59, "camtm_sel"),
FMCLK(CKGEN, 60, "pwm_sel"),
FMCLK(CKGEN, 61, "audio_h_sel"),
FMCLK(CKGEN, 62, "camtg5_sel"),
FMCLK(CKGEN, 63, "camtg6_sel"),
FMCLK(ABIST, 1, "AD_ADSPPLL_CK"),
FMCLK(ABIST, 2, "AD_APLL1_CK"),
FMCLK(ABIST, 3, "AD_APLL2_CK"),
FMCLK(ABIST, 4, "AD_APPLLGP_MON_FM_CK"),
FMCLK(ABIST, 5, "AD_APUPLL_CK"),
FMCLK(ABIST, 6, "AD_ARMPLL_BL0_CK"),
FMCLK(ABIST, 7, "AD_ARMPLL_BL1_CK"),
FMCLK(ABIST, 8, "AD_ARMPLL_BL2_CK"),
FMCLK(ABIST, 9, "AD_ARMPLL_BL3_CK"),
FMCLK(ABIST, 10, "AD_ARMPLL_LL_CK"),
FMCLK(ABIST, 11, "AD_CCIPLL_CK"),
FMCLK(ABIST, 12, "AD_CSI0A_CDPHY_DELAYCAL_CK"),
FMCLK(ABIST, 13, "AD_CSI0B_CDPHY_DELAYCAL_CK"),
FMCLK(ABIST, 14, "AD_CSI1A_DPHY_DELAYCAL_CK"),
FMCLK(ABIST, 15, "AD_CSI1B_DPHY_DELAYCAL_CK"),
FMCLK(ABIST, 16, "AD_CSI2A_DPHY_DELAYCAL_CK"),
FMCLK(ABIST, 17, "AD_CSI2B_DPHY_DELAYCAL_CK"),
FMCLK(ABIST, 18, "AD_CSI3A_DPHY_DELAYCAL_CK"),
FMCLK(ABIST, 19, "AD_CSI3B_DPHY_DELAYCAL_CK"),
FMCLK(ABIST, 20, "AD_DSI0_LNTC_DSICLK"),
FMCLK(ABIST, 21, "AD_DSI0_MPPLL_TST_CK"),
FMCLK(ABIST, 22, "AD_DSI1_LNTC_DSICLK"),
FMCLK(ABIST, 23, "AD_DSI1_MPPLL_TST_CK"),
FMCLK(ABIST, 24, "AD_MAINPLL_CK"),
FMCLK(ABIST, 25, "AD_MDPLL1_FS26M_CK_guide"),
FMCLK(ABIST, 26, "AD_MFGPLL_CK"),
FMCLK(ABIST, 27, "AD_MMPLL_CK"),
FMCLK(ABIST, 28, "AD_MMPLL_D3_CK"),
FMCLK(ABIST, 29, "AD_MPLL_CK"),
FMCLK(ABIST, 30, "AD_MSDCPLL_CK"),
FMCLK(ABIST, 31, "AD_RCLRPLL_DIV4_CK_ch02"),
FMCLK(ABIST, 32, "AD_RCLRPLL_DIV4_CK_ch13"),
FMCLK(ABIST, 33, "AD_RPHYPLL_DIV4_CK_ch02"),
FMCLK(ABIST, 34, "AD_RPHYPLL_DIV4_CK_ch13"),
FMCLK(ABIST, 35, "AD_TVDPLL_CK"),
FMCLK(ABIST, 36, "AD_ULPOSC2_CK"),
FMCLK(ABIST, 37, "AD_ULPOSC_CK"),
FMCLK(ABIST, 38, "AD_UNIVPLL_CK"),
FMCLK(ABIST, 39, "AD_USB20_192M_CK"),
FMCLK(ABIST, 40, "DA_MPLL_52M_DIV_CK"),
FMCLK(ABIST, 41, "UFS_MP_CLK2FREQ"),
FMCLK(ABIST, 42, "ad_wbg_dig_bpll_ck"),
FMCLK(ABIST, 43, "ad_wbg_dig_wpll_ck960"),
FMCLK(ABIST, 44, "fmem_ck_aft_dcm_ch0"),
FMCLK(ABIST, 45, "fmem_ck_aft_dcm_ch1"),
FMCLK(ABIST, 46, "fmem_ck_aft_dcm_ch2"),
FMCLK(ABIST, 47, "fmem_ck_aft_dcm_ch3"),
FMCLK(ABIST, 48, "fmem_ck_bfe_dcm_ch0"),
FMCLK(ABIST, 49, "fmem_ck_bfe_dcm_ch1"),
FMCLK(ABIST, 50, "hd_466m_fmem_ck_infrasys"),
FMCLK(ABIST, 51, "mcusys_arm_clk_out_all"),
FMCLK(ABIST, 52, "msdc01_in_ck"),
FMCLK(ABIST, 53, "msdc02_in_ck"),
FMCLK(ABIST, 54, "msdc11_in_ck"),
FMCLK(ABIST, 55, "msdc12_in_ck"),
FMCLK(ABIST, 56, "msdc21_in_ck"),
FMCLK(ABIST, 57, "msdc22_in_ck"),
FMCLK(ABIST, 58, "rtc32k_ck_i_vao"),
FMCLK(ABIST, 60, "ckomo1_ck"),
FMCLK(ABIST, 61, "ckmon2_ck"),
FMCLK(ABIST, 62, "ckmon3_ck"),
FMCLK(ABIST, 63, "ckmon4_ck"),
{}
};
#define _CKGEN(x) (topck_base + (x))
#define CLK_MISC_CFG_0 _CKGEN(0x140)
#define CLK_DBG_CFG _CKGEN(0x17C)
#define CLK26CALI_0 _CKGEN(0x220)
#define CLK26CALI_1 _CKGEN(0x224)
static void __iomem *topck_base;
const struct fmeter_clk *get_fmeter_clks(void)
{
return fclks;
}
static unsigned int mux_table[64][2] = {
/* ID offset pdn_bit */
{0, 0}, //dummy index
{0x10, 7},//axi=1
{0x10, 15},//spm
{0x10, 23},//scp
{0x10, 31},//aximem
{0x20, 7},//disp
{0x20, 15},//mdp
{0x20, 23},//img1
{0x20, 31},//img2
{0x30, 7},//ipe
{0x30, 15},//dpe
{0x30, 23},//cam
{0x30, 31},//ccu
{0x40, 7},//dsp
{0x40, 15},//dsp1
{0x40, 23},//dsp2
{0x40, 31},//dsp3
{0x50, 7},//dsp4
{0x50, 15},//dsp5
{0x50, 23},//dsp6
{0x50, 31},//dsp7
{0x60, 7},//ipu if
{0x60, 15},//mfg
{0x60, 23},//camtg
{0x60, 31},//camtg2
{0x70, 7},//camtg3
{0x70, 15},//camtg4
{0x70, 23},//uart
{0x70, 31},//spi
{0x80, 7},//msdc50_0_hclk
{0x80, 15},//msdc50_0
{0x80, 23},//msdc30_1
{0x80, 31},//audio
{0x90, 7},//aud_intbus
{0x90, 15},//pwrap_ulposc
{0x90, 23},//atb
{0x90, 31},//sspm
{0xA0, 7},//dp
{0xA0, 15},//scam
{0xA0, 23},//disp_pwm
{0xA0, 31},//usb top
{0xB0, 7},//ssusb xhci
{0xB0, 15},//i2c
{0xB0, 23},//seninf
{0x100, 31},//mcupm
{0x110, 7},//spmi mst
{0x110, 15},//dvfsrc
{0xC0, 23},//dxcc
{0xC0, 31},//aud_engen1
{0xD0, 7},//aud_engen2
{0xD0, 15},//aes ufsfde
{0xD0, 23},//ufs
{0xD0, 31},//aud_1
{0xE0, 7},//aud_2
{0xE0, 15},//adsp
{0xE0, 23},//dpmaif
{0xE0, 31},//venc
{0xF0, 7},//vdec
{0xF0, 15},//vdec_lat
{0xF0, 23},//camtm
{0xF0, 31},//pwm
{0x100, 7},//audio_h
{0x100, 15},//camtg5
{0x100, 23},//camtg6=63
};
unsigned int check_mux_pdn(unsigned int ID)
{
#if 0
pr_notice("%s: ID=%d, check:%08x, %08x(%08x)\r\n",
__func__, ID, mux_table[ID][0], BIT(mux_table[ID][1]),
clk_readl(cksys_base + mux_table[ID][0])
& BIT(mux_table[ID][1]));
#endif
if ((ID > 0) && (ID < 64)) {
if ((clk_readl(_CKGEN(mux_table[ID][0]))
& BIT(mux_table[ID][1])))
return 1;
else
return 0;
} else
return 1;
}
unsigned int mt_get_ckgen_freq(unsigned int ID)
{
int output = 0, i = 0;
unsigned int temp, clk_dbg_cfg, clk_misc_cfg_0, clk26cali_1 = 0;
unsigned long flags;
if (check_mux_pdn(ID)) {
/* pr_notice("ID-%d: MUX PDN, return 0.\n", ID); */
return 0;
}
fmeter_lock(flags);
while (clk_readl(CLK26CALI_0) & 0x1000) {
udelay(10);
i++;
if (i > 30)
break;
}
clk_dbg_cfg = clk_readl(CLK_DBG_CFG);
clk_writel(CLK_DBG_CFG, (clk_dbg_cfg & 0xFFFFC0FC)|(ID << 8)|(0x1));
clk_misc_cfg_0 = clk_readl(CLK_MISC_CFG_0);
clk_writel(CLK_MISC_CFG_0, (clk_misc_cfg_0 & 0x00FFFFFF) | (3 << 24));
clk26cali_1 = clk_readl(CLK26CALI_1);
clk_writel(CLK26CALI_0, 0x1000);
clk_writel(CLK26CALI_0, 0x1010);
/* wait frequency meter finish */
i = 0;
while (clk_readl(CLK26CALI_0) & 0x10) {
udelay(10);
i++;
if (i > 30)
break;
}
/* illegal pass */
if (i == 0) {
clk_writel(CLK26CALI_0, 0x0000);
//re-trigger
clk_writel(CLK26CALI_0, 0x1000);
clk_writel(CLK26CALI_0, 0x1010);
while (clk_readl(CLK26CALI_0) & 0x10) {
udelay(10);
i++;
if (i > 30)
break;
}
}
temp = clk_readl(CLK26CALI_1) & 0xFFFF;
output = (temp * 26000) / 1024;
clk_writel(CLK_DBG_CFG, clk_dbg_cfg);
clk_writel(CLK_MISC_CFG_0, clk_misc_cfg_0);
/*clk_writel(CLK26CALI_0, clk26cali_0);*/
/*clk_writel(CLK26CALI_1, clk26cali_1);*/
clk_writel(CLK26CALI_0, 0x0000);
fmeter_unlock(flags);
/*print("ckgen meter[%d] = %d Khz\n", ID, output);*/
if (i > 30)
return 0;
if ((output * 4) < 25000) {
pr_notice("%s: CLK_DBG_CFG = 0x%x, CLK_MISC_CFG_0 = 0x%x, CLK26CALI_0 = 0x%x, CLK26CALI_1 = 0x%x\n",
__func__,
clk_readl(CLK_DBG_CFG),
clk_readl(CLK_MISC_CFG_0),
clk_readl(CLK26CALI_0),
clk_readl(CLK26CALI_1));
}
return (output * 4);
}
unsigned int mt_get_abist_freq(unsigned int ID)
{
int output = 0, i = 0;
unsigned int temp, clk_dbg_cfg, clk_misc_cfg_0, clk26cali_1 = 0;
unsigned long flags;
fmeter_lock(flags);
while (clk_readl(CLK26CALI_0) & 0x1000) {
udelay(10);
i++;
if (i > 30)
break;
}
clk_dbg_cfg = clk_readl(CLK_DBG_CFG);
clk_writel(CLK_DBG_CFG, (clk_dbg_cfg & 0xFFC0FFFC)|(ID << 16));
clk_misc_cfg_0 = clk_readl(CLK_MISC_CFG_0);
clk_writel(CLK_MISC_CFG_0, (clk_misc_cfg_0 & 0x00FFFFFF) | (3 << 24));
clk26cali_1 = clk_readl(CLK26CALI_1);
clk_writel(CLK26CALI_0, 0x1000);
clk_writel(CLK26CALI_0, 0x1010);
i = 0;
/* wait frequency meter finish */
while (clk_readl(CLK26CALI_0) & 0x10) {
udelay(10);
i++;
if (i > 30)
break;
}
/* illegal pass */
if (i == 0) {
clk_writel(CLK26CALI_0, 0x0000);
//re-trigger
clk_writel(CLK26CALI_0, 0x1000);
clk_writel(CLK26CALI_0, 0x1010);
while (clk_readl(CLK26CALI_0) & 0x10) {
udelay(10);
i++;
if (i > 30)
break;
}
}
temp = clk_readl(CLK26CALI_1) & 0xFFFF;
output = (temp * 26000) / 1024;
clk_writel(CLK_DBG_CFG, clk_dbg_cfg);
clk_writel(CLK_MISC_CFG_0, clk_misc_cfg_0);
/*clk_writel(CLK26CALI_0, clk26cali_0);*/
/*clk_writel(CLK26CALI_1, clk26cali_1);*/
clk_writel(CLK26CALI_0, 0x0000);
fmeter_unlock(flags);
if (i > 30)
return 0;
if ((output * 4) < 25000) {
pr_notice("%s: %s = 0x%x, %s = 0x%x, %s = 0x%x, %s = 0x%x\n",
__func__,
"CLK_DBG_CFG", clk_readl(CLK_DBG_CFG),
"CLK_MISC_CFG_0", clk_readl(CLK_MISC_CFG_0),
"CLK26CALI_0", clk_readl(CLK26CALI_0),
"CLK26CALI_1", clk_readl(CLK26CALI_1));
}
return (output * 4);
}
static int __init clk_fmeter_mt6885_init(void)
{
struct device_node *node;
node = of_find_compatible_node(NULL, NULL,
"mediatek,topckgen");
if (node) {
topck_base = of_iomap(node, 0);
if (!topck_base) {
pr_notice("%s() can't find iomem for topckgen\n",
__func__);
return -1;
}
} else {
pr_notice("%s can't find compatible node for topckgen\n",
__func__);
return -1;
}
return 0;
}
subsys_initcall(clk_fmeter_mt6885_init);