133-ARM-BCM-Add-SMP-support-for-Broadcom-NSP.patch 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
  1. From e99fb6d01cddf38cffc11655aba4a96a981d604e Mon Sep 17 00:00:00 2001
  2. From: Kapil Hali <kapilh@broadcom.com>
  3. Date: Wed, 25 Nov 2015 13:25:55 -0500
  4. Subject: [PATCH 133/134] ARM: BCM: Add SMP support for Broadcom NSP
  5. Add SMP support for Broadcom's Northstar Plus SoC
  6. cpu enable method. This changes also consolidates
  7. iProc family's - BCM NSP and BCM Kona, platform
  8. SMP handling in a common file.
  9. Northstar Plus SoC is based on ARM Cortex-A9
  10. revision r3p0 which requires configuration for ARM
  11. Errata 764369 for SMP. This change adds the needed
  12. configuration option.
  13. Signed-off-by: Kapil Hali <kapilh@broadcom.com>
  14. ---
  15. arch/arm/mach-bcm/Kconfig | 2 +
  16. arch/arm/mach-bcm/Makefile | 8 +-
  17. arch/arm/mach-bcm/kona_smp.c | 228 ----------------------------------
  18. arch/arm/mach-bcm/platsmp.c | 290 +++++++++++++++++++++++++++++++++++++++++++
  19. 4 files changed, 298 insertions(+), 230 deletions(-)
  20. delete mode 100644 arch/arm/mach-bcm/kona_smp.c
  21. create mode 100644 arch/arm/mach-bcm/platsmp.c
  22. --- a/arch/arm/mach-bcm/Makefile
  23. +++ b/arch/arm/mach-bcm/Makefile
  24. @@ -20,7 +20,7 @@ obj-$(CONFIG_ARCH_BCM_281XX) += board_bc
  25. obj-$(CONFIG_ARCH_BCM_21664) += board_bcm21664.o
  26. # BCM281XX and BCM21664 SMP support
  27. -obj-$(CONFIG_ARCH_BCM_MOBILE_SMP) += kona_smp.o
  28. +obj-$(CONFIG_ARCH_BCM_MOBILE_SMP) += platsmp.o
  29. # BCM281XX and BCM21664 L2 cache control
  30. obj-$(CONFIG_ARCH_BCM_MOBILE_L2_CACHE) += kona_l2_cache.o
  31. --- a/arch/arm/mach-bcm/kona_smp.c
  32. +++ /dev/null
  33. @@ -1,228 +0,0 @@
  34. -/*
  35. - * Copyright (C) 2014-2015 Broadcom Corporation
  36. - * Copyright 2014 Linaro Limited
  37. - *
  38. - * This program is free software; you can redistribute it and/or
  39. - * modify it under the terms of the GNU General Public License as
  40. - * published by the Free Software Foundation version 2.
  41. - *
  42. - * This program is distributed "as is" WITHOUT ANY WARRANTY of any
  43. - * kind, whether express or implied; without even the implied warranty
  44. - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  45. - * GNU General Public License for more details.
  46. - */
  47. -
  48. -#include <linux/init.h>
  49. -#include <linux/errno.h>
  50. -#include <linux/io.h>
  51. -#include <linux/of.h>
  52. -#include <linux/sched.h>
  53. -
  54. -#include <asm/smp.h>
  55. -#include <asm/smp_plat.h>
  56. -#include <asm/smp_scu.h>
  57. -
  58. -/* Size of mapped Cortex A9 SCU address space */
  59. -#define CORTEX_A9_SCU_SIZE 0x58
  60. -
  61. -#define SECONDARY_TIMEOUT_NS NSEC_PER_MSEC /* 1 msec (in nanoseconds) */
  62. -#define BOOT_ADDR_CPUID_MASK 0x3
  63. -
  64. -/* Name of device node property defining secondary boot register location */
  65. -#define OF_SECONDARY_BOOT "secondary-boot-reg"
  66. -#define MPIDR_CPUID_BITMASK 0x3
  67. -
  68. -/* I/O address of register used to coordinate secondary core startup */
  69. -static u32 secondary_boot_addr;
  70. -
  71. -/*
  72. - * Enable the Cortex A9 Snoop Control Unit
  73. - *
  74. - * By the time this is called we already know there are multiple
  75. - * cores present. We assume we're running on a Cortex A9 processor,
  76. - * so any trouble getting the base address register or getting the
  77. - * SCU base is a problem.
  78. - *
  79. - * Return 0 if successful or an error code otherwise.
  80. - */
  81. -static int __init scu_a9_enable(void)
  82. -{
  83. - unsigned long config_base;
  84. - void __iomem *scu_base;
  85. -
  86. - if (!scu_a9_has_base()) {
  87. - pr_err("no configuration base address register!\n");
  88. - return -ENXIO;
  89. - }
  90. -
  91. - /* Config base address register value is zero for uniprocessor */
  92. - config_base = scu_a9_get_base();
  93. - if (!config_base) {
  94. - pr_err("hardware reports only one core\n");
  95. - return -ENOENT;
  96. - }
  97. -
  98. - scu_base = ioremap((phys_addr_t)config_base, CORTEX_A9_SCU_SIZE);
  99. - if (!scu_base) {
  100. - pr_err("failed to remap config base (%lu/%u) for SCU\n",
  101. - config_base, CORTEX_A9_SCU_SIZE);
  102. - return -ENOMEM;
  103. - }
  104. -
  105. - scu_enable(scu_base);
  106. -
  107. - iounmap(scu_base); /* That's the last we'll need of this */
  108. -
  109. - return 0;
  110. -}
  111. -
  112. -static void __init bcm_smp_prepare_cpus(unsigned int max_cpus)
  113. -{
  114. - static cpumask_t only_cpu_0 = { CPU_BITS_CPU0 };
  115. - struct device_node *cpus_node = NULL;
  116. - struct device_node *cpu_node = NULL;
  117. - int ret;
  118. -
  119. - /*
  120. - * This function is only called via smp_ops->smp_prepare_cpu().
  121. - * That only happens if a "/cpus" device tree node exists
  122. - * and has an "enable-method" property that selects the SMP
  123. - * operations defined herein.
  124. - */
  125. - cpus_node = of_find_node_by_path("/cpus");
  126. - if (!cpus_node)
  127. - return;
  128. -
  129. - for_each_child_of_node(cpus_node, cpu_node) {
  130. - u32 cpuid;
  131. -
  132. - if (of_node_cmp(cpu_node->type, "cpu"))
  133. - continue;
  134. -
  135. - if (of_property_read_u32(cpu_node, "reg", &cpuid)) {
  136. - pr_debug("%s: missing reg property\n",
  137. - cpu_node->full_name);
  138. - ret = -ENOENT;
  139. - goto out;
  140. - }
  141. -
  142. - /*
  143. - * "secondary-boot-reg" property should be defined only
  144. - * for secondary cpu
  145. - */
  146. - if ((cpuid & MPIDR_CPUID_BITMASK) == 1) {
  147. - /*
  148. - * Our secondary enable method requires a
  149. - * "secondary-boot-reg" property to specify a register
  150. - * address used to request the ROM code boot a secondary
  151. - * core. If we have any trouble getting this we fall
  152. - * back to uniprocessor mode.
  153. - */
  154. - if (of_property_read_u32(cpu_node,
  155. - OF_SECONDARY_BOOT,
  156. - &secondary_boot_addr)) {
  157. - pr_warn("%s: no" OF_SECONDARY_BOOT "property\n",
  158. - cpu_node->name);
  159. - ret = -ENOENT;
  160. - goto out;
  161. - }
  162. - }
  163. - }
  164. -
  165. - /*
  166. - * Enable the SCU on Cortex A9 based SoCs. If -ENOENT is
  167. - * returned, the SoC reported a uniprocessor configuration.
  168. - * We bail on any other error.
  169. - */
  170. - ret = scu_a9_enable();
  171. -out:
  172. - of_node_put(cpu_node);
  173. - of_node_put(cpus_node);
  174. -
  175. - if (ret) {
  176. - /* Update the CPU present map to reflect uniprocessor mode */
  177. - pr_warn("disabling SMP\n");
  178. - init_cpu_present(&only_cpu_0);
  179. - }
  180. -}
  181. -
  182. -/*
  183. - * The ROM code has the secondary cores looping, waiting for an event.
  184. - * When an event occurs each core examines the bottom two bits of the
  185. - * secondary boot register. When a core finds those bits contain its
  186. - * own core id, it performs initialization, including computing its boot
  187. - * address by clearing the boot register value's bottom two bits. The
  188. - * core signals that it is beginning its execution by writing its boot
  189. - * address back to the secondary boot register, and finally jumps to
  190. - * that address.
  191. - *
  192. - * So to start a core executing we need to:
  193. - * - Encode the (hardware) CPU id with the bottom bits of the secondary
  194. - * start address.
  195. - * - Write that value into the secondary boot register.
  196. - * - Generate an event to wake up the secondary CPU(s).
  197. - * - Wait for the secondary boot register to be re-written, which
  198. - * indicates the secondary core has started.
  199. - */
  200. -static int kona_boot_secondary(unsigned int cpu, struct task_struct *idle)
  201. -{
  202. - void __iomem *boot_reg;
  203. - phys_addr_t boot_func;
  204. - u64 start_clock;
  205. - u32 cpu_id;
  206. - u32 boot_val;
  207. - bool timeout = false;
  208. -
  209. - cpu_id = cpu_logical_map(cpu);
  210. - if (cpu_id & ~BOOT_ADDR_CPUID_MASK) {
  211. - pr_err("bad cpu id (%u > %u)\n", cpu_id, BOOT_ADDR_CPUID_MASK);
  212. - return -EINVAL;
  213. - }
  214. -
  215. - if (!secondary_boot_addr) {
  216. - pr_err("required secondary boot register not specified\n");
  217. - return -EINVAL;
  218. - }
  219. -
  220. - boot_reg = ioremap_nocache(
  221. - (phys_addr_t)secondary_boot_addr, sizeof(u32));
  222. - if (!boot_reg) {
  223. - pr_err("unable to map boot register for cpu %u\n", cpu_id);
  224. - return -ENOMEM;
  225. - }
  226. -
  227. - /*
  228. - * Secondary cores will start in secondary_startup(),
  229. - * defined in "arch/arm/kernel/head.S"
  230. - */
  231. - boot_func = virt_to_phys(secondary_startup);
  232. - BUG_ON(boot_func & BOOT_ADDR_CPUID_MASK);
  233. - BUG_ON(boot_func > (phys_addr_t)U32_MAX);
  234. -
  235. - /* The core to start is encoded in the low bits */
  236. - boot_val = (u32)boot_func | cpu_id;
  237. - writel_relaxed(boot_val, boot_reg);
  238. -
  239. - sev();
  240. -
  241. - /* The low bits will be cleared once the core has started */
  242. - start_clock = local_clock();
  243. - while (!timeout && readl_relaxed(boot_reg) == boot_val)
  244. - timeout = local_clock() - start_clock > SECONDARY_TIMEOUT_NS;
  245. -
  246. - iounmap(boot_reg);
  247. -
  248. - if (!timeout)
  249. - return 0;
  250. -
  251. - pr_err("timeout waiting for cpu %u to start\n", cpu_id);
  252. -
  253. - return -ENXIO;
  254. -}
  255. -
  256. -static struct smp_operations bcm_smp_ops __initdata = {
  257. - .smp_prepare_cpus = bcm_smp_prepare_cpus,
  258. - .smp_boot_secondary = kona_boot_secondary,
  259. -};
  260. -CPU_METHOD_OF_DECLARE(bcm_smp_bcm281xx, "brcm,bcm11351-cpu-method",
  261. - &bcm_smp_ops);
  262. --- /dev/null
  263. +++ b/arch/arm/mach-bcm/platsmp.c
  264. @@ -0,0 +1,290 @@
  265. +/*
  266. + * Copyright (C) 2014-2015 Broadcom Corporation
  267. + * Copyright 2014 Linaro Limited
  268. + *
  269. + * This program is free software; you can redistribute it and/or
  270. + * modify it under the terms of the GNU General Public License as
  271. + * published by the Free Software Foundation version 2.
  272. + *
  273. + * This program is distributed "as is" WITHOUT ANY WARRANTY of any
  274. + * kind, whether express or implied; without even the implied warranty
  275. + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  276. + * GNU General Public License for more details.
  277. + */
  278. +
  279. +#include <linux/cpumask.h>
  280. +#include <linux/delay.h>
  281. +#include <linux/errno.h>
  282. +#include <linux/init.h>
  283. +#include <linux/io.h>
  284. +#include <linux/jiffies.h>
  285. +#include <linux/of.h>
  286. +#include <linux/sched.h>
  287. +#include <linux/smp.h>
  288. +
  289. +#include <asm/cacheflush.h>
  290. +#include <asm/smp.h>
  291. +#include <asm/smp_plat.h>
  292. +#include <asm/smp_scu.h>
  293. +
  294. +/* Size of mapped Cortex A9 SCU address space */
  295. +#define CORTEX_A9_SCU_SIZE 0x58
  296. +
  297. +#define SECONDARY_TIMEOUT_NS NSEC_PER_MSEC /* 1 msec (in nanoseconds) */
  298. +#define BOOT_ADDR_CPUID_MASK 0x3
  299. +
  300. +/* Name of device node property defining secondary boot register location */
  301. +#define OF_SECONDARY_BOOT "secondary-boot-reg"
  302. +#define MPIDR_CPUID_BITMASK 0x3
  303. +
  304. +/* I/O address of register used to coordinate secondary core startup */
  305. +static u32 secondary_boot_addr;
  306. +
  307. +/*
  308. + * Enable the Cortex A9 Snoop Control Unit
  309. + *
  310. + * By the time this is called we already know there are multiple
  311. + * cores present. We assume we're running on a Cortex A9 processor,
  312. + * so any trouble getting the base address register or getting the
  313. + * SCU base is a problem.
  314. + *
  315. + * Return 0 if successful or an error code otherwise.
  316. + */
  317. +static int __init scu_a9_enable(void)
  318. +{
  319. + unsigned long config_base;
  320. + void __iomem *scu_base;
  321. +
  322. + if (!scu_a9_has_base()) {
  323. + pr_err("no configuration base address register!\n");
  324. + return -ENXIO;
  325. + }
  326. +
  327. + /* Config base address register value is zero for uniprocessor */
  328. + config_base = scu_a9_get_base();
  329. + if (!config_base) {
  330. + pr_err("hardware reports only one core\n");
  331. + return -ENOENT;
  332. + }
  333. +
  334. + scu_base = ioremap((phys_addr_t)config_base, CORTEX_A9_SCU_SIZE);
  335. + if (!scu_base) {
  336. + pr_err("failed to remap config base (%lu/%u) for SCU\n",
  337. + config_base, CORTEX_A9_SCU_SIZE);
  338. + return -ENOMEM;
  339. + }
  340. +
  341. + scu_enable(scu_base);
  342. +
  343. + iounmap(scu_base); /* That's the last we'll need of this */
  344. +
  345. + return 0;
  346. +}
  347. +
  348. +static int nsp_write_lut(void)
  349. +{
  350. + void __iomem *sku_rom_lut;
  351. + phys_addr_t secondary_startup_phy;
  352. +
  353. + if (!secondary_boot_addr) {
  354. + pr_warn("required secondary boot register not specified\n");
  355. + return -EINVAL;
  356. + }
  357. +
  358. + sku_rom_lut = ioremap_nocache((phys_addr_t)secondary_boot_addr,
  359. + sizeof(secondary_boot_addr));
  360. + if (!sku_rom_lut) {
  361. + pr_warn("unable to ioremap SKU-ROM LUT register\n");
  362. + return -ENOMEM;
  363. + }
  364. +
  365. + secondary_startup_phy = virt_to_phys(secondary_startup);
  366. + BUG_ON(secondary_startup_phy > (phys_addr_t)U32_MAX);
  367. +
  368. + writel_relaxed(secondary_startup_phy, sku_rom_lut);
  369. +
  370. + /* Ensure the write is visible to the secondary core */
  371. + smp_wmb();
  372. +
  373. + iounmap(sku_rom_lut);
  374. +
  375. + return 0;
  376. +}
  377. +
  378. +static void __init bcm_smp_prepare_cpus(unsigned int max_cpus)
  379. +{
  380. + static cpumask_t only_cpu_0 = { CPU_BITS_CPU0 };
  381. + struct device_node *cpus_node = NULL;
  382. + struct device_node *cpu_node = NULL;
  383. + int ret;
  384. +
  385. + /*
  386. + * This function is only called via smp_ops->smp_prepare_cpu().
  387. + * That only happens if a "/cpus" device tree node exists
  388. + * and has an "enable-method" property that selects the SMP
  389. + * operations defined herein.
  390. + */
  391. + cpus_node = of_find_node_by_path("/cpus");
  392. + if (!cpus_node)
  393. + return;
  394. +
  395. + for_each_child_of_node(cpus_node, cpu_node) {
  396. + u32 cpuid;
  397. +
  398. + if (of_node_cmp(cpu_node->type, "cpu"))
  399. + continue;
  400. +
  401. + if (of_property_read_u32(cpu_node, "reg", &cpuid)) {
  402. + pr_debug("%s: missing reg property\n",
  403. + cpu_node->full_name);
  404. + ret = -ENOENT;
  405. + goto out;
  406. + }
  407. +
  408. + /*
  409. + * "secondary-boot-reg" property should be defined only
  410. + * for secondary cpu
  411. + */
  412. + if ((cpuid & MPIDR_CPUID_BITMASK) == 1) {
  413. + /*
  414. + * Our secondary enable method requires a
  415. + * "secondary-boot-reg" property to specify a register
  416. + * address used to request the ROM code boot a secondary
  417. + * core. If we have any trouble getting this we fall
  418. + * back to uniprocessor mode.
  419. + */
  420. + if (of_property_read_u32(cpu_node,
  421. + OF_SECONDARY_BOOT,
  422. + &secondary_boot_addr)) {
  423. + pr_warn("%s: no" OF_SECONDARY_BOOT "property\n",
  424. + cpu_node->name);
  425. + ret = -ENOENT;
  426. + goto out;
  427. + }
  428. + }
  429. + }
  430. +
  431. + /*
  432. + * Enable the SCU on Cortex A9 based SoCs. If -ENOENT is
  433. + * returned, the SoC reported a uniprocessor configuration.
  434. + * We bail on any other error.
  435. + */
  436. + ret = scu_a9_enable();
  437. +out:
  438. + of_node_put(cpu_node);
  439. + of_node_put(cpus_node);
  440. +
  441. + if (ret) {
  442. + /* Update the CPU present map to reflect uniprocessor mode */
  443. + pr_warn("disabling SMP\n");
  444. + init_cpu_present(&only_cpu_0);
  445. + }
  446. +}
  447. +
  448. +/*
  449. + * The ROM code has the secondary cores looping, waiting for an event.
  450. + * When an event occurs each core examines the bottom two bits of the
  451. + * secondary boot register. When a core finds those bits contain its
  452. + * own core id, it performs initialization, including computing its boot
  453. + * address by clearing the boot register value's bottom two bits. The
  454. + * core signals that it is beginning its execution by writing its boot
  455. + * address back to the secondary boot register, and finally jumps to
  456. + * that address.
  457. + *
  458. + * So to start a core executing we need to:
  459. + * - Encode the (hardware) CPU id with the bottom bits of the secondary
  460. + * start address.
  461. + * - Write that value into the secondary boot register.
  462. + * - Generate an event to wake up the secondary CPU(s).
  463. + * - Wait for the secondary boot register to be re-written, which
  464. + * indicates the secondary core has started.
  465. + */
  466. +static int kona_boot_secondary(unsigned int cpu, struct task_struct *idle)
  467. +{
  468. + void __iomem *boot_reg;
  469. + phys_addr_t boot_func;
  470. + u64 start_clock;
  471. + u32 cpu_id;
  472. + u32 boot_val;
  473. + bool timeout = false;
  474. +
  475. + cpu_id = cpu_logical_map(cpu);
  476. + if (cpu_id & ~BOOT_ADDR_CPUID_MASK) {
  477. + pr_err("bad cpu id (%u > %u)\n", cpu_id, BOOT_ADDR_CPUID_MASK);
  478. + return -EINVAL;
  479. + }
  480. +
  481. + if (!secondary_boot_addr) {
  482. + pr_err("required secondary boot register not specified\n");
  483. + return -EINVAL;
  484. + }
  485. +
  486. + boot_reg = ioremap_nocache(
  487. + (phys_addr_t)secondary_boot_addr, sizeof(u32));
  488. + if (!boot_reg) {
  489. + pr_err("unable to map boot register for cpu %u\n", cpu_id);
  490. + return -ENOMEM;
  491. + }
  492. +
  493. + /*
  494. + * Secondary cores will start in secondary_startup(),
  495. + * defined in "arch/arm/kernel/head.S"
  496. + */
  497. + boot_func = virt_to_phys(secondary_startup);
  498. + BUG_ON(boot_func & BOOT_ADDR_CPUID_MASK);
  499. + BUG_ON(boot_func > (phys_addr_t)U32_MAX);
  500. +
  501. + /* The core to start is encoded in the low bits */
  502. + boot_val = (u32)boot_func | cpu_id;
  503. + writel_relaxed(boot_val, boot_reg);
  504. +
  505. + sev();
  506. +
  507. + /* The low bits will be cleared once the core has started */
  508. + start_clock = local_clock();
  509. + while (!timeout && readl_relaxed(boot_reg) == boot_val)
  510. + timeout = local_clock() - start_clock > SECONDARY_TIMEOUT_NS;
  511. +
  512. + iounmap(boot_reg);
  513. +
  514. + if (!timeout)
  515. + return 0;
  516. +
  517. + pr_err("timeout waiting for cpu %u to start\n", cpu_id);
  518. +
  519. + return -ENXIO;
  520. +}
  521. +
  522. +static int nsp_boot_secondary(unsigned int cpu, struct task_struct *idle)
  523. +{
  524. + int ret;
  525. +
  526. + /*
  527. + * After wake up, secondary core branches to the startup
  528. + * address programmed at SKU ROM LUT location.
  529. + */
  530. + ret = nsp_write_lut();
  531. + if (ret) {
  532. + pr_err("unable to write startup addr to SKU ROM LUT\n");
  533. + goto out;
  534. + }
  535. +
  536. + /* Send a CPU wakeup interrupt to the secondary core */
  537. + arch_send_wakeup_ipi_mask(cpumask_of(cpu));
  538. +
  539. +out:
  540. + return ret;
  541. +}
  542. +
  543. +static struct smp_operations bcm_smp_ops __initdata = {
  544. + .smp_prepare_cpus = bcm_smp_prepare_cpus,
  545. + .smp_boot_secondary = kona_boot_secondary,
  546. +};
  547. +CPU_METHOD_OF_DECLARE(bcm_smp_bcm281xx, "brcm,bcm11351-cpu-method",
  548. + &bcm_smp_ops);
  549. +
  550. +struct smp_operations nsp_smp_ops __initdata = {
  551. + .smp_prepare_cpus = bcm_smp_prepare_cpus,
  552. + .smp_boot_secondary = nsp_boot_secondary,
  553. +};
  554. +CPU_METHOD_OF_DECLARE(bcm_smp_nsp, "brcm,bcm-nsp-smp", &nsp_smp_ops);