blob: 2c44e632b8ac91fa1cfffdcb4e28f38139e6b162 [file] [log] [blame] [edit]
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2022 MediaTek Inc.
* Author: Chong-ming Wei <chong-ming.wei@mediatek.com>
*/
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include "clk-fmeter.h"
#include "clk-mt6886-fmeter.h"
#define FM_TIMEOUT 30
#define SUBSYS_PLL_NUM 4
#define VLP_FM_WAIT_TIME 40 /* ~= 38.64ns * 1023 */
#define FM_PLL_CK 0
#define FM_PLL_CKDIV_CK 1
#define FM_CKDIV_SHIFT (7)
#define FM_CKDIV_MASK GENMASK(10, 7)
#define FM_POSTDIV_SHIFT (24)
#define FM_POSTDIV_MASK GENMASK(26, 24)
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)
static DEFINE_SPINLOCK(subsys_meter_lock);
#define subsys_fmeter_lock(flags) spin_lock_irqsave(&subsys_meter_lock, flags)
#define subsys_fmeter_unlock(flags) spin_unlock_irqrestore(&subsys_meter_lock, flags)
#define clk_readl(addr) readl(addr)
#define clk_writel(addr, val) \
do { writel(val, addr); wmb(); } while (0) /* sync write */
#define CLK26CALI_0 (0x220)
#define CLK26CALI_1 (0x224)
#define CLK_MISC_CFG_0 (0x240)
#define CLK_DBG_CFG (0x28C)
#define VLP_FQMTR_CON0 (0x230)
#define VLP_FQMTR_CON1 (0x234)
/* MFGPLL_PLL_CTRL Register */
#define MFGPLL_CON0 (0x0008)
#define MFGPLL_CON1 (0x000C)
#define MFGPLL_FQMTR_CON0 (0x0040)
#define MFGPLL_FQMTR_CON1 (0x0044)
/* MFGSCPLL_PLL_CTRL Register */
#define MFGSCPLL_CON0 (0x0008)
#define MFGSCPLL_CON1 (0x000C)
#define MFGSCPLL_FQMTR_CON0 (0x0040)
#define MFGSCPLL_FQMTR_CON1 (0x0044)
/* CCIPLL_PLL_CTRL Register */
#define CCIPLL_CON0 (0x0008)
#define CCIPLL_CON1 (0x000C)
#define CCIPLL_FQMTR_CON0 (0x0040)
#define CCIPLL_FQMTR_CON1 (0x0044)
/* ARMPLL_LL_PLL_CTRL Register */
#define ARMPLL_LL_CON0 (0x0008)
#define ARMPLL_LL_CON1 (0x000C)
#define ARMPLL_LL_FQMTR_CON0 (0x0040)
#define ARMPLL_LL_FQMTR_CON1 (0x0044)
/* ARMPLL_BL_PLL_CTRL Register */
#define ARMPLL_BL_CON0 (0x0008)
#define ARMPLL_BL_CON1 (0x000C)
#define ARMPLL_BL_FQMTR_CON0 (0x0040)
#define ARMPLL_BL_FQMTR_CON1 (0x0044)
/* PTPPLL_PLL_CTRL Register */
#define PTPPLL_CON0 (0x0008)
#define PTPPLL_CON1 (0x000C)
#define PTPPLL_FQMTR_CON0 (0x0040)
#define PTPPLL_FQMTR_CON1 (0x0044)
static void __iomem *fm_base[FM_SYS_NUM];
struct fmeter_data {
enum fm_sys_id type;
const char *name;
unsigned int pll_con0;
unsigned int pll_con1;
unsigned int con0;
unsigned int con1;
};
static struct fmeter_data subsys_fm[] = {
[FM_VLP_CKSYS] = {FM_VLP_CKSYS, "fm_vlp_cksys",
0, 0, VLP_FQMTR_CON0, VLP_FQMTR_CON1},
[FM_MFGPLL] = {FM_MFGPLL, "fm_mfgpll",
MFGPLL_CON0, MFGPLL_CON1, MFGPLL_FQMTR_CON0, MFGPLL_FQMTR_CON1},
[FM_MFGSCPLL] = {FM_MFGSCPLL, "fm_mfgscpll",
MFGSCPLL_CON0, MFGSCPLL_CON1, MFGSCPLL_FQMTR_CON0, MFGSCPLL_FQMTR_CON1},
[FM_CCIPLL] = {FM_CCIPLL, "fm_ccipll",
CCIPLL_CON0, CCIPLL_CON1, CCIPLL_FQMTR_CON0, CCIPLL_FQMTR_CON1},
[FM_ARMPLL_LL] = {FM_ARMPLL_LL, "fm_armpll_ll",
ARMPLL_LL_CON0, ARMPLL_LL_CON1, ARMPLL_LL_FQMTR_CON0, ARMPLL_LL_FQMTR_CON1},
[FM_ARMPLL_BL] = {FM_ARMPLL_BL, "fm_armpll_bl",
ARMPLL_BL_CON0, ARMPLL_BL_CON1, ARMPLL_BL_FQMTR_CON0, ARMPLL_BL_FQMTR_CON1},
[FM_PTPPLL] = {FM_PTPPLL, "fm_ptppll",
PTPPLL_CON0, PTPPLL_CON1, PTPPLL_FQMTR_CON0, PTPPLL_FQMTR_CON1},
};
const char *comp_list[] = {
[FM_TOPCKGEN] = "mediatek,mt6886-topckgen",
[FM_APMIXED] = "mediatek,mt6886-apmixedsys",
[FM_VLP_CKSYS] = "mediatek,mt6886-vlp_cksys",
[FM_MFGPLL] = "mediatek,mt6886-mfgpll_pll_ctrl",
[FM_MFGSCPLL] = "mediatek,mt6886-mfgscpll_pll_ctrl",
[FM_CCIPLL] = "mediatek,mt6886-ccipll_pll_ctrl",
[FM_ARMPLL_LL] = "mediatek,mt6886-armpll_ll_pll_ctrl",
[FM_ARMPLL_BL] = "mediatek,mt6886-armpll_bl_pll_ctrl",
[FM_PTPPLL] = "mediatek,mt6886-ptppll_pll_ctrl",
};
/*
* clk fmeter
*/
#define FMCLK3(_t, _i, _n, _o, _g, _c) { .type = _t, \
.id = _i, .name = _n, .ofs = _o, .grp = _g, .ck_div = _c}
#define FMCLK2(_t, _i, _n, _o, _p, _c) { .type = _t, \
.id = _i, .name = _n, .ofs = _o, .pdn = _p, .ck_div = _c}
#define FMCLK(_t, _i, _n, _c) { .type = _t, .id = _i, .name = _n, .ck_div = _c}
static const struct fmeter_clk fclks[] = {
/* CKGEN Part */
FMCLK2(CKGEN, FM_AXI_CK, "fm_axi_ck", 0x0010, 7, 1),
FMCLK2(CKGEN, FM_AXI_CK_2, "fm_axi_ck_2", 0x0010, 15, 1),
FMCLK2(CKGEN, FM_U_HAXI_CK, "fm_u_haxi_ck", 0x0010, 23, 1),
FMCLK2(CKGEN, FM_BUS_AXIMEM_CK, "fm_bus_aximem_ck", 0x0010, 31, 1),
FMCLK2(CKGEN, FM_DISP0_CK, "fm_disp0_ck", 0x0020, 7, 1),
FMCLK2(CKGEN, FM_MDP0_CK, "fm_mdp0_ck", 0x0020, 15, 1),
FMCLK2(CKGEN, FM_MMINFRA_CK, "fm_mminfra_ck", 0x0020, 23, 1),
FMCLK2(CKGEN, FM_MMUP_CK, "fm_mmup_ck", 0x0020, 31, 1),
FMCLK(CKGEN, FM_DSP_CK, "fm_dsp_ck", 1),
FMCLK(CKGEN, FM_DSP1_CK, "fm_dsp1_ck", 1),
FMCLK(CKGEN, FM_DSP2_CK, "fm_dsp2_ck", 1),
FMCLK(CKGEN, FM_DSP3_CK, "fm_dsp3_ck", 1),
FMCLK(CKGEN, FM_DSP4_CK, "fm_dsp4_ck", 1),
FMCLK(CKGEN, FM_DSP5_CK, "fm_dsp5_ck", 1),
FMCLK(CKGEN, FM_DSP6_CK, "fm_dsp6_ck", 1),
FMCLK(CKGEN, FM_DSP7_CK, "fm_dsp7_ck", 1),
FMCLK2(CKGEN, FM_CAMTG_CK, "fm_camtg_ck", 0x0050, 7, 1),
FMCLK2(CKGEN, FM_CAMTG2_CK, "fm_camtg2_ck", 0x0050, 15, 1),
FMCLK2(CKGEN, FM_CAMTG3_CK, "fm_camtg3_ck", 0x0050, 23, 1),
FMCLK2(CKGEN, FM_CAMTG4_CK, "fm_camtg4_ck", 0x0050, 31, 1),
FMCLK2(CKGEN, FM_CAMTG5_CK, "fm_camtg5_ck", 0x0060, 7, 1),
FMCLK2(CKGEN, FM_CAMTG6_CK, "fm_camtg6_ck", 0x0060, 15, 1),
FMCLK2(CKGEN, FM_UART_CK, "fm_uart_ck", 0x0060, 23, 1),
FMCLK2(CKGEN, FM_SPI_CK, "fm_spi_ck", 0x0060, 31, 1),
FMCLK2(CKGEN, FM_MSDC_MACRO_CK, "fm_msdc_macro_ck", 0x0070, 7, 1),
FMCLK2(CKGEN, FM_MSDC30_1_CK, "fm_msdc30_1_ck", 0x0070, 15, 1),
FMCLK2(CKGEN, FM_MSDC30_2_CK, "fm_msdc30_2_ck", 0x0070, 23, 1),
FMCLK2(CKGEN, FM_AUDIO_CK, "fm_audio_ck", 0x0070, 31, 1),
FMCLK2(CKGEN, FM_AUD_INTBUS_CK, "fm_aud_intbus_ck", 0x0080, 7, 1),
FMCLK2(CKGEN, FM_ATB_CK, "fm_atb_ck", 0x0080, 15, 1),
FMCLK2(CKGEN, FM_DISP_PWM_CK, "fm_disp_pwm_ck", 0x0080, 23, 1),
FMCLK2(CKGEN, FM_USB_CK, "fm_usb_ck", 0x0080, 31, 1),
FMCLK2(CKGEN, FM_USB_XHCI_CK, "fm_usb_xhci_ck", 0x0090, 7, 1),
FMCLK(CKGEN, FM_USB_1P_CK, "fm_usb_1p_ck", 1),
FMCLK(CKGEN, FM_USB_XHCI_1P_CK, "fm_usb_xhci_1p_ck", 1),
FMCLK2(CKGEN, FM_I2C_CK, "fm_i2c_ck", 0x0090, 31, 1),
FMCLK2(CKGEN, FM_SENINF_CK, "fm_seninf_ck", 0x00A0, 7, 1),
FMCLK2(CKGEN, FM_SENINF1_CK, "fm_seninf1_ck", 0x00A0, 15, 1),
FMCLK2(CKGEN, FM_SENINF2_CK, "fm_seninf2_ck", 0x00A0, 23, 1),
FMCLK2(CKGEN, FM_SENINF3_CK, "fm_seninf3_ck", 0x00A0, 31, 1),
FMCLK(CKGEN, FM_DXCC_CK, "fm_dxcc_ck", 1),
FMCLK2(CKGEN, FM_AUD_ENGEN1_CK, "fm_aud_engen1_ck", 0x00B0, 15, 1),
FMCLK2(CKGEN, FM_AUD_ENGEN2_CK, "fm_aud_engen2_ck", 0x00B0, 23, 1),
FMCLK2(CKGEN, FM_AES_UFSFDE_CK, "fm_aes_ufsfde_ck", 0x00B0, 31, 1),
FMCLK2(CKGEN, FM_U_CK, "fm_u_ck", 0x00C0, 7, 1),
FMCLK2(CKGEN, FM_U_MBIST_CK, "fm_u_mbist_ck", 0x00C0, 15, 1),
FMCLK(CKGEN, FM_PEXTP_MBIST_CK, "fm_pextp_mbist_ck", 1),
FMCLK2(CKGEN, FM_AUD_1_CK, "fm_aud_1_ck", 0x00C0, 31, 1),
FMCLK2(CKGEN, FM_AUD_2_CK, "fm_aud_2_ck", 0x00D0, 7, 1),
FMCLK2(CKGEN, FM_ADSP_CK, "fm_adsp_ck", 0x00D0, 15, 1),
FMCLK2(CKGEN, FM_DPMAIF_MAIN_CK, "fm_dpmaif_main_ck", 0x00D0, 23, 1),
FMCLK2(CKGEN, FM_VENC_CK, "fm_venc_ck", 0x00D0, 31, 1),
FMCLK2(CKGEN, FM_VDEC_CK, "fm_vdec_ck", 0x00E0, 7, 1),
FMCLK2(CKGEN, FM_PWM_CK, "fm_pwm_ck", 0x00E0, 15, 1),
FMCLK2(CKGEN, FM_AUDIO_H_CK, "fm_audio_h_ck", 0x00E0, 23, 1),
FMCLK2(CKGEN, FM_MCUPM_CK, "fm_mcupm_ck", 0x00E0, 31, 1),
FMCLK2(CKGEN, FM_MEM_SUB_CK, "fm_mem_sub_ck", 0x00F0, 7, 1),
FMCLK2(CKGEN, FM_MEM_CK, "fm_mem_ck", 0x00F0, 15, 1),
FMCLK2(CKGEN, FM_U_MEM_CK, "fm_u_mem_ck", 0x00F0, 23, 1),
FMCLK2(CKGEN, FM_EMI_N_CK, "fm_emi_n_ck", 0x00F0, 31, 1),
FMCLK2(CKGEN, FM_DSI_OCC_CK, "fm_dsi_occ_ck", 0x0100, 7, 1),
FMCLK2(CKGEN, FM_CCU_AHB_CK, "fm_ccu_ahb_ck", 0x0100, 15, 1),
FMCLK2(CKGEN, FM_AP2CONN_HOST_CK, "fm_ap2conn_host_ck", 0x0100, 23, 1),
FMCLK2(CKGEN, FM_IMG1_CK, "fm_img1_ck", 0x0100, 31, 1),
FMCLK2(CKGEN, FM_IPE_CK, "fm_ipe_ck", 0x0110, 7, 1),
FMCLK2(CKGEN, FM_CAM_CK, "fm_cam_ck", 0x0110, 15, 1),
FMCLK2(CKGEN, FM_CCUSYS_CK, "fm_ccusys_ck", 0x0110, 23, 1),
FMCLK2(CKGEN, FM_CAMTM_CK, "fm_camtm_ck", 0x0110, 31, 1),
FMCLK2(CKGEN, FM_MCU_ACP_CK, "fm_mcu_acp_ck", 0x0120, 7, 1),
FMCLK2(CKGEN, FM_CSI_OCC_SCAN_CK, "fm_csi_occ_scan_ck", 0x0120, 15, 1),
FMCLK2(CKGEN, FM_IPSWEST_CK, "fm_ipswest_ck", 0x0120, 23, 1),
FMCLK2(CKGEN, FM_IPSNORTH_CK, "fm_ipsnorth_ck", 0x0120, 31, 1),
FMCLK(CKGEN, FM_MCU_ATB_CK, "fm_mcu_atb_ck", 1),
FMCLK2(CKGEN, FM_AXI_L3GIC_CK, "fm_axi_l3gic_ck", 0x0130, 15, 1),
FMCLK(CKGEN, FM_DUMMY_1_CK, "fm_dummy_1_ck", 1),
FMCLK(CKGEN, FM_DUMMY_2_CK, "fm_dummy_2_ck", 1),
/* ABIST Part */
FMCLK(ABIST, FM_LVTS_CKMON_LM, "fm_lvts_ckmon_lm", 1),
FMCLK(ABIST, FM_LVTS_CKMON_L8, "fm_lvts_ckmon_l8", 1),
FMCLK(ABIST, FM_LVTS_CKMON_L7, "fm_lvts_ckmon_l7", 1),
FMCLK(ABIST, FM_LVTS_CKMON_L6, "fm_lvts_ckmon_l6", 1),
FMCLK(ABIST, FM_LVTS_CKMON_L5, "fm_lvts_ckmon_l5", 1),
FMCLK(ABIST, FM_LVTS_CKMON_L4, "fm_lvts_ckmon_l4", 1),
FMCLK(ABIST, FM_LVTS_CKMON_L3, "fm_lvts_ckmon_l3", 1),
FMCLK(ABIST, FM_LVTS_CKMON_L2, "fm_lvts_ckmon_l2", 1),
FMCLK(ABIST, FM_LVTS_CKMON_L1, "fm_lvts_ckmon_l1", 1),
FMCLK(ABIST, FM_RCLRPLL_DIV4_CHC, "fm_rclrpll_div4_chc", 1),
FMCLK(ABIST, FM_RPHYPLL_DIV4_CHC, "fm_rphypll_div4_chc", 1),
FMCLK(ABIST, FM_RCLRPLL_DIV4_CHA, "fm_rclrpll_div4_cha", 1),
FMCLK(ABIST, FM_RPHYPLL_DIV4_CHA, "fm_rphypll_div4_cha", 1),
FMCLK(ABIST, FM_ADSPPLL_CK, "fm_adsppll_ck", 1),
FMCLK(ABIST, FM_APLL1_CK, "fm_apll1_ck", 1),
FMCLK(ABIST, FM_APLL2_CK, "fm_apll2_ck", 1),
FMCLK(ABIST, FM_APPLLGP_MON_FM_CK, "fm_appllgp_mon_fm_ck", 1),
FMCLK(ABIST, FM_UNIVPLL_DIV3_CK, "fm_univpll_div3_ck", 1),
FMCLK(ABIST, FM_UNIVPLL_DIV4_CK, "fm_univpll_div4_ck", 1),
FMCLK(ABIST, FM_UNIVPLL_DIV5_CK, "fm_univpll_div5_ck", 1),
FMCLK(ABIST, FM_UNIVPLL_DIV6_CK, "fm_univpll_div6_ck", 1),
FMCLK(ABIST, FM_UNIVPLL_DIV7_CK, "fm_univpll_div7_ck", 1),
FMCLK(ABIST, FM_CSI0A_CDPHY_DELAYCAL_CK, "fm_csi0a_cdphy_delaycal_ck", 1),
FMCLK(ABIST, FM_CSI0B_CDPHY_DELAYCAL_CK, "fm_csi0b_cdphy_delaycal_ck", 1),
FMCLK(ABIST, FM_CSI1A_DPHY_DELAYCAL_CK, "fm_csi1a_dphy_delaycal_ck", 1),
FMCLK(ABIST, FM_CSI1B_DPHY_DELAYCAL_CK, "fm_csi1b_dphy_delaycal_ck", 1),
FMCLK(ABIST, FM_CSI2A_DPHY_DELAYCAL_CK, "fm_csi2a_dphy_delaycal_ck", 1),
FMCLK(ABIST, FM_CSI2B_DPHY_DELAYCAL_CK, "fm_csi2b_dphy_delaycal_ck", 1),
FMCLK(ABIST, FM_CSI3A_DPHY_DELAYCAL_CK, "fm_csi3a_dphy_delaycal_ck", 1),
FMCLK(ABIST, FM_CSI3B_DPHY_DELAYCAL_CK, "fm_csi3b_dphy_delaycal_ck", 1),
FMCLK(ABIST, FM_DSI0_LNTC_DSICLK, "fm_dsi0_lntc_dsiclk", 1),
FMCLK(ABIST, FM_DSI0_MPPLL_TST_CK, "fm_dsi0_mppll_tst_ck", 1),
FMCLK(ABIST, FM_MMPLL_D4_CK, "fm_mmpll_d4_ck", 1),
FMCLK(ABIST, FM_MAINPLL_CK, "fm_mainpll_ck", 1),
FMCLK(ABIST, FM_MDPLL1_FS26M_GUIDE, "fm_mdpll1_fs26m_guide", 1),
FMCLK(ABIST, FM_MMPLL_D5_CK, "fm_mmpll_d5_ck", 1),
FMCLK(ABIST, FM_MMPLL_CK, "fm_mmpll_ck", 1),
FMCLK(ABIST, FM_MMPLL_D3_CK, "fm_mmpll_d3_ck", 1),
FMCLK(ABIST, FM_MPLL_CK, "fm_mpll_ck", 1),
FMCLK(ABIST, FM_MSDCPLL_CK, "fm_msdcpll_ck", 1),
FMCLK(ABIST, FM_IMGPLL_CK, "fm_imgpll_ck", 1),
FMCLK(ABIST, FM_EMIPLL_CK, "fm_emipll_ck", 1),
FMCLK(ABIST, FM_UFSPLL_CK, "fm_ufspll_ck", 1),
FMCLK(ABIST, FM_ULPOSC2_MON_V_VCORE_CK, "fm_ulposc2_mon_v_vcore_ck", 1),
FMCLK(ABIST, FM_ULPOSC_MON_VCROE_CK, "fm_ulposc_mon_vcroe_ck", 1),
FMCLK(ABIST, FM_UNIVPLL_CK, "fm_univpll_ck", 1),
FMCLK(ABIST, FM_UNIVPLL_DIV2_CK, "fm_univpll_div2_ck", 1),
FMCLK(ABIST, FM_UNIVPLL_192M_CK, "fm_univpll_192m_ck", 1),
FMCLK(ABIST, FM_U_CLK2FREQ, "fm_u_clk2freq", 1),
FMCLK(ABIST, FM_WBG_DIG_BPLL_CK, "fm_wbg_dig_bpll_ck", 1),
FMCLK(ABIST, FM_WBG_DIG_WPLL_CK960, "fm_wbg_dig_wpll_ck960", 1),
FMCLK(ABIST, FM_466M_FMEM_INFRASYS, "fm_466m_fmem_infrasys", 1),
FMCLK(ABIST, FM_MCUSYS_ARM_OUT_ALL, "fm_mcusys_arm_out_all", 1),
FMCLK(ABIST, FM_APPLLGP_MON_FM_CK_2, "fm_appllgp_mon_fm_ck_2", 1),
FMCLK(ABIST, FM_MMPLL_D6_CK, "fm_mmpll_d6_ck", 1),
FMCLK(ABIST, FM_MMPLL_D7_CK, "fm_mmpll_d7_ck", 1),
FMCLK(ABIST, FM_MMPLL_D9_CK, "fm_mmpll_d9_ck", 1),
FMCLK(ABIST, FM_MAINPLL_DIV3_CK, "fm_mainpll_div3_ck", 1),
FMCLK(ABIST, FM_MSDC11_IN_CK, "fm_msdc11_in_ck", 1),
FMCLK(ABIST, FM_MSDC01_IN_CK, "fm_msdc01_in_ck", 1),
FMCLK(ABIST, FM_F32K_VCORE_CK, "fm_f32k_vcore_ck", 1),
FMCLK(ABIST, FM_MAINPLL_DIV4_CK, "fm_mainpll_div4_ck", 1),
FMCLK(ABIST, FM_MAINPLL_DIV5_CK, "fm_mainpll_div5_ck", 1),
FMCLK(ABIST, FM_MAINPLL_DIV6_CK, "fm_mainpll_div6_ck", 1),
FMCLK(ABIST, FM_MAINPLL_DIV7_CK, "fm_mainpll_div7_ck", 1),
FMCLK(ABIST, FM_UNIVPLL_DIV3_CK_2, "fm_univpll_div3_ck_2", 1),
FMCLK3(ABIST, FM_APLL2_CKDIV_CK, "fm_apll2_ckdiv_ck", 0x0340, 1, 8),
FMCLK3(ABIST, FM_APLL1_CKDIV_CK, "fm_apll1_ckdiv_ck", 0x032c, 1, 8),
FMCLK3(ABIST, FM_ADSPPLL_CKDIV_CK, "fm_adsppll_ckdiv_ck", 0x0384, 1, 8),
FMCLK3(ABIST, FM_UFSPLL_CKDIV_CK, "fm_ufspll_ckdiv_ck", 0x024c, 1, 8),
FMCLK3(ABIST, FM_MPLL_CKDIV_CK, "fm_mpll_ckdiv_ck", 0x0394, 1, 8),
FMCLK3(ABIST, FM_MMPLL_CKDIV_CK, "fm_mmpll_ckdiv_ck", 0x03A4, 1, 8),
FMCLK3(ABIST, FM_MAINPLL_CKDIV_CK, "fm_mainpll_ckdiv_ck", 0x0354, 1, 8),
FMCLK3(ABIST, FM_IMGPLL_CKDIV_CK, "fm_imgpll_ckdiv_ck", 0x0374, 1, 8),
FMCLK3(ABIST, FM_EMIPLL_CKDIV_CK, "fm_emipll_ckdiv_ck", 0x03B4, 1, 8),
FMCLK3(ABIST, FM_MSDCPLL_CKDIV_CK, "fm_msdcpll_ckdiv_ck", 0x0364, 1, 8),
/* VLPCK Part */
FMCLK2(VLPCK, FM_SCP_VLP_CK, "fm_scp_vlp_ck", 0x0008, 7, 1),
FMCLK2(VLPCK, FM_PWRAP_ULPOSC_CK, "fm_pwrap_ulposc_ck", 0x0008, 15, 1),
FMCLK2(VLPCK, FM_F26M_APXGPT_VLP_CK, "fm_f26m_apxgpt_vlp_ck", 0x0008, 23, 1),
FMCLK2(VLPCK, FM_DXCC_VLP_CK, "fm_dxcc_vlp_ck", 0x0008, 31, 1),
FMCLK2(VLPCK, FM_SPMI_P_CK, "fm_spmi_p_ck", 0x0014, 7, 1),
FMCLK2(VLPCK, FM_SPMI_M_CK, "fm_spmi_m_ck", 0x0014, 15, 1),
FMCLK2(VLPCK, FM_DVFSRC_CK, "fm_dvfsrc_ck", 0x0014, 23, 1),
FMCLK2(VLPCK, FM_PWM_VLP_CK, "fm_pwm_vlp_ck", 0x0014, 31, 1),
FMCLK2(VLPCK, FM_AXI_VLP_CK, "fm_axi_vlp_ck", 0x0020, 7, 1),
FMCLK2(VLPCK, FM_DBGAO_26M_VLP_CK, "fm_dbgao_26m_vlp_ck", 0x0020, 15, 1),
FMCLK2(VLPCK, FM_SYSTIMER_26M_VLP_CK, "fm_systimer_26m_vlp_ck", 0x0020, 23, 1),
FMCLK2(VLPCK, FM_SSPM_VLP_CK, "fm_sspm_vlp_ck", 0x0020, 31, 1),
FMCLK2(VLPCK, FM_SSPM_F26M_CK, "fm_sspm_f26m_ck", 0x002C, 7, 1),
FMCLK2(VLPCK, FM_SRCK_CK, "fm_srck_ck", 0x002C, 15, 1),
FMCLK2(VLPCK, FM_SCP_SPI_CK, "fm_scp_spi_ck", 0x002C, 23, 1),
FMCLK2(VLPCK, FM_SCP_IIC_CK, "fm_scp_iic_ck", 0x002C, 31, 1),
FMCLK2(VLPCK, FM_PSVLP_CK, "fm_psvlp_ck", 0x0038, 7, 1),
FMCLK(VLPCK, FM_MD_BUCK_26M_CK, "fm_md_buck_26m_ck", 1),
FMCLK(VLPCK, FM_SSPM_ULPOSC_CK, "fm_sspm_ulposc_ck", 1),
FMCLK(VLPCK, FM_CLKRTC, "fm_clkrtc", 1),
FMCLK(VLPCK, FM_OSC_2, "fm_osc_2", 1),
FMCLK(VLPCK, FM_OSC_CK, "fm_osc_ck", 1),
FMCLK(VLPCK, FM_OSC_CKDIV_CK, "fm_osc_ckdiv_ck", 1),
FMCLK(VLPCK, FM_OSC_CKDIV_2, "fm_osc_ckdiv_2", 1),
{},
};
const struct fmeter_clk *mt6886_get_fmeter_clks(void)
{
return fclks;
}
static unsigned int check_pdn(void __iomem *base,
unsigned int type, unsigned int ID)
{
int i;
for (i = 0; i < ARRAY_SIZE(fclks) - 1; i++) {
if (fclks[i].type == type && fclks[i].id == ID)
break;
}
if (i >= ARRAY_SIZE(fclks) - 1)
return 1;
if (!fclks[i].ofs)
return 0;
if (type == SUBSYS) {
if ((clk_readl(base + fclks[i].ofs) & fclks[i].pdn)
!= fclks[i].pdn) {
return 1;
}
} else if (type != SUBSYS && ((clk_readl(base + fclks[i].ofs)
& BIT(fclks[i].pdn)) == BIT(fclks[i].pdn)))
return 1;
return 0;
}
static unsigned int get_post_div(unsigned int type, unsigned int ID)
{
unsigned int post_div = 1;
int i;
if ((ID <= 0) || (ID >= FM_ABIST_NUM))
return post_div;
for (i = 0; i < ARRAY_SIZE(fclks) - 1; i++) {
if (fclks[i].type == type && fclks[i].id == ID
&& fclks[i].grp == 1) {
post_div = clk_readl(fm_base[FM_APMIXED] + fclks[i].ofs);
post_div = 1 << ((post_div >> 24) & 0x7);
break;
}
}
return post_div;
}
static unsigned int get_clk_div(unsigned int type, unsigned int ID)
{
unsigned int clk_div = 1;
int i;
if ((ID <= 0) || (ID >= FM_CKGEN_NUM))
return clk_div;
for (i = 0; i < ARRAY_SIZE(fclks) - 1; i++)
if (fclks[i].type == type && fclks[i].id == ID)
break;
if (i >= ARRAY_SIZE(fclks) - 1)
return clk_div;
return fclks[i].ck_div;
}
/* need implement ckgen&abist api here */
/* implement done */
static int __mt_get_freq(unsigned int ID, int type)
{
void __iomem *dbg_addr = fm_base[FM_TOPCKGEN] + CLK_DBG_CFG;
void __iomem *misc_addr = fm_base[FM_TOPCKGEN] + CLK_MISC_CFG_0;
void __iomem *cali0_addr = fm_base[FM_TOPCKGEN] + CLK26CALI_0;
void __iomem *cali1_addr = fm_base[FM_TOPCKGEN] + CLK26CALI_1;
unsigned int temp, clk_dbg_cfg, clk_misc_cfg_0, clk26cali_1 = 0;
unsigned int clk_div = 1, post_div = 1;
unsigned long flags;
int output = 0, i = 0;
fmeter_lock(flags);
if (type == CKGEN && check_pdn(fm_base[FM_TOPCKGEN], CKGEN, ID)) {
pr_notice("ID-%d: MUX PDN, return 0.\n", ID);
fmeter_unlock(flags);
return 0;
}
while (clk_readl(cali0_addr) & 0x10) {
udelay(10);
i++;
if (i > FM_TIMEOUT)
break;
}
/* CLK26CALI_0[15]: rst 1 -> 0 */
clk_writel(cali0_addr, (clk_readl(cali0_addr) & 0xFFFF7FFF));
/* CLK26CALI_0[15]: rst 0 -> 1 */
clk_writel(cali0_addr, (clk_readl(cali0_addr) | 0x00008000));
if (type == CKGEN) {
clk_dbg_cfg = clk_readl(dbg_addr);
clk_writel(dbg_addr,
(clk_dbg_cfg & 0xFFFF80FC) | (ID << 8) | (0x1));
} else if (type == ABIST) {
clk_dbg_cfg = clk_readl(dbg_addr);
clk_writel(dbg_addr,
(clk_dbg_cfg & 0xFF80FFFC) | (ID << 16));
} else {
fmeter_unlock(flags);
return 0;
}
clk_misc_cfg_0 = clk_readl(misc_addr);
clk_writel(misc_addr, (clk_misc_cfg_0 & 0x00FFFFFF) | (3 << 24));
clk26cali_1 = clk_readl(cali1_addr);
clk_writel(cali0_addr, 0x9000);
clk_writel(cali0_addr, 0x9010);
/* wait frequency meter finish */
i = 0;
do {
udelay(10);
i++;
if (i > FM_TIMEOUT)
break;
} while (clk_readl(cali0_addr) & 0x10);
temp = clk_readl(cali1_addr) & 0xFFFF;
if (type == ABIST)
post_div = get_post_div(type, ID);
clk_div = get_clk_div(type, ID);
output = (temp * 26000) / 1024 * clk_div / post_div;
clk_writel(dbg_addr, clk_dbg_cfg);
clk_writel(misc_addr, clk_misc_cfg_0);
/*clk_writel(CLK26CALI_0, clk26cali_0);*/
/*clk_writel(CLK26CALI_1, clk26cali_1);*/
clk_writel(cali0_addr, 0x8000);
fmeter_unlock(flags);
if (i > FM_TIMEOUT)
return 0;
if ((output * 4) < 1000) {
pr_notice("%s(%d): CLK_DBG_CFG = 0x%x, CLK_MISC_CFG_0 = 0x%x, CLK26CALI_0 = 0x%x, CLK26CALI_1 = 0x%x\n",
__func__,
ID,
clk_readl(dbg_addr),
clk_readl(misc_addr),
clk_readl(cali0_addr),
clk_readl(cali1_addr));
}
return (output * 4);
}
static int __mt_get_freq2(unsigned int type, unsigned int id)
{
void __iomem *pll_con0 = fm_base[type] + subsys_fm[type].pll_con0;
void __iomem *pll_con1 = fm_base[type] + subsys_fm[type].pll_con1;
void __iomem *con0 = fm_base[type] + subsys_fm[type].con0;
void __iomem *con1 = fm_base[type] + subsys_fm[type].con1;
unsigned int temp, clk_div = 1, post_div = 1;
unsigned long flags;
int output = 0, i = 0;
fmeter_lock(flags);
/* PLL4H_FQMTR_CON1[15]: rst 1 -> 0 */
clk_writel(con0, clk_readl(con0) & 0xFFFF7FFF);
/* PLL4H_FQMTR_CON1[15]: rst 0 -> 1 */
clk_writel(con0, clk_readl(con0) | 0x8000);
/* sel fqmtr_cksel */
if (type == FM_VLP_CKSYS)
clk_writel(con0, (clk_readl(con0) & 0xFFE0FFFF) | (id << 16));
else
clk_writel(con0, (clk_readl(con0) & 0x00FFFFF8) | (id << 0));
/* set ckgen_load_cnt to 1024 */
clk_writel(con1, (clk_readl(con1) & 0xFC00FFFF) | (0x3FF << 16));
/* sel fqmtr_cksel and set ckgen_k1 to 0(DIV4) */
clk_writel(con0, (clk_readl(con0) & 0x00FFFFFF) | (3 << 24));
/* fqmtr_en set to 1, fqmtr_exc set to 0, fqmtr_start set to 0 */
clk_writel(con0, (clk_readl(con0) & 0xFFFF8007) | 0x1000);
/*fqmtr_start set to 1 */
clk_writel(con0, clk_readl(con0) | 0x10);
/* wait frequency meter finish */
if (type == FM_VLP_CKSYS) {
udelay(VLP_FM_WAIT_TIME);
} else {
while (clk_readl(con0) & 0x10) {
udelay(10);
i++;
if (i > 30) {
pr_notice("[%d]con0: 0x%x, con1: 0x%x\n",
id, clk_readl(con0), clk_readl(con1));
break;
}
}
}
temp = clk_readl(con1) & 0xFFFF;
output = ((temp * 26000)) / 1024; // Khz
if (type != FM_VLP_CKSYS && id == FM_PLL_CKDIV_CK)
clk_div = (clk_readl(pll_con0) & FM_CKDIV_MASK) >> FM_CKDIV_SHIFT;
if (clk_div == 0)
clk_div = 1;
if (type != FM_VLP_CKSYS)
post_div = 1 << ((clk_readl(pll_con1) & FM_POSTDIV_MASK) >> FM_POSTDIV_SHIFT);
clk_writel(con0, 0x8000);
fmeter_unlock(flags);
return (output * 4 * clk_div) / post_div;
}
static unsigned int mt6886_get_ckgen_freq(unsigned int ID)
{
return __mt_get_freq(ID, CKGEN);
}
static unsigned int mt6886_get_abist_freq(unsigned int ID)
{
return __mt_get_freq(ID, ABIST);
}
static unsigned int mt6886_get_vlpck_freq(unsigned int ID)
{
return __mt_get_freq2(FM_VLP_CKSYS, ID);
}
static unsigned int mt6886_get_subsys_freq(unsigned int ID)
{
int output = 0;
unsigned long flags;
subsys_fmeter_lock(flags);
pr_notice("subsys ID: %d\n", ID);
if (ID >= FM_SYS_NUM)
return 0;
output = __mt_get_freq2(ID, FM_PLL_CKDIV_CK);
subsys_fmeter_unlock(flags);
return output;
}
static unsigned int mt6886_get_fmeter_freq(unsigned int id,
enum FMETER_TYPE type)
{
if (type == CKGEN)
return mt6886_get_ckgen_freq(id);
else if (type == ABIST)
return mt6886_get_abist_freq(id);
else if (type == SUBSYS)
return mt6886_get_subsys_freq(id);
else if (type == VLPCK)
return mt6886_get_vlpck_freq(id);
return FT_NULL;
}
static int mt6886_get_fmeter_id(enum FMETER_ID fid)
{
if (fid == FID_DISP_PWM)
return FM_DISP_PWM_CK;
else if (fid == FID_ULPOSC1)
return FM_OSC_CK;
else if (fid == FID_ULPOSC2)
return FM_OSC_2;
return FID_NULL;
}
static void __iomem *get_base_from_comp(const char *comp)
{
struct device_node *node;
static void __iomem *base;
node = of_find_compatible_node(NULL, NULL, comp);
if (node) {
base = of_iomap(node, 0);
if (!base) {
pr_err("%s() can't find iomem for %s\n",
__func__, comp);
return ERR_PTR(-EINVAL);
}
return base;
}
pr_err("%s can't find compatible node\n", __func__);
return ERR_PTR(-EINVAL);
}
/*
* init functions
*/
static struct fmeter_ops fm_ops = {
.get_fmeter_clks = mt6886_get_fmeter_clks,
.get_fmeter_freq = mt6886_get_fmeter_freq,
.get_fmeter_id = mt6886_get_fmeter_id,
};
static int clk_fmeter_mt6886_probe(struct platform_device *pdev)
{
int i;
for (i = 0; i < FM_SYS_NUM; i++) {
fm_base[i] = get_base_from_comp(comp_list[i]);
if (IS_ERR(fm_base[i]))
goto ERR;
}
fmeter_set_ops(&fm_ops);
return 0;
ERR:
pr_err("%s(%s) can't find base\n", __func__, comp_list[i]);
return -EINVAL;
}
static struct platform_driver clk_fmeter_mt6886_drv = {
.probe = clk_fmeter_mt6886_probe,
.driver = {
.name = "clk-fmeter-mt6886",
.owner = THIS_MODULE,
},
};
static int __init clk_fmeter_init(void)
{
static struct platform_device *clk_fmeter_dev;
clk_fmeter_dev = platform_device_register_simple("clk-fmeter-mt6886", -1, NULL, 0);
if (IS_ERR(clk_fmeter_dev))
pr_warn("unable to register clk-fmeter device");
return platform_driver_register(&clk_fmeter_mt6886_drv);
}
static void __exit clk_fmeter_exit(void)
{
platform_driver_unregister(&clk_fmeter_mt6886_drv);
}
subsys_initcall(clk_fmeter_init);
module_exit(clk_fmeter_exit);
MODULE_LICENSE("GPL");