// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2016 MediaTek Inc. */ #include #include #include #include #include #include #include #include #include /* local_clock() */ #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(CONFIG_MTK_AEE_FEATURE) #include #endif #include #include "ccci_config.h" #include "ccci_common_config.h" #include "ccci_core.h" #include "ccci_modem.h" #include "ccci_bm.h" #include "ccci_platform.h" #include "md_sys1_platform.h" #include "modem_reg_base.h" #include "ccci_debug.h" #include "hif/ccci_hif_cldma.h" #include "hif/ccci_hif_ccif.h" #define TAG "mcd" static void debug_in_flight_mode(struct ccci_modem *md); void ccif_enable_irq(struct ccci_modem *md) { struct md_sys1_info *md_info = (struct md_sys1_info *)md->private_data; if (atomic_cmpxchg(&md_info->ccif_irq_enabled, 0, 1) == 0) { enable_irq(md_info->ap_ccif_irq_id); CCCI_NORMAL_LOG(md->index, TAG, "enable ccif irq\n"); } } void ccif_disable_irq(struct ccci_modem *md) { struct md_sys1_info *md_info = (struct md_sys1_info *)md->private_data; if (atomic_cmpxchg(&md_info->ccif_irq_enabled, 1, 0) == 1) { disable_irq_nosync(md_info->ap_ccif_irq_id); CCCI_NORMAL_LOG(md->index, TAG, "disable ccif irq\n"); } } void wdt_enable_irq(struct ccci_modem *md) { if (atomic_cmpxchg(&md->wdt_enabled, 0, 1) == 0) { enable_irq(md->md_wdt_irq_id); CCCI_NORMAL_LOG(md->index, TAG, "enable wdt irq\n"); } } void wdt_disable_irq(struct ccci_modem *md) { if (atomic_cmpxchg(&md->wdt_enabled, 1, 0) == 1) { /* * may be called in isr, so use disable_irq_nosync. * if use disable_irq in isr, system will hang */ disable_irq_nosync(md->md_wdt_irq_id); CCCI_NORMAL_LOG(md->index, TAG, "disable wdt irq\n"); } } static irqreturn_t md_cd_wdt_isr(int irq, void *data) { struct ccci_modem *md = (struct ccci_modem *)data; CCCI_ERROR_LOG(md->index, TAG, "MD WDT IRQ\n"); ccif_disable_irq(md); wdt_disable_irq(md); ccci_event_log("md%d: MD WDT IRQ\n", md->index); #ifndef DISABLE_MD_WDT_PROCESS /* 1. disable MD WDT */ #ifdef ENABLE_MD_WDT_DBG unsigned int state; state = ccci_read32(md->md_rgu_base, WDT_MD_STA); ccci_write32(md->md_rgu_base, WDT_MD_MODE, WDT_MD_MODE_KEY); CCCI_NORMAL_LOG(md->index, TAG, "WDT IRQ disabled for debug, state=%X\n", state); #ifdef L1_BASE_ADDR_L1RGU state = ccci_read32(md->l1_rgu_base, REG_L1RSTCTL_WDT_STA); ccci_write32(md->l1_rgu_base, REG_L1RSTCTL_WDT_MODE, L1_WDT_MD_MODE_KEY); CCCI_NORMAL_LOG(md->index, TAG, "WDT IRQ disabled for debug, L1 state=%X\n", state); #endif #endif #endif ccci_fsm_recv_md_interrupt(md->index, MD_IRQ_WDT); return IRQ_HANDLED; } static void md_cd_ccif_delayed_work(struct ccci_modem *md) { if (md->hif_flag & (1<index, TAG, "%s: stop cldma done\n", __func__); /*dump rxq after cldma stop to avoid race condition*/ ccci_hif_dump_status(1 << CLDMA_HIF_ID, DUMP_FLAG_QUEUE_0_1, NULL, 1 << IN); CCCI_NORMAL_LOG(md->index, TAG, "%s: dump queue0-1 done\n", __func__); cldma_plat_hw_reset(md->index); CCCI_NORMAL_LOG(md->index, TAG, "%s: hw reset done\n", __func__); md_cd_clear_all_queue(1 << CLDMA_HIF_ID, IN); } } static void md_cd_exception(struct ccci_modem *md, enum HIF_EX_STAGE stage) { struct ccci_smem_region *mdccci_dbg = ccci_md_get_smem_by_user_id(md->index, SMEM_USER_RAW_MDCCCI_DBG); CCCI_ERROR_LOG(md->index, TAG, "MD exception HIF %d\n", stage); ccci_event_log("md%d:MD exception HIF %d\n", md->index, stage); __pm_wakeup_event(md->trm_wake_lock, jiffies_to_msecs(50 * HZ)); /* in exception mode, MD won't sleep, so we do not * need to request MD resource first */ switch (stage) { case HIF_EX_INIT: ccci_hif_dump_status(1 << CCIF_HIF_ID, DUMP_FLAG_CCIF | DUMP_FLAG_IRQ_STATUS, NULL, 0); if (*((int *)(mdccci_dbg->base_ap_view_vir + CCCI_SMEM_OFFSET_SEQERR)) != 0) { CCCI_ERROR_LOG(md->index, TAG, "MD found wrong sequence number\n"); } if (md->hif_flag & (1<index, TAG, "dump cldma on ccif hs0\n"); ccci_hif_dump_status(1 << CLDMA_HIF_ID, DUMP_FLAG_CLDMA, NULL, -1); /* disable CLDMA except un-stop queues */ cldma_stop_for_ee(CLDMA_HIF_ID); /* purge Tx queue */ md_cd_clear_all_queue(CLDMA_HIF_ID, OUT); } ccci_hif_md_exception(md->hif_flag, stage); /* Rx dispatch does NOT depend on queue index * in port structure, so it still can find right port. */ ccci_hif_send_data(CCIF_HIF_ID, H2D_EXCEPTION_ACK); break; case HIF_EX_INIT_DONE: break; case HIF_EX_CLEARQ_DONE: /* give DHL some time to flush data */ msleep(2000); md_cd_ccif_delayed_work(md); ccci_hif_md_exception(md->hif_flag, stage); /* tell MD to reset CLDMA */ ccci_hif_send_data(CCIF_HIF_ID, H2D_EXCEPTION_CLEARQ_ACK); CCCI_NORMAL_LOG(md->index, TAG, "send clearq_ack to MD\n"); break; case HIF_EX_ALLQ_RESET: md->per_md_data.is_in_ee_dump = 1; if (md->hif_flag & (1<hif_flag, stage); break; default: break; }; } static void polling_ready(struct ccci_modem *md, int step) { int cnt = 500; /*MD timeout is 10s*/ int time_once = 10; struct md_sys1_info *md_info = (struct md_sys1_info *)md->private_data; #ifdef CCCI_EE_HS_POLLING_TIME cnt = CCCI_EE_HS_POLLING_TIME / time_once; #endif while (cnt > 0) { if (md_info->channel_id & (1 << step)) { CCCI_DEBUG_LOG(md->index, TAG, "poll RCHNUM %d\n", md_info->channel_id); ccif_write32(md_info->ap_ccif_base, APCCIF_ACK, (1 << step)); return; } msleep(time_once); cnt--; } CCCI_ERROR_LOG(md->index, TAG, "poll EE HS timeout, RCHNUM %d\n", md_info->channel_id); } static int md_cd_ee_handshake(struct ccci_modem *md, int timeout) { /* seems sometime MD send D2H_EXCEPTION_INIT_DONE and * D2H_EXCEPTION_CLEARQ_DONE together */ /*polling_ready(md_ctrl, D2H_EXCEPTION_INIT);*/ __pm_wakeup_event(md->trm_wake_lock, jiffies_to_msecs(20 * HZ)); md_cd_exception(md, HIF_EX_INIT); __pm_wakeup_event(md->trm_wake_lock, jiffies_to_msecs(20 * HZ)); polling_ready(md, D2H_EXCEPTION_INIT_DONE); md_cd_exception(md, HIF_EX_INIT_DONE); __pm_wakeup_event(md->trm_wake_lock, jiffies_to_msecs(20 * HZ)); polling_ready(md, D2H_EXCEPTION_CLEARQ_DONE); md_cd_exception(md, HIF_EX_CLEARQ_DONE); __pm_wakeup_event(md->trm_wake_lock, jiffies_to_msecs(20 * HZ)); polling_ready(md, D2H_EXCEPTION_ALLQ_RESET); md_cd_exception(md, HIF_EX_ALLQ_RESET); return 0; } int md_fsm_exp_info(int md_id, unsigned int channel_id) { struct ccci_modem *md; struct md_sys1_info *md_info; CCCI_DEBUG_LOG(0, TAG, "%s\n", __func__); md = ccci_md_get_modem_by_id(md_id); if (!md) return 0; md_info = (struct md_sys1_info *)md->private_data; if (channel_id & (1 << D2H_EXCEPTION_INIT)) { ccci_fsm_recv_md_interrupt(md->index, MD_IRQ_CCIF_EX); md_info->channel_id = channel_id & ~(1 << D2H_EXCEPTION_INIT); return 0; } if (channel_id & (1<peer_wake_lock, jiffies_to_msecs(HZ)); channel_id &= ~(1 << AP_MD_PEER_WAKEUP); } if (channel_id & (1<index, TAG, "MD check seq fail\n"); md->ops->dump_info(md, DUMP_FLAG_CCIF, NULL, 0); channel_id &= ~(1 << AP_MD_SEQ_ERROR); } if (channel_id & (1 << D2H_EXCEPTION_INIT)) { /* do not disable IRQ, as CCB still needs it */ ccci_fsm_recv_md_interrupt(md->index, MD_IRQ_CCIF_EX); } md_info->channel_id |= channel_id; return 0; } EXPORT_SYMBOL(md_fsm_exp_info); static inline int md_sys1_sw_init(struct ccci_modem *md) { struct md_sys1_info *md_info = (struct md_sys1_info *)md->private_data; int ret; CCCI_BOOTUP_LOG(md->index, TAG, "%s, MD_WDT IRQ(%d) CCIF_IRQ %d\n", __func__, md->md_wdt_irq_id, md_info->ap_ccif_irq_id); ret = request_irq(md->md_wdt_irq_id, md_cd_wdt_isr, md->md_wdt_irq_flags, "MD_WDT", md); if (ret) { CCCI_ERROR_LOG(md->index, TAG, "request MD_WDT IRQ(%d) error %d\n", md->md_wdt_irq_id, ret); return ret; } ret = irq_set_irq_wake(md->md_wdt_irq_id, 1); if (ret) CCCI_ERROR_LOG(md->index, TAG, "irq_set_irq_wake MD_WDT IRQ(%d) error %d\n", md->md_wdt_irq_id, ret); return 0; } static int md_cd_init(struct ccci_modem *md) { CCCI_INIT_LOG(md->index, TAG, "CCCI: modem is initializing\n"); return 0; } /* Please delete this function once it can be deleted. */ static int ccci_md_hif_start(struct ccci_modem *md, int stage) { switch (stage) { case 1: /*enable clk: cldma*/ if (md->hw_info->plat_ptr->set_clk_cg) md->hw_info->plat_ptr->set_clk_cg(md, 1); //ccci_hif_set_clk_cg(1 << CLDMA_HIF_ID, md->index, 1); //if (md->hif_flag & (1 << CLDMA_HIF_ID)) { /* 2. clearring buffer, just in case */ //ccci_hif_clear_all_queue(1 << CLDMA_HIF_ID, OUT); //ccci_hif_clear_all_queue(1 << CLDMA_HIF_ID, IN); //if (md->hw_info->plat_ptr->cldma_hw_rst) // md->hw_info->plat_ptr->cldma_hw_rst(md->index); //ccci_hif_hw_reset(1 << CLDMA_HIF_ID, md->index); //} break; case 2: if (md->hif_flag & (1 << CCIF_HIF_ID)) ccif_enable_irq(md); //if (md->hif_flag & (1 << CLDMA_HIF_ID)) { /* 8. start CLDMA */ //ccci_hif_start(CLDMA_HIF_ID); //} break; default: break; } return 0; } static int md_cd_start(struct ccci_modem *md) { int ret = 0; if (md->per_md_data.config.setting & MD_SETTING_FIRST_BOOT) { if (md->hw_info->plat_ptr->remap_md_reg) md->hw_info->plat_ptr->remap_md_reg(md); md_sys1_sw_init(md); //ccci_hif_late_init(md->index, md->hif_flag); /* init security, as security depends on dummy_char, * which is ready very late. */ ccci_init_security(); ccci_md_clear_smem(md->index, 1); #if 0 //#if (MD_GENERATION >= 6293) md_ccif_ring_buf_init(CCIF_HIF_ID); #endif if (md->hw_info->plat_ptr->start_platform) { ret = md->hw_info->plat_ptr->start_platform(md); if (ret) { CCCI_BOOTUP_LOG(md->index, TAG, "power on MD BROM fail %d\n", ret); goto out; } } md->per_md_data.config.setting &= ~MD_SETTING_FIRST_BOOT; } else ccci_md_clear_smem(md->index, 0); CCCI_BOOTUP_LOG(md->index, TAG, "modem is starting\n"); /* 1. load modem image */ CCCI_BOOTUP_LOG(md->index, TAG, "modem image ready, bypass load\n"); ret = ccci_get_md_check_hdr_inf(md->index, &md->per_md_data.img_info[IMG_MD], md->per_md_data.img_post_fix); if (ret < 0) { CCCI_BOOTUP_LOG(md->index, TAG, "partition read fail(%d)\n", ret); /* goto out; */ } else CCCI_BOOTUP_LOG(md->index, TAG, "partition read success\n"); #ifdef FEATURE_BSI_BPI_SRAM_CFG ccci_set_bsi_bpi_SRAM_cfg(md, 1, MD_FLIGHT_MODE_NONE); #endif ccci_md_hif_start(md, 1); /* 4. power on modem, do NOT touch MD register before this */ if (md->hw_info->plat_ptr->power_on) { ret = md->hw_info->plat_ptr->power_on(md); if (ret) { CCCI_BOOTUP_LOG(md->index, TAG, "power on MD fail %d\n", ret); goto out; } } #ifdef SET_EMI_STEP_BY_STAGE ccci_set_mem_access_protection_1st_stage(md); #endif /* 5. update mutex */ atomic_set(&md->reset_on_going, 0); md->per_md_data.md_dbg_dump_flag = MD_DBG_DUMP_AP_REG; /* Notify ATF update md sec smem info */ ccci_get_md_sec_smem_size_and_update(); /* 7. let modem go */ if (md->hw_info->plat_ptr->let_md_go) md->hw_info->plat_ptr->let_md_go(md); wdt_enable_irq(md); ccci_md_hif_start(md, 2); md->per_md_data.is_in_ee_dump = 0; md->is_force_asserted = 0; out: CCCI_BOOTUP_LOG(md->index, TAG, "modem started %d\n", ret); /* used for throttling feature - start */ /*ccci_modem_boot_count[md->index]++;*/ /* used for throttling feature - end */ return ret; } static int check_power_off_en(struct ccci_modem *md) { int smem_val; struct ccci_smem_region *mdss_dbg = ccci_md_get_smem_by_user_id(md->index, SMEM_USER_RAW_MDSS_DBG); if (md->index != MD_SYS1) return 1; smem_val = *((int *)((long)mdss_dbg->base_ap_view_vir + md->hw_info->plat_val->offset_epof_md1)); CCCI_NORMAL_LOG(md->index, TAG, "share for power off:%x\n", smem_val); if (smem_val != 0) { CCCI_NORMAL_LOG(md->index, TAG, "[ccci]enable power off check\n"); return 1; } CCCI_NORMAL_LOG(md->index, TAG, "disable power off check\n"); return 0; } static int md_cd_soft_start(struct ccci_modem *md, unsigned int mode) { if (md->hw_info->plat_ptr->soft_power_on == NULL) return -1; return md->hw_info->plat_ptr->soft_power_on(md, mode); } static int md_cd_soft_stop(struct ccci_modem *md, unsigned int mode) { if (md->hw_info->plat_ptr->soft_power_off == NULL) return -1; return md->hw_info->plat_ptr->soft_power_off(md, mode); } void __weak md1_sleep_timeout_proc(void) { CCCI_DEBUG_LOG(-1, TAG, "No %s\n", __func__); } static int md_cd_pre_stop(struct ccci_modem *md, unsigned int stop_type) { int en_power_check; u32 pending; struct ccci_smem_region *mdccci_dbg = ccci_md_get_smem_by_user_id(md->index, SMEM_USER_RAW_MDCCCI_DBG); struct ccci_smem_region *mdss_dbg = ccci_md_get_smem_by_user_id(md->index, SMEM_USER_RAW_MDSS_DBG); struct ccci_per_md *per_md_data = ccci_get_per_md_data(md->index); int md_dbg_dump_flag = per_md_data->md_dbg_dump_flag; /* 1. mutex check */ if (atomic_add_return(1, &md->reset_on_going) > 1) { CCCI_NORMAL_LOG(md->index, TAG, "One reset flow is on-going\n"); return -CCCI_ERR_MD_IN_RESET; } CCCI_NORMAL_LOG(md->index, TAG, "%s: CCCI modem is resetting\n", __func__); /* 2. disable WDT IRQ */ wdt_disable_irq(md); en_power_check = check_power_off_en(md); /* only debug in Flight mode */ if (stop_type == MD_FLIGHT_MODE_ENTER) { debug_in_flight_mode(md); #ifdef CCCI_KMODULE_ENABLE pending = 0; #else pending = mt_irq_get_pending(md->md_wdt_irq_id); #endif if (pending) { CCCI_NORMAL_LOG(md->index, TAG, "WDT IRQ occur."); CCCI_MEM_LOG_TAG(md->index, TAG, "Dump MD EX log\n"); if (md_dbg_dump_flag & (1 << MD_DBG_DUMP_SMEM)) { ccci_util_mem_dump(md->index, CCCI_DUMP_MEM_DUMP, mdccci_dbg->base_ap_view_vir, mdccci_dbg->size); ccci_util_mem_dump(md->index, CCCI_DUMP_MEM_DUMP, mdss_dbg->base_ap_view_vir, mdss_dbg->size); } if (md->hw_info->plat_ptr->debug_reg) md->hw_info->plat_ptr->debug_reg(md); /* cldma_dump_register(CLDMA_HIF_ID);*/ #if defined(CONFIG_MTK_AEE_FEATURE) aed_md_exception_api(NULL, 0, NULL, 0, "WDT IRQ occur.", DB_OPT_DEFAULT); #endif } } CCCI_NORMAL_LOG(md->index, TAG, "Reset when MD state: %d\n", ccci_fsm_get_md_state(md->index)); return 0; } static void debug_in_flight_mode(struct ccci_modem *md) { int count = 0; int en_power_check; struct ccci_smem_region *mdccci_dbg = ccci_md_get_smem_by_user_id(md->index, SMEM_USER_RAW_MDCCCI_DBG); struct ccci_smem_region *mdss_dbg = ccci_md_get_smem_by_user_id(md->index, SMEM_USER_RAW_MDSS_DBG); struct ccci_per_md *per_md_data = ccci_get_per_md_data(md->index); int md_dbg_dump_flag = per_md_data->md_dbg_dump_flag; en_power_check = check_power_off_en(md); count = 5; while (spm_is_md1_sleep() == 0) { count--; if (count == 0) { if (en_power_check) { CCCI_NORMAL_LOG(md->index, TAG, "MD is not in sleep mode, dump md status!\n"); CCCI_MEM_LOG_TAG(md->index, TAG, "Dump MD EX log\n"); if (md_dbg_dump_flag & (1 << MD_DBG_DUMP_SMEM)) { ccci_util_mem_dump(md->index, CCCI_DUMP_MEM_DUMP, mdccci_dbg->base_ap_view_vir, mdccci_dbg->size); ccci_util_mem_dump(md->index, CCCI_DUMP_MEM_DUMP, mdss_dbg->base_ap_view_vir, mdss_dbg->size); } if (md->hw_info->plat_ptr->debug_reg) md->hw_info->plat_ptr->debug_reg(md); /* cldma_dump_register(CLDMA_HIF_ID);*/ #if defined(CONFIG_MTK_AEE_FEATURE) aed_md_exception_api( mdss_dbg->base_ap_view_vir, mdss_dbg->size, NULL, 0, "After AP send EPOF, MD didn't go to sleep in 4 seconds.", DB_OPT_DEFAULT); #endif } else md1_sleep_timeout_proc(); break; } if (md->hw_info->plat_ptr->lock_cldma_clock_src) { md->hw_info->plat_ptr->lock_cldma_clock_src(1); msleep(1000); md->hw_info->plat_ptr->lock_cldma_clock_src(0); msleep(20); } } } static int md_cd_stop(struct ccci_modem *md, unsigned int stop_type) { int ret = 0; int i; struct md_sys1_info *md_info = (struct md_sys1_info *)md->private_data; unsigned int rx_ch_bitmap; CCCI_NORMAL_LOG(md->index, TAG, "modem is power off, stop_type=%d\n", stop_type); ccif_disable_irq(md); /* Check EMI before */ if (md->hw_info->plat_ptr->check_emi_state) md->hw_info->plat_ptr->check_emi_state(md, 1); /* power off MD */ if (md->hw_info->plat_ptr->power_off) ret = md->hw_info->plat_ptr->power_off(md, stop_type == MD_FLIGHT_MODE_ENTER ? 100 : 0); CCCI_NORMAL_LOG(md->index, TAG, "modem is power off done, %d\n", ret); if (md->hif_flag & (1<index); cldma_plat_set_clk_cg(md->index, 0); } rx_ch_bitmap = ccif_read32(md_info->md_ccif_base, APCCIF_RCHNUM); if (rx_ch_bitmap) { CCCI_NORMAL_LOG(md->index, TAG, "CCIF rx bitmap: 0x%x\n", rx_ch_bitmap); for (i = 0; i < CCIF_CH_NUM; i++) { /* Ack one by one */ if (rx_ch_bitmap & (1 << i)) ccif_write32(md_info->md_ccif_base, APCCIF_ACK, (1 << i)); } rx_ch_bitmap = ccif_read32(md_info->md_ccif_base, APCCIF_RCHNUM); CCCI_NORMAL_LOG(md->index, TAG, "CCIF rx bitmap: 0x%x(after ack)\n", rx_ch_bitmap); } /* Check EMI after */ if (md->hw_info->plat_ptr->check_emi_state) md->hw_info->plat_ptr->check_emi_state(md, 0); /*disable cldma & ccif clk*/ if (md->hw_info->plat_ptr->set_clk_cg) md->hw_info->plat_ptr->set_clk_cg(md, 0); #ifdef FEATURE_BSI_BPI_SRAM_CFG ccci_set_bsi_bpi_SRAM_cfg(md, 0, stop_type); #endif return 0; } static void dump_runtime_data_v2(struct ccci_modem *md, struct ap_query_md_feature *ap_feature) { u8 i = 0; CCCI_BOOTUP_LOG(md->index, TAG, "head_pattern 0x%x\n", ap_feature->head_pattern); for (i = BOOT_INFO; i < AP_RUNTIME_FEATURE_ID_MAX; i++) { CCCI_BOOTUP_LOG(md->index, TAG, "feature %u: mask %u, version %u\n", i, ap_feature->feature_set[i].support_mask, ap_feature->feature_set[i].version); } CCCI_BOOTUP_LOG(md->index, TAG, "share_memory_support 0x%x\n", ap_feature->share_memory_support); CCCI_BOOTUP_LOG(md->index, TAG, "ap_runtime_data_addr 0x%x\n", ap_feature->ap_runtime_data_addr); CCCI_BOOTUP_LOG(md->index, TAG, "ap_runtime_data_size 0x%x\n", ap_feature->ap_runtime_data_size); CCCI_BOOTUP_LOG(md->index, TAG, "md_runtime_data_addr 0x%x\n", ap_feature->md_runtime_data_addr); CCCI_BOOTUP_LOG(md->index, TAG, "md_runtime_data_size 0x%x\n", ap_feature->md_runtime_data_size); CCCI_BOOTUP_LOG(md->index, TAG, "set_md_mpu_start_addr 0x%x\n", ap_feature->set_md_mpu_start_addr); CCCI_BOOTUP_LOG(md->index, TAG, "set_md_mpu_total_size 0x%x\n", ap_feature->set_md_mpu_total_size); CCCI_BOOTUP_LOG(md->index, TAG, "tail_pattern 0x%x\n", ap_feature->tail_pattern); } static void dump_runtime_data_v2_1(struct ccci_modem *md, struct ap_query_md_feature_v2_1 *ap_feature) { u8 i = 0; CCCI_BOOTUP_LOG(md->index, TAG, "head_pattern 0x%x\n", ap_feature->head_pattern); for (i = BOOT_INFO; i < AP_RUNTIME_FEATURE_ID_MAX; i++) { CCCI_BOOTUP_LOG(md->index, TAG, "feature %u: mask %u, version %u\n", i, ap_feature->feature_set[i].support_mask, ap_feature->feature_set[i].version); } CCCI_BOOTUP_LOG(md->index, TAG, "share_memory_support 0x%x\n", ap_feature->share_memory_support); CCCI_BOOTUP_LOG(md->index, TAG, "ap_runtime_data_addr 0x%x\n", ap_feature->ap_runtime_data_addr); CCCI_BOOTUP_LOG(md->index, TAG, "ap_runtime_data_size 0x%x\n", ap_feature->ap_runtime_data_size); CCCI_BOOTUP_LOG(md->index, TAG, "md_runtime_data_addr 0x%x\n", ap_feature->md_runtime_data_addr); CCCI_BOOTUP_LOG(md->index, TAG, "md_runtime_data_size 0x%x\n", ap_feature->md_runtime_data_size); CCCI_BOOTUP_LOG(md->index, TAG, "set_md_mpu_noncached_start_addr 0x%x\n", ap_feature->noncached_mpu_start_addr); CCCI_BOOTUP_LOG(md->index, TAG, "set_md_mpu_noncached_total_size 0x%x\n", ap_feature->noncached_mpu_total_size); CCCI_BOOTUP_LOG(md->index, TAG, "set_md_mpu_cached_start_addr 0x%x\n", ap_feature->cached_mpu_start_addr); CCCI_BOOTUP_LOG(md->index, TAG, "set_md_mpu_cached_total_size 0x%x\n", ap_feature->cached_mpu_total_size); CCCI_BOOTUP_LOG(md->index, TAG, "tail_pattern 0x%x\n", ap_feature->tail_pattern); } static void md_cd_smem_sub_region_init(struct ccci_modem *md) { int __iomem *addr; int i; struct ccci_smem_region *dbm = ccci_md_get_smem_by_user_id(md->index, SMEM_USER_RAW_DBM); /* Region 0, dbm */ addr = (int __iomem *)dbm->base_ap_view_vir; addr[0] = 0x44444444; /* Guard pattern 1 header */ addr[1] = 0x44444444; /* Guard pattern 2 header */ #ifdef DISABLE_PBM_FEATURE for (i = 2; i < (CCCI_SMEM_SIZE_DBM/4+2); i++) addr[i] = 0xFFFFFFFF; #else for (i = 2; i < (CCCI_SMEM_SIZE_DBM/4+2); i++) addr[i] = 0x00000000; #endif addr[i++] = 0x44444444; /* Guard pattern 1 tail */ addr[i++] = 0x44444444; /* Guard pattern 2 tail */ /* Notify PBM */ #ifndef DISABLE_PBM_FEATURE init_md_section_level(KR_MD1); #endif } static void config_ap_runtime_data_v2(struct ccci_modem *md, struct ap_query_md_feature *ap_feature) { struct ccci_smem_region *runtime_data = ccci_md_get_smem_by_user_id(md->index, SMEM_USER_RAW_RUNTIME_DATA); ap_feature->head_pattern = AP_FEATURE_QUERY_PATTERN; /*AP query MD feature set */ ap_feature->share_memory_support = INTERNAL_MODEM; ap_feature->ap_runtime_data_addr = runtime_data->base_md_view_phy; ap_feature->ap_runtime_data_size = CCCI_SMEM_SIZE_RUNTIME_AP; ap_feature->md_runtime_data_addr = ap_feature->ap_runtime_data_addr + CCCI_SMEM_SIZE_RUNTIME_AP; ap_feature->md_runtime_data_size = CCCI_SMEM_SIZE_RUNTIME_MD; ap_feature->set_md_mpu_start_addr = md->mem_layout.md_bank4_noncacheable_total.base_md_view_phy; ap_feature->set_md_mpu_total_size = md->mem_layout.md_bank4_noncacheable_total.size; /* Set Flag for modem on feature_set[1].version, * specially: [1].support_mask = 0 */ ap_feature->feature_set[1].support_mask = 0; /* ver.1: set_md_mpu_total_size = * ap md1 share + md1&md3 share */ /* ver.0: set_md_mpu_total_size = ap md1 share */ ap_feature->feature_set[1].version = 1; ap_feature->tail_pattern = AP_FEATURE_QUERY_PATTERN; } static void config_ap_runtime_data_v2_1(struct ccci_modem *md, struct ap_query_md_feature_v2_1 *ap_feature) { struct ccci_smem_region *runtime_data = ccci_md_get_smem_by_user_id(md->index, SMEM_USER_RAW_RUNTIME_DATA); int sec_smem_size = ccci_get_md_sec_smem_size_and_update(); ap_feature->head_pattern = AP_FEATURE_QUERY_PATTERN; /*AP query MD feature set */ /* to let md know that this is new AP. */ ap_feature->share_memory_support = MULTI_MD_MPU_SUPPORT; ap_feature->ap_runtime_data_addr = runtime_data->base_md_view_phy; ap_feature->ap_runtime_data_size = CCCI_SMEM_SIZE_RUNTIME_AP; ap_feature->md_runtime_data_addr = ap_feature->ap_runtime_data_addr + CCCI_SMEM_SIZE_RUNTIME_AP; ap_feature->md_runtime_data_size = CCCI_SMEM_SIZE_RUNTIME_MD; ap_feature->noncached_mpu_start_addr = md->mem_layout.md_bank4_noncacheable_total.base_md_view_phy; ap_feature->noncached_mpu_total_size = md->mem_layout.md_bank4_noncacheable_total.size + sec_smem_size; ap_feature->cached_mpu_start_addr = md->mem_layout.md_bank4_cacheable_total.base_md_view_phy; ap_feature->cached_mpu_total_size = md->mem_layout.md_bank4_cacheable_total.size; /* Set Flag for modem on feature_set[1].version, * specially: [1].support_mask = 0 */ ap_feature->feature_set[1].support_mask = 0; /* ver.1: set_md_mpu_total_size = * ap md1 share + md1&md3 share */ /* ver.0: set_md_mpu_total_size = ap md1 share */ ap_feature->feature_set[1].version = 1; ap_feature->tail_pattern = AP_FEATURE_QUERY_PATTERN; } static int md_cd_send_runtime_data_v2(struct ccci_modem *md, unsigned int tx_ch, unsigned int txqno, int skb_from_pool) { int packet_size; struct ap_query_md_feature *ap_rt_data; struct ap_query_md_feature_v2_1 *ap_rt_data_v2_1; int ret; if (md->runtime_version < AP_MD_HS_V2) { CCCI_ERROR_LOG(md->index, TAG, "unsupported runtime version %d\n", md->runtime_version); return -CCCI_ERR_CCIF_INVALID_RUNTIME_LEN; } if (md->multi_md_mpu_support) { packet_size = sizeof(struct ap_query_md_feature_v2_1) + sizeof(struct ccci_header); ap_rt_data_v2_1 = (struct ap_query_md_feature_v2_1 *) ccci_hif_fill_rt_header(CCIF_HIF_ID, packet_size, tx_ch, txqno); if (!ap_rt_data_v2_1) { CCCI_ERROR_LOG(md->index, TAG, "rt header v2 NULL!\n"); return -1; } memset_io(ap_rt_data_v2_1, 0, sizeof(struct ap_query_md_feature_v2_1)); config_ap_runtime_data_v2_1(md, ap_rt_data_v2_1); dump_runtime_data_v2_1(md, ap_rt_data_v2_1); } else { /* infactly, 6292 should not be this else condition */ packet_size = sizeof(struct ap_query_md_feature) + sizeof(struct ccci_header); ap_rt_data = (struct ap_query_md_feature *) ccci_hif_fill_rt_header(CCIF_HIF_ID, packet_size, tx_ch, txqno); if (!ap_rt_data) { CCCI_ERROR_LOG(md->index, TAG, "rt header NULL!\n"); return -1; } memset_io(ap_rt_data, 0, sizeof(struct ap_query_md_feature)); config_ap_runtime_data_v2(md, ap_rt_data); dump_runtime_data_v2(md, ap_rt_data); } md_cd_smem_sub_region_init(md); ret = ccci_hif_send_data(CCIF_HIF_ID, H2D_SRAM); return ret; } static int md_cd_force_assert(struct ccci_modem *md, enum MD_COMM_TYPE type) { CCCI_NORMAL_LOG(md->index, TAG, "force assert MD using %d\n", type); if (type == CCIF_INTERRUPT) ccci_hif_send_data(CCIF_HIF_ID, AP_MD_SEQ_ERROR); else if (type == CCIF_MPU_INTR) { ccci_hif_send_data(CCIF_HIF_ID, H2D_MPU_FORCE_ASSERT); md->ops->dump_info(md, DUMP_FLAG_CCIF_REG, NULL, 0); } return 0; } static int md_cd_dump_info(struct ccci_modem *md, enum MODEM_DUMP_FLAG flag, void *buff, int length) { struct md_sys1_info *md_info = (struct md_sys1_info *)md->private_data; if (flag & DUMP_FLAG_CCIF_REG) { CCCI_MEM_LOG_TAG(md->index, TAG, "Dump CCIF REG\n"); ccci_hif_dump_status(CCIF_HIF_ID, DUMP_FLAG_CCIF_REG, NULL, -1); } if (flag & DUMP_FLAG_PCCIF_REG) { CCCI_MEM_LOG_TAG(md->index, TAG, "ignore Dump PCCIF REG\n"); /*md_cd_dump_pccif_reg(md);*/ } if (flag & DUMP_FLAG_CCIF) { unsigned int *dest_buff = NULL; unsigned char ccif_sram[CCCI_EE_SIZE_CCIF_SRAM] = { 0 }; if (buff) dest_buff = (unsigned int *)buff; else dest_buff = (unsigned int *)ccif_sram; if (length < sizeof(ccif_sram) && length > 0) { CCCI_ERROR_LOG(md->index, TAG, "dump CCIF SRAM length illegal %d/%zu\n", length, sizeof(ccif_sram)); dest_buff = (unsigned int *)ccif_sram; } else { length = sizeof(ccif_sram); } ccci_hif_dump_status(1 << CCIF_HIF_ID, DUMP_FLAG_CCIF, buff, length); } /*HIF related dump flag*/ if (flag & (DUMP_FLAG_QUEUE_0_1 | DUMP_FLAG_QUEUE_0 | DUMP_FLAG_IRQ_STATUS | DUMP_FLAG_CLDMA)) ccci_hif_dump_status(md->hif_flag, flag, NULL, length); if ((flag & DUMP_FLAG_REG) && md->hw_info->plat_ptr->debug_reg) md->hw_info->plat_ptr->debug_reg(md); if (flag & DUMP_FLAG_SMEM_EXP) { struct ccci_smem_region *mdccci_dbg = ccci_md_get_smem_by_user_id(md->index, SMEM_USER_RAW_MDCCCI_DBG); struct ccci_smem_region *mdss_dbg = ccci_md_get_smem_by_user_id(md->index, SMEM_USER_RAW_MDSS_DBG); CCCI_MEM_LOG_TAG(md->index, TAG, "Dump exception share memory\n"); ccci_util_mem_dump(md->index, CCCI_DUMP_MEM_DUMP, mdccci_dbg->base_ap_view_vir, mdccci_dbg->size); ccci_util_mem_dump(md->index, CCCI_DUMP_MEM_DUMP, mdss_dbg->base_ap_view_vir, mdss_dbg->size); } if (flag & DUMP_FLAG_SMEM_CCISM) { struct ccci_smem_region *scp = ccci_md_get_smem_by_user_id(md->index, SMEM_USER_CCISM_SCP); CCCI_MEM_LOG_TAG(md->index, TAG, "Dump CCISM share memory\n"); ccci_util_mem_dump(md->index, CCCI_DUMP_MEM_DUMP, scp->base_ap_view_vir, scp->size); } if (flag & DUMP_FLAG_SMEM_CCB_CTRL) { struct ccci_smem_region *ccb_ctl = ccci_md_get_smem_by_user_id(md->index, SMEM_USER_RAW_CCB_CTRL); if (ccb_ctl) { CCCI_MEM_LOG_TAG(md->index, TAG, "Dump CCB CTRL share memory\n"); ccci_util_mem_dump(md->index, CCCI_DUMP_MEM_DUMP, ccb_ctl->base_ap_view_vir, 32 * ccb_configs_len * 2); } } if (flag & DUMP_FLAG_SMEM_CCB_DATA) { int i, j; unsigned char *curr_ch_p; unsigned int *curr_p; struct ccci_smem_region *ccb_data = ccci_md_get_smem_by_user_id(md->index, SMEM_USER_CCB_START); struct ccci_smem_region *dhl_raw = ccci_md_get_smem_by_user_id(md->index, SMEM_USER_RAW_DHL); if (ccb_data && ccb_data->size != 0) { CCCI_MEM_LOG_TAG(md->index, TAG, "Dump CCB DATA share memory\n"); curr_ch_p = ccb_data->base_ap_view_vir; curr_p = (unsigned int *)curr_ch_p; for (i = 0; i < ccb_configs_len; i++) { /* dump dl buffer */ for (j = 0; j < ccb_configs[i].dl_buff_size / ccb_configs[i].dl_page_size; j++) { ccci_dump_write(md->index, CCCI_DUMP_MEM_DUMP, 0, "ul_buf%2d-page%2d %p: %08X %08X %08X %08X\n", i, j, curr_p, *curr_p, *(curr_p + 1), *(curr_p + 2), *(curr_p + 3)); curr_ch_p += ccb_configs[i].dl_page_size; curr_p = (unsigned int *)curr_ch_p; } /* dump ul buffer */ for (j = 0; j < ccb_configs[i].ul_buff_size / ccb_configs[i].ul_page_size; j++) { ccci_dump_write(md->index, CCCI_DUMP_MEM_DUMP, 0, "dl_buf%2d-page%2d %p: %08X %08X %08X %08X\n", i, j, curr_p, *curr_p, *(curr_p + 1), *(curr_p + 2), *(curr_p + 3)); curr_ch_p += ccb_configs[i].ul_page_size; curr_p = (unsigned int *)curr_ch_p; } } } if (dhl_raw && dhl_raw->size) { CCCI_MEM_LOG_TAG(md->index, TAG, "Dump DHL RAW share memory\n"); curr_ch_p = dhl_raw->base_ap_view_vir; curr_p = (unsigned int *)curr_ch_p; ccci_dump_write(md->index, CCCI_DUMP_MEM_DUMP, 0, "%p: %08X %08X %08X %08X\n", curr_p, *curr_p, *(curr_p + 1), *(curr_p + 2), *(curr_p + 3)); } } if (flag & DUMP_FLAG_IMAGE) { CCCI_MEM_LOG_TAG(md->index, TAG, "Dump MD image not support\n"); } if (flag & DUMP_FLAG_LAYOUT) { CCCI_MEM_LOG_TAG(md->index, TAG, "Dump MD layout struct\n"); ccci_util_mem_dump(md->index, CCCI_DUMP_MEM_DUMP, &md->mem_layout, sizeof(struct ccci_mem_layout)); } if (flag & DUMP_FLAG_SMEM_MDSLP) { struct ccci_smem_region *low_pwr = ccci_md_get_smem_by_user_id(md->index, SMEM_USER_RAW_DBM); CCCI_MEM_LOG_TAG(md->index, TAG, "Dump MD SLP registers\n"); ccci_cmpt_mem_dump(md->index, low_pwr->base_ap_view_vir, low_pwr->size); } if (flag & DUMP_FLAG_MD_WDT) { CCCI_MEM_LOG_TAG(md->index, TAG, "Dump MD RGU registers\n"); if (md->hw_info->plat_ptr->lock_modem_clock_src) md->hw_info->plat_ptr->lock_modem_clock_src(1); #ifdef BASE_ADDR_MDRSTCTL ccci_util_mem_dump(md->index, CCCI_DUMP_MEM_DUMP, md_info->md_rgu_base, 0x88); ccci_util_mem_dump(md->index, CCCI_DUMP_MEM_DUMP, (md_info->md_rgu_base + 0x200), 0x5c); #else ccci_util_mem_dump(md->index, CCCI_DUMP_MEM_DUMP, md_info->md_rgu_base, 0x30); #endif if (md->hw_info->plat_ptr->lock_modem_clock_src) md->hw_info->plat_ptr->lock_modem_clock_src(0); CCCI_MEM_LOG_TAG(md->index, TAG, "wdt_enabled=%d\n", atomic_read(&md->wdt_enabled)); } if ((flag & DUMP_MD_BOOTUP_STATUS) && md->hw_info->plat_ptr->get_md_bootup_status) md->hw_info->plat_ptr->get_md_bootup_status(md, (unsigned int *)buff, length); return length; } static int md_cd_ee_callback(struct ccci_modem *md, enum MODEM_EE_FLAG flag) { if (flag & EE_FLAG_ENABLE_WDT) wdt_enable_irq(md); if (flag & EE_FLAG_DISABLE_WDT) wdt_disable_irq(md); return 0; } static int md_cd_send_ccb_tx_notify(struct ccci_modem *md, int core_id) { /* CCCI_NORMAL_LOG(md->index, TAG, * "ccb tx notify to core %d\n", core_id); */ switch (core_id) { case P_CORE: ccci_hif_send_data(CCIF_HIF_ID, AP_MD_CCB_WAKEUP); break; case VOLTE_CORE: default: break; } return 0; } static struct ccci_modem_ops md_cd_ops = { .init = &md_cd_init, .start = &md_cd_start, .stop = &md_cd_stop, .soft_start = &md_cd_soft_start, .soft_stop = &md_cd_soft_stop, .pre_stop = &md_cd_pre_stop, .send_runtime_data = &md_cd_send_runtime_data_v2, .ee_handshake = &md_cd_ee_handshake, .force_assert = &md_cd_force_assert, .dump_info = &md_cd_dump_info, .ee_callback = &md_cd_ee_callback, .send_ccb_tx_notify = &md_cd_send_ccb_tx_notify, }; static ssize_t md_cd_debug_show(struct ccci_modem *md, char *buf) { int curr = 0; curr = snprintf(buf, 16, "%d\n", ccci_debug_enable); if (curr < 0 || curr >= 16) { CCCI_ERROR_LOG(md->index, TAG, "%s-%d:snprintf fail,curr=%d\n", __func__, __LINE__, curr); return -1; } return curr; } static ssize_t md_cd_debug_store(struct ccci_modem *md, const char *buf, size_t count) { ccci_debug_enable = buf[0] - '0'; return count; } static ssize_t md_cd_dump_show(struct ccci_modem *md, char *buf) { int count = 0; count = snprintf(buf, 256, "support: ccif cldma register smem image layout\n"); if (count < 0 || count >= 256) { CCCI_ERROR_LOG(md->index, TAG, "%s-%d:snprintf fail,count=%d\n", __func__, __LINE__, count); return -1; } return count; } static ssize_t md_cd_dump_store(struct ccci_modem *md, const char *buf, size_t count) { enum MD_STATE md_state = ccci_fsm_get_md_state(md->index); /* echo will bring "xxx\n" here, * so we eliminate the "\n" during comparing */ if (md_state != GATED && md_state != INVALID) { if (strncmp(buf, "ccif", count - 1) == 0) ccci_hif_dump_status(1 << CCIF_HIF_ID, DUMP_FLAG_CCIF_REG | DUMP_FLAG_CCIF, NULL, 0); if ((strncmp(buf, "cldma", count - 1) == 0) && (md->hif_flag&(1<ops->dump_info(md, DUMP_FLAG_REG, NULL, 0); if (strncmp(buf, "smem_exp", count-1) == 0) md->ops->dump_info(md, DUMP_FLAG_SMEM_EXP, NULL, 0); if (strncmp(buf, "smem_ccism", count-1) == 0) md->ops->dump_info(md, DUMP_FLAG_SMEM_CCISM, NULL, 0); if (strncmp(buf, "smem_ccb_ctrl", count-1) == 0) md->ops->dump_info(md, DUMP_FLAG_SMEM_CCB_CTRL, NULL, 0); if (strncmp(buf, "smem_ccb_data", count-1) == 0) md->ops->dump_info(md, DUMP_FLAG_SMEM_CCB_DATA, NULL, 0); if (strncmp(buf, "pccif", count - 1) == 0) md->ops->dump_info(md, DUMP_FLAG_PCCIF_REG, NULL, 0); if (strncmp(buf, "image", count - 1) == 0) md->ops->dump_info(md, DUMP_FLAG_IMAGE, NULL, 0); if (strncmp(buf, "layout", count - 1) == 0) md->ops->dump_info(md, DUMP_FLAG_LAYOUT, NULL, 0); if (strncmp(buf, "mdslp", count - 1) == 0) md->ops->dump_info(md, DUMP_FLAG_SMEM_MDSLP, NULL, 0); if (strncmp(buf, "dpmaif", count - 1) == 0) ccci_hif_dump_status(1<index); } return count; } static ssize_t md_cd_control_show(struct ccci_modem *md, char *buf) { int count = 0; count = snprintf(buf, 256, "support: cldma_reset cldma_stop ccif_assert md_type trace_sample\n"); if (count < 0 || count >= 256) { CCCI_ERROR_LOG(md->index, TAG, "%s-%d:snprintf fail,count=%d\n", __func__, __LINE__, count); return -1; } return count; } static ssize_t md_cd_control_store(struct ccci_modem *md, const char *buf, size_t count) { int size = 0; if (md->hif_flag&(1<hw_info->plat_ptr->lock_cldma_clock_src) { if (strncmp(buf, "cldma_reset", count - 1) == 0) { CCCI_NORMAL_LOG(md->index, TAG, "reset CLDMA\n"); md->hw_info->plat_ptr->lock_cldma_clock_src(1); ccci_hif_stop(CLDMA_HIF_ID); md_cd_clear_all_queue(1 << CLDMA_HIF_ID, OUT); md_cd_clear_all_queue(1 << CLDMA_HIF_ID, IN); ccci_hif_start(CLDMA_HIF_ID); md->hw_info->plat_ptr->lock_cldma_clock_src(0); } if (strncmp(buf, "cldma_stop", count - 1) == 0) { CCCI_NORMAL_LOG(md->index, TAG, "stop CLDMA\n"); md->hw_info->plat_ptr->lock_cldma_clock_src(1); ccci_hif_stop(CLDMA_HIF_ID); md->hw_info->plat_ptr->lock_cldma_clock_src(0); } } } if (strncmp(buf, "ccif_assert", count - 1) == 0) { CCCI_NORMAL_LOG(md->index, TAG, "use CCIF to force MD assert\n"); md->ops->force_assert(md, CCIF_INTERRUPT); } if (strncmp(buf, "ccif_reset", count - 1) == 0) { CCCI_NORMAL_LOG(md->index, TAG, "reset AP MD1 CCIF\n"); ccci_hif_debug(CCIF_HIF_ID, CCCI_HIF_DEBUG_RESET, NULL, -1); } if (strncmp(buf, "ccci_trm", count - 1) == 0) { CCCI_NORMAL_LOG(md->index, TAG, "TRM triggered\n"); /* ccci_md_send_msg_to_user(md, CCCI_MONITOR_CH, * CCCI_MD_MSG_RESET_REQUEST, 0); */ } size = strlen("md_type="); if (strncmp(buf, "md_type=", size) == 0) { md->per_md_data.config.load_type_saving = buf[size] - '0'; CCCI_NORMAL_LOG(md->index, TAG, "md_type_store %d\n", md->per_md_data.config.load_type_saving); /* ccci_md_send_msg_to_user(md, CCCI_MONITOR_CH, * CCCI_MD_MSG_STORE_NVRAM_MD_TYPE, 0); */ } size = strlen("trace_sample="); if (strncmp(buf, "trace_sample=", size) == 0) { trace_sample_time = (buf[size] - '0') * 100000000; CCCI_NORMAL_LOG(md->index, TAG, "trace_sample_time %u\n", trace_sample_time); } size = strlen("md_dbg_dump="); if (strncmp(buf, "md_dbg_dump=", size) == 0 && size < count - 1) { size = kstrtouint(buf+size, 16, &md->per_md_data.md_dbg_dump_flag); if (size) md->per_md_data.md_dbg_dump_flag = MD_DBG_DUMP_ALL; CCCI_NORMAL_LOG(md->index, TAG, "md_dbg_dump 0x%X\n", md->per_md_data.md_dbg_dump_flag); } return count; } static ssize_t md_cd_parameter_show(struct ccci_modem *md, char *buf) { int count = 0; int ret = 0; ret = snprintf(buf + count, 128, "PACKET_HISTORY_DEPTH=%d\n", PACKET_HISTORY_DEPTH); if (ret < 0 || ret >= 128) { CCCI_ERROR_LOG(md->index, TAG, "%s-%d:snprintf fail,ret=%d\n", __func__, __LINE__, ret); return -1; } count += ret; ret = snprintf(buf + count, 128, "BD_NUM=%ld\n", MAX_BD_NUM); if (ret < 0 || ret >= 128) { CCCI_ERROR_LOG(md->index, TAG, "%s-%d:snprintf fail,ret=%d\n", __func__, __LINE__, ret); return -1; } count += ret; return count; } static ssize_t md_cd_parameter_store(struct ccci_modem *md, const char *buf, size_t count) { return count; } CCCI_MD_ATTR(NULL, debug, 0660, md_cd_debug_show, md_cd_debug_store); CCCI_MD_ATTR(NULL, dump, 0660, md_cd_dump_show, md_cd_dump_store); CCCI_MD_ATTR(NULL, control, 0660, md_cd_control_show, md_cd_control_store); CCCI_MD_ATTR(NULL, parameter, 0660, md_cd_parameter_show, md_cd_parameter_store); static void md_cd_sysfs_init(struct ccci_modem *md) { int ret; ccci_md_attr_debug.modem = md; ret = sysfs_create_file(&md->kobj, &ccci_md_attr_debug.attr); if (ret) CCCI_ERROR_LOG(md->index, TAG, "fail to add sysfs node %s %d\n", ccci_md_attr_debug.attr.name, ret); ccci_md_attr_dump.modem = md; ret = sysfs_create_file(&md->kobj, &ccci_md_attr_dump.attr); if (ret) CCCI_ERROR_LOG(md->index, TAG, "fail to add sysfs node %s %d\n", ccci_md_attr_dump.attr.name, ret); ccci_md_attr_control.modem = md; ret = sysfs_create_file(&md->kobj, &ccci_md_attr_control.attr); if (ret) CCCI_ERROR_LOG(md->index, TAG, "fail to add sysfs node %s %d\n", ccci_md_attr_control.attr.name, ret); ccci_md_attr_parameter.modem = md; ret = sysfs_create_file(&md->kobj, &ccci_md_attr_parameter.attr); if (ret) CCCI_ERROR_LOG(md->index, TAG, "fail to add sysfs node %s %d\n", ccci_md_attr_parameter.attr.name, ret); } /* weak function for compatibility */ int __weak ccci_modem_suspend_noirq(struct device *dev) { CCCI_NORMAL_LOG(-1, TAG, "%s:weak function\n", __func__); return 0; } int __weak ccci_modem_resume_noirq(struct device *dev) { CCCI_NORMAL_LOG(-1, TAG, "%s:weak function\n", __func__); return 0; } int __weak ccci_modem_plt_suspend(struct ccci_modem *md) { CCCI_NORMAL_LOG(0, TAG, "[%s] md->hif_flag = %d,move to drivers module\n", __func__, md->hif_flag); return 0; } int ccci_modem_syssuspend(void) { struct ccci_modem *md; md = ccci_md_get_modem_by_id(0); if (md != NULL) ccci_modem_plt_suspend(md); else CCCI_ERROR_LOG(0, TAG, "[%s] error: md is NULL.\n", __func__); return 0; } void __weak ccci_modem_plt_resume(struct ccci_modem *md) { CCCI_NORMAL_LOG(0, TAG, "[%s] md->hif_flag = %d,move to drivers module\n", __func__, md->hif_flag); } void ccci_modem_sysresume(void) { struct ccci_modem *md; md = ccci_md_get_modem_by_id(0); if (md != NULL) ccci_modem_plt_resume(md); else CCCI_ERROR_LOG(0, TAG, "[%s] error: md is NULL.\n", __func__); } static struct syscore_ops ccci_modem_sysops = { .suspend = ccci_modem_syssuspend, .resume = ccci_modem_sysresume, }; #define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : ((1ULL<<(n))-1)) static u64 cldma_dmamask = DMA_BIT_MASK(36); static int ccci_modem_probe(struct platform_device *plat_dev) { struct ccci_modem *md = NULL; struct md_sys1_info *md_info = NULL; int md_id; struct ccci_dev_cfg dev_cfg; int ret; struct md_hw_info *md_hw; /* Allocate modem hardware info structure memory */ md_hw = kzalloc(sizeof(struct md_hw_info), GFP_KERNEL); if (md_hw == NULL) { CCCI_ERROR_LOG(-1, TAG, "%s:alloc md hw mem fail\n", __func__); return -1; } ret = md_cd_get_modem_hw_info(plat_dev, &dev_cfg, md_hw); if (ret != 0) { CCCI_ERROR_LOG(-1, TAG, "%s:get hw info fail(%d)\n", __func__, ret); kfree(md_hw); md_hw = NULL; return -1; } /* Allocate md ctrl memory and do initialize */ md = ccci_md_alloc(sizeof(struct md_sys1_info)); if (md == NULL) { CCCI_ERROR_LOG(-1, TAG, "%s:alloc modem ctrl mem fail\n", __func__); kfree(md_hw); md_hw = NULL; return -1; } md->index = md_id = dev_cfg.index; md->per_md_data.md_capability = dev_cfg.capability; md->hw_info = md_hw; md->plat_dev = plat_dev; md->plat_dev->dev.dma_mask = &cldma_dmamask; md->plat_dev->dev.coherent_dma_mask = cldma_dmamask; md->ops = &md_cd_ops; CCCI_INIT_LOG(md_id, TAG, "%s:md=%p,md->private_data=%p\n", __func__, md, md->private_data); /* register modem */ ccci_md_register(md); /* init modem private data */ md_info = (struct md_sys1_info *)md->private_data; ret = snprintf(md->trm_wakelock_name, sizeof(md->trm_wakelock_name), "md%d_cldma_trm", md_id + 1); if (ret <= 0 || ret >= sizeof(md->trm_wakelock_name)) { CCCI_ERROR_LOG(md->index, TAG, "%s %d, md->trm_wakelock_name maybe wrong\n", __func__, __LINE__); return -1; } /*need review:wakeup_source_register*/ md->trm_wake_lock = wakeup_source_register(NULL, md->trm_wakelock_name); if (!md->trm_wake_lock) { CCCI_ERROR_LOG(md->index, TAG, "%s %d: init wakeup source fail\n", __func__, __LINE__); return -1; } ret = snprintf(md_info->peer_wakelock_name, sizeof(md_info->peer_wakelock_name), "md%d_cldma_peer", md_id + 1); if (ret <= 0 || ret >= sizeof(md_info->peer_wakelock_name)) { CCCI_ERROR_LOG(md->index, TAG, "%s %d,md_info->peer_wakelock_name maybe wrong\n", __func__, __LINE__); return -1; } md_info->peer_wake_lock = wakeup_source_register(NULL, md_info->peer_wakelock_name); if (!md_info->peer_wake_lock) { CCCI_ERROR_LOG(md->index, TAG, "%s %d: init wakeup source fail\n", __func__, __LINE__); return -1; } /* Copy HW info */ md_info->ap_ccif_base = (void __iomem *)md_hw->ap_ccif_base; md_info->md_ccif_base = (void __iomem *)md_hw->md_ccif_base; #if (MD_GENERATION <= 6292) md_info->ap_ccif_irq_id = md_hw->ap_ccif_irq_id; #else md_info->ap_ccif_irq_id = md_hw->ap_ccif_irq1_id; #endif md_info->channel_id = 0; atomic_set(&md_info->ccif_irq_enabled, 1); md->md_wdt_irq_id = md_hw->md_wdt_irq_id; atomic_set(&md->reset_on_going, 1); /* IRQ is default enabled after request_irq */ atomic_set(&md->wdt_enabled, 1); ret = of_property_read_u32(plat_dev->dev.of_node, "mediatek,mdhif_type", &md->hif_flag); if (ret != 0) md->hif_flag = (1 << MD1_NET_HIF | 1 << MD1_NORMAL_HIF); // ccci_hif_init(md->index, md->hif_flag); /* register SYS CORE suspend resume call back */ register_syscore_ops(&ccci_modem_sysops); /* add sysfs entries */ md_cd_sysfs_init(md); /* hook up to device */ plat_dev->dev.platform_data = md; return 0; } //EXPORT_SYMBOL(ccci_modem_init_common); void ccci_platform_common_init(struct ccci_modem *md) { if (md->hw_info->plat_ptr->init) md->hw_info->plat_ptr->init(md); } static const struct dev_pm_ops ccci_modem_pm_ops = { .suspend = ccci_modem_pm_suspend, .resume = ccci_modem_pm_resume, .freeze = ccci_modem_pm_suspend, .thaw = ccci_modem_pm_resume, .poweroff = ccci_modem_pm_suspend, .restore = ccci_modem_pm_resume, .restore_noirq = ccci_modem_pm_restore_noirq, .suspend_noirq = ccci_modem_suspend_noirq, .resume_noirq = ccci_modem_resume_noirq, }; #ifdef CONFIG_OF /*#if (MD_GENERATION <= 6293) static const struct of_device_id ccci_modem_of_ids[] = { {.compatible = "mediatek,mdcldma",}, {} }; #else */ static const struct of_device_id ccci_modem_of_ids[] = { {.compatible = "mediatek,mddriver",}, {} }; //#endif #endif static struct platform_driver ccci_modem_driver = { .driver = { .name = "driver_modem", #ifdef CONFIG_OF .of_match_table = ccci_modem_of_ids, #endif #ifdef CONFIG_PM .pm = &ccci_modem_pm_ops, #endif }, .probe = ccci_modem_probe, .remove = ccci_modem_remove, .shutdown = ccci_modem_shutdown, .suspend = ccci_modem_suspend, .resume = ccci_modem_resume, }; static int __init modem_cd_init(void) { int ret; ret = platform_driver_register(&ccci_modem_driver); if (ret) { CCCI_ERROR_LOG(-1, TAG, "clmda modem platform driver register fail(%d)\n", ret); return ret; } return 0; } module_init(modem_cd_init); MODULE_AUTHOR("CCCI"); MODULE_DESCRIPTION("CCCI modem driver v0.1"); MODULE_LICENSE("GPL");