| /* Copyright Statement: |
| * |
| * This software/firmware and related documentation ("MediaTek Software") are |
| * protected under relevant copyright laws. The information contained herein is |
| * confidential and proprietary to MediaTek Inc. and/or its licensors. Without |
| * the prior written permission of MediaTek inc. and/or its licensors, any |
| * reproduction, modification, use or disclosure of MediaTek Software, and |
| * information contained herein, in whole or in part, shall be strictly |
| * prohibited. |
| * |
| * MediaTek Inc. (C) 2019. All rights reserved. |
| * |
| * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES |
| * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") |
| * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER |
| * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL |
| * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED |
| * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR |
| * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH |
| * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, |
| * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES |
| * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. |
| * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO |
| * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK |
| * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE |
| * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR |
| * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S |
| * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE |
| * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE |
| * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE |
| * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. |
| * |
| * The following software/firmware and/or related documentation ("MediaTek |
| * Software") have been modified by MediaTek Inc. All revisions are subject to |
| * any receiver's applicable license agreements with MediaTek Inc. |
| */ |
| /* |
| * MTK PMIF Driver |
| * |
| * Copyright 2019 MediaTek Co.,Ltd. |
| * |
| * DESCRIPTION: |
| * This file provides API for other drivers to access PMIC registers |
| * |
| */ |
| |
| #include <pmif.h> |
| #include <spmi.h> |
| #include <pmif_sw.h> |
| #include <spmi_sw.h> |
| |
| #define GET_SWINF_0_FSM(x) ((x>>1) & 0x00000007) |
| #define GET_PMIF_INIT_DONE(x) ((x>>15) & 0x00000001) |
| #define TIMEOUT_WAIT_IDLE (1000000) /* ap latency concern 1ms */ |
| |
| #define PMIF_CMD_PER_3 (0x1 << PMIF_CMD_EXT_REG_LONG) |
| #define PMIF_CMD_PER_1_3 \ |
| ((0x1 << PMIF_CMD_REG) | (0x1 << PMIF_CMD_EXT_REG_LONG)) |
| #define PMIF_CMD_PER_2_3 \ |
| ((0x1 << PMIF_CMD_EXT_REG) | (0x1 << PMIF_CMD_EXT_REG_LONG)) |
| |
| static int pmif_spmi_read_cmd(struct pmif *arb, unsigned char opc, |
| unsigned char sid, unsigned short addr, unsigned char *buf, |
| unsigned short len); |
| static int pmif_spmi_write_cmd(struct pmif *arb, unsigned char opc, |
| unsigned char sid, unsigned short addr, const unsigned char *buf, |
| unsigned short len); |
| #if PMIF_NO_PMIC |
| static int pmif_spmi_read_cmd(struct pmif *arb, unsigned char opc, |
| unsigned char sid, unsigned short addr, unsigned char *buf, |
| unsigned short len) |
| { |
| PMIF_INFO("do Nothing.\n"); |
| return 0; |
| } |
| |
| static int pmif_spmi_write_cmd(struct pmif *arb, unsigned char opc, |
| unsigned char sid, unsigned short addr, const unsigned char *buf, |
| unsigned short len) |
| { |
| PMIF_INFO("do Nothing.\n"); |
| return 0; |
| } |
| |
| /* init interface */ |
| int pmif_spmi_init(int mstid) |
| { |
| PMIF_INFO("do Nothing.\n"); |
| return 0; |
| } |
| #else /* #if PMIF_NO_PMIC */ |
| /* pmif internal API declaration */ |
| #if PMIF_TIMEOUT |
| static unsigned long long pmif_get_current_time(void); |
| static int pmif_timeout_ns(unsigned long long start_time_ns, |
| unsigned long long timeout_time_ns); |
| static unsigned long long pmif_time2ns(unsigned long long time_us); |
| #endif |
| static void pmif_enable_soft_reset(int mstid); |
| static void pmif_spmi_enable_clk_set(int mstid); |
| static void pmif_spmi_force_normal_mode(int mstid); |
| static void pmif_spmi_enable_swinf(int mstid, unsigned int chan_no, |
| unsigned int swinf_no); |
| static void pmif_spmi_enable_cmdIssue(int mstid, kal_bool en); |
| static void pmif_spmi_enable(int mstid); |
| |
| |
| enum pmif_regs { |
| PMIF_INIT_DONE, |
| PMIF_INF_EN, |
| PMIF_INF_CMD_PER_0, |
| PMIF_INF_CMD_PER_1, |
| PMIF_INF_CMD_PER_2, |
| PMIF_INF_CMD_PER_3, |
| PMIF_INF_MAX_BYTECNT_PER_0, |
| PMIF_INF_MAX_BYTECNT_PER_1, |
| PMIF_INF_MAX_BYTECNT_PER_2, |
| PMIF_INF_MAX_BYTECNT_PER_3, |
| PMIF_ARB_EN, |
| PMIF_CMDISSUE_EN, |
| PMIF_TIMER_CTRL, |
| PMIF_SPI_MODE_CTRL, |
| PMIF_IRQ_EVENT_EN_0, |
| PMIF_IRQ_FLAG_0, |
| PMIF_IRQ_CLR_0, |
| PMIF_SWINF_0_ACC, |
| PMIF_SWINF_0_WDATA_31_0, |
| PMIF_SWINF_0_WDATA_63_32, |
| PMIF_SWINF_0_RDATA_31_0, |
| PMIF_SWINF_0_RDATA_63_32, |
| PMIF_SWINF_0_VLD_CLR, |
| PMIF_SWINF_0_STA, |
| PMIF_SWINF_1_ACC, |
| PMIF_SWINF_1_WDATA_31_0, |
| PMIF_SWINF_1_WDATA_63_32, |
| PMIF_SWINF_1_RDATA_31_0, |
| PMIF_SWINF_1_RDATA_63_32, |
| PMIF_SWINF_1_VLD_CLR, |
| PMIF_SWINF_1_STA, |
| PMIF_SWINF_2_ACC, |
| PMIF_SWINF_2_WDATA_31_0, |
| PMIF_SWINF_2_WDATA_63_32, |
| PMIF_SWINF_2_RDATA_31_0, |
| PMIF_SWINF_2_RDATA_63_32, |
| PMIF_SWINF_2_VLD_CLR, |
| PMIF_SWINF_2_STA, |
| PMIF_SWINF_3_ACC, |
| PMIF_SWINF_3_WDATA_31_0, |
| PMIF_SWINF_3_WDATA_63_32, |
| PMIF_SWINF_3_RDATA_31_0, |
| PMIF_SWINF_3_RDATA_63_32, |
| PMIF_SWINF_3_VLD_CLR, |
| PMIF_SWINF_3_STA, |
| }; |
| |
| static int mt6885_regs[] = { |
| [PMIF_INIT_DONE] = 0x0000, |
| [PMIF_INF_EN] = 0x0024, |
| [PMIF_INF_CMD_PER_0] = 0x002c, |
| [PMIF_INF_CMD_PER_1] = 0x0030, |
| [PMIF_INF_CMD_PER_2] = 0x0034, |
| [PMIF_INF_CMD_PER_3] = 0x0038, |
| [PMIF_INF_MAX_BYTECNT_PER_0] = 0x003c, |
| [PMIF_INF_MAX_BYTECNT_PER_1] = 0x0040, |
| [PMIF_INF_MAX_BYTECNT_PER_2] = 0x0044, |
| [PMIF_INF_MAX_BYTECNT_PER_3] = 0x0048, |
| [PMIF_ARB_EN] = 0x0150, |
| [PMIF_CMDISSUE_EN] = 0x03B4, |
| [PMIF_TIMER_CTRL] = 0x03E0, |
| [PMIF_SPI_MODE_CTRL] = 0x0400, |
| [PMIF_IRQ_EVENT_EN_0] = 0x0418, |
| [PMIF_IRQ_FLAG_0] = 0x0420, |
| [PMIF_IRQ_CLR_0] = 0x0424, |
| [PMIF_SWINF_0_ACC] = 0x0C00, |
| [PMIF_SWINF_0_WDATA_31_0] = 0x0C04, |
| [PMIF_SWINF_0_WDATA_63_32] = 0x0C08, |
| [PMIF_SWINF_0_RDATA_31_0] = 0x0C14, |
| [PMIF_SWINF_0_RDATA_63_32] = 0x0C18, |
| [PMIF_SWINF_0_VLD_CLR] = 0x0C24, |
| [PMIF_SWINF_0_STA] = 0x0C28, |
| [PMIF_SWINF_1_ACC] = 0x0C40, |
| [PMIF_SWINF_1_WDATA_31_0] = 0x0C44, |
| [PMIF_SWINF_1_WDATA_63_32] = 0x0C48, |
| [PMIF_SWINF_1_RDATA_31_0] = 0x0C54, |
| [PMIF_SWINF_1_RDATA_63_32] = 0x0C58, |
| [PMIF_SWINF_1_VLD_CLR] = 0x0C64, |
| [PMIF_SWINF_1_STA] = 0x0C68, |
| [PMIF_SWINF_2_ACC] = 0x0C80, |
| [PMIF_SWINF_2_WDATA_31_0] = 0x0C84, |
| [PMIF_SWINF_2_WDATA_63_32] = 0x0C88, |
| [PMIF_SWINF_2_RDATA_31_0] = 0x0C94, |
| [PMIF_SWINF_2_RDATA_63_32] = 0x0C98, |
| [PMIF_SWINF_2_VLD_CLR] = 0x0CA4, |
| [PMIF_SWINF_2_STA] = 0x0CA8, |
| [PMIF_SWINF_3_ACC] = 0x0CC0, |
| [PMIF_SWINF_3_WDATA_31_0] = 0x0CC4, |
| [PMIF_SWINF_3_WDATA_63_32] = 0x0CC8, |
| [PMIF_SWINF_3_RDATA_31_0] = 0x0CD4, |
| [PMIF_SWINF_3_RDATA_63_32] = 0x0CD8, |
| [PMIF_SWINF_3_VLD_CLR] = 0x0CE4, |
| [PMIF_SWINF_3_STA] = 0x0CE8, |
| }; |
| |
| #if defined(CHIP10992) |
| static int mt6880_regs[] = { |
| [PMIF_INIT_DONE] = 0x0000, |
| [PMIF_INF_EN] = 0x0024, |
| [PMIF_INF_CMD_PER_0] = 0x002c, |
| [PMIF_INF_CMD_PER_1] = 0x0030, |
| [PMIF_INF_CMD_PER_2] = 0x0034, |
| [PMIF_INF_CMD_PER_3] = 0x0038, |
| [PMIF_INF_MAX_BYTECNT_PER_0] = 0x003c, |
| [PMIF_INF_MAX_BYTECNT_PER_1] = 0x0040, |
| [PMIF_INF_MAX_BYTECNT_PER_2] = 0x0044, |
| [PMIF_INF_MAX_BYTECNT_PER_3] = 0x0048, |
| [PMIF_ARB_EN] = 0x0150, |
| [PMIF_CMDISSUE_EN] = 0x03B8, |
| [PMIF_TIMER_CTRL] = 0x03E4, |
| [PMIF_SPI_MODE_CTRL] = 0x0408, |
| [PMIF_IRQ_EVENT_EN_0] = 0x0420, |
| [PMIF_IRQ_FLAG_0] = 0x0428, |
| [PMIF_IRQ_CLR_0] = 0x042C, |
| [PMIF_SWINF_0_ACC] = 0x0800, |
| [PMIF_SWINF_0_WDATA_31_0] = 0x0804, |
| [PMIF_SWINF_0_RDATA_31_0] = 0x0814, |
| [PMIF_SWINF_0_VLD_CLR] = 0x0824, |
| [PMIF_SWINF_0_STA] = 0x0828, |
| [PMIF_SWINF_1_ACC] = 0x0840, |
| [PMIF_SWINF_1_WDATA_31_0] = 0x0844, |
| [PMIF_SWINF_1_RDATA_31_0] = 0x0854, |
| [PMIF_SWINF_1_VLD_CLR] = 0x0864, |
| [PMIF_SWINF_1_STA] = 0x0868, |
| [PMIF_SWINF_2_ACC] = 0x0880, |
| [PMIF_SWINF_2_WDATA_31_0] = 0x0884, |
| [PMIF_SWINF_2_RDATA_31_0] = 0x0894, |
| [PMIF_SWINF_2_VLD_CLR] = 0x08A4, |
| [PMIF_SWINF_2_STA] = 0x08A8, |
| [PMIF_SWINF_3_ACC] = 0x08C0, |
| [PMIF_SWINF_3_WDATA_31_0] = 0x08C4, |
| [PMIF_SWINF_3_RDATA_31_0] = 0x08D4, |
| [PMIF_SWINF_3_VLD_CLR] = 0x08E4, |
| [PMIF_SWINF_3_STA] = 0x08E8, |
| }; |
| #else |
| static int mt6853_regs[] = { |
| [PMIF_INIT_DONE] = 0x0000, |
| [PMIF_INF_EN] = 0x0024, |
| [PMIF_INF_CMD_PER_0] = 0x002c, |
| [PMIF_INF_CMD_PER_1] = 0x0030, |
| [PMIF_INF_CMD_PER_2] = 0x0034, |
| [PMIF_INF_CMD_PER_3] = 0x0038, |
| [PMIF_INF_MAX_BYTECNT_PER_0] = 0x003c, |
| [PMIF_INF_MAX_BYTECNT_PER_1] = 0x0040, |
| [PMIF_INF_MAX_BYTECNT_PER_2] = 0x0044, |
| [PMIF_INF_MAX_BYTECNT_PER_3] = 0x0048, |
| [PMIF_ARB_EN] = 0x0150, |
| [PMIF_CMDISSUE_EN] = 0x03B8, |
| [PMIF_TIMER_CTRL] = 0x03E4, |
| [PMIF_SPI_MODE_CTRL] = 0x0408, |
| [PMIF_IRQ_EVENT_EN_0] = 0x0420, |
| [PMIF_IRQ_FLAG_0] = 0x0428, |
| [PMIF_IRQ_CLR_0] = 0x042C, |
| [PMIF_SWINF_0_ACC] = 0x0C00, |
| [PMIF_SWINF_0_WDATA_31_0] = 0x0C04, |
| [PMIF_SWINF_0_WDATA_63_32] = 0x0C08, |
| [PMIF_SWINF_0_RDATA_31_0] = 0x0C14, |
| [PMIF_SWINF_0_RDATA_63_32] = 0x0C18, |
| [PMIF_SWINF_0_VLD_CLR] = 0x0C24, |
| [PMIF_SWINF_0_STA] = 0x0C28, |
| [PMIF_SWINF_1_ACC] = 0x0C40, |
| [PMIF_SWINF_1_WDATA_31_0] = 0x0C44, |
| [PMIF_SWINF_1_WDATA_63_32] = 0x0C48, |
| [PMIF_SWINF_1_RDATA_31_0] = 0x0C54, |
| [PMIF_SWINF_1_RDATA_63_32] = 0x0C58, |
| [PMIF_SWINF_1_VLD_CLR] = 0x0C64, |
| [PMIF_SWINF_1_STA] = 0x0C68, |
| [PMIF_SWINF_2_ACC] = 0x0C80, |
| [PMIF_SWINF_2_WDATA_31_0] = 0x0C84, |
| [PMIF_SWINF_2_WDATA_63_32] = 0x0C88, |
| [PMIF_SWINF_2_RDATA_31_0] = 0x0C94, |
| [PMIF_SWINF_2_RDATA_63_32] = 0x0C98, |
| [PMIF_SWINF_2_VLD_CLR] = 0x0CA4, |
| [PMIF_SWINF_2_STA] = 0x0CA8, |
| [PMIF_SWINF_3_ACC] = 0x0CC0, |
| [PMIF_SWINF_3_WDATA_31_0] = 0x0CC4, |
| [PMIF_SWINF_3_WDATA_63_32] = 0x0CC8, |
| [PMIF_SWINF_3_RDATA_31_0] = 0x0CD4, |
| [PMIF_SWINF_3_RDATA_63_32] = 0x0CD8, |
| [PMIF_SWINF_3_VLD_CLR] = 0x0CE4, |
| [PMIF_SWINF_3_STA] = 0x0CE8, |
| }; |
| #endif |
| |
| static struct pmif pmif_spmi_arb[] = { |
| { |
| .base = (unsigned int *)PMIF_SPMI_BASE, |
| .regs = mt6885_regs, |
| .spmimst_base = (unsigned int *)SPMI_MST_BASE, |
| .swinf_ch_start = PMIF_SWINF_0_CHAN_NO, |
| .swinf_no = PMIF_AP_SWINF_NO, |
| .write = 0x0, |
| .mstid = SPMI_MASTER_0, |
| .pmifid = PMIF_PMIFID, |
| .read_cmd = pmif_spmi_read_cmd, |
| .write_cmd = pmif_spmi_write_cmd, |
| .pmif_enable_clk_set = pmif_spmi_enable_clk_set, |
| .pmif_force_normal_mode = pmif_spmi_force_normal_mode, |
| .pmif_enable_swinf = pmif_spmi_enable_swinf, |
| .pmif_enable_cmdIssue = pmif_spmi_enable_cmdIssue, |
| .pmif_enable = pmif_spmi_enable, |
| .is_pmif_init_done = is_pmif_spmi_init_done, |
| }, |
| { |
| .base = (unsigned int *)PMIF_SPMI_BASE, |
| #if defined(CHIP10992) |
| .regs = mt6880_regs, |
| #else |
| .regs = mt6853_regs, |
| #endif |
| .spmimst_base = (unsigned int *)SPMI_MST_BASE, |
| .swinf_ch_start = PMIF_SWINF_0_CHAN_NO, |
| .swinf_no = PMIF_AP_SWINF_NO, |
| .write = 0x0, |
| .mstid = SPMI_MASTER_1, |
| .pmifid = PMIF_PMIFID, |
| .read_cmd = pmif_spmi_read_cmd, |
| .write_cmd = pmif_spmi_write_cmd, |
| .pmif_enable_clk_set = pmif_spmi_enable_clk_set, |
| .pmif_force_normal_mode = pmif_spmi_force_normal_mode, |
| .pmif_enable_swinf = pmif_spmi_enable_swinf, |
| .pmif_enable_cmdIssue = pmif_spmi_enable_cmdIssue, |
| .pmif_enable = pmif_spmi_enable, |
| .is_pmif_init_done = is_pmif_spmi_init_done, |
| }, |
| #if !defined(MT6885) && !defined(MT6873) |
| { |
| .base = (unsigned int *)PMIF_SPMI_P_BASE, |
| #if defined(CHIP10992) |
| .regs = mt6880_regs, |
| #else |
| .regs = mt6853_regs, |
| #endif |
| .spmimst_base = (unsigned int *)SPMI_MST_P_BASE, |
| .swinf_ch_start = PMIF_SWINF_0_CHAN_NO_P, |
| .swinf_no = PMIF_AP_SWINF_NO_P, |
| .write = 0x0, |
| .mstid = SPMI_MASTER_P_1, |
| .pmifid = PMIF_PMIFID_2, |
| .read_cmd = pmif_spmi_read_cmd, |
| .write_cmd = pmif_spmi_write_cmd, |
| .pmif_enable_clk_set = pmif_spmi_enable_clk_set, |
| .pmif_force_normal_mode = pmif_spmi_force_normal_mode, |
| .pmif_enable_swinf = pmif_spmi_enable_swinf, |
| .pmif_enable_cmdIssue = pmif_spmi_enable_cmdIssue, |
| .pmif_enable = pmif_spmi_enable, |
| .is_pmif_init_done = is_pmif_spmi_init_done, |
| }, |
| #endif |
| }; |
| /* static struct pmif pmif_spi_arb[0]; */ |
| |
| /* pmif timeout */ |
| #if PMIF_TIMEOUT |
| static unsigned long long pmif_get_current_time(void) |
| { |
| return gpt4_get_current_tick(); |
| } |
| |
| static int pmif_timeout_ns(unsigned long long start_time_ns, |
| unsigned long long timeout_time_ns) |
| { |
| return gpt4_timeout_tick(start_time_ns, timeout_time_ns); |
| } |
| |
| static unsigned long long pmif_time2ns(unsigned long long time_us) |
| { |
| return gpt4_time2tick_us(time_us); |
| } |
| #endif |
| static inline unsigned int pmif_check_idle(int mstid) { |
| struct pmif *arb = get_pmif_controller(PMIF_SPMI, mstid); |
| unsigned int reg_rdata, offset = 0; |
| #if PMIF_TIMEOUT |
| unsigned long long start_time_ns = 0, end_time_ns = 0, timeout_ns = 0; |
| unsigned long time_cnt = 100000; |
| |
| start_time_ns = pmif_get_current_time(); |
| timeout_ns = pmif_time2ns(TIMEOUT_WAIT_IDLE); |
| #endif |
| |
| do { |
| #if PMIF_TIMEOUT |
| if (pmif_timeout_ns(start_time_ns, timeout_ns)) { |
| end_time_ns = pmif_get_current_time(); |
| PMIF_ERR("%s timeout %d %d\n", __func__, start_time_ns, |
| end_time_ns - start_time_ns); |
| return -ETIMEDOUT; |
| } |
| if ((time_cnt--) == 0) { |
| PMIF_ERR("%s timeout %d %d\n", __func__, start_time_ns, |
| end_time_ns - start_time_ns); |
| return -ETIMEDOUT; |
| } |
| #endif |
| offset = arb->regs[PMIF_SWINF_0_STA] + (0x40 * arb->swinf_no); |
| reg_rdata = DRV_Reg32(arb->base + offset); |
| } while(GET_SWINF_0_FSM(reg_rdata) != SWINF_FSM_IDLE); |
| |
| return 0; |
| } |
| |
| static inline unsigned int pmif_check_vldclr(int mstid) { |
| struct pmif *arb = get_pmif_controller(PMIF_SPMI, mstid); |
| unsigned int reg_rdata, offset = 0; |
| #if PMIF_TIMEOUT |
| unsigned long long start_time_ns = 0, end_time_ns = 0, timeout_ns = 0; |
| unsigned long time_cnt = 100000; |
| |
| start_time_ns = pmif_get_current_time(); |
| timeout_ns = pmif_time2ns(TIMEOUT_WAIT_IDLE); |
| #endif |
| |
| do { |
| #if PMIF_TIMEOUT |
| if (pmif_timeout_ns(start_time_ns, timeout_ns)) { |
| end_time_ns = pmif_get_current_time(); |
| PMIF_ERR("%s timeout %d %d\n", __func__, start_time_ns, |
| end_time_ns - start_time_ns); |
| return -ETIMEDOUT; |
| } |
| if ((time_cnt--) == 0) { |
| PMIF_ERR("%s timeout %d %d\n", __func__, start_time_ns, |
| end_time_ns - start_time_ns); |
| return -ETIMEDOUT; |
| } |
| #endif |
| offset = arb->regs[PMIF_SWINF_0_STA] + (0x40 * arb->swinf_no); |
| reg_rdata = DRV_Reg32(arb->base + offset); |
| } while(GET_SWINF_0_FSM(reg_rdata) != SWINF_FSM_WFVLDCLR); |
| |
| return 0; |
| } |
| static void pmif_enable_soft_reset(int mstid) |
| { |
| DRV_WriteReg32(INFRA_GLOBALCON_RST2_SET, 0x1 << 14); |
| DRV_WriteReg32(INFRA_GLOBALCON_RST2_CLR, 0x1 << 14); |
| |
| PMIF_INFO("%s done\n", __func__); |
| } |
| |
| static void pmif_spmi_enable_clk_set(int mstid) |
| { |
| #if !defined(CONFIG_FPGA_EARLY_PORTING) |
| /* TBD */ |
| DRV_WriteReg32(CLK_CFG_8_CLR, (0x1 << 15) | (0x1 << 12) | (0x7 << 8)); |
| DRV_WriteReg32(CLK_CFG_UPDATE1, 0x1 << 2); |
| #endif |
| |
| /* sys_ck cg enable, turn off clock */ |
| DRV_WriteReg32(MODULE_SW_CG_0_SET, 0x0000000f); |
| /* turn off clock */ |
| DRV_WriteReg32(MODULE_SW_CG_2_SET, 0x00000100); |
| |
| /* toggle SPMI sw reset */ |
| pmif_enable_soft_reset(mstid); |
| |
| /* sys_ck cg enable, turn on clock */ |
| DRV_WriteReg32(MODULE_SW_CG_0_CLR, 0x0000000f); |
| /* turn on clock */ |
| DRV_WriteReg32(MODULE_SW_CG_2_CLR, 0x00000100); |
| |
| PMIF_INFO("%s done\n", __func__); |
| } |
| |
| static void pmif_spmi_force_normal_mode(int mstid) |
| { |
| struct pmif *arb = get_pmif_controller(PMIF_SPMI, SPMI_MASTER_0); |
| unsigned int offset = 0; |
| |
| /* Force SPMI in normal mode. */ |
| offset = arb->regs[PMIF_SPI_MODE_CTRL]; |
| DRV_WriteReg32(arb->base + offset, |
| DRV_Reg32(arb->base + offset) & (~(0x3 << 9))); |
| DRV_WriteReg32(arb->base + offset, |
| DRV_Reg32(arb->base + offset) | (0x1 << 9)); |
| |
| PMIF_INFO("%s done\n", __func__); |
| } |
| |
| static void pmif_spmi_enable_swinf(int mstid, unsigned int chan_no, |
| unsigned int swinf_no) |
| { |
| struct pmif *arb = get_pmif_controller(PMIF_SPMI, mstid); |
| unsigned int offset = 0; |
| |
| /* Enable swinf */ |
| offset = arb->regs[PMIF_INF_EN]; |
| DRV_WriteReg32(arb->base + offset, |
| 0x1 << (arb->swinf_ch_start + arb->swinf_no)); |
| |
| /* Enable arbitration */ |
| offset = arb->regs[PMIF_ARB_EN]; |
| DRV_WriteReg32(arb->base + offset, |
| 0x1 << (arb->swinf_ch_start + arb->swinf_no)); |
| |
| PMIF_INFO("%s done\n", __func__); |
| } |
| |
| static void pmif_spmi_enable_cmdIssue(int mstid, kal_bool en) |
| { |
| struct pmif *arb = get_pmif_controller(PMIF_SPMI, mstid); |
| |
| /* Enable cmdIssue */ |
| DRV_WriteReg32(arb->base + arb->regs[PMIF_CMDISSUE_EN], en); |
| |
| PMIF_INFO("%s done\n", __func__); |
| } |
| |
| static void pmif_spmi_enable(int mstid) |
| { |
| struct pmif *arb = get_pmif_controller(PMIF_SPMI, mstid); |
| #if PMIF_NORMAL_BOOT |
| unsigned int bytecnt_per = 0, hw_bytecnt = 0; |
| unsigned int cmd_per = 0; |
| |
| /* clear all cmd permission for per channel */ |
| DRV_WriteReg32(arb->base + arb->regs[PMIF_INF_CMD_PER_0], 0); |
| DRV_WriteReg32(arb->base + arb->regs[PMIF_INF_CMD_PER_1], 0); |
| DRV_WriteReg32(arb->base + arb->regs[PMIF_INF_CMD_PER_2], 0); |
| DRV_WriteReg32(arb->base + arb->regs[PMIF_INF_CMD_PER_3], 0); |
| /* enable if we need cmd 0~3 permission for per channel */ |
| cmd_per = PMIF_CMD_PER_3 << 28 | PMIF_CMD_PER_3 << 24 | |
| PMIF_CMD_PER_3 << 20 | PMIF_CMD_PER_1_3 << 16 | |
| PMIF_CMD_PER_3 << 8 | PMIF_CMD_PER_1_3 << 0; |
| DRV_WriteReg32(arb->base + arb->regs[PMIF_INF_CMD_PER_0], cmd_per); |
| cmd_per = PMIF_CMD_PER_3 << 4; |
| DRV_WriteReg32(arb->base + arb->regs[PMIF_INF_CMD_PER_1], cmd_per); |
| |
| /* set bytecnt max limitation*/ |
| DRV_WriteReg32(arb->base + arb->regs[PMIF_INF_MAX_BYTECNT_PER_0], 0); |
| DRV_WriteReg32(arb->base + arb->regs[PMIF_INF_MAX_BYTECNT_PER_1], 0); |
| DRV_WriteReg32(arb->base + arb->regs[PMIF_INF_MAX_BYTECNT_PER_2], 0); |
| DRV_WriteReg32(arb->base + arb->regs[PMIF_INF_MAX_BYTECNT_PER_3], 0); |
| /* hw bytecnt indicate when we set 0, it can send 1 byte; |
| * set 1, it can send 2 byte. |
| */ |
| hw_bytecnt = PMIF_BYTECNT_MAX -1; |
| if (hw_bytecnt > 0) { |
| bytecnt_per = hw_bytecnt << 28 | hw_bytecnt << 24 | |
| hw_bytecnt << 20 | hw_bytecnt << 16 | |
| hw_bytecnt << 12 | hw_bytecnt << 8 | |
| hw_bytecnt << 4 | hw_bytecnt << 0; |
| } |
| DRV_WriteReg32(arb->base + arb->regs[PMIF_INF_MAX_BYTECNT_PER_0], |
| bytecnt_per); |
| DRV_WriteReg32(arb->base + arb->regs[PMIF_INF_MAX_BYTECNT_PER_1], |
| bytecnt_per); |
| DRV_WriteReg32(arb->base + arb->regs[PMIF_INF_MAX_BYTECNT_PER_2], |
| bytecnt_per); |
| DRV_WriteReg32(arb->base + arb->regs[PMIF_INF_MAX_BYTECNT_PER_3], |
| bytecnt_per); |
| #endif /* end of #if PMIF_NORMAL_BOOT */ |
| DRV_WriteReg32(arb->base + arb->regs[PMIF_INF_EN], 0x2F5); |
| DRV_WriteReg32(arb->base + arb->regs[PMIF_ARB_EN], 0x2F5); |
| DRV_WriteReg32(arb->base + arb->regs[PMIF_TIMER_CTRL], 0x3); |
| DRV_WriteReg32(arb->base + arb->regs[PMIF_INIT_DONE], 0x1); |
| |
| PMIF_INFO("%s done\n", __func__); |
| } |
| |
| static int pmif_spmi_read_cmd(struct pmif *arb, unsigned char opc, |
| unsigned char sid, unsigned short addr, unsigned char *buf, |
| unsigned short len) |
| { |
| int write = 0x0; |
| unsigned int ret = 0, offset = 0, data = 0; |
| unsigned char bc = len - 1; |
| |
| if ((sid & ~(0xf)) != 0x0) |
| return -EINVAL; |
| |
| if (len > PMIF_BYTECNT_MAX) |
| return -EINVAL; |
| |
| /* Check the opcode */ |
| if (opc >= 0x60 && opc <= 0x7F) |
| opc = PMIF_CMD_REG; |
| else if (opc >= 0x20 && opc <= 0x2F) |
| opc = PMIF_CMD_EXT_REG; |
| else if (opc >= 0x38 && opc <= 0x3F) |
| opc = PMIF_CMD_EXT_REG_LONG; |
| else |
| return -EINVAL; |
| |
| /* ENTER_CRITICAL(); */ |
| kal_hrt_take_itc_lock(KAL_ITC_SPMI_LOCK, KAL_INFINITE_WAIT); |
| |
| /* Wait for Software Interface FSM state to be IDLE. */ |
| ret = pmif_check_idle(arb->mstid); |
| if(ret) |
| return ret; |
| |
| /* Send the command. */ |
| offset = arb->regs[PMIF_SWINF_0_ACC] + (0x40 * arb->swinf_no); |
| DRV_WriteReg32(arb->base + offset, |
| (opc << 30) | (write << 29) | (sid << 24) | (bc << 16) | addr); |
| |
| /* Wait for Software Interface FSM state to be WFVLDCLR, |
| * |
| * read the data and clear the valid flag. |
| */ |
| if(write == 0) |
| { |
| ret = pmif_check_vldclr(arb->mstid); |
| if(ret) |
| return ret; |
| |
| offset = |
| arb->regs[PMIF_SWINF_0_RDATA_31_0] + (0x40 * arb->swinf_no); |
| data = DRV_Reg32(arb->base + offset); |
| memcpy(buf, &data, (bc & 3) + 1); |
| offset = |
| arb->regs[PMIF_SWINF_0_VLD_CLR] + (0x40 * arb->swinf_no); |
| DRV_WriteReg32(arb->base + offset, 0x1); |
| } |
| kal_hrt_give_itc_lock(KAL_ITC_SPMI_LOCK); |
| /* EXIT_CRITICAL(); */ |
| |
| return 0x0; |
| } |
| |
| static int pmif_spmi_write_cmd(struct pmif *arb, unsigned char opc, |
| unsigned char sid, unsigned short addr, const unsigned char *buf, |
| unsigned short len) |
| { |
| int write = 0x1; |
| unsigned int ret = 0, offset = 0, data = 0; |
| unsigned char bc = len - 1; |
| |
| if ((sid & ~(0xf)) != 0x0) |
| return -EINVAL; |
| |
| if (len > PMIF_BYTECNT_MAX) |
| return -EINVAL; |
| |
| /* Check the opcode */ |
| if (opc >= 0x40 && opc <= 0x5F) |
| opc = PMIF_CMD_REG; |
| else if (opc <= 0x0F) |
| opc = PMIF_CMD_EXT_REG; |
| else if (opc >= 0x30 && opc <= 0x37) |
| opc = PMIF_CMD_EXT_REG_LONG; |
| else if (opc >= 0x80) |
| opc = PMIF_CMD_REG_0; |
| else |
| return -EINVAL; |
| |
| /* ENTER_CRITICAL(); */ |
| kal_hrt_take_itc_lock(KAL_ITC_SPMI_LOCK, KAL_INFINITE_WAIT); |
| |
| /* Wait for Software Interface FSM state to be IDLE. */ |
| ret = pmif_check_idle(arb->mstid); |
| if(ret) |
| return ret; |
| |
| /* Set the write data. */ |
| if (write == 1) |
| { |
| offset = |
| arb->regs[PMIF_SWINF_0_WDATA_31_0] + (0x40 * arb->swinf_no); |
| memcpy(&data, buf, (bc & 3) + 1); |
| DRV_WriteReg32(arb->base + offset, data); |
| } |
| /* Send the command. */ |
| offset = arb->regs[PMIF_SWINF_0_ACC] + (0x40 * arb->swinf_no); |
| DRV_WriteReg32(arb->base + offset, |
| (opc << 30) | (write << 29) | (sid << 24) | |
| (bc << 16) | addr); |
| |
| kal_hrt_give_itc_lock(KAL_ITC_SPMI_LOCK); |
| /* EXIT_CRITICAL(); */ |
| |
| return 0x0; |
| } |
| |
| struct pmif *get_pmif_controller(int inf, int mstid) |
| { |
| if (inf == PMIF_SPMI) { |
| return &pmif_spmi_arb[mstid]; |
| } else if (inf == PMIF_SPI) { |
| /* TBD |
| *pmif_spi_arb[mstid].base = (unsigned int *)PMIF_SPI_BASE; |
| *pmif_spi_arb[mstid].swinf_no = 0x0; |
| *pmif_spi_arb[mstid].write = 0x0; |
| *pmif_spi_arb[mstid].pmifid = 0x0; |
| *pmif_spi_arb[mstid].read_cmd = pmif_spi_read_cmd; |
| *pmif_spi_arb[mstid].write_cmd = pmif_spi_write_cmd; |
| *pmif_spi_arb[mstid].read_cmd_nochk = pmif_spi_read_cmd_nochk; |
| *pmif_spi_arb[mstid].write_cmd_nochk = |
| * pmif_spi_write_cmd_nochk; |
| *return &pmif_spi_arb[mstid]; |
| */ |
| } |
| |
| return 0; |
| } |
| int is_pmif_spmi_init_done(int mstid) |
| { |
| int ret = 0; |
| |
| struct pmif *arb = get_pmif_controller(PMIF_SPMI, mstid); |
| |
| ret = DRV_Reg32(arb->base + arb->regs[PMIF_INIT_DONE]); |
| PMIF_INFO("%s ret = %d\n", __func__, ret); |
| if ((ret & 0x1) == 1) |
| return 0; |
| |
| return -ENODEV; |
| } |
| |
| int pmif_spmi_init(int mstid) |
| { |
| struct pmif *arb = get_pmif_controller(PMIF_SPMI, mstid); |
| int ret = 0; |
| |
| INIT_CRITICAL(); |
| |
| if (is_pmif_spmi_init_done(mstid) != 0) { |
| arb->pmif_enable_clk_set(mstid); |
| arb->pmif_force_normal_mode(mstid); |
| /* Enable SWINF and arbitration for AP. */ |
| arb->pmif_enable_swinf(mstid, PMIF_SWINF_0_CHAN_NO, |
| PMIF_AP_SWINF_NO); |
| arb->pmif_enable_cmdIssue(mstid,KAL_TRUE); |
| |
| arb->pmif_enable(mstid); |
| ret = arb->is_pmif_init_done(mstid); |
| if(ret) { |
| PMIF_ERR("init done check fail\n"); |
| return -ENODEV; |
| } |
| } |
| |
| ret = spmi_init(arb); |
| if(ret) { |
| PMIF_ERR("init fail\n"); |
| return -ENODEV; |
| } |
| |
| return 0; |
| } |
| |
| #endif /* endif PMIF_NO_PMIC */ |