xref: /openbmc/linux/arch/arm/mach-mstar/mstarv7.c (revision 7af6fbdd)
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 static void __iomem *l3bridge;
35 
36 static const char * const mstarv7_board_dt_compat[] __initconst = {
37 	"mstar,infinity",
38 	"mstar,infinity3",
39 	"mstar,mercury5",
40 	NULL,
41 };
42 
43 /*
44  * This may need locking to deal with situations where an interrupt
45  * happens while we are in here and mb() gets called by the interrupt handler.
46  *
47  * The vendor code did have a spin lock but it doesn't seem to be needed and
48  * removing it hasn't caused any side effects so far.
49  *
50  * [writel|readl]_relaxed have to be used here because otherwise
51  * we'd end up right back in here.
52  */
53 static void mstarv7_mb(void)
54 {
55 	/* toggle the flush miu pipe fire bit */
56 	writel_relaxed(0, l3bridge + MSTARV7_L3BRIDGE_FLUSH);
57 	writel_relaxed(MSTARV7_L3BRIDGE_FLUSH_TRIGGER, l3bridge
58 			+ MSTARV7_L3BRIDGE_FLUSH);
59 	while (!(readl_relaxed(l3bridge + MSTARV7_L3BRIDGE_STATUS)
60 			& MSTARV7_L3BRIDGE_STATUS_DONE)) {
61 		/* wait for flush to complete */
62 	}
63 }
64 
65 static void __init mstarv7_init(void)
66 {
67 	struct device_node *np;
68 
69 	np = of_find_compatible_node(NULL, NULL, "mstar,l3bridge");
70 	l3bridge = of_iomap(np, 0);
71 	if (l3bridge)
72 		soc_mb = mstarv7_mb;
73 	else
74 		pr_warn("Failed to install memory barrier, DMA will be broken!\n");
75 }
76 
77 DT_MACHINE_START(MSTARV7_DT, "MStar/Sigmastar Armv7 (Device Tree)")
78 	.dt_compat	= mstarv7_board_dt_compat,
79 	.init_machine	= mstarv7_init,
80 MACHINE_END
81