1 /*
2  * xen/arch/arm/platform_vexpress.c
3  *
4  * Versatile Express specific settings
5  *
6  * Stefano Stabellini <stefano.stabellini@eu.citrix.com>
7  * Copyright (c) 2013 Citrix Systems.
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  */
19 
20 #include <asm/platforms/vexpress.h>
21 #include <asm/platform.h>
22 #include <xen/mm.h>
23 #include <xen/vmap.h>
24 #include <asm/io.h>
25 
26 #define DCC_SHIFT      26
27 #define FUNCTION_SHIFT 20
28 #define SITE_SHIFT     16
29 #define POSITION_SHIFT 12
30 #define DEVICE_SHIFT   0
31 
vexpress_ctrl_start(uint32_t * syscfg,int write,int function,int device)32 static inline int vexpress_ctrl_start(uint32_t *syscfg, int write,
33                                       int function, int device)
34 {
35     int dcc = 0; /* DCC to access */
36     int site = 0; /* motherboard */
37     int position = 0; /* daughterboard */
38     uint32_t stat;
39 
40     /* set control register */
41     syscfg[V2M_SYS_CFGCTRL/4] = V2M_SYS_CFG_START |
42         (write ? V2M_SYS_CFG_WRITE : 0) |
43         (dcc << DCC_SHIFT) | (function << FUNCTION_SHIFT) |
44         (site << SITE_SHIFT) | (position << POSITION_SHIFT) |
45         (device << DEVICE_SHIFT);
46 
47     /* wait for complete flag to be set */
48     do {
49         stat = syscfg[V2M_SYS_CFGSTAT/4];
50         dsb(sy);
51     } while ( !(stat & V2M_SYS_CFG_COMPLETE) );
52 
53     /* check error status and return error flag if set */
54     if ( stat & V2M_SYS_CFG_ERROR )
55     {
56         printk(KERN_ERR "V2M SYS_CFGSTAT reported a configuration error\n");
57         return -1;
58     }
59     return 0;
60 }
61 
62 /*
63  * TODO: Get base address from the device tree
64  * See arm,vexpress-reset node
65  */
vexpress_reset(void)66 static void vexpress_reset(void)
67 {
68     void __iomem *sp810;
69 
70     /* Use the SP810 system controller to force a reset */
71     sp810 = ioremap_nocache(SP810_ADDRESS, PAGE_SIZE);
72 
73     if ( !sp810 )
74     {
75         dprintk(XENLOG_ERR, "Unable to map SP810\n");
76         return;
77     }
78 
79     /* switch to slow mode */
80     writel(0x3, sp810);
81     dsb(sy); isb();
82     /* writing any value to SCSYSSTAT reg will reset the system */
83     writel(0x1, sp810 + 4);
84     dsb(sy); isb();
85 
86     iounmap(sp810);
87 }
88 
89 #ifdef CONFIG_ARM_32
90 
vexpress_smp_init(void)91 static int __init vexpress_smp_init(void)
92 {
93     void __iomem *sysflags;
94 
95     sysflags = ioremap_nocache(V2M_SYS_MMIO_BASE, PAGE_SIZE);
96     if ( !sysflags )
97     {
98         dprintk(XENLOG_ERR, "Unable to map vexpress MMIO\n");
99         return -EFAULT;
100     }
101 
102     printk("Set SYS_FLAGS to %"PRIpaddr" (%p)\n",
103            __pa(init_secondary), init_secondary);
104     writel(~0, sysflags + V2M_SYS_FLAGSCLR);
105     writel(__pa(init_secondary), sysflags + V2M_SYS_FLAGSSET);
106 
107     iounmap(sysflags);
108 
109     return 0;
110 }
111 
112 #endif
113 
114 static const char * const vexpress_dt_compat[] __initconst =
115 {
116     "arm,vexpress",
117     NULL
118 };
119 
120 static const struct dt_device_match vexpress_blacklist_dev[] __initconst =
121 {
122     /* Cache Coherent Interconnect */
123     DT_MATCH_COMPATIBLE("arm,cci-400"),
124     DT_MATCH_COMPATIBLE("arm,cci-400-pmu"),
125     /* Video device
126      * TODO: remove it once memreserve is handled properly by Xen
127      */
128     DT_MATCH_COMPATIBLE("arm,hdlcd"),
129     /* Hardware power management */
130     DT_MATCH_COMPATIBLE("arm,vexpress-reset"),
131     DT_MATCH_COMPATIBLE("arm,vexpress-reboot"),
132     DT_MATCH_COMPATIBLE("arm,vexpress-shutdown"),
133     { /* sentinel */ },
134 };
135 
136 PLATFORM_START(vexpress, "VERSATILE EXPRESS")
137     .compatible = vexpress_dt_compat,
138 #ifdef CONFIG_ARM_32
139     .smp_init = vexpress_smp_init,
140     .cpu_up = cpu_up_send_sgi,
141 #endif
142     .reset = vexpress_reset,
143     .blacklist_dev = vexpress_blacklist_dev,
144 PLATFORM_END
145 
146 /*
147  * Local variables:
148  * mode: C
149  * c-file-style: "BSD"
150  * c-basic-offset: 4
151  * indent-tabs-mode: nil
152  * End:
153  */
154