blob: c58b150a5856cb91c4d39ce9dd230a28890810bc [file] [log] [blame]
/* 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 <linux/platform_device.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <mach/msm_iomap.h>
#include <mach/msm_ipc_logging.h>
#include <smd_private.h>
#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, 0);
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