Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Device Tree support for MStar/Sigmastar Armv7 SoCs
0004  *
0005  * Copyright (c) 2020 thingy.jp
0006  * Author: Daniel Palmer <daniel@thingy.jp>
0007  */
0008 
0009 #include <linux/init.h>
0010 #include <asm/mach/arch.h>
0011 #include <asm/mach/map.h>
0012 #include <linux/of.h>
0013 #include <linux/of_address.h>
0014 #include <linux/io.h>
0015 
0016 /*
0017  * In the u-boot code the area these registers are in is
0018  * called "L3 bridge" and there are register descriptions
0019  * for something in the same area called "AXI".
0020  *
0021  * It's not exactly known what this is but the vendor code
0022  * for both u-boot and linux share calls to "flush the miu pipe".
0023  * This seems to be to force pending CPU writes to memory so that
0024  * the state is right before DMA capable devices try to read
0025  * descriptors and data the CPU has prepared. Without doing this
0026  * ethernet doesn't work reliably for example.
0027  */
0028 
0029 #define MSTARV7_L3BRIDGE_FLUSH      0x14
0030 #define MSTARV7_L3BRIDGE_STATUS     0x40
0031 #define MSTARV7_L3BRIDGE_FLUSH_TRIGGER  BIT(0)
0032 #define MSTARV7_L3BRIDGE_STATUS_DONE    BIT(12)
0033 
0034 #ifdef CONFIG_SMP
0035 #define MSTARV7_CPU1_BOOT_ADDR_HIGH 0x4c
0036 #define MSTARV7_CPU1_BOOT_ADDR_LOW  0x50
0037 #define MSTARV7_CPU1_UNLOCK     0x58
0038 #define MSTARV7_CPU1_UNLOCK_MAGIC   0xbabe
0039 #endif
0040 
0041 static void __iomem *l3bridge;
0042 
0043 static const char * const mstarv7_board_dt_compat[] __initconst = {
0044     "mstar,infinity",
0045     "mstar,infinity2m",
0046     "mstar,infinity3",
0047     "mstar,mercury5",
0048     NULL,
0049 };
0050 
0051 /*
0052  * This may need locking to deal with situations where an interrupt
0053  * happens while we are in here and mb() gets called by the interrupt handler.
0054  *
0055  * The vendor code did have a spin lock but it doesn't seem to be needed and
0056  * removing it hasn't caused any side effects so far.
0057  *
0058  * [writel|readl]_relaxed have to be used here because otherwise
0059  * we'd end up right back in here.
0060  */
0061 static void mstarv7_mb(void)
0062 {
0063     /* toggle the flush miu pipe fire bit */
0064     writel_relaxed(0, l3bridge + MSTARV7_L3BRIDGE_FLUSH);
0065     writel_relaxed(MSTARV7_L3BRIDGE_FLUSH_TRIGGER, l3bridge
0066             + MSTARV7_L3BRIDGE_FLUSH);
0067     while (!(readl_relaxed(l3bridge + MSTARV7_L3BRIDGE_STATUS)
0068             & MSTARV7_L3BRIDGE_STATUS_DONE)) {
0069         /* wait for flush to complete */
0070     }
0071 }
0072 
0073 #ifdef CONFIG_SMP
0074 static int mstarv7_boot_secondary(unsigned int cpu, struct task_struct *idle)
0075 {
0076     struct device_node *np;
0077     u32 bootaddr = (u32) __pa_symbol(secondary_startup_arm);
0078     void __iomem *smpctrl;
0079 
0080     /*
0081      * right now we don't know how to boot anything except
0082      * cpu 1.
0083      */
0084     if (cpu != 1)
0085         return -EINVAL;
0086 
0087     np = of_find_compatible_node(NULL, NULL, "mstar,smpctrl");
0088     smpctrl = of_iomap(np, 0);
0089 
0090     if (!smpctrl)
0091         return -ENODEV;
0092 
0093     /* set the boot address for the second cpu */
0094     writew(bootaddr & 0xffff, smpctrl + MSTARV7_CPU1_BOOT_ADDR_LOW);
0095     writew((bootaddr >> 16) & 0xffff, smpctrl + MSTARV7_CPU1_BOOT_ADDR_HIGH);
0096 
0097     /* unlock the second cpu */
0098     writew(MSTARV7_CPU1_UNLOCK_MAGIC, smpctrl + MSTARV7_CPU1_UNLOCK);
0099 
0100     /* and away we go...*/
0101     arch_send_wakeup_ipi_mask(cpumask_of(cpu));
0102 
0103     iounmap(smpctrl);
0104 
0105     return 0;
0106 }
0107 
0108 static const struct smp_operations __initdata mstarv7_smp_ops = {
0109     .smp_boot_secondary = mstarv7_boot_secondary,
0110 };
0111 #endif
0112 
0113 static void __init mstarv7_init(void)
0114 {
0115     struct device_node *np;
0116 
0117     np = of_find_compatible_node(NULL, NULL, "mstar,l3bridge");
0118     l3bridge = of_iomap(np, 0);
0119     if (l3bridge)
0120         soc_mb = mstarv7_mb;
0121     else
0122         pr_warn("Failed to install memory barrier, DMA will be broken!\n");
0123 }
0124 
0125 DT_MACHINE_START(MSTARV7_DT, "MStar/Sigmastar Armv7 (Device Tree)")
0126     .dt_compat  = mstarv7_board_dt_compat,
0127     .init_machine   = mstarv7_init,
0128     .smp        = smp_ops(mstarv7_smp_ops),
0129 MACHINE_END