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 41 static void __iomem *l3bridge; 42 43 static 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 */ 61 static 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 74 static 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 108 static const struct smp_operations __initdata mstarv7_smp_ops = { 109 .smp_boot_secondary = mstarv7_boot_secondary, 110 }; 111 #endif 112 113 static 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 125 DT_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), 129 MACHINE_END 130