| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313 |
- /*
- * Copyright (c) 2015 MediaTek Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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.
- */
- #include <linux/init.h>
- #include <linux/smp.h>
- #include <linux/spinlock.h>
- #include <linux/jiffies.h>
- #include <linux/delay.h>
- #include <asm/fiq_glue.h>
- #include <mt-plat/sync_write.h>
- #include <mach/mt_spm_mtcmos.h>
- #include <mach/mt_secure_api.h>
- #include "mt-smp.h"
- #include "smp.h"
- #include "hotplug.h"
- #define SLAVE1_MAGIC_REG (SRAMROM_BASE+0x38)
- #define SLAVE2_MAGIC_REG (SRAMROM_BASE+0x38)
- #define SLAVE3_MAGIC_REG (SRAMROM_BASE+0x38)
- #define SLAVE4_MAGIC_REG (SRAMROM_BASE+0x3C)
- #define SLAVE5_MAGIC_REG (SRAMROM_BASE+0x3C)
- #define SLAVE6_MAGIC_REG (SRAMROM_BASE+0x3C)
- #define SLAVE7_MAGIC_REG (SRAMROM_BASE+0x3C)
- #define SLAVE1_MAGIC_NUM 0x534C4131
- #define SLAVE2_MAGIC_NUM 0x4C415332
- #define SLAVE3_MAGIC_NUM 0x41534C33
- #define SLAVE4_MAGIC_NUM 0x534C4134
- #define SLAVE5_MAGIC_NUM 0x4C415335
- #define SLAVE6_MAGIC_NUM 0x41534C36
- #define SLAVE7_MAGIC_NUM 0x534C4137
- #define SLAVE_JUMP_REG (SRAMROM_BASE+0x34)
- static DEFINE_SPINLOCK(boot_lock);
- /*
- * Write pen_release in a way that is guaranteed to be visible to all
- * observers, irrespective of whether they're taking part in coherency
- * or not. This is necessary for the hotplug code to work reliably.
- */
- static void __cpuinit write_pen_release(int val)
- {
- pen_release = val;
- /* Make sure this is visible to other CPUs */
- smp_wmb();
- /* sync_cache_w(&pen_release); */
- __cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release));
- outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1));
- }
- void __cpuinit mt_smp_secondary_init(unsigned int cpu)
- {
- pr_debug("Slave cpu init\n");
- HOTPLUG_INFO("platform_secondary_init, cpu: %d\n", cpu);
- #ifndef CONFIG_MTK_GIC
- mt_gic_secondary_init();
- #endif
- /*
- * let the primary processor know we're out of the
- * pen, then head off into the C entry point
- */
- write_pen_release(-1);
- #if !defined(CONFIG_ARM_PSCI)
- fiq_glue_resume();
- #endif
- /*
- * Synchronise with the boot thread.
- */
- spin_lock(&boot_lock);
- spin_unlock(&boot_lock);
- }
- #define MT6735_INFRACFG_AO 0x10001000
- static void __init smp_set_boot_addr(void)
- {
- static void __iomem *infracfg_ao_base;
- infracfg_ao_base = ioremap(MT6735_INFRACFG_AO, 0x1000);
- if (!infracfg_ao_base)
- pr_err("%s: Unable to map I/O memory\n", __func__);
- /* Write the address of slave startup into boot address
- register for bootrom power down mode */
- writel_relaxed(virt_to_phys(mt_secondary_startup),
- infracfg_ao_base + 0x800);
- iounmap(infracfg_ao_base);
- }
- int __cpuinit mt_smp_boot_secondary(unsigned int cpu, struct task_struct *idle)
- {
- unsigned long timeout;
- atomic_inc(&hotplug_cpu_count);
- /*
- * Set synchronisation state between this boot processor
- * and the secondary one
- */
- spin_lock(&boot_lock);
- HOTPLUG_INFO("mt_smp_boot_secondary, cpu: %d\n", cpu);
- /*
- * The secondary processor is waiting to be released from
- * the holding pen - release it, then wait for it to flag
- * that it has been released by resetting pen_release.
- *
- * Note that "pen_release" is the hardware CPU ID, whereas
- * "cpu" is Linux's internal ID.
- */
- /*
- * This is really belt and braces; we hold unintended secondary
- * CPUs in the holding pen until we're ready for them. However,
- * since we haven't sent them a soft interrupt, they shouldn't
- * be there.
- */
- write_pen_release(cpu);
- switch (cpu) {
- case 1:
- #ifdef CONFIG_MTK_FPGA
- mt_reg_sync_writel(SLAVE1_MAGIC_NUM, SLAVE1_MAGIC_REG);
- HOTPLUG_INFO("SLAVE1_MAGIC_NUM:%x\n", SLAVE1_MAGIC_NUM);
- #endif
- spm_mtcmos_ctrl_cpu1(STA_POWER_ON, 1);
- break;
- case 2:
- #ifdef CONFIG_MTK_FPGA
- mt_reg_sync_writel(SLAVE2_MAGIC_NUM, SLAVE2_MAGIC_REG);
- HOTPLUG_INFO("SLAVE2_MAGIC_NUM:%x\n", SLAVE2_MAGIC_NUM);
- #endif
- spm_mtcmos_ctrl_cpu2(STA_POWER_ON, 1);
- break;
- case 3:
- #ifdef CONFIG_MTK_FPGA
- mt_reg_sync_writel(SLAVE3_MAGIC_NUM, SLAVE3_MAGIC_REG);
- HOTPLUG_INFO("SLAVE3_MAGIC_NUM:%x\n", SLAVE3_MAGIC_NUM);
- #endif
- spm_mtcmos_ctrl_cpu3(STA_POWER_ON, 1);
- break;
- #ifdef CONFIG_ARCH_MT6753
- case 4:
- #ifdef CONFIG_MTK_FPGA
- mt_reg_sync_writel(SLAVE4_MAGIC_NUM, SLAVE4_MAGIC_REG);
- HOTPLUG_INFO("SLAVE4_MAGIC_NUM:%x\n", SLAVE4_MAGIC_NUM);
- #endif
- spm_mtcmos_ctrl_cpu4(STA_POWER_ON, 1);
- break;
- case 5:
- if ((cpu_online(4) == 0) && (cpu_online(6) == 0) &&
- (cpu_online(7) == 0)) {
- HOTPLUG_INFO("up CPU%d fail, CPU4 first\n", cpu);
- spin_unlock(&boot_lock);
- atomic_dec(&hotplug_cpu_count);
- return -ENOSYS;
- }
- #ifdef CONFIG_MTK_FPGA
- mt_reg_sync_writel(SLAVE5_MAGIC_NUM, SLAVE5_MAGIC_REG);
- HOTPLUG_INFO("SLAVE5_MAGIC_NUM:%x\n", SLAVE5_MAGIC_NUM);
- #endif
- spm_mtcmos_ctrl_cpu5(STA_POWER_ON, 1);
- break;
- case 6:
- if ((cpu_online(4) == 0) && (cpu_online(5) == 0) &&
- (cpu_online(7) == 0)) {
- HOTPLUG_INFO("up CPU%d fail, CPU4 first\n", cpu);
- spin_unlock(&boot_lock);
- atomic_dec(&hotplug_cpu_count);
- return -ENOSYS;
- }
- #ifdef CONFIG_MTK_FPGA
- mt_reg_sync_writel(SLAVE6_MAGIC_NUM, SLAVE6_MAGIC_REG);
- HOTPLUG_INFO("SLAVE6_MAGIC_NUM:%x\n", SLAVE6_MAGIC_NUM);
- #endif
- spm_mtcmos_ctrl_cpu6(STA_POWER_ON, 1);
- break;
- case 7:
- if ((cpu_online(4) == 0) && (cpu_online(5) == 0) &&
- (cpu_online(6) == 0)) {
- HOTPLUG_INFO("up CPU%d fail, CPU4 first\n", cpu);
- spin_unlock(&boot_lock);
- atomic_dec(&hotplug_cpu_count);
- return -ENOSYS;
- }
- #ifdef CONFIG_MTK_FPGA
- mt_reg_sync_writel(SLAVE7_MAGIC_NUM, SLAVE7_MAGIC_REG);
- HOTPLUG_INFO("SLAVE7_MAGIC_NUM:%x\n", SLAVE7_MAGIC_NUM);
- #endif
- spm_mtcmos_ctrl_cpu7(STA_POWER_ON, 1);
- break;
- #endif /* CONFIG_ARCH_MT6753 */
- default:
- break;
- }
- /*
- * Now the secondary core is starting up let it run its
- * calibrations, then wait for it to finish
- */
- spin_unlock(&boot_lock);
- timeout = jiffies + (1 * HZ);
- while (time_before(jiffies, timeout)) {
- /* */
- smp_rmb();
- if (pen_release == -1)
- break;
- udelay(10);
- }
- if (pen_release != -1) {
- on_each_cpu((smp_call_func_t) dump_stack, NULL, 0);
- atomic_dec(&hotplug_cpu_count);
- return -ENOSYS;
- }
- return 0;
- }
- void __init mt_smp_init_cpus(void)
- {
- /* Enable CA7 snoop function */
- #if defined(CONFIG_ARM_PSCI) || defined(CONFIG_MTK_PSCI)
- mcusys_smc_write_phy(virt_to_phys((void *)MP0_AXI_CONFIG),
- readl((void *)MP0_AXI_CONFIG) & ~ACINACTM);
- #else
- mcusys_smc_write(MP0_AXI_CONFIG, readl(MP0_AXI_CONFIG) & ~ACINACTM);
- #endif
- /* Enable snoop requests and DVM message requests */
- REG_WRITE((void *)CCI400_SI4_SNOOP_CONTROL,
- readl((void *)CCI400_SI4_SNOOP_CONTROL) | (SNOOP_REQ |
- DVM_MSG_REQ));
- while (readl((void *)CCI400_STATUS) & CHANGE_PENDING)
- ;
- pr_emerg("@@@### num_possible_cpus(): %u ###@@@\n",
- num_possible_cpus());
- pr_emerg("@@@### num_present_cpus(): %u ###@@@\n", num_present_cpus());
- #ifndef CONFIG_MTK_GIC
- irq_total_secondary_cpus = num_possible_cpus() - 1;
- #endif
- }
- void __init mt_smp_prepare_cpus(unsigned int max_cpus)
- {
- #if !defined(CONFIG_ARM_PSCI)
- #ifdef CONFIG_MTK_FPGA
- /* write the address of slave startup into the system-wide
- flags register */
- mt_reg_sync_writel(virt_to_phys(mt_secondary_startup), SLAVE_JUMP_REG);
- #endif
- /* Set all cpus into AArch32 */
- mcusys_smc_write(MP0_MISC_CONFIG3,
- readl(MP0_MISC_CONFIG3) & 0xFFFF0FFF);
- mcusys_smc_write(MP1_MISC_CONFIG3,
- readl(MP1_MISC_CONFIG3) & 0xFFFF0FFF);
- /* enable bootrom power down mode */
- REG_WRITE(BOOTROM_SEC_CTRL, readl(BOOTROM_SEC_CTRL) | SW_ROM_PD);
- /* write the address of slave startup into boot address register
- for bootrom power down mode */
- mt_reg_sync_writel(virt_to_phys(mt_secondary_startup),
- BOOTROM_BOOT_ADDR);
- #endif
- /* set boot address */
- smp_set_boot_addr();
- /* initial spm_mtcmos memory map */
- spm_mtcmos_cpu_init();
- }
- struct smp_operations __initdata mt_smp_ops = {
- .smp_init_cpus = mt_smp_init_cpus,
- .smp_prepare_cpus = mt_smp_prepare_cpus,
- .smp_secondary_init = mt_smp_secondary_init,
- .smp_boot_secondary = mt_smp_boot_secondary,
- #ifdef CONFIG_HOTPLUG_CPU
- .cpu_kill = mt_cpu_kill,
- .cpu_die = mt_cpu_die,
- .cpu_disable = mt_cpu_disable,
- #endif
- };
|