Linux Audio

Check our new training course

Loading...
v6.13.7
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Broadcom BCM63138 DSL SoCs SMP support code
  4 *
  5 * Copyright (C) 2015, Broadcom Corporation
  6 */
  7
  8#include <linux/delay.h>
  9#include <linux/init.h>
 10#include <linux/smp.h>
 11#include <linux/io.h>
 12#include <linux/of.h>
 13#include <linux/of_address.h>
 14
 15#include <asm/cacheflush.h>
 16#include <asm/smp_scu.h>
 17#include <asm/smp_plat.h>
 18#include <asm/vfp.h>
 19
 20#include "bcm63xx_smp.h"
 21
 22/* Size of mapped Cortex A9 SCU address space */
 23#define CORTEX_A9_SCU_SIZE	0x58
 24
 25/*
 26 * Enable the Cortex A9 Snoop Control Unit
 27 *
 28 * By the time this is called we already know there are multiple
 29 * cores present.  We assume we're running on a Cortex A9 processor,
 30 * so any trouble getting the base address register or getting the
 31 * SCU base is a problem.
 32 *
 33 * Return 0 if successful or an error code otherwise.
 34 */
 35static int __init scu_a9_enable(void)
 36{
 37	unsigned long config_base;
 38	void __iomem *scu_base;
 39	unsigned int i, ncores;
 40
 41	if (!scu_a9_has_base()) {
 42		pr_err("no configuration base address register!\n");
 43		return -ENXIO;
 44	}
 45
 46	/* Config base address register value is zero for uniprocessor */
 47	config_base = scu_a9_get_base();
 48	if (!config_base) {
 49		pr_err("hardware reports only one core\n");
 50		return -ENOENT;
 51	}
 52
 53	scu_base = ioremap((phys_addr_t)config_base, CORTEX_A9_SCU_SIZE);
 54	if (!scu_base) {
 55		pr_err("failed to remap config base (%lu/%u) for SCU\n",
 56			config_base, CORTEX_A9_SCU_SIZE);
 57		return -ENOMEM;
 58	}
 59
 60	scu_enable(scu_base);
 61
 62	ncores = scu_base ? scu_get_core_count(scu_base) : 1;
 63
 64	if (ncores > nr_cpu_ids) {
 65		pr_warn("SMP: %u cores greater than maximum (%u), clipping\n",
 66				ncores, nr_cpu_ids);
 67		ncores = nr_cpu_ids;
 68	}
 69
 70	/* The BCM63138 SoC has two Cortex-A9 CPUs, CPU0 features a complete
 71	 * and fully functional VFP unit that can be used, but CPU1 does not.
 72	 * Since we will not be able to trap kernel-mode NEON to force
 73	 * migration to CPU0, just do not advertise VFP support at all.
 74	 *
 75	 * This will make vfp_init bail out and do not attempt to use VFP at
 76	 * all, for kernel-mode NEON, we do not want to introduce any
 77	 * conditionals in hot-paths, so we just restrict the system to UP.
 78	 */
 79#ifdef CONFIG_VFP
 80	if (ncores > 1) {
 81		pr_warn("SMP: secondary CPUs lack VFP unit, disabling VFP\n");
 82		vfp_disable();
 83
 84#ifdef CONFIG_KERNEL_MODE_NEON
 85		WARN(1, "SMP: kernel-mode NEON enabled, restricting to UP\n");
 86		ncores = 1;
 87#endif
 88	}
 89#endif
 90
 91	for (i = 0; i < ncores; i++)
 92		set_cpu_possible(i, true);
 93
 94	iounmap(scu_base);	/* That's the last we'll need of this */
 95
 96	return 0;
 97}
 98
 99static const struct of_device_id bcm63138_bootlut_ids[] = {
100	{ .compatible = "brcm,bcm63138-bootlut", },
101	{ /* sentinel */ },
102};
103
104#define BOOTLUT_RESET_VECT	0x20
105
106static int bcm63138_smp_boot_secondary(unsigned int cpu,
107				       struct task_struct *idle)
108{
109	void __iomem *bootlut_base;
110	struct device_node *dn;
111	int ret = 0;
112	u32 val;
113
114	dn = of_find_matching_node(NULL, bcm63138_bootlut_ids);
115	if (!dn) {
116		pr_err("SMP: unable to find bcm63138 boot LUT node\n");
117		return -ENODEV;
118	}
119
120	bootlut_base = of_iomap(dn, 0);
121	of_node_put(dn);
122
123	if (!bootlut_base) {
124		pr_err("SMP: unable to remap boot LUT base register\n");
125		return -ENOMEM;
126	}
127
128	/* Locate the secondary CPU node */
129	dn = of_get_cpu_node(cpu, NULL);
130	if (!dn) {
131		pr_err("SMP: failed to locate secondary CPU%d node\n", cpu);
132		ret = -ENODEV;
133		goto out;
134	}
135
136	/* Write the secondary init routine to the BootLUT reset vector */
137	val = __pa_symbol(secondary_startup);
138	writel_relaxed(val, bootlut_base + BOOTLUT_RESET_VECT);
139
140	/* Power up the core, will jump straight to its reset vector when we
141	 * return
142	 */
143	ret = bcm63xx_pmb_power_on_cpu(dn);
144	of_node_put(dn);
145
146out:
147	iounmap(bootlut_base);
148
149	return ret;
150}
151
152static void __init bcm63138_smp_prepare_cpus(unsigned int max_cpus)
153{
154	int ret;
155
156	ret = scu_a9_enable();
157	if (ret) {
158		pr_warn("SMP: Cortex-A9 SCU setup failed\n");
159		return;
160	}
161}
162
163static const struct smp_operations bcm63138_smp_ops __initconst = {
164	.smp_prepare_cpus	= bcm63138_smp_prepare_cpus,
165	.smp_boot_secondary	= bcm63138_smp_boot_secondary,
166};
167
168CPU_METHOD_OF_DECLARE(bcm63138_smp, "brcm,bcm63138", &bcm63138_smp_ops);
v6.8
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Broadcom BCM63138 DSL SoCs SMP support code
  4 *
  5 * Copyright (C) 2015, Broadcom Corporation
  6 */
  7
  8#include <linux/delay.h>
  9#include <linux/init.h>
 10#include <linux/smp.h>
 11#include <linux/io.h>
 12#include <linux/of.h>
 13#include <linux/of_address.h>
 14
 15#include <asm/cacheflush.h>
 16#include <asm/smp_scu.h>
 17#include <asm/smp_plat.h>
 18#include <asm/vfp.h>
 19
 20#include "bcm63xx_smp.h"
 21
 22/* Size of mapped Cortex A9 SCU address space */
 23#define CORTEX_A9_SCU_SIZE	0x58
 24
 25/*
 26 * Enable the Cortex A9 Snoop Control Unit
 27 *
 28 * By the time this is called we already know there are multiple
 29 * cores present.  We assume we're running on a Cortex A9 processor,
 30 * so any trouble getting the base address register or getting the
 31 * SCU base is a problem.
 32 *
 33 * Return 0 if successful or an error code otherwise.
 34 */
 35static int __init scu_a9_enable(void)
 36{
 37	unsigned long config_base;
 38	void __iomem *scu_base;
 39	unsigned int i, ncores;
 40
 41	if (!scu_a9_has_base()) {
 42		pr_err("no configuration base address register!\n");
 43		return -ENXIO;
 44	}
 45
 46	/* Config base address register value is zero for uniprocessor */
 47	config_base = scu_a9_get_base();
 48	if (!config_base) {
 49		pr_err("hardware reports only one core\n");
 50		return -ENOENT;
 51	}
 52
 53	scu_base = ioremap((phys_addr_t)config_base, CORTEX_A9_SCU_SIZE);
 54	if (!scu_base) {
 55		pr_err("failed to remap config base (%lu/%u) for SCU\n",
 56			config_base, CORTEX_A9_SCU_SIZE);
 57		return -ENOMEM;
 58	}
 59
 60	scu_enable(scu_base);
 61
 62	ncores = scu_base ? scu_get_core_count(scu_base) : 1;
 63
 64	if (ncores > nr_cpu_ids) {
 65		pr_warn("SMP: %u cores greater than maximum (%u), clipping\n",
 66				ncores, nr_cpu_ids);
 67		ncores = nr_cpu_ids;
 68	}
 69
 70	/* The BCM63138 SoC has two Cortex-A9 CPUs, CPU0 features a complete
 71	 * and fully functional VFP unit that can be used, but CPU1 does not.
 72	 * Since we will not be able to trap kernel-mode NEON to force
 73	 * migration to CPU0, just do not advertise VFP support at all.
 74	 *
 75	 * This will make vfp_init bail out and do not attempt to use VFP at
 76	 * all, for kernel-mode NEON, we do not want to introduce any
 77	 * conditionals in hot-paths, so we just restrict the system to UP.
 78	 */
 79#ifdef CONFIG_VFP
 80	if (ncores > 1) {
 81		pr_warn("SMP: secondary CPUs lack VFP unit, disabling VFP\n");
 82		vfp_disable();
 83
 84#ifdef CONFIG_KERNEL_MODE_NEON
 85		WARN(1, "SMP: kernel-mode NEON enabled, restricting to UP\n");
 86		ncores = 1;
 87#endif
 88	}
 89#endif
 90
 91	for (i = 0; i < ncores; i++)
 92		set_cpu_possible(i, true);
 93
 94	iounmap(scu_base);	/* That's the last we'll need of this */
 95
 96	return 0;
 97}
 98
 99static const struct of_device_id bcm63138_bootlut_ids[] = {
100	{ .compatible = "brcm,bcm63138-bootlut", },
101	{ /* sentinel */ },
102};
103
104#define BOOTLUT_RESET_VECT	0x20
105
106static int bcm63138_smp_boot_secondary(unsigned int cpu,
107				       struct task_struct *idle)
108{
109	void __iomem *bootlut_base;
110	struct device_node *dn;
111	int ret = 0;
112	u32 val;
113
114	dn = of_find_matching_node(NULL, bcm63138_bootlut_ids);
115	if (!dn) {
116		pr_err("SMP: unable to find bcm63138 boot LUT node\n");
117		return -ENODEV;
118	}
119
120	bootlut_base = of_iomap(dn, 0);
121	of_node_put(dn);
122
123	if (!bootlut_base) {
124		pr_err("SMP: unable to remap boot LUT base register\n");
125		return -ENOMEM;
126	}
127
128	/* Locate the secondary CPU node */
129	dn = of_get_cpu_node(cpu, NULL);
130	if (!dn) {
131		pr_err("SMP: failed to locate secondary CPU%d node\n", cpu);
132		ret = -ENODEV;
133		goto out;
134	}
135
136	/* Write the secondary init routine to the BootLUT reset vector */
137	val = __pa_symbol(secondary_startup);
138	writel_relaxed(val, bootlut_base + BOOTLUT_RESET_VECT);
139
140	/* Power up the core, will jump straight to its reset vector when we
141	 * return
142	 */
143	ret = bcm63xx_pmb_power_on_cpu(dn);
144	of_node_put(dn);
145
146out:
147	iounmap(bootlut_base);
148
149	return ret;
150}
151
152static void __init bcm63138_smp_prepare_cpus(unsigned int max_cpus)
153{
154	int ret;
155
156	ret = scu_a9_enable();
157	if (ret) {
158		pr_warn("SMP: Cortex-A9 SCU setup failed\n");
159		return;
160	}
161}
162
163static const struct smp_operations bcm63138_smp_ops __initconst = {
164	.smp_prepare_cpus	= bcm63138_smp_prepare_cpus,
165	.smp_boot_secondary	= bcm63138_smp_boot_secondary,
166};
167
168CPU_METHOD_OF_DECLARE(bcm63138_smp, "brcm,bcm63138", &bcm63138_smp_ops);