/* arch/arm/mach-msm/smd_init_plat.c * * Copyright (c) 2013, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and * may be copied, distributed, and modified under those terms. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * */ #ifndef CONFIG_OF #include #include #include #include #include #include #include #include #define MODULE_NAME "msm_smd" #define IPC_LOG(level, x...) do { \ if (smd_log_ctx) \ ipc_log_string(smd_log_ctx, x); \ else \ printk(level x); \ } while (0) #if defined(CONFIG_MSM_SMD_DEBUG) #define SMD_DBG(x...) do { \ if (msm_smd_debug_mask & MSM_SMD_DEBUG) \ IPC_LOG(KERN_DEBUG, x); \ } while (0) #define SMD_INFO(x...) do { \ if (msm_smd_debug_mask & MSM_SMD_INFO) \ IPC_LOG(KERN_INFO, x); \ } while (0) #else #define SMD_DBG(x...) do { } while (0) #define SMD_INFO(x...) do { } while (0) #endif #if defined(CONFIG_ARCH_QSD8X50) || defined(CONFIG_ARCH_MSM8X60) \ || defined(CONFIG_ARCH_MSM8960) || defined(CONFIG_ARCH_FSM9XXX) \ || defined(CONFIG_ARCH_MSM9615) || defined(CONFIG_ARCH_APQ8064) #define CONFIG_QDSP6 1 #endif #if defined(CONFIG_ARCH_MSM8X60) || defined(CONFIG_ARCH_MSM8960) \ || defined(CONFIG_ARCH_APQ8064) #define CONFIG_DSPS 1 #endif #if defined(CONFIG_ARCH_MSM8960) \ || defined(CONFIG_ARCH_APQ8064) #define CONFIG_WCNSS 1 #define CONFIG_DSPS_SMSM 1 #endif #if defined(CONFIG_ARCH_MSM7X30) #define MSM_CFG_A2M_SMD_INT \ (smd_cfg_smd_intr(SMD_MODEM, 1 << 0, MSM_APCS_GCC_BASE + 0x8)) #define MSM_CFG_A2Q6_SMD_INT \ (smd_cfg_smd_intr(SMD_Q6, 1 << 8, MSM_APCS_GCC_BASE + 0x8)) #define MSM_CFG_A2M_SMSM_INT \ (smd_cfg_smsm_intr(SMD_MODEM, 1 << 5, MSM_APCS_GCC_BASE + 0x8)) #define MSM_CFG_A2Q6_SMSM_INT \ (smd_cfg_smsm_intr(SMD_Q6, 1 << 8, MSM_APCS_GCC_BASE + 0x8)) #define MSM_CFG_A2DSPS_SMD_INT #define MSM_CFG_A2DSPS_SMSM_INT #define MSM_CFG_A2WCNSS_SMD_INT #define MSM_CFG_A2WCNSS_SMSM_INT #elif defined(CONFIG_ARCH_MSM8X60) #define MSM_CFG_A2M_SMD_INT \ (smd_cfg_smd_intr(SMD_MODEM, 1 << 3, MSM_GCC_BASE + 0x8)) #define MSM_CFG_A2Q6_SMD_INT \ (smd_cfg_smd_intr(SMD_Q6, 1 << 15, MSM_GCC_BASE + 0x8)) #define MSM_CFG_A2M_SMSM_INT \ (smd_cfg_smsm_intr(SMD_MODEM, 1 << 4, MSM_GCC_BASE + 0x8)) #define MSM_CFG_A2Q6_SMSM_INT \ (smd_cfg_smsm_intr(SMD_Q6, 1 << 14, MSM_GCC_BASE + 0x8)) #define MSM_CFG_A2DSPS_SMD_INT \ (smd_cfg_smd_intr(SMD_DSPS, 1, \ MSM_SIC_NON_SECURE_BASE + 0x4080)) #define MSM_CFG_A2DSPS_SMSM_INT #define MSM_CFG_A2WCNSS_SMD_INT #define MSM_CFG_A2WCNSS_SMSM_INT #elif defined(CONFIG_ARCH_MSM9615) #define MSM_CFG_A2M_SMD_INT \ (smd_cfg_smd_intr(SMD_MODEM, 1 << 3, MSM_APCS_GCC_BASE + 0x8)) #define MSM_CFG_A2Q6_SMD_INT \ (smd_cfg_smd_intr(SMD_Q6, 1 << 15, MSM_APCS_GCC_BASE + 0x8)) #define MSM_CFG_A2M_SMSM_INT \ (smd_cfg_smsm_intr(SMD_MODEM, 1 << 4, MSM_APCS_GCC_BASE + 0x8)) #define MSM_CFG_A2Q6_SMSM_INT \ (smd_cfg_smsm_intr(SMD_Q6, 1 << 14, MSM_APCS_GCC_BASE + 0x8)) #define MSM_CFG_A2DSPS_SMD_INT #define MSM_CFG_A2DSPS_SMSM_INT #define MSM_CFG_A2WCNSS_SMD_INT #define MSM_CFG_A2WCNSS_SMSM_INT #elif defined(CONFIG_ARCH_FSM9XXX) #define MSM_CFG_A2Q6_SMD_INT \ (smd_cfg_smd_intr(SMD_Q6, 1 << 10, MSM_GCC_BASE + 0x8)) #define MSM_CFG_A2Q6_SMSM_INT \ (smd_cfg_smsm_intr(SMD_Q6, 1 << 10, MSM_GCC_BASE + 0x8)) #define MSM_CFG_A2M_SMD_INT \ (smd_cfg_smd_intr(SMD_MODEM, 1 << 0, MSM_GCC_BASE + 0x8)) #define MSM_CFG_A2M_SMSM_INT \ (smd_cfg_smsm_intr(SMD_MODEM, 1 << 5, MSM_GCC_BASE + 0x8)) #define MSM_CFG_A2DSPS_SMD_INT #define MSM_CFG_A2DSPS_SMSM_INT #define MSM_CFG_A2WCNSS_SMD_INT #define MSM_CFG_A2WCNSS_SMSM_INT #elif defined(CONFIG_ARCH_MSM7X01A) || defined(CONFIG_ARCH_MSM7x25) #define MSM_CFG_A2M_SMD_INT \ (smd_cfg_smd_intr(SMD_MODEM, 1, MSM_CSR_BASE + 0x400 + (0) * 4)) #define MSM_CFG_A2Q6_SMD_INT #define MSM_CFG_A2M_SMSM_INT \ (smd_cfg_smsm_intr(SMD_MODEM, 1, \ MSM_CSR_BASE + 0x400 + (5) * 4)) #define MSM_CFG_A2Q6_SMSM_INT #define MSM_CFG_A2DSPS_SMD_INT #define MSM_CFG_A2DSPS_SMSM_INT #define MSM_CFG_A2WCNSS_SMD_INT #define MSM_CFG_A2WCNSS_SMSM_INT #elif defined(CONFIG_ARCH_MSM7X27) || defined(CONFIG_ARCH_MSM7X27A) #define MSM_CFG_A2M_SMD_INT \ (smd_cfg_smd_intr(SMD_MODEM, 1, MSM_CSR_BASE + 0x400 + (0) * 4)) #define MSM_CFG_A2Q6_SMD_INT #define MSM_CFG_A2M_SMSM_INT \ (smd_cfg_smsm_intr(SMD_MODEM, 1, \ MSM_CSR_BASE + 0x400 + (5) * 4)) #define MSM_CFG_A2Q6_SMSM_INT #define MSM_CFG_A2DSPS_SMD_INT #define MSM_CFG_A2DSPS_SMSM_INT #define MSM_CFG_A2WCNSS_SMD_INT #define MSM_CFG_A2WCNSS_SMSM_INT #else /* use platform device / device tree configuration */ #define MSM_CFG_A2M_SMD_INT #define MSM_CFG_A2Q6_SMD_INT #define MSM_CFG_A2M_SMSM_INT #define MSM_CFG_A2Q6_SMSM_INT #define MSM_CFG_A2DSPS_SMD_INT #define MSM_CFG_A2DSPS_SMSM_INT #define MSM_CFG_A2WCNSS_SMD_INT #define MSM_CFG_A2WCNSS_SMSM_INT #endif /* * stub out legacy macros if they are not being used so that the legacy * code compiles even though it is not used * * these definitions should not be used in active code and will cause * an early failure */ #ifndef INT_A9_M2A_0 #define INT_A9_M2A_0 -1 #endif #ifndef INT_A9_M2A_5 #define INT_A9_M2A_5 -1 #endif #ifndef INT_ADSP_A11 #define INT_ADSP_A11 -1 #endif #ifndef INT_ADSP_A11_SMSM #define INT_ADSP_A11_SMSM -1 #endif #ifndef INT_DSPS_A11 #define INT_DSPS_A11 -1 #endif #ifndef INT_DSPS_A11_SMSM #define INT_DSPS_A11_SMSM -1 #endif #ifndef INT_WCNSS_A11 #define INT_WCNSS_A11 -1 #endif #ifndef INT_WCNSS_A11_SMSM #define INT_WCNSS_A11_SMSM -1 #endif static int intr_init(struct interrupt_config_item *private_irq, struct smd_irq_config *platform_irq, struct platform_device *pdev ) { int irq_id; int ret; int ret_wake; private_irq->out_bit_pos = platform_irq->out_bit_pos; private_irq->out_offset = platform_irq->out_offset; private_irq->out_base = platform_irq->out_base; irq_id = platform_get_irq_byname( pdev, platform_irq->irq_name ); SMD_DBG("smd: %s: register irq: %s id: %d\n", __func__, platform_irq->irq_name, irq_id); ret = request_irq(irq_id, private_irq->irq_handler, platform_irq->flags, platform_irq->device_name, (void *)platform_irq->dev_id ); if (ret < 0) { platform_irq->irq_id = ret; private_irq->irq_id = ret; } else { platform_irq->irq_id = irq_id; private_irq->irq_id = irq_id; ret_wake = enable_irq_wake(irq_id); if (ret_wake < 0) { pr_err("smd: enable_irq_wake failed on %s", platform_irq->irq_name); } } return ret; } int smd_core_init(void) { int r; unsigned long flags = IRQF_TRIGGER_RISING; SMD_INFO("smd_core_init()\n"); MSM_CFG_A2M_SMD_INT; MSM_CFG_A2Q6_SMD_INT; MSM_CFG_A2M_SMSM_INT; MSM_CFG_A2Q6_SMSM_INT; MSM_CFG_A2DSPS_SMD_INT; MSM_CFG_A2DSPS_SMSM_INT; MSM_CFG_A2WCNSS_SMD_INT; MSM_CFG_A2WCNSS_SMSM_INT; r = request_irq(INT_A9_M2A_0, smd_modem_irq_handler, flags, "smd_dev", 0); if (r < 0) return r; interrupt_stats[SMD_MODEM].smd_interrupt_id = INT_A9_M2A_0; r = enable_irq_wake(INT_A9_M2A_0); if (r < 0) pr_err("%s: enable_irq_wake failed for INT_A9_M2A_0\n", __func__); r = request_irq(INT_A9_M2A_5, smsm_modem_irq_handler, flags, "smsm_dev", 0); if (r < 0) { free_irq(INT_A9_M2A_0, 0); return r; } interrupt_stats[SMD_MODEM].smsm_interrupt_id = INT_A9_M2A_5; r = enable_irq_wake(INT_A9_M2A_5); if (r < 0) pr_err("%s: enable_irq_wake failed for INT_A9_M2A_5\n", __func__); #if defined(CONFIG_QDSP6) #if (INT_ADSP_A11 == INT_ADSP_A11_SMSM) flags |= IRQF_SHARED; #endif r = request_irq(INT_ADSP_A11, smd_dsp_irq_handler, flags, "smd_dev", smd_dsp_irq_handler); if (r < 0) { free_irq(INT_A9_M2A_0, 0); free_irq(INT_A9_M2A_5, 0); return r; } interrupt_stats[SMD_Q6].smd_interrupt_id = INT_ADSP_A11; r = request_irq(INT_ADSP_A11_SMSM, smsm_dsp_irq_handler, flags, "smsm_dev", smsm_dsp_irq_handler); if (r < 0) { free_irq(INT_A9_M2A_0, 0); free_irq(INT_A9_M2A_5, 0); free_irq(INT_ADSP_A11, smd_dsp_irq_handler); return r; } interrupt_stats[SMD_Q6].smsm_interrupt_id = INT_ADSP_A11_SMSM; r = enable_irq_wake(INT_ADSP_A11); if (r < 0) pr_err("%s: enable_irq_wake failed for INT_ADSP_A11\n", __func__); #if (INT_ADSP_A11 != INT_ADSP_A11_SMSM) r = enable_irq_wake(INT_ADSP_A11_SMSM); if (r < 0) pr_err("%s: enable_irq_wake failed for INT_ADSP_A11_SMSM\n", __func__); #endif flags &= ~IRQF_SHARED; #endif #if defined(CONFIG_DSPS) r = request_irq(INT_DSPS_A11, smd_dsps_irq_handler, flags, "smd_dev", smd_dsps_irq_handler); if (r < 0) { free_irq(INT_A9_M2A_0, 0); free_irq(INT_A9_M2A_5, 0); free_irq(INT_ADSP_A11, smd_dsp_irq_handler); free_irq(INT_ADSP_A11_SMSM, smsm_dsp_irq_handler); return r; } interrupt_stats[SMD_DSPS].smd_interrupt_id = INT_DSPS_A11; r = enable_irq_wake(INT_DSPS_A11); if (r < 0) pr_err("%s: enable_irq_wake failed for INT_ADSP_A11\n", __func__); #endif #if defined(CONFIG_WCNSS) r = request_irq(INT_WCNSS_A11, smd_wcnss_irq_handler, flags, "smd_dev", smd_wcnss_irq_handler); if (r < 0) { free_irq(INT_A9_M2A_0, 0); free_irq(INT_A9_M2A_5, 0); free_irq(INT_ADSP_A11, smd_dsp_irq_handler); free_irq(INT_ADSP_A11_SMSM, smsm_dsp_irq_handler); free_irq(INT_DSPS_A11, smd_dsps_irq_handler); return r; } interrupt_stats[SMD_WCNSS].smd_interrupt_id = INT_WCNSS_A11; r = enable_irq_wake(INT_WCNSS_A11); if (r < 0) pr_err("%s: enable_irq_wake failed for INT_WCNSS_A11\n", __func__); r = request_irq(INT_WCNSS_A11_SMSM, smsm_wcnss_irq_handler, flags, "smsm_dev", smsm_wcnss_irq_handler); if (r < 0) { free_irq(INT_A9_M2A_0, 0); free_irq(INT_A9_M2A_5, 0); free_irq(INT_ADSP_A11, smd_dsp_irq_handler); free_irq(INT_ADSP_A11_SMSM, smsm_dsp_irq_handler); free_irq(INT_DSPS_A11, smd_dsps_irq_handler); free_irq(INT_WCNSS_A11, smd_wcnss_irq_handler); return r; } interrupt_stats[SMD_WCNSS].smsm_interrupt_id = INT_WCNSS_A11_SMSM; r = enable_irq_wake(INT_WCNSS_A11_SMSM); if (r < 0) pr_err("%s: enable_irq_wake failed for INT_WCNSS_A11_SMSM\n", __func__); #endif #if defined(CONFIG_DSPS_SMSM) r = request_irq(INT_DSPS_A11_SMSM, smsm_dsps_irq_handler, flags, "smsm_dev", smsm_dsps_irq_handler); if (r < 0) { free_irq(INT_A9_M2A_0, 0); free_irq(INT_A9_M2A_5, 0); free_irq(INT_ADSP_A11, smd_dsp_irq_handler); free_irq(INT_ADSP_A11_SMSM, smsm_dsp_irq_handler); free_irq(INT_DSPS_A11, smd_dsps_irq_handler); free_irq(INT_WCNSS_A11, smd_wcnss_irq_handler); free_irq(INT_WCNSS_A11_SMSM, smsm_wcnss_irq_handler); return r; } interrupt_stats[SMD_DSPS].smsm_interrupt_id = INT_DSPS_A11_SMSM; r = enable_irq_wake(INT_DSPS_A11_SMSM); if (r < 0) pr_err("%s: enable_irq_wake failed for INT_DSPS_A11_SMSM\n", __func__); #endif SMD_INFO("smd_core_init() done\n"); return 0; } int smd_core_platform_init(struct platform_device *pdev) { int i; int ret; uint32_t num_ss; struct smd_platform *smd_platform_data; struct smd_subsystem_config *smd_ss_config_list; struct smd_subsystem_config *cfg; struct interrupt_config *private_intr_config; int err_ret = 0; smd_platform_data = pdev->dev.platform_data; num_ss = smd_platform_data->num_ss_configs; smd_ss_config_list = smd_platform_data->smd_ss_configs; if (smd_platform_data->smd_ssr_config) disable_smsm_reset_handshake = smd_platform_data-> smd_ssr_config->disable_smsm_reset_handshake; for (i = 0; i < num_ss; i++) { cfg = &smd_ss_config_list[i]; private_intr_config = smd_get_intr_config(cfg->edge); if (!private_intr_config) { pr_err("%s: invalid edge\n", __func__); goto intr_failed; } ret = intr_init( &private_intr_config->smd, &cfg->smd_int, pdev ); if (ret < 0) { err_ret = ret; pr_err("smd: register irq failed on %s\n", cfg->smd_int.irq_name); goto intr_failed; } interrupt_stats[cfg->irq_config_id].smd_interrupt_id = cfg->smd_int.irq_id; /* only init smsm structs if this edge supports smsm */ if (cfg->smsm_int.irq_id) ret = intr_init( &private_intr_config->smsm, &cfg->smsm_int, pdev ); if (ret < 0) { err_ret = ret; pr_err("smd: register irq failed on %s\n", cfg->smsm_int.irq_name); goto intr_failed; } if (cfg->smsm_int.irq_id) interrupt_stats[cfg->irq_config_id].smsm_interrupt_id = cfg->smsm_int.irq_id; if (cfg->subsys_name) smd_set_edge_subsys_name(cfg->edge, cfg->subsys_name); smd_set_edge_initialized(cfg->edge); } SMD_INFO("smd_core_platform_init() done\n"); return 0; intr_failed: pr_err("smd: deregistering IRQs\n"); for (i = 0; i < num_ss; ++i) { cfg = &smd_ss_config_list[i]; if (cfg->smd_int.irq_id >= 0) free_irq(cfg->smd_int.irq_id, (void *)cfg->smd_int.dev_id ); if (cfg->smsm_int.irq_id >= 0) free_irq(cfg->smsm_int.irq_id, (void *)cfg->smsm_int.dev_id ); } return err_ret; } static int msm_smd_probe_legacy(struct platform_device *pdev) { int ret; if (!smem_initialized_check()) return -ENODEV; SMD_INFO("smd probe\n"); if (pdev) { if (pdev->dev.of_node) { pr_err("%s: invalid device tree init\n", __func__); return -ENODEV; } else if (pdev->dev.platform_data) { ret = smd_core_platform_init(pdev); if (ret) { pr_err( "SMD: smd_core_platform_init() failed\n"); return -ENODEV; } } else { ret = smd_core_init(); if (ret) { pr_err("smd_core_init() failed\n"); return -ENODEV; } } } else { pr_err("SMD: PDEV not found\n"); return -ENODEV; } ret = smsm_post_init(); if (ret) { pr_err("smd_post_init() failed ret = %d\n", ret); return ret; } smd_post_init(1); return 0; } static struct platform_driver msm_smd_driver_legacy = { .probe = msm_smd_probe_legacy, .driver = { .name = MODULE_NAME, .owner = THIS_MODULE, }, }; int msm_smd_driver_register(void) { int rc; rc = platform_driver_register(&msm_smd_driver_legacy); if (rc) { pr_err("%s: smd_driver register failed %d\n", __func__, rc); return rc; } return 0; } EXPORT_SYMBOL(msm_smd_driver_register); MODULE_DESCRIPTION("MSM SMD Legacy/Platform Device Init"); MODULE_LICENSE("GPL v2"); #endif