/* * Copyright (C) 2014 Freescale Semiconductor, Inc. * Freescale IMX Linux-specific MCC implementation. * iMX6sx-specific MCC library functions. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope 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. * * You should have received a copy of the GNU General Public License along with * this program. If not, see . */ #include #include #include #include #include #include /*! * \brief This function returns the core number * * \return int */ unsigned int _psp_core_num(void) { return 0; } /* * This field contains CPU-to-CPU interrupt vector numbers * for all device cores. */ static const unsigned int mcc_cpu_to_cpu_vectors[] = {INT_CPU_TO_CPU_MU_A2M, INT_CPU_TO_CPU_MU_M2A}; /*! * \brief This function gets the CPU-to-CPU vector num for the particular core. * * Platform-specific inter-CPU vector numbers for each core are defined in the * mcc_cpu_to_cpu_vectors[] field. * * \param[in] core Core number. * * \return vector number for the particular core * \return MCC_VECTOR_NUMBER_INVALID (vector number for the particular core * number not found) */ unsigned int mcc_get_cpu_to_cpu_vector(unsigned int core) { u32 val; val = sizeof(mcc_cpu_to_cpu_vectors)/sizeof(mcc_cpu_to_cpu_vectors[0]); if (core < val) return mcc_cpu_to_cpu_vectors[core]; return MCC_VECTOR_NUMBER_INVALID; } /*! * \brief This function clears the CPU-to-CPU int flag for the particular core. * * Implementation is platform-specific. * * \param[in] core Core number. */ void mcc_clear_cpu_to_cpu_interrupt(unsigned int core) { u32 val; regmap_read(imx_mu_reg, MU_ASR, &val); /* write 1 to BIT31 to clear the bit31(GIP3) of MU_ASR */ val = val | (1 << 31); regmap_write(imx_mu_reg, MU_ASR, val); } /*! * \brief This function triggers the CPU-to-CPU interrupt. * * Platform-specific software triggering the inter-CPU interrupts. */ void mcc_triger_cpu_to_cpu_interrupt(void) { int i = 0; u32 val; regmap_read(imx_mu_reg, MU_ACR, &val); if ((val & BIT(19)) != 0) { do { regmap_read(imx_mu_reg, MU_ACR, &val); msleep(1); } while (((val & BIT(19)) > 0) && (i++ < 100)); } if ((val & BIT(19)) == 0) /* Enable the bit19(GIR3) of MU_ACR */ regmap_update_bits(imx_mu_reg, MU_ACR, BIT(19), BIT(19)); else pr_info("mcc int still be triggered after %d ms polling!\n", i); } /*! * \brief This function disable the CPU-to-CPU interrupt. * * Platform-specific software disable the inter-CPU interrupts. */ int imx_mcc_bsp_int_disable(unsigned int vector_number) { u32 val; if (vector_number == INT_CPU_TO_CPU_MU_A2M) { /* Disable the bit31(GIE3) of MU_ACR */ regmap_update_bits(imx_mu_reg, MU_ACR, BIT(31), 0); /* flush */ regmap_read(imx_mu_reg, MU_ACR, &val); } else pr_err("ERR:wrong vector number in mcc.\n"); return 0; } /*! * \brief This function enable the CPU-to-CPU interrupt. * * Platform-specific software enable the inter-CPU interrupts. */ int imx_mcc_bsp_int_enable(unsigned int vector_number) { u32 val; if (vector_number == INT_CPU_TO_CPU_MU_A2M) { /* Enable the bit31(GIE3) of MU_ACR */ regmap_update_bits(imx_mu_reg, MU_ACR, BIT(31), BIT(31)); /* flush */ regmap_read(imx_mu_reg, MU_ACR, &val); return 0; } else { pr_err("ERR:wrong vector number in mcc.\n"); return -EINVAL; } }