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