static void exynos_pm_resume(void) { u32 cpuid = read_cpuid_part(); if (exynos_pm_central_resume()) goto early_wakeup; /* For release retention */ exynos_pm_release_retention(); s3c_pm_do_restore_core(exynos_core_save, ARRAY_SIZE(exynos_core_save)); if (cpuid == ARM_CPU_PART_CORTEX_A9) scu_enable(S5P_VA_SCU); if (call_firmware_op(resume) == -ENOSYS && cpuid == ARM_CPU_PART_CORTEX_A9) exynos_cpu_restore_register(); early_wakeup: /* Clear SLEEP mode set in INFORM1 */ pmu_raw_writel(0x0, S5P_INFORM1); exynos_set_delayed_reset_assertion(true); }
void __init exynos_firmware_init(void) { struct device_node *nd; const __be32 *addr; nd = of_find_compatible_node(NULL, NULL, "samsung,secure-firmware"); if (!nd) return; addr = of_get_address(nd, 0, NULL, NULL); if (!addr) { pr_err("%s: No address specified.\n", __func__); return; } pr_info("Running under secure firmware.\n"); register_firmware_ops(&exynos_firmware_ops); /* * Exynos 4 SoCs (based on Cortex A9 and equipped with L2C-310), * running under secure firmware, require certain registers of L2 * cache controller to be written in secure mode. Here .write_sec * callback is provided to perform necessary SMC calls. */ if (IS_ENABLED(CONFIG_CACHE_L2X0) && read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) { outer_cache.write_sec = exynos_l2_write_sec; outer_cache.configure = exynos_l2_configure; } }
static int exynos_suspend(void) { if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) exynos_save_cp15(); writel(EXYNOS_SLEEP_MAGIC, sysram_ns_base_addr + EXYNOS_BOOT_FLAG); writel(virt_to_phys(exynos_cpu_resume_ns), sysram_ns_base_addr + EXYNOS_BOOT_ADDR); return cpu_suspend(0, exynos_cpu_suspend); }
static int exynos_pm_suspend(void) { exynos_pm_central_suspend(); /* Setting SEQ_OPTION register */ pmu_raw_writel(S5P_USE_STANDBY_WFI0 | S5P_USE_STANDBY_WFE0, S5P_CENTRAL_SEQ_OPTION); if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) exynos_cpu_save_register(); return 0; }
/* * CPU PMU identification and probing. */ static int probe_current_pmu(struct arm_pmu *pmu) { int cpu = get_cpu(); int ret = -ENODEV; pr_info("probing PMU on CPU %d\n", cpu); switch (read_cpuid_part()) { /* ARM Ltd CPUs. */ case ARM_CPU_PART_ARM1136: ret = armv6_1136_pmu_init(pmu); break; case ARM_CPU_PART_ARM1156: ret = armv6_1156_pmu_init(pmu); break; case ARM_CPU_PART_ARM1176: ret = armv6_1176_pmu_init(pmu); break; case ARM_CPU_PART_ARM11MPCORE: ret = armv6mpcore_pmu_init(pmu); break; case ARM_CPU_PART_CORTEX_A8: ret = armv7_a8_pmu_init(pmu); break; case ARM_CPU_PART_CORTEX_A9: ret = armv7_a9_pmu_init(pmu); break; default: if (read_cpuid_implementor() == ARM_CPU_IMP_INTEL) { switch (xscale_cpu_arch_version()) { case ARM_CPU_XSCALE_ARCH_V1: ret = xscale1pmu_init(pmu); break; case ARM_CPU_XSCALE_ARCH_V2: ret = xscale2pmu_init(pmu); break; } } break; } put_cpu(); return ret; }
static void exynos3250_pm_resume(void) { u32 cpuid = read_cpuid_part(); if (exynos_pm_central_resume()) goto early_wakeup; /* For release retention */ exynos_pm_release_retention(); pmu_raw_writel(S5P_USE_STANDBY_WFI_ALL, S5P_CENTRAL_SEQ_OPTION); if (call_firmware_op(resume) == -ENOSYS && cpuid == ARM_CPU_PART_CORTEX_A9) exynos_cpu_restore_register(); early_wakeup: /* Clear SLEEP mode set in INFORM1 */ pmu_raw_writel(0x0, S5P_INFORM1); }
static void __init exynos_smp_prepare_cpus(unsigned int max_cpus) { int i; exynos_sysram_init(); if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) scu_enable(scu_base_addr()); /* * Write the address of secondary startup into the * system-wide flags register. The boot monitor waits * until it receives a soft interrupt, and then the * secondary CPU branches to this address. * * Try using firmware operation first and fall back to * boot register if it fails. */ for (i = 1; i < max_cpus; ++i) { unsigned long boot_addr; u32 mpidr; u32 core_id; int ret; mpidr = cpu_logical_map(i); core_id = MPIDR_AFFINITY_LEVEL(mpidr, 0); boot_addr = virt_to_phys(exynos4_secondary_startup); ret = call_firmware_op(set_cpu_boot_addr, core_id, boot_addr); if (ret && ret != -ENOSYS) break; if (ret == -ENOSYS) { void __iomem *boot_reg = cpu_boot_reg(core_id); if (IS_ERR(boot_reg)) break; __raw_writel(boot_addr, cpu_boot_reg(core_id)); } } }
static int exynos_do_idle(unsigned long mode) { switch (mode) { case FW_DO_IDLE_AFTR: if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) exynos_save_cp15(); __raw_writel(virt_to_phys(exynos_cpu_resume_ns), sysram_ns_base_addr + 0x24); __raw_writel(EXYNOS_AFTR_MAGIC, sysram_ns_base_addr + 0x20); if (soc_is_exynos3250()) { exynos_smc(SMC_CMD_SAVE, OP_TYPE_CORE, SMC_POWERSTATE_IDLE, 0); exynos_smc(SMC_CMD_SHUTDOWN, OP_TYPE_CLUSTER, SMC_POWERSTATE_IDLE, 0); } else exynos_smc(SMC_CMD_CPU0AFTR, 0, 0, 0); break; case FW_DO_IDLE_SLEEP: exynos_smc(SMC_CMD_SLEEP, 0, 0, 0); } return 0; }
static void __init exynos_smp_init_cpus(void) { void __iomem *scu_base = scu_base_addr(); unsigned int i, ncores; if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) ncores = scu_base ? scu_get_core_count(scu_base) : 1; else /* * CPU Nodes are passed thru DT and set_cpu_possible * is set by "arm_dt_init_cpu_maps". */ return; /* sanity check */ if (ncores > nr_cpu_ids) { pr_warn("SMP: %u cores greater than maximum (%u), clipping\n", ncores, nr_cpu_ids); ncores = nr_cpu_ids; } for (i = 0; i < ncores; i++) set_cpu_possible(i, true); }
static int __init rockchip_ca9_cpuidle_init(void) { struct device_node *np; int ret; if (!cpu_is_rockchip()) return -ENODEV; if (read_cpuid_part() != ARM_CPU_PART_CORTEX_A9) return -ENODEV; np = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-gic"); if (!np) return -ENODEV; gic_cpu_base = of_iomap(np, 1); if (!gic_cpu_base) { pr_err("%s: failed to map gic cpu registers\n", __func__); return -EINVAL; } rockchip_ca9_cpuidle_driver.states[0].enter = rockchip_ca9_cpuidle_enter; ret = cpuidle_register(&rockchip_ca9_cpuidle_driver, NULL); if (ret) pr_err("%s: failed to register cpuidle driver: %d\n", __func__, ret); return ret; }
static void __init global_timer_of_register(struct device_node *np) { struct clk *gt_clk; int err = 0; /* * In A9 r2p0 the comparators for each processor with the global timer * fire when the timer value is greater than or equal to. In previous * revisions the comparators fired when the timer value was equal to. */ if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9 && (read_cpuid_id() & 0xf0000f) < 0x200000) { pr_warn("global-timer: non support for this cpu version.\n"); return; } gt_ppi = irq_of_parse_and_map(np, 0); if (!gt_ppi) { pr_warn("global-timer: unable to parse irq\n"); return; } gt_base = of_iomap(np, 0); if (!gt_base) { pr_warn("global-timer: invalid base address\n"); return; } gt_clk = of_clk_get(np, 0); if (!IS_ERR(gt_clk)) { err = clk_prepare_enable(gt_clk); if (err) goto out_unmap; } else { pr_warn("global-timer: clk not found\n"); err = -EINVAL; goto out_unmap; } gt_clk_rate = clk_get_rate(gt_clk); gt_evt = alloc_percpu(struct clock_event_device); if (!gt_evt) { pr_warn("global-timer: can't allocate memory\n"); err = -ENOMEM; goto out_clk; } err = request_percpu_irq(gt_ppi, gt_clockevent_interrupt, "gt", gt_evt); if (err) { pr_warn("global-timer: can't register interrupt %d (%d)\n", gt_ppi, err); goto out_free; } err = register_cpu_notifier(>_cpu_nb); if (err) { pr_warn("global-timer: unable to register cpu notifier.\n"); goto out_irq; } /* Immediately configure the timer on the boot CPU */ gt_clocksource_init(); gt_clockevents_init(this_cpu_ptr(gt_evt)); return; out_irq: free_percpu_irq(gt_ppi, gt_evt); out_free: free_percpu(gt_evt); out_clk: clk_disable_unprepare(gt_clk); out_unmap: iounmap(gt_base); WARN(err, "ARM Global timer register failed (%d)\n", err); }