1089 lines
29 KiB
C
1089 lines
29 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
/*
|
|
* Copyright (c) 2019 MediaTek Inc.
|
|
*/
|
|
|
|
#include <linux/delay.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/irq.h>
|
|
#include <linux/of.h>
|
|
#include <linux/of_fdt.h>
|
|
#include <linux/of_irq.h>
|
|
#include <linux/of_address.h>
|
|
#include "ccci_config.h"
|
|
#include <linux/clk.h>
|
|
#include <mtk_pbm.h>
|
|
|
|
#ifdef FEATURE_CLK_BUF
|
|
#include <mtk_clkbuf_ctl.h>
|
|
#endif
|
|
#ifdef CONFIG_MTK_EMI_BWL
|
|
#include <emi_mbw.h>
|
|
#endif
|
|
|
|
#ifdef FEATURE_INFORM_NFC_VSIM_CHANGE
|
|
#include <mach/mt6605.h>
|
|
#endif
|
|
|
|
#include "include/pmic_api_buck.h"
|
|
#include <mt-plat/upmu_common.h>
|
|
#include <mtk_spm_sleep.h>
|
|
|
|
#ifdef CONFIG_MTK_QOS_SUPPORT
|
|
#include <linux/pm_qos.h>
|
|
#include <helio-dvfsrc-opp.h>
|
|
#endif
|
|
#ifdef CCCI_PLATFORM_MT6877
|
|
#include <clk-mt6877-pg.h>
|
|
#else
|
|
#include <clk-mt6853-pg.h>
|
|
#endif
|
|
#include "ccci_core.h"
|
|
#include "ccci_platform.h"
|
|
|
|
#include "md_sys1_platform.h"
|
|
#include "modem_secure_base.h"
|
|
#include "modem_reg_base.h"
|
|
#ifdef CCCI_PLATFORM_MT6877
|
|
#include "ap_md_reg_dump_6877.h"
|
|
#else
|
|
#include "ap_md_reg_dump.h"
|
|
#endif
|
|
#include <devapc_public.h>
|
|
#include "ccci_fsm.h"
|
|
#include "hif/ccci_hif_dpmaif.h"
|
|
|
|
static struct ccci_clk_node clk_table[] = {
|
|
{ NULL, "scp-sys-md1-main"},
|
|
};
|
|
|
|
extern unsigned int devapc_check_flag;
|
|
extern spinlock_t devapc_flag_lock;
|
|
|
|
#define TAG "mcd"
|
|
|
|
#define ROr2W(a, b, c) ccci_write32(a, b, (ccci_read32(a, b)|c))
|
|
#define RAnd2W(a, b, c) ccci_write32(a, b, (ccci_read32(a, b)&c))
|
|
#define RabIsc(a, b, c) ((ccci_read32(a, b)&c) != c)
|
|
|
|
static int md_cd_io_remap_md_side_register(struct ccci_modem *md);
|
|
static void md_cd_dump_debug_register(struct ccci_modem *md);
|
|
static void md_cd_dump_md_bootup_status(struct ccci_modem *md);
|
|
static void md_cd_get_md_bootup_status(struct ccci_modem *md,
|
|
unsigned int *buff, int length);
|
|
static void md_cd_check_emi_state(struct ccci_modem *md, int polling);
|
|
static int md_start_platform(struct ccci_modem *md);
|
|
static int md_cd_power_on(struct ccci_modem *md);
|
|
static int md_cd_power_off(struct ccci_modem *md, unsigned int timeout);
|
|
static int md_cd_soft_power_off(struct ccci_modem *md, unsigned int mode);
|
|
static int md_cd_soft_power_on(struct ccci_modem *md, unsigned int mode);
|
|
static int md_cd_let_md_go(struct ccci_modem *md);
|
|
static void md_cd_lock_cldma_clock_src(int locked);
|
|
static void md_cd_lock_modem_clock_src(int locked);
|
|
|
|
static struct ccci_plat_ops md_cd_plat_ptr = {
|
|
#ifdef CCCI_PLATFORM_MT6877
|
|
.md_dump_reg = &md_dump_register_6877,
|
|
#else
|
|
.md_dump_reg = &internal_md_dump_debug_register,
|
|
#endif
|
|
.remap_md_reg = &md_cd_io_remap_md_side_register,
|
|
.lock_cldma_clock_src = &md_cd_lock_cldma_clock_src,
|
|
.lock_modem_clock_src = &md_cd_lock_modem_clock_src,
|
|
.dump_md_bootup_status = &md_cd_dump_md_bootup_status,
|
|
.get_md_bootup_status = &md_cd_get_md_bootup_status,
|
|
.debug_reg = &md_cd_dump_debug_register,
|
|
.check_emi_state = &md_cd_check_emi_state,
|
|
.soft_power_off = &md_cd_soft_power_off,
|
|
.soft_power_on = &md_cd_soft_power_on,
|
|
.start_platform = &md_start_platform,
|
|
.power_on = &md_cd_power_on,
|
|
.let_md_go = &md_cd_let_md_go,
|
|
.power_off = &md_cd_power_off,
|
|
.vcore_config = NULL,
|
|
};
|
|
static int s_md_start_completed;
|
|
|
|
int ccif_read32(void *b, unsigned long a)
|
|
{
|
|
unsigned long flags;
|
|
int ret = 0;
|
|
|
|
spin_lock_irqsave(&devapc_flag_lock, flags);
|
|
ret = ((devapc_check_flag == 1) ?
|
|
ioread32((void __iomem *)((b)+(a))) : 0);
|
|
spin_unlock_irqrestore(&devapc_flag_lock, flags);
|
|
|
|
return ret;
|
|
}
|
|
|
|
void md1_subsys_debug_dump(enum subsys_id sys)
|
|
{
|
|
struct ccci_modem *md = NULL;
|
|
|
|
if (sys != 0)
|
|
return;
|
|
/* add debug dump */
|
|
|
|
CCCI_NORMAL_LOG(0, TAG, "%s\n", __func__);
|
|
md = ccci_md_get_modem_by_id(0);
|
|
if (md != NULL) {
|
|
CCCI_NORMAL_LOG(0, TAG, "%s dump start\n", __func__);
|
|
md->ops->dump_info(md, DUMP_FLAG_CCIF_REG | DUMP_FLAG_CCIF |
|
|
DUMP_FLAG_REG | DUMP_FLAG_QUEUE_0_1 |
|
|
DUMP_MD_BOOTUP_STATUS, NULL, 0);
|
|
mdelay(1000);
|
|
md->ops->dump_info(md, DUMP_FLAG_REG, NULL, 0);
|
|
}
|
|
CCCI_NORMAL_LOG(0, TAG, "%s exit\n", __func__);
|
|
}
|
|
|
|
struct pg_callbacks md1_subsys_handle = {
|
|
.debug_dump = md1_subsys_debug_dump,
|
|
};
|
|
|
|
/*devapc_violation_triggered*/
|
|
/* need fix, avoid build error, use option */
|
|
#if IS_ENABLED(CONFIG_MTK_DEVAPC) && !IS_ENABLED(CONFIG_DEVAPC_LEGACY)
|
|
static enum devapc_cb_status devapc_dump_adv_cb(uint32_t vio_addr)
|
|
{
|
|
int count;
|
|
|
|
CCCI_NORMAL_LOG(0, TAG,
|
|
"[%s] vio_addr: 0x%x; is normal mdee: %d\n",
|
|
__func__, vio_addr, ccci_fsm_is_normal_mdee());
|
|
|
|
if (ccci_fsm_get_md_state(0) == EXCEPTION &&
|
|
ccci_fsm_is_normal_mdee()) {
|
|
count = ccci_fsm_increase_devapc_dump_counter();
|
|
|
|
CCCI_NORMAL_LOG(0, TAG,
|
|
"[%s] count: %d\n", __func__, count);
|
|
|
|
if (count == 1)
|
|
ccci_md_dump_in_interrupt((char *)__func__);
|
|
|
|
return DEVAPC_NOT_KE;
|
|
|
|
} else {
|
|
ccci_md_dump_in_interrupt((char *)__func__);
|
|
|
|
return DEVAPC_OK;
|
|
}
|
|
}
|
|
|
|
static struct devapc_vio_callbacks devapc_test_handle = {
|
|
.id = INFRA_SUBSYS_MD,
|
|
.debug_dump_adv = devapc_dump_adv_cb,
|
|
};
|
|
|
|
void __weak register_devapc_vio_callback(
|
|
struct devapc_vio_callbacks *viocb)
|
|
{
|
|
CCCI_ERROR_LOG(-1, TAG, "[%s] is not supported!\n", __func__);
|
|
}
|
|
|
|
void ccci_md_devapc_register_cb(void)
|
|
{
|
|
/*register handle function*/
|
|
register_devapc_vio_callback(&devapc_test_handle);
|
|
}
|
|
#endif
|
|
|
|
void ccci_md_dump_in_interrupt(char *user_info)
|
|
{
|
|
struct ccci_modem *md = NULL;
|
|
|
|
CCCI_NORMAL_LOG(0, TAG, "%s called by %s\n", __func__, user_info);
|
|
md = ccci_md_get_modem_by_id(0);
|
|
if (md != NULL) {
|
|
CCCI_NORMAL_LOG(0, TAG, "%s dump start\n", __func__);
|
|
md->ops->dump_info(md, DUMP_FLAG_CCIF_REG | DUMP_FLAG_CCIF |
|
|
DUMP_FLAG_REG | DUMP_FLAG_QUEUE_0_1 |
|
|
DUMP_MD_BOOTUP_STATUS, NULL, 0);
|
|
} else
|
|
CCCI_NORMAL_LOG(0, TAG, "%s error\n", __func__);
|
|
CCCI_NORMAL_LOG(0, TAG, "%s exit\n", __func__);
|
|
}
|
|
EXPORT_SYMBOL(ccci_md_dump_in_interrupt);
|
|
|
|
void ccci_md_debug_dump(char *user_info)
|
|
{
|
|
struct ccci_modem *md = NULL;
|
|
|
|
if (!s_md_start_completed) {
|
|
CCCI_ERROR_LOG(0, TAG,
|
|
"[%s] error: md start no call.\n", __func__);
|
|
return;
|
|
}
|
|
|
|
CCCI_NORMAL_LOG(0, TAG, "%s called by %s\n", __func__, user_info);
|
|
md = ccci_md_get_modem_by_id(0);
|
|
if (md != NULL) {
|
|
CCCI_NORMAL_LOG(0, TAG, "%s dump start\n", __func__);
|
|
md->ops->dump_info(md, DUMP_FLAG_CCIF_REG | DUMP_FLAG_CCIF |
|
|
DUMP_FLAG_REG | DUMP_FLAG_QUEUE_0_1 |
|
|
DUMP_MD_BOOTUP_STATUS, NULL, 0);
|
|
mdelay(1000);
|
|
md->ops->dump_info(md, DUMP_FLAG_REG, NULL, 0);
|
|
} else
|
|
CCCI_NORMAL_LOG(0, TAG, "%s error\n", __func__);
|
|
CCCI_NORMAL_LOG(0, TAG, "%s exit\n", __func__);
|
|
}
|
|
EXPORT_SYMBOL(ccci_md_debug_dump);
|
|
|
|
int md_cd_get_modem_hw_info(struct platform_device *dev_ptr,
|
|
struct ccci_dev_cfg *dev_cfg, struct md_hw_info *hw_info)
|
|
{
|
|
struct device_node *node = NULL;
|
|
int idx = 0;
|
|
int retval;
|
|
|
|
if (dev_ptr->dev.of_node == NULL) {
|
|
CCCI_ERROR_LOG(0, TAG, "modem OF node NULL\n");
|
|
return -1;
|
|
}
|
|
|
|
memset(dev_cfg, 0, sizeof(struct ccci_dev_cfg));
|
|
of_property_read_u32(dev_ptr->dev.of_node,
|
|
"mediatek,md_id", &dev_cfg->index);
|
|
CCCI_DEBUG_LOG(dev_cfg->index, TAG,
|
|
"modem hw info get idx:%d\n", dev_cfg->index);
|
|
if (!get_modem_is_enabled(dev_cfg->index)) {
|
|
CCCI_ERROR_LOG(dev_cfg->index, TAG,
|
|
"modem %d not enable, exit\n", dev_cfg->index + 1);
|
|
return -1;
|
|
}
|
|
|
|
switch (dev_cfg->index) {
|
|
case 0: /* MD_SYS1 */
|
|
dev_cfg->major = 0;
|
|
dev_cfg->minor_base = 0;
|
|
of_property_read_u32(dev_ptr->dev.of_node,
|
|
"mediatek,cldma_capability", &dev_cfg->capability);
|
|
|
|
hw_info->ap_ccif_base =
|
|
(unsigned long)of_iomap(dev_ptr->dev.of_node, 0);
|
|
hw_info->md_ccif_base =
|
|
(unsigned long)of_iomap(dev_ptr->dev.of_node, 1);
|
|
|
|
hw_info->md_wdt_irq_id =
|
|
irq_of_parse_and_map(dev_ptr->dev.of_node, 0);
|
|
hw_info->ap_ccif_irq0_id =
|
|
irq_of_parse_and_map(dev_ptr->dev.of_node, 1);
|
|
hw_info->ap_ccif_irq1_id =
|
|
irq_of_parse_and_map(dev_ptr->dev.of_node, 2);
|
|
|
|
hw_info->md_pcore_pccif_base =
|
|
ioremap_nocache(MD_PCORE_PCCIF_BASE, 0x20);
|
|
CCCI_BOOTUP_LOG(dev_cfg->index, TAG,
|
|
"pccif:%x\n", MD_PCORE_PCCIF_BASE);
|
|
|
|
/* Device tree using none flag to register irq,
|
|
* sensitivity has set at "irq_of_parse_and_map"
|
|
*/
|
|
hw_info->ap_ccif_irq0_flags = IRQF_TRIGGER_NONE;
|
|
hw_info->ap_ccif_irq1_flags = IRQF_TRIGGER_NONE;
|
|
hw_info->md_wdt_irq_flags = IRQF_TRIGGER_NONE;
|
|
|
|
hw_info->sram_size = CCIF_SRAM_SIZE;
|
|
hw_info->md_rgu_base = MD_RGU_BASE;
|
|
hw_info->md_boot_slave_En = MD_BOOT_VECTOR_EN;
|
|
of_property_read_u32(dev_ptr->dev.of_node,
|
|
"mediatek,md_generation", &md_cd_plat_val_ptr.md_gen);
|
|
node = of_find_compatible_node(NULL, NULL,
|
|
"mediatek,infracfg_ao");
|
|
md_cd_plat_val_ptr.infra_ao_base = of_iomap(node, 0);
|
|
|
|
hw_info->plat_ptr = &md_cd_plat_ptr;
|
|
hw_info->plat_val = &md_cd_plat_val_ptr;
|
|
if ((hw_info->plat_ptr == NULL) || (hw_info->plat_val == NULL))
|
|
return -1;
|
|
hw_info->plat_val->offset_epof_md1 = CCCI_EE_OFFSET_EPOF_MD1;
|
|
for (idx = 0; idx < ARRAY_SIZE(clk_table); idx++) {
|
|
clk_table[idx].clk_ref = devm_clk_get(&dev_ptr->dev,
|
|
clk_table[idx].clk_name);
|
|
if (IS_ERR(clk_table[idx].clk_ref)) {
|
|
CCCI_ERROR_LOG(dev_cfg->index, TAG,
|
|
"md%d get %s failed\n",
|
|
dev_cfg->index + 1,
|
|
clk_table[idx].clk_name);
|
|
clk_table[idx].clk_ref = NULL;
|
|
}
|
|
}
|
|
|
|
if (!IS_ERR(clk_table[0].clk_ref)) {
|
|
CCCI_BOOTUP_LOG(dev_cfg->index, TAG,
|
|
"dummy md sys clk\n");
|
|
retval = clk_prepare_enable(clk_table[0].clk_ref);
|
|
if (retval)
|
|
CCCI_ERROR_LOG(dev_cfg->index, TAG,
|
|
"error: enable mtcmos: ret: %d\n",
|
|
retval);
|
|
CCCI_BOOTUP_LOG(dev_cfg->index, TAG,
|
|
"dummy md sys clk done\n");
|
|
}
|
|
|
|
node = of_find_compatible_node(NULL, NULL,
|
|
"mediatek,md_ccif4");
|
|
if (node) {
|
|
hw_info->md_ccif4_base = of_iomap(node, 0);
|
|
if (!hw_info->md_ccif4_base) {
|
|
CCCI_ERROR_LOG(dev_cfg->index, TAG,
|
|
"ccif4_base fail: 0x%p!\n",
|
|
(void *)hw_info->md_ccif4_base);
|
|
return -1;
|
|
}
|
|
}
|
|
/* for ccif5 */
|
|
node = of_find_compatible_node(NULL, NULL,
|
|
"mediatek,md_ccif5");
|
|
if (node) {
|
|
hw_info->md_ccif5_base = of_iomap(node, 0);
|
|
if (!hw_info->md_ccif5_base) {
|
|
CCCI_ERROR_LOG(dev_cfg->index, TAG,
|
|
"ccif5_base fail: 0x%p!\n",
|
|
(void *)hw_info->md_ccif5_base);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
node = of_find_compatible_node(NULL, NULL,
|
|
"mediatek,topckgen");
|
|
if (node)
|
|
hw_info->ap_topclkgen_base = of_iomap(node, 0);
|
|
|
|
else {
|
|
CCCI_ERROR_LOG(-1, TAG,
|
|
"%s:ioremap topclkgen base address fail\n",
|
|
__func__);
|
|
return -1;
|
|
}
|
|
|
|
break;
|
|
default:
|
|
return -1;
|
|
}
|
|
|
|
if (hw_info->ap_ccif_base == 0 ||
|
|
hw_info->md_ccif_base == 0) {
|
|
CCCI_ERROR_LOG(dev_cfg->index, TAG,
|
|
"ap_ccif_base:0x%p, md_ccif_base:0x%p\n",
|
|
(void *)hw_info->ap_ccif_base,
|
|
(void *)hw_info->md_ccif_base);
|
|
return -1;
|
|
}
|
|
if (hw_info->ap_ccif_irq0_id == 0 ||
|
|
hw_info->ap_ccif_irq1_id == 0 ||
|
|
hw_info->md_wdt_irq_id == 0) {
|
|
CCCI_ERROR_LOG(dev_cfg->index, TAG,
|
|
"ccif_irq0:%d,ccif_irq0:%d,md_wdt_irq:%d\n",
|
|
hw_info->ap_ccif_irq0_id, hw_info->ap_ccif_irq1_id,
|
|
hw_info->md_wdt_irq_id);
|
|
return -1;
|
|
}
|
|
|
|
/* Get spm sleep base */
|
|
node = of_find_compatible_node(NULL, NULL, "mediatek,sleep");
|
|
hw_info->spm_sleep_base = (unsigned long)of_iomap(node, 0);
|
|
if (!hw_info->spm_sleep_base) {
|
|
CCCI_ERROR_LOG(0, TAG,
|
|
"%s: spm_sleep_base of_iomap failed\n",
|
|
__func__);
|
|
return -1;
|
|
}
|
|
CCCI_INIT_LOG(-1, TAG, "spm_sleep_base:0x%lx\n",
|
|
(unsigned long)hw_info->spm_sleep_base);
|
|
|
|
CCCI_DEBUG_LOG(dev_cfg->index, TAG,
|
|
"dev_major:%d,minor_base:%d,capability:%d\n",
|
|
dev_cfg->major, dev_cfg->minor_base, dev_cfg->capability);
|
|
|
|
CCCI_DEBUG_LOG(dev_cfg->index, TAG,
|
|
"ap_ccif_base:0x%p, md_ccif_base:0x%p\n",
|
|
(void *)hw_info->ap_ccif_base,
|
|
(void *)hw_info->md_ccif_base);
|
|
CCCI_DEBUG_LOG(dev_cfg->index, TAG,
|
|
"ccif_irq0:%d,ccif_irq1:%d,md_wdt_irq:%d\n",
|
|
hw_info->ap_ccif_irq0_id, hw_info->ap_ccif_irq1_id,
|
|
hw_info->md_wdt_irq_id);
|
|
|
|
register_pg_callback(&md1_subsys_handle);
|
|
return 0;
|
|
}
|
|
|
|
int md_cd_io_remap_md_side_register(struct ccci_modem *md)
|
|
{
|
|
struct md_pll_reg *md_reg = NULL;
|
|
struct md_sys1_info *md_info = (struct md_sys1_info *)md->private_data;
|
|
|
|
/* call internal_dump io_remap */
|
|
md_io_remap_internal_dump_register(md);
|
|
|
|
md_info->md_boot_slave_En =
|
|
ioremap_nocache(md->hw_info->md_boot_slave_En, 0x4);
|
|
md_info->md_rgu_base =
|
|
ioremap_nocache(md->hw_info->md_rgu_base, 0x300);
|
|
|
|
md_reg = kzalloc(sizeof(struct md_pll_reg), GFP_KERNEL);
|
|
if (md_reg == NULL) {
|
|
CCCI_ERROR_LOG(-1, TAG,
|
|
"md_sw_init:alloc md reg map mem fail\n");
|
|
return -1;
|
|
}
|
|
|
|
md_reg->md_boot_stats_select =
|
|
ioremap_nocache(MD1_BOOT_STATS_SELECT, 4);
|
|
md_reg->md_boot_stats = ioremap_nocache(MD1_CFG_BOOT_STATS, 4);
|
|
/*just for dump end*/
|
|
|
|
md_info->md_pll_base = md_reg;
|
|
|
|
#ifdef MD_PEER_WAKEUP
|
|
md_info->md_peer_wakeup = ioremap_nocache(MD_PEER_WAKEUP, 0x4);
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
void md_cd_lock_cldma_clock_src(int locked)
|
|
{
|
|
/* spm_ap_mdsrc_req(locked); */
|
|
}
|
|
|
|
void md_cd_lock_modem_clock_src(int locked)
|
|
{
|
|
size_t ret;
|
|
|
|
/* spm_ap_mdsrc_req(locked); */
|
|
mt_secure_call(MD_CLOCK_REQUEST,
|
|
MD_REG_AP_MDSRC_REQ, locked, 0, 0, 0, 0);
|
|
if (locked) {
|
|
int settle = mt_secure_call(MD_CLOCK_REQUEST,
|
|
MD_REG_AP_MDSRC_SETTLE, 0, 0, 0, 0, 0);
|
|
|
|
if (!(settle > 0 && settle < 10))
|
|
settle = 3;
|
|
|
|
mdelay(settle);
|
|
ret = mt_secure_call(MD_CLOCK_REQUEST,
|
|
MD_REG_AP_MDSRC_ACK, 0, 0, 0, 0, 0);
|
|
|
|
CCCI_NOTICE_LOG(-1, TAG,
|
|
"settle = %d; ret = %lu\n", settle, ret);
|
|
}
|
|
}
|
|
|
|
void md_cd_dump_md_bootup_status(struct ccci_modem *md)
|
|
{
|
|
struct arm_smccc_res res;
|
|
|
|
arm_smccc_smc(MTK_SIP_KERNEL_CCCI_CONTROL,
|
|
MD_POWER_CONFIG, MD_BOOT_STATUS,
|
|
0, 0, 0, 0, 0, &res);
|
|
|
|
CCCI_NOTICE_LOG(md->index, TAG,
|
|
"[%s] AP: boot_ret=%lu, boot_status_0=%lX, boot_status_1=%lX\n",
|
|
__func__, res.a0, res.a1, res.a2);
|
|
|
|
}
|
|
|
|
void md_cd_get_md_bootup_status(
|
|
struct ccci_modem *md, unsigned int *buff, int length)
|
|
{
|
|
struct arm_smccc_res res;
|
|
|
|
arm_smccc_smc(MTK_SIP_KERNEL_CCCI_CONTROL,
|
|
MD_POWER_CONFIG, MD_BOOT_STATUS,
|
|
0, 0, 0, 0, 0, &res);
|
|
|
|
if (buff && (length >= 2)) {
|
|
buff[0] = (unsigned int)res.a1;
|
|
buff[1] = (unsigned int)res.a2;
|
|
}
|
|
|
|
CCCI_NOTICE_LOG(md->index, TAG,
|
|
"boot_ret=%lu; md_boot_stats0 / 1:0x%lX / 0x%lX\n",
|
|
res.a0, res.a1, res.a2);
|
|
}
|
|
|
|
static int dump_emi_last_bm(struct ccci_modem *md)
|
|
{
|
|
u32 buf_len = 1024;
|
|
u32 i, j;
|
|
char temp_char;
|
|
char *buf = NULL;
|
|
char *temp_buf = NULL;
|
|
|
|
buf = kzalloc(buf_len, GFP_ATOMIC);
|
|
if (!buf) {
|
|
CCCI_MEM_LOG_TAG(md->index, TAG,
|
|
"alloc memory failed for emi last bm\n");
|
|
return -1;
|
|
}
|
|
#ifdef CONFIG_MTK_EMI_BWL
|
|
dump_last_bm(buf, buf_len);
|
|
#endif
|
|
CCCI_MEM_LOG_TAG(md->index, TAG, "Dump EMI last bm\n");
|
|
buf[buf_len - 1] = '\0';
|
|
temp_buf = buf;
|
|
for (i = 0, j = 1; i < buf_len - 1; i++, j++) {
|
|
if (buf[i] == 0x0) /* 0x0 end of hole string. */
|
|
break;
|
|
if (buf[i] == 0x0A && j < 256) {
|
|
/* 0x0A stands for end of string, no 0x0D */
|
|
buf[i] = '\0';
|
|
CCCI_MEM_LOG(md->index, TAG,
|
|
"%s\n", temp_buf);/* max 256 bytes */
|
|
temp_buf = buf + i + 1;
|
|
j = 0;
|
|
} else if (unlikely(j >= 255)) {
|
|
/* ccci_mem_log max buffer length: 256,
|
|
* but dm log maybe only less than 50 bytes.
|
|
*/
|
|
temp_char = buf[i];
|
|
buf[i] = '\0';
|
|
CCCI_MEM_LOG(md->index, TAG, "%s\n", temp_buf);
|
|
temp_buf = buf + i;
|
|
j = 0;
|
|
buf[i] = temp_char;
|
|
}
|
|
}
|
|
|
|
kfree(buf);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void __weak dump_emi_outstanding(void)
|
|
{
|
|
CCCI_DEBUG_LOG(-1, TAG, "No %s\n", __func__);
|
|
}
|
|
|
|
void md_cd_dump_debug_register(struct ccci_modem *md)
|
|
{
|
|
/* MD no need dump because of bus hang happened - open for debug */
|
|
unsigned int reg_value[2] = { 0 };
|
|
unsigned int ccif_sram[
|
|
CCCI_EE_SIZE_CCIF_SRAM/sizeof(unsigned int)] = { 0 };
|
|
|
|
/*dump_emi_latency();*/
|
|
dump_emi_outstanding();
|
|
dump_emi_last_bm(md);
|
|
|
|
md_cd_get_md_bootup_status(md, reg_value, 2);
|
|
md->ops->dump_info(md, DUMP_FLAG_CCIF, ccif_sram, 0);
|
|
/* copy from HS1 timeout */
|
|
if ((reg_value[0] == 0) && (ccif_sram[1] == 0))
|
|
return;
|
|
else if (!((reg_value[0] == 0x5443000C) || (reg_value[0] == 0) ||
|
|
(reg_value[0] >= 0x53310000 && reg_value[0] <= 0x533100FF)))
|
|
return;
|
|
|
|
md_cd_lock_modem_clock_src(1);
|
|
|
|
/* This function needs to be cancelled temporarily for bringup */
|
|
internal_md_dump_debug_register(md->index);
|
|
|
|
md_cd_lock_modem_clock_src(0);
|
|
|
|
}
|
|
|
|
int md_cd_pccif_send(struct ccci_modem *md, int channel_id)
|
|
{
|
|
int busy = 0;
|
|
struct md_hw_info *hw_info = md->hw_info;
|
|
|
|
md_cd_lock_modem_clock_src(1);
|
|
|
|
busy = ccif_read32(hw_info->md_pcore_pccif_base, APCCIF_BUSY);
|
|
if (busy & (1 << channel_id)) {
|
|
md_cd_lock_modem_clock_src(0);
|
|
return -1;
|
|
}
|
|
ccif_write32(hw_info->md_pcore_pccif_base,
|
|
APCCIF_BUSY, 1 << channel_id);
|
|
ccif_write32(hw_info->md_pcore_pccif_base,
|
|
APCCIF_TCHNUM, channel_id);
|
|
|
|
md_cd_lock_modem_clock_src(0);
|
|
return 0;
|
|
}
|
|
|
|
void md_cd_dump_pccif_reg(struct ccci_modem *md)
|
|
{
|
|
struct md_hw_info *hw_info = md->hw_info;
|
|
|
|
md_cd_lock_modem_clock_src(1);
|
|
|
|
CCCI_MEM_LOG_TAG(md->index, TAG,
|
|
"AP_CON(%p)=%x\n",
|
|
hw_info->md_pcore_pccif_base + APCCIF_CON,
|
|
ccif_read32(hw_info->md_pcore_pccif_base, APCCIF_CON));
|
|
CCCI_MEM_LOG_TAG(md->index, TAG,
|
|
"AP_BUSY(%p)=%x\n",
|
|
hw_info->md_pcore_pccif_base + APCCIF_BUSY,
|
|
ccif_read32(hw_info->md_pcore_pccif_base, APCCIF_BUSY));
|
|
CCCI_MEM_LOG_TAG(md->index, TAG,
|
|
"AP_START(%p)=%x\n",
|
|
hw_info->md_pcore_pccif_base + APCCIF_START,
|
|
ccif_read32(hw_info->md_pcore_pccif_base, APCCIF_START));
|
|
CCCI_MEM_LOG_TAG(md->index, TAG,
|
|
"AP_TCHNUM(%p)=%x\n",
|
|
hw_info->md_pcore_pccif_base + APCCIF_TCHNUM,
|
|
ccif_read32(hw_info->md_pcore_pccif_base, APCCIF_TCHNUM));
|
|
CCCI_MEM_LOG_TAG(md->index, TAG,
|
|
"AP_RCHNUM(%p)=%x\n",
|
|
hw_info->md_pcore_pccif_base + APCCIF_RCHNUM,
|
|
ccif_read32(hw_info->md_pcore_pccif_base, APCCIF_RCHNUM));
|
|
CCCI_MEM_LOG_TAG(md->index, TAG,
|
|
"AP_ACK(%p)=%x\n",
|
|
hw_info->md_pcore_pccif_base + APCCIF_ACK,
|
|
ccif_read32(hw_info->md_pcore_pccif_base, APCCIF_ACK));
|
|
|
|
md_cd_lock_modem_clock_src(0);
|
|
}
|
|
|
|
void md_cd_check_emi_state(struct ccci_modem *md, int polling)
|
|
{
|
|
}
|
|
|
|
void md1_pmic_setting_on(void)
|
|
{
|
|
CCCI_NORMAL_LOG(-1, "POWER ON", "vmd1_pmic_setting_on() start.\n");
|
|
CCCI_BOOTUP_LOG(-1, TAG, "[POWER ON] vmd1_pmic_setting_on() start.\n");
|
|
vmd1_pmic_setting_on();
|
|
CCCI_NORMAL_LOG(-1, "POWER ON", "vmd1_pmic_setting_on() end.\n");
|
|
CCCI_BOOTUP_LOG(-1, TAG, "[POWER ON] vmd1_pmic_setting_on() end.\n");
|
|
}
|
|
|
|
void md1_pmic_setting_off(void)
|
|
{
|
|
vmd1_pmic_setting_off();
|
|
}
|
|
|
|
/* callback for system power off*/
|
|
void ccci_power_off(void)
|
|
{
|
|
md1_pmic_setting_on();
|
|
}
|
|
|
|
void __attribute__((weak)) kicker_pbm_by_md(enum pbm_kicker kicker,
|
|
bool status)
|
|
{
|
|
CCCI_NORMAL_LOG(-1, TAG, "kicker_pbm_by_md() no support.\n");
|
|
CCCI_BOOTUP_LOG(-1, TAG, "kicker_pbm_by_md() no support.\n");
|
|
}
|
|
|
|
#ifdef FEATURE_CLK_BUF
|
|
static void flight_mode_set_by_atf(struct ccci_modem *md,
|
|
unsigned int flightMode)
|
|
{
|
|
struct arm_smccc_res res;
|
|
|
|
arm_smccc_smc(MTK_SIP_KERNEL_CCCI_CONTROL, MD_FLIGHT_MODE_SET,
|
|
flightMode, 0, 0, 0, 0, 0, &res);
|
|
|
|
CCCI_BOOTUP_LOG(md->index, TAG,
|
|
"[%s] flag_1=%lu, flag_2=%lu, flag_3=%lu, flag_4=%lu\n",
|
|
__func__, res.a0, res.a1, res.a2, res.a3);
|
|
}
|
|
#endif
|
|
|
|
int md_cd_soft_power_off(struct ccci_modem *md, unsigned int mode)
|
|
{
|
|
#ifdef FEATURE_CLK_BUF
|
|
flight_mode_set_by_atf(md, true);
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
int md_cd_soft_power_on(struct ccci_modem *md, unsigned int mode)
|
|
{
|
|
#ifdef FEATURE_CLK_BUF
|
|
flight_mode_set_by_atf(md, false);
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
int md_start_platform(struct ccci_modem *md)
|
|
{
|
|
struct arm_smccc_res res;
|
|
int timeout = 100; /* 100 * 20ms = 2s */
|
|
int ret = -1;
|
|
|
|
s_md_start_completed = 1;
|
|
|
|
if ((md->per_md_data.config.setting&MD_SETTING_FIRST_BOOT) == 0)
|
|
return 0;
|
|
|
|
while (timeout > 0) {
|
|
ret = mt_secure_call(MD_POWER_CONFIG, MD_CHECK_DONE,
|
|
0, 0, 0, 0, 0);
|
|
if (!ret) {
|
|
CCCI_BOOTUP_LOG(md->index, TAG, "BROM PASS\n");
|
|
break;
|
|
}
|
|
timeout--;
|
|
msleep(20);
|
|
}
|
|
arm_smccc_smc(MTK_SIP_KERNEL_CCCI_CONTROL, MD_POWER_CONFIG,
|
|
MD_CHECK_FLAG, 0, 0, 0, 0, 0, &res);
|
|
CCCI_BOOTUP_LOG(md->index, TAG,
|
|
"flag_1=%lu, flag_2=%lu, flag_3=%lu, flag_4=%lu\n",
|
|
res.a0, res.a1, res.a2, res.a3);
|
|
|
|
arm_smccc_smc(MTK_SIP_KERNEL_CCCI_CONTROL, MD_POWER_CONFIG,
|
|
MD_BOOT_STATUS, 0, 0, 0, 0, 0, &res);
|
|
CCCI_BOOTUP_LOG(md->index, TAG,
|
|
"AP: boot_ret=%lu, boot_status_0=%lX, boot_status_1=%lX\n",
|
|
res.a0, res.a1, res.a2);
|
|
|
|
if (ret != 0) {
|
|
/* BROM */
|
|
CCCI_ERROR_LOG(md->index, TAG, "BROM Failed\n");
|
|
}
|
|
md_cd_power_off(md, 0);
|
|
return ret;
|
|
}
|
|
|
|
|
|
static int mtk_ccci_cfg_srclken_o1_on(struct ccci_modem *md)
|
|
{
|
|
unsigned int val;
|
|
struct md_hw_info *hw_info = md->hw_info;
|
|
|
|
if (hw_info->spm_sleep_base) {
|
|
CCCI_NORMAL_LOG(-1, "POWER ON", "%s() start.\n", __func__);
|
|
CCCI_BOOTUP_LOG(-1, TAG, "[POWER ON] %s() start.\n", __func__);
|
|
|
|
ccci_write32(hw_info->spm_sleep_base, 0, 0x0B160001);
|
|
val = ccci_read32(hw_info->spm_sleep_base, 0);
|
|
CCCI_BOOTUP_LOG(-1, TAG, "[POWER ON] spm_sleep_base: val:0x%x\n", val);
|
|
|
|
|
|
val = ccci_read32(hw_info->spm_sleep_base, 8);
|
|
CCCI_BOOTUP_LOG(-1, TAG, "[POWER ON] spm_sleep_base+8: val:0x%x +\n", val);
|
|
#ifdef CCCI_PLATFORM_MT6877
|
|
val |= 0x1<<15;
|
|
#else
|
|
val |= 0x1<<21;
|
|
#endif
|
|
ccci_write32(hw_info->spm_sleep_base, 8, val);
|
|
val = ccci_read32(hw_info->spm_sleep_base, 8);
|
|
CCCI_NORMAL_LOG(-1, "POWER ON", "spm_sleep_base+8: val:0x%x -\n", val);
|
|
CCCI_BOOTUP_LOG(-1, TAG, "[POWER ON] spm_sleep_base+8: val:0x%x -\n", val);
|
|
CCCI_NORMAL_LOG(-1, "POWER ON", "%s() end.\n", __func__);
|
|
CCCI_BOOTUP_LOG(-1, TAG, "[POWER ON] %s() end.\n", __func__);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int md_cd_topclkgen_on(struct ccci_modem *md)
|
|
{
|
|
unsigned int reg_value;
|
|
|
|
reg_value = ccci_read32(md->hw_info->ap_topclkgen_base, 0);
|
|
reg_value &= ~((1<<8) | (1<<9));
|
|
ccci_write32(md->hw_info->ap_topclkgen_base, 0, reg_value);
|
|
|
|
CCCI_NORMAL_LOG(md->index, "POWER ON", "%s: set md1_clk_mod = 0x%x\n",
|
|
__func__, ccci_read32(md->hw_info->ap_topclkgen_base, 0));
|
|
CCCI_BOOTUP_LOG(md->index, TAG, "[POWER ON] %s: set md1_clk_mod = 0x%x\n",
|
|
__func__, ccci_read32(md->hw_info->ap_topclkgen_base, 0));
|
|
|
|
return 0;
|
|
}
|
|
|
|
int md_cd_power_on(struct ccci_modem *md)
|
|
{
|
|
int ret = 0;
|
|
#ifndef CCCI_PLATFORM_MT6877
|
|
unsigned int reg_value;
|
|
#endif
|
|
/* step 1: PMIC setting */
|
|
md1_pmic_setting_on();
|
|
|
|
/* modem topclkgen on setting */
|
|
md_cd_topclkgen_on(md);
|
|
|
|
#ifndef CCCI_PLATFORM_MT6877
|
|
/* step 2: MD srcclkena setting */
|
|
CCCI_NORMAL_LOG(-1, "POWER ON", "set md1 srcclkena start.\n");
|
|
CCCI_BOOTUP_LOG(-1, TAG, "[POWER ON] set md1 srcclkena start.\n");
|
|
reg_value = ccci_read32(infra_ao_base, INFRA_AO_MD_SRCCLKENA);
|
|
reg_value &= ~(0xFF);
|
|
reg_value |= 0x21;
|
|
ccci_write32(infra_ao_base, INFRA_AO_MD_SRCCLKENA, reg_value);
|
|
CCCI_NORMAL_LOG(-1, "POWER ON",
|
|
"set md1 srcclkena end. bit(0x1000_0F0C)=0x%x\n",
|
|
ccci_read32(infra_ao_base, INFRA_AO_MD_SRCCLKENA));
|
|
CCCI_BOOTUP_LOG(-1, TAG,
|
|
"[POWER ON] set md1 srcclkena end. bit(0x1000_0F0C)=0x%x\n",
|
|
ccci_read32(infra_ao_base, INFRA_AO_MD_SRCCLKENA));
|
|
#endif
|
|
mtk_ccci_cfg_srclken_o1_on(md);
|
|
/* steip 3: power on MD_INFRA and MODEM_TOP */
|
|
switch (md->index) {
|
|
case MD_SYS1:
|
|
#ifdef FEATURE_CLK_BUF
|
|
flight_mode_set_by_atf(md, false);
|
|
#endif
|
|
CCCI_NORMAL_LOG(-1, "POWER ON", "clk_prepare_enable() start.\n");
|
|
CCCI_BOOTUP_LOG(-1, TAG, "[POWER ON] clk_prepare_enable() start.\n");
|
|
ret = clk_prepare_enable(clk_table[0].clk_ref);
|
|
CCCI_NORMAL_LOG(-1, "POWER ON",
|
|
"clk_prepare_enable() end. ret=%d\n", ret);
|
|
CCCI_BOOTUP_LOG(-1, TAG,
|
|
"[POWER ON] clk_prepare_enable() end. ret=%d\n", ret);
|
|
kicker_pbm_by_md(KR_MD1, true);
|
|
|
|
break;
|
|
}
|
|
if (ret)
|
|
return ret;
|
|
|
|
#ifdef FEATURE_INFORM_NFC_VSIM_CHANGE
|
|
/* notify NFC */
|
|
CCCI_NORMAL_LOG(-1, "POWER ON", "inform_nfc_vsim_change() start.\n");
|
|
CCCI_BOOTUP_LOG(-1, TAG, "[POWER ON] inform_nfc_vsim_change() start.\n");
|
|
inform_nfc_vsim_change(md->index, 1, 0);
|
|
CCCI_NORMAL_LOG(-1, "POWER ON", "inform_nfc_vsim_change() end.\n");
|
|
CCCI_BOOTUP_LOG(-1, TAG, "[POWER ON] inform_nfc_vsim_change() end.\n");
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
int md_cd_bootup_cleanup(struct ccci_modem *md, int success)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int md_cd_let_md_go(struct ccci_modem *md)
|
|
{
|
|
struct arm_smccc_res res;
|
|
|
|
CCCI_NORMAL_LOG(-1, "POWER ON", "%s() start.\n", __func__);
|
|
CCCI_BOOTUP_LOG(-1, TAG, "[POWER ON] %s() start.\n", __func__);
|
|
|
|
if (MD_IN_DEBUG(md))
|
|
return -1;
|
|
CCCI_BOOTUP_LOG(md->index, TAG, "set MD boot slave\n");
|
|
|
|
/* make boot vector take effect */
|
|
arm_smccc_smc(MTK_SIP_KERNEL_CCCI_CONTROL, MD_POWER_CONFIG,
|
|
MD_KERNEL_BOOT_UP, 0, 0, 0, 0, 0, &res);
|
|
CCCI_NORMAL_LOG(md->index, "POWER ON",
|
|
"MD: boot_ret=%lu, boot_status_0=%lu, boot_status_1=%lu\n",
|
|
res.a0, res.a1, res.a2);
|
|
CCCI_BOOTUP_LOG(md->index, TAG,
|
|
"[POWER ON] MD: boot_ret=%lu, boot_status_0=%lu, boot_status_1=%lu\n",
|
|
res.a0, res.a1, res.a2);
|
|
|
|
CCCI_NORMAL_LOG(-1, "POWER ON", "%s() end.\n", __func__);
|
|
CCCI_BOOTUP_LOG(-1, TAG, "[POWER ON] %s() end.\n", __func__);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int md_cd_topclkgen_off(struct ccci_modem *md)
|
|
{
|
|
unsigned int reg_value;
|
|
|
|
reg_value = ccci_read32(md->hw_info->ap_topclkgen_base, 0);
|
|
reg_value |= ((1<<8) | (1<<9));
|
|
ccci_write32(md->hw_info->ap_topclkgen_base, 0, reg_value);
|
|
|
|
CCCI_NORMAL_LOG(md->index, "POWER OFF", "%s: set md1_clk_mod = 0x%x\n",
|
|
__func__, ccci_read32(md->hw_info->ap_topclkgen_base, 0));
|
|
CCCI_BOOTUP_LOG(md->index, TAG, "[POWER OFF] %s: set md1_clk_mod = 0x%x\n",
|
|
__func__, ccci_read32(md->hw_info->ap_topclkgen_base, 0));
|
|
|
|
return 0;
|
|
}
|
|
|
|
int md_cd_power_off(struct ccci_modem *md, unsigned int timeout)
|
|
{
|
|
int ret = 0;
|
|
#ifndef CCCI_PLATFORM_MT6877
|
|
unsigned int reg_value;
|
|
#endif
|
|
|
|
#ifdef FEATURE_INFORM_NFC_VSIM_CHANGE
|
|
/* notify NFC */
|
|
CCCI_NORMAL_LOG(-1, "POWER OFF", "inform_nfc_vsim_change() start.\n");
|
|
CCCI_BOOTUP_LOG(-1, TAG, "[POWER OFF] inform_nfc_vsim_change() start.\n");
|
|
inform_nfc_vsim_change(md->index, 0, 0);
|
|
CCCI_NORMAL_LOG(-1, "POWER OFF", "inform_nfc_vsim_change() end.\n");
|
|
CCCI_BOOTUP_LOG(-1, TAG, "[POWER OFF] inform_nfc_vsim_change() end.\n");
|
|
#endif
|
|
|
|
/* power off MD_INFRA and MODEM_TOP */
|
|
switch (md->index) {
|
|
case MD_SYS1:
|
|
/* 1. power off MD MTCMOS */
|
|
CCCI_NORMAL_LOG(-1, "POWER OFF", "clk_disable_unprepare() start.\n");
|
|
CCCI_BOOTUP_LOG(-1, TAG, "[POWER OFF] clk_disable_unprepare() start.\n");
|
|
clk_disable_unprepare(clk_table[0].clk_ref);
|
|
CCCI_NORMAL_LOG(-1, "POWER OFF", "clk_disable_unprepare() end.\n");
|
|
CCCI_BOOTUP_LOG(-1, TAG, "[POWER OFF] clk_disable_unprepare() end.\n");
|
|
/* 2. disable srcclkena */
|
|
#ifndef CCCI_PLATFORM_MT6877
|
|
CCCI_NORMAL_LOG(-1, "POWER OFF", "set infra_ao_base start.\n");
|
|
CCCI_BOOTUP_LOG(-1, TAG, "[POWER OFF] set infra_ao_base start.\n");
|
|
reg_value = ccci_read32(infra_ao_base, INFRA_AO_MD_SRCCLKENA);
|
|
reg_value &= ~(0xFF);
|
|
ccci_write32(infra_ao_base, INFRA_AO_MD_SRCCLKENA, reg_value);
|
|
CCCI_NORMAL_LOG(md->index, "POWER OFF",
|
|
"%s: set md1_srcclkena=0x%x\n", __func__,
|
|
ccci_read32(infra_ao_base, INFRA_AO_MD_SRCCLKENA));
|
|
CCCI_BOOTUP_LOG(md->index, TAG,
|
|
"[POWER OFF] %s: set md1_srcclkena=0x%x\n", __func__,
|
|
ccci_read32(infra_ao_base, INFRA_AO_MD_SRCCLKENA));
|
|
CCCI_NORMAL_LOG(-1, "POWER OFF", "set infra_ao_base end.\n");
|
|
CCCI_BOOTUP_LOG(-1, TAG, "[POWER OFF] set infra_ao_base end.\n");
|
|
#endif
|
|
|
|
#ifdef FEATURE_CLK_BUF
|
|
flight_mode_set_by_atf(md, true);
|
|
#endif
|
|
/* modem topclkgen off setting */
|
|
md_cd_topclkgen_off(md);
|
|
|
|
/* 3. PMIC off */
|
|
md1_pmic_setting_off();
|
|
|
|
/* 5. DLPT */
|
|
kicker_pbm_by_md(KR_MD1, false);
|
|
CCCI_BOOTUP_LOG(md->index, TAG,
|
|
"Call end kicker_pbm_by_md(0,false)\n");
|
|
break;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ccci_modem_remove(struct platform_device *dev)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
void ccci_modem_shutdown(struct platform_device *dev)
|
|
{
|
|
}
|
|
|
|
int ccci_modem_suspend(struct platform_device *dev, pm_message_t state)
|
|
{
|
|
struct ccci_modem *md = (struct ccci_modem *)dev->dev.platform_data;
|
|
|
|
CCCI_DEBUG_LOG(md->index, TAG, "%s\n", __func__);
|
|
return 0;
|
|
}
|
|
|
|
int ccci_modem_resume(struct platform_device *dev)
|
|
{
|
|
struct ccci_modem *md = (struct ccci_modem *)dev->dev.platform_data;
|
|
|
|
CCCI_DEBUG_LOG(md->index, TAG, "%s\n", __func__);
|
|
return 0;
|
|
}
|
|
|
|
int ccci_modem_pm_suspend(struct device *device)
|
|
{
|
|
struct platform_device *pdev = to_platform_device(device);
|
|
|
|
if (pdev == NULL) {
|
|
CCCI_ERROR_LOG(MD_SYS1, TAG, "%s pdev == NULL\n", __func__);
|
|
return -1;
|
|
}
|
|
return ccci_modem_suspend(pdev, PMSG_SUSPEND);
|
|
}
|
|
|
|
int ccci_modem_pm_resume(struct device *device)
|
|
{
|
|
struct platform_device *pdev = to_platform_device(device);
|
|
|
|
if (pdev == NULL) {
|
|
CCCI_ERROR_LOG(MD_SYS1, TAG, "%s pdev == NULL\n", __func__);
|
|
return -1;
|
|
}
|
|
return ccci_modem_resume(pdev);
|
|
}
|
|
|
|
int ccci_modem_pm_restore_noirq(struct device *device)
|
|
{
|
|
struct ccci_modem *md = (struct ccci_modem *)device->platform_data;
|
|
|
|
/* set flag for next md_start */
|
|
md->per_md_data.config.setting |= MD_SETTING_RELOAD;
|
|
md->per_md_data.config.setting |= MD_SETTING_FIRST_BOOT;
|
|
/* restore IRQ */
|
|
#ifdef FEATURE_PM_IPO_H
|
|
irq_set_irq_type(md_ctrl->cldma_irq_id, IRQF_TRIGGER_HIGH);
|
|
irq_set_irq_type(md_ctrl->md_wdt_irq_id, IRQF_TRIGGER_RISING);
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
void ccci_hif_cldma_restore_reg(struct ccci_modem *md)
|
|
{
|
|
}
|
|
|
|
void ccci_modem_restore_reg(struct ccci_modem *md)
|
|
{
|
|
enum MD_STATE md_state = ccci_fsm_get_md_state(md->index);
|
|
|
|
if (md_state == GATED || md_state == WAITING_TO_STOP ||
|
|
md_state == INVALID) {
|
|
CCCI_NORMAL_LOG(md->index, TAG,
|
|
"Resume no need restore for md_state=%d\n", md_state);
|
|
return;
|
|
}
|
|
|
|
if (md->hif_flag & (1 << CLDMA_HIF_ID))
|
|
ccci_hif_cldma_restore_reg(md);
|
|
|
|
ccci_hif_resume(md->index, md->hif_flag);
|
|
}
|
|
|
|
int ccci_modem_plt_suspend(void)
|
|
{
|
|
struct ccci_modem *md;
|
|
|
|
CCCI_DEBUG_LOG(0, TAG, "%s\n", __func__);
|
|
md = ccci_md_get_modem_by_id(0);
|
|
if (md != NULL)
|
|
ccci_hif_suspend(md->index, md->hif_flag);
|
|
return 0;
|
|
}
|
|
|
|
void ccci_modem_plt_resume(void)
|
|
{
|
|
struct ccci_modem *md;
|
|
|
|
CCCI_DEBUG_LOG(0, TAG, "%s\n", __func__);
|
|
md = ccci_md_get_modem_by_id(0);
|
|
if (md != NULL)
|
|
ccci_modem_restore_reg(md);
|
|
}
|
|
|
|
int ccci_modem_suspend_noirq(struct device *dev)
|
|
{
|
|
return dpmaif_suspend_noirq(dev);
|
|
}
|
|
|
|
int ccci_modem_resume_noirq(struct device *dev)
|
|
{
|
|
return dpmaif_resume_noirq(dev);
|
|
}
|
|
|
|
/* notify atf set scp smem addr to scp reg */
|
|
void ccci_notify_set_scpmem(void)
|
|
{
|
|
struct arm_smccc_res res = {0};
|
|
|
|
arm_smccc_smc(MTK_SIP_KERNEL_CCCI_CONTROL, SCP_CLK_SET_DONE,
|
|
0, 0, 0, 0, 0, 0, &res);
|
|
CCCI_NORMAL_LOG(MD_SYS1, TAG, "%s [done] res.a0 = %lu\n", __func__, res.a0);
|
|
}
|