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 #include <asm/gic.h>
26
27 #define DCC_SHIFT 26
28 #define FUNCTION_SHIFT 20
29 #define SITE_SHIFT 16
30 #define POSITION_SHIFT 12
31 #define DEVICE_SHIFT 0
32
vexpress_ctrl_start(uint32_t * syscfg,int write,int function,int device)33 static inline int vexpress_ctrl_start(uint32_t *syscfg, int write,
34 int function, int device)
35 {
36 int dcc = 0; /* DCC to access */
37 int site = 0; /* motherboard */
38 int position = 0; /* daughterboard */
39 uint32_t stat;
40
41 /* set control register */
42 syscfg[V2M_SYS_CFGCTRL/4] = V2M_SYS_CFG_START |
43 (write ? V2M_SYS_CFG_WRITE : 0) |
44 (dcc << DCC_SHIFT) | (function << FUNCTION_SHIFT) |
45 (site << SITE_SHIFT) | (position << POSITION_SHIFT) |
46 (device << DEVICE_SHIFT);
47
48 /* wait for complete flag to be set */
49 do {
50 stat = syscfg[V2M_SYS_CFGSTAT/4];
51 dsb(sy);
52 } while ( !(stat & V2M_SYS_CFG_COMPLETE) );
53
54 /* check error status and return error flag if set */
55 if ( stat & V2M_SYS_CFG_ERROR )
56 {
57 printk(KERN_ERR "V2M SYS_CFGSTAT reported a configuration error\n");
58 return -1;
59 }
60 return 0;
61 }
62
vexpress_syscfg(int write,int function,int device,uint32_t * data)63 int vexpress_syscfg(int write, int function, int device, uint32_t *data)
64 {
65 uint32_t *syscfg = (uint32_t *) FIXMAP_ADDR(FIXMAP_MISC);
66 int ret = -1;
67
68 set_fixmap(FIXMAP_MISC, maddr_to_mfn(V2M_SYS_MMIO_BASE),
69 PAGE_HYPERVISOR_NOCACHE);
70
71 if ( syscfg[V2M_SYS_CFGCTRL/4] & V2M_SYS_CFG_START )
72 goto out;
73
74 /* clear the complete bit in the V2M_SYS_CFGSTAT status register */
75 syscfg[V2M_SYS_CFGSTAT/4] = 0;
76
77 if ( write )
78 {
79 /* write data */
80 syscfg[V2M_SYS_CFGDATA/4] = *data;
81
82 if ( vexpress_ctrl_start(syscfg, write, function, device) < 0 )
83 goto out;
84 } else {
85 if ( vexpress_ctrl_start(syscfg, write, function, device) < 0 )
86 goto out;
87 else
88 /* read data */
89 *data = syscfg[V2M_SYS_CFGDATA/4];
90 }
91
92 ret = 0;
93 out:
94 clear_fixmap(FIXMAP_MISC);
95 return ret;
96 }
97
98 /*
99 * TODO: Get base address from the device tree
100 * See arm,vexpress-reset node
101 */
vexpress_reset(void)102 static void vexpress_reset(void)
103 {
104 void __iomem *sp810;
105
106 /* Use the SP810 system controller to force a reset */
107 sp810 = ioremap_nocache(SP810_ADDRESS, PAGE_SIZE);
108
109 if ( !sp810 )
110 {
111 dprintk(XENLOG_ERR, "Unable to map SP810\n");
112 return;
113 }
114
115 /* switch to slow mode */
116 writel(0x3, sp810);
117 dsb(sy); isb();
118 /* writing any value to SCSYSSTAT reg will reset the system */
119 writel(0x1, sp810 + 4);
120 dsb(sy); isb();
121
122 iounmap(sp810);
123 }
124
125 #ifdef CONFIG_ARM_32
126
vexpress_smp_init(void)127 static int __init vexpress_smp_init(void)
128 {
129 void __iomem *sysflags;
130
131 sysflags = ioremap_nocache(V2M_SYS_MMIO_BASE, PAGE_SIZE);
132 if ( !sysflags )
133 {
134 dprintk(XENLOG_ERR, "Unable to map vexpress MMIO\n");
135 return -EFAULT;
136 }
137
138 printk("Set SYS_FLAGS to %"PRIpaddr" (%p)\n",
139 __pa(init_secondary), init_secondary);
140 writel(~0, sysflags + V2M_SYS_FLAGSCLR);
141 writel(__pa(init_secondary), sysflags + V2M_SYS_FLAGSSET);
142
143 iounmap(sysflags);
144
145 return 0;
146 }
147
148 #endif
149
150 static const char * const vexpress_dt_compat[] __initconst =
151 {
152 "arm,vexpress",
153 NULL
154 };
155
156 static const struct dt_device_match vexpress_blacklist_dev[] __initconst =
157 {
158 /* Cache Coherent Interconnect */
159 DT_MATCH_COMPATIBLE("arm,cci-400"),
160 DT_MATCH_COMPATIBLE("arm,cci-400-pmu"),
161 /* Video device
162 * TODO: remove it once memreserve is handled properly by Xen
163 */
164 DT_MATCH_COMPATIBLE("arm,hdlcd"),
165 /* Hardware power management */
166 DT_MATCH_COMPATIBLE("arm,vexpress-reset"),
167 DT_MATCH_COMPATIBLE("arm,vexpress-reboot"),
168 DT_MATCH_COMPATIBLE("arm,vexpress-shutdown"),
169 { /* sentinel */ },
170 };
171
172 PLATFORM_START(vexpress, "VERSATILE EXPRESS")
173 .compatible = vexpress_dt_compat,
174 #ifdef CONFIG_ARM_32
175 .smp_init = vexpress_smp_init,
176 .cpu_up = cpu_up_send_sgi,
177 #endif
178 .reset = vexpress_reset,
179 .blacklist_dev = vexpress_blacklist_dev,
180 PLATFORM_END
181
182 /*
183 * Local variables:
184 * mode: C
185 * c-file-style: "BSD"
186 * c-basic-offset: 4
187 * indent-tabs-mode: nil
188 * End:
189 */
190