linux/arch/arm/mach-mstar/mstarv7.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Device Tree support for MStar/Sigmastar Armv7 SoCs
   4 *
   5 * Copyright (c) 2020 thingy.jp
   6 * Author: Daniel Palmer <daniel@thingy.jp>
   7 */
   8
   9#include <linux/init.h>
  10#include <asm/mach/arch.h>
  11#include <asm/mach/map.h>
  12#include <linux/of.h>
  13#include <linux/of_address.h>
  14#include <linux/io.h>
  15
  16/*
  17 * In the u-boot code the area these registers are in is
  18 * called "L3 bridge" and there are register descriptions
  19 * for something in the same area called "AXI".
  20 *
  21 * It's not exactly known what this is but the vendor code
  22 * for both u-boot and linux share calls to "flush the miu pipe".
  23 * This seems to be to force pending CPU writes to memory so that
  24 * the state is right before DMA capable devices try to read
  25 * descriptors and data the CPU has prepared. Without doing this
  26 * ethernet doesn't work reliably for example.
  27 */
  28
  29#define MSTARV7_L3BRIDGE_FLUSH          0x14
  30#define MSTARV7_L3BRIDGE_STATUS         0x40
  31#define MSTARV7_L3BRIDGE_FLUSH_TRIGGER  BIT(0)
  32#define MSTARV7_L3BRIDGE_STATUS_DONE    BIT(12)
  33
  34#ifdef CONFIG_SMP
  35#define MSTARV7_CPU1_BOOT_ADDR_HIGH     0x4c
  36#define MSTARV7_CPU1_BOOT_ADDR_LOW      0x50
  37#define MSTARV7_CPU1_UNLOCK             0x58
  38#define MSTARV7_CPU1_UNLOCK_MAGIC       0xbabe
  39#endif
  40
  41static void __iomem *l3bridge;
  42
  43static const char * const mstarv7_board_dt_compat[] __initconst = {
  44        "mstar,infinity",
  45        "mstar,infinity2m",
  46        "mstar,infinity3",
  47        "mstar,mercury5",
  48        NULL,
  49};
  50
  51/*
  52 * This may need locking to deal with situations where an interrupt
  53 * happens while we are in here and mb() gets called by the interrupt handler.
  54 *
  55 * The vendor code did have a spin lock but it doesn't seem to be needed and
  56 * removing it hasn't caused any side effects so far.
  57 *
  58 * [writel|readl]_relaxed have to be used here because otherwise
  59 * we'd end up right back in here.
  60 */
  61static void mstarv7_mb(void)
  62{
  63        /* toggle the flush miu pipe fire bit */
  64        writel_relaxed(0, l3bridge + MSTARV7_L3BRIDGE_FLUSH);
  65        writel_relaxed(MSTARV7_L3BRIDGE_FLUSH_TRIGGER, l3bridge
  66                        + MSTARV7_L3BRIDGE_FLUSH);
  67        while (!(readl_relaxed(l3bridge + MSTARV7_L3BRIDGE_STATUS)
  68                        & MSTARV7_L3BRIDGE_STATUS_DONE)) {
  69                /* wait for flush to complete */
  70        }
  71}
  72
  73#ifdef CONFIG_SMP
  74static int mstarv7_boot_secondary(unsigned int cpu, struct task_struct *idle)
  75{
  76        struct device_node *np;
  77        u32 bootaddr = (u32) __pa_symbol(secondary_startup_arm);
  78        void __iomem *smpctrl;
  79
  80        /*
  81         * right now we don't know how to boot anything except
  82         * cpu 1.
  83         */
  84        if (cpu != 1)
  85                return -EINVAL;
  86
  87        np = of_find_compatible_node(NULL, NULL, "mstar,smpctrl");
  88        smpctrl = of_iomap(np, 0);
  89
  90        if (!smpctrl)
  91                return -ENODEV;
  92
  93        /* set the boot address for the second cpu */
  94        writew(bootaddr & 0xffff, smpctrl + MSTARV7_CPU1_BOOT_ADDR_LOW);
  95        writew((bootaddr >> 16) & 0xffff, smpctrl + MSTARV7_CPU1_BOOT_ADDR_HIGH);
  96
  97        /* unlock the second cpu */
  98        writew(MSTARV7_CPU1_UNLOCK_MAGIC, smpctrl + MSTARV7_CPU1_UNLOCK);
  99
 100        /* and away we go...*/
 101        arch_send_wakeup_ipi_mask(cpumask_of(cpu));
 102
 103        iounmap(smpctrl);
 104
 105        return 0;
 106}
 107
 108static const struct smp_operations __initdata mstarv7_smp_ops = {
 109        .smp_boot_secondary = mstarv7_boot_secondary,
 110};
 111#endif
 112
 113static void __init mstarv7_init(void)
 114{
 115        struct device_node *np;
 116
 117        np = of_find_compatible_node(NULL, NULL, "mstar,l3bridge");
 118        l3bridge = of_iomap(np, 0);
 119        if (l3bridge)
 120                soc_mb = mstarv7_mb;
 121        else
 122                pr_warn("Failed to install memory barrier, DMA will be broken!\n");
 123}
 124
 125DT_MACHINE_START(MSTARV7_DT, "MStar/Sigmastar Armv7 (Device Tree)")
 126        .dt_compat      = mstarv7_board_dt_compat,
 127        .init_machine   = mstarv7_init,
 128        .smp            = smp_ops(mstarv7_smp_ops),
 129MACHINE_END
 130