[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen master] xen/arm: Add support for the Odroid-XU board.



commit 0bf8ddecb4df674a9df976f349c98691b2560721
Author:     Suriyan Ramasami <suriyan.r@xxxxxxxxx>
AuthorDate: Thu Sep 4 15:57:23 2014 -0700
Commit:     Ian Campbell <ian.campbell@xxxxxxxxxx>
CommitDate: Wed Sep 10 14:38:21 2014 +0100

    xen/arm: Add support for the Odroid-XU board.
    
    The Odroid-XU from hardkernel is an Exynos 5410 based board.
    
    This patch introduces a generic PLATFORM exynos5 which hopefully is
    applicable to the majority of  exynos5 based SoCs. It currently has
    only been tested on an exynos5410 based (OdroidXU) board and hence
    that is the only board listed.
    
    Previously only the Arndale board, based on an exynos5250 was
    supported. It was the only exynos based platform that was supported
    and it was called exynos5. It has now been renamed to exynos5250. The
    Arndale currently is a separate platform mostly cause I do not have
    one to test and for the most part the code path for that board is
    preserved. To be specific it varies from the generic implementation
    as follows:
    
    1. exynos5250 based specific DT mapping for CHIPID and PWM region. I
       believe mainline kernel's DTS for the arndale has those mappings
       already in place.
    2. exynos5250 based cpu up code. It appears that exynos5250 already
       has the secondary core powered up and in wfe and hence a
       cpu_up_send_sgi suffices. Here too, I believe that the generic
       code path might be acceptable.
    
    Most of the code for the cpu bring up has been ported over from
    mainline linux, and hence should be generic enough for future exynos
    based SoCs. All reference to hardcoded memory locations have been
    avoided. They are now gleaned from the device tree.
    
    The existing SMP bringup code has been broken since 4557c2292854
    "xen: arm: rewrite start of day page table and cpu bring up" which
    moved the arndale CPU kick from secure world to non-secure world
    without updating it to match the new environment.  Specifically the
    sysram address remained hardcoded to the S sysram address and not the
    NS sysram address, this is now correctly taken from DT. Secondly the
    offset within the sysram where the start address is written is 0x1c
    for NS bringup, rather than 0x0 as it is in S bringup.
    
    Signed-off-by: Suriyan Ramasami <suriyan.r@xxxxxxxxx>
    Acked-by: Ian Campbell <ian.campbell@xxxxxxxxxx>
    [ ijc -- updated commit log as discussed on list, plus reformatted
             slightly.
             s/exynos5XXXX/exynos5XXX/ in one error message ]
---
 xen/arch/arm/platforms/exynos5.c        |  197 +++++++++++++++++++++++++++++--
 xen/include/asm-arm/platforms/exynos5.h |    3 -
 2 files changed, 184 insertions(+), 16 deletions(-)

diff --git a/xen/arch/arm/platforms/exynos5.c b/xen/arch/arm/platforms/exynos5.c
index b65c2c2..bc9ae15 100644
--- a/xen/arch/arm/platforms/exynos5.c
+++ b/xen/arch/arm/platforms/exynos5.c
@@ -23,18 +23,45 @@
 #include <xen/domain_page.h>
 #include <xen/mm.h>
 #include <xen/vmap.h>
+#include <xen/delay.h>
 #include <asm/platforms/exynos5.h>
 #include <asm/platform.h>
 #include <asm/io.h>
 
+#define EXYNOS_ARM_CORE0_CONFIG     0x2000
+#define EXYNOS_ARM_CORE_CONFIG(_nr) (0x80 * (_nr))
+#define EXYNOS_ARM_CORE_STATUS(_nr) (EXYNOS_ARM_CORE_CONFIG(_nr) + 0x4)
+#define S5P_CORE_LOCAL_PWR_EN       0x3
+
 static int exynos5_init_time(void)
 {
     uint32_t reg;
     void __iomem *mct;
+    int rc;
+    struct dt_device_node *node;
+    u64 mct_base_addr;
+    u64 size;
 
     BUILD_BUG_ON(EXYNOS5_MCT_G_TCON >= PAGE_SIZE);
 
-    mct = ioremap_attr(EXYNOS5_MCT_BASE, PAGE_SIZE, PAGE_HYPERVISOR_NOCACHE);
+    node = dt_find_compatible_node(NULL, NULL, "samsung,exynos4210-mct");
+    if ( !node )
+    {
+        dprintk(XENLOG_ERR, "samsung,exynos4210-mct missing in DT\n");
+        return -ENXIO;
+    }
+
+    rc = dt_device_get_address(node, 0, &mct_base_addr, &size);
+    if ( rc )
+    {
+        dprintk(XENLOG_ERR, "Error in \"samsung,exynos4210-mct\"\n");
+        return -ENXIO;
+    }
+
+    dprintk(XENLOG_INFO, "mct_base_addr: %016llx size: %016llx\n",
+            mct_base_addr, size);
+
+    mct = ioremap_attr(mct_base_addr, PAGE_SIZE, PAGE_HYPERVISOR_NOCACHE);
     if ( !mct )
     {
         dprintk(XENLOG_ERR, "Unable to map MCT\n");
@@ -51,7 +78,7 @@ static int exynos5_init_time(void)
 }
 
 /* Additional mappings for dom0 (Not in the DTS) */
-static int exynos5_specific_mapping(struct domain *d)
+static int exynos5250_specific_mapping(struct domain *d)
 {
     /* Map the chip ID */
     map_mmio_regions(d, paddr_to_pfn(EXYNOS5_PA_CHIPID), 1,
@@ -67,8 +94,29 @@ static int exynos5_specific_mapping(struct domain *d)
 static int __init exynos5_smp_init(void)
 {
     void __iomem *sysram;
+    struct dt_device_node *node;
+    u64 sysram_ns_base_addr;
+    u64 size;
+    int rc;
+
+    node = dt_find_compatible_node(NULL, NULL, "samsung,exynos4210-sysram-ns");
+    if ( !node )
+    {
+        dprintk(XENLOG_ERR, "samsung,exynos4210-sysram-ns missing in DT\n");
+        return -ENXIO;
+    }
 
-    sysram = ioremap_nocache(S5P_PA_SYSRAM, PAGE_SIZE);
+    rc = dt_device_get_address(node, 0, &sysram_ns_base_addr, &size);
+    if ( rc )
+    {
+        dprintk(XENLOG_ERR, "Error in \"samsung,exynos4210-sysram-ns\"\n");
+        return -ENXIO;
+    }
+
+    dprintk(XENLOG_INFO, "sysram_ns_base_addr: %016llx size: %016llx\n",
+            sysram_ns_base_addr, size);
+
+    sysram = ioremap_nocache(sysram_ns_base_addr, PAGE_SIZE);
     if ( !sysram )
     {
         dprintk(XENLOG_ERR, "Unable to map exynos5 MMIO\n");
@@ -77,20 +125,127 @@ static int __init exynos5_smp_init(void)
 
     printk("Set SYSRAM to %"PRIpaddr" (%p)\n",
            __pa(init_secondary), init_secondary);
-    writel(__pa(init_secondary), sysram);
+    writel(__pa(init_secondary), sysram + 0x1c);
 
     iounmap(sysram);
 
     return 0;
 }
 
+static int exynos_cpu_power_state(void __iomem *power, int cpu)
+{
+    return __raw_readl(power + EXYNOS_ARM_CORE_STATUS(cpu)) &
+                       S5P_CORE_LOCAL_PWR_EN;
+}
+
+static void exynos_cpu_power_up(void __iomem *power, int cpu)
+{
+    __raw_writel(S5P_CORE_LOCAL_PWR_EN,
+                 power + EXYNOS_ARM_CORE_CONFIG(cpu));
+}
+
+static int exynos5_cpu_power_up(void __iomem *power, int cpu)
+{
+    unsigned int timeout;
+
+    if ( !exynos_cpu_power_state(power, cpu) )
+    {
+        exynos_cpu_power_up(power, cpu);
+        timeout = 10;
+
+        /* wait max 10 ms until cpu is on */
+        while ( exynos_cpu_power_state(power, cpu) != S5P_CORE_LOCAL_PWR_EN )
+        {
+            if ( timeout-- == 0 )
+                break;
+
+            mdelay(1);
+        }
+
+        if ( timeout == 0 )
+        {
+            dprintk(XENLOG_ERR, "CPU%d power enable failed", cpu);
+            return -ETIMEDOUT;
+        }
+    }
+    return 0;
+}
+
+static int exynos5_get_pmu_base_addr(u64 *power_base_addr) {
+    u64 size;
+    struct dt_device_node *node;
+    int rc;
+    static const struct dt_device_match exynos_dt_pmu_matches[] __initconst =
+    {
+        DT_MATCH_COMPATIBLE("samsung,exynos5250-pmu"),
+        DT_MATCH_COMPATIBLE("samsung,exynos5410-pmu"),
+        DT_MATCH_COMPATIBLE("samsung,exynos5420-pmu"),
+        { /*sentinel*/ },
+    };
+
+    node = dt_find_matching_node(NULL, exynos_dt_pmu_matches);
+    if ( !node )
+    {
+        dprintk(XENLOG_ERR, "samsung,exynos5XXX-pmu missing in DT\n");
+        return -ENXIO;
+    }
+
+    rc = dt_device_get_address(node, 0, power_base_addr, &size);
+    if ( rc )
+    {
+        dprintk(XENLOG_ERR, "Error in \"samsung,exynos5XXX-pmu\"\n");
+        return -ENXIO;
+    }
+
+    dprintk(XENLOG_DEBUG, "power_base_addr: %016llx size: %016llx\n",
+            *power_base_addr, size);
+
+    return 0;
+}
+
+static int exynos5_cpu_up(int cpu)
+{
+    u64 power_base_addr;
+    void __iomem *power;
+    int rc;
+
+    rc = exynos5_get_pmu_base_addr(&power_base_addr);
+    if ( rc )
+        return rc;
+
+    power = ioremap_nocache(power_base_addr +
+                            EXYNOS_ARM_CORE0_CONFIG, PAGE_SIZE);
+    if ( !power )
+    {
+        dprintk(XENLOG_ERR, "Unable to map power MMIO\n");
+        return -EFAULT;
+    }
+
+    rc = exynos5_cpu_power_up(power, cpu);
+    if ( rc )
+    {
+        iounmap(power);
+        return -ETIMEDOUT;
+    }
+
+    iounmap(power);
+
+    return cpu_up_send_sgi(cpu);
+}
+
 static void exynos5_reset(void)
 {
+    u64 power_base_addr;
     void __iomem *pmu;
+    int rc;
 
     BUILD_BUG_ON(EXYNOS5_SWRESET >= PAGE_SIZE);
 
-    pmu = ioremap_nocache(EXYNOS5_PA_PMU, PAGE_SIZE);
+    rc = exynos5_get_pmu_base_addr(&power_base_addr);
+    if ( rc )
+        return;
+
+    pmu = ioremap_nocache(power_base_addr, PAGE_SIZE);
     if ( !pmu )
     {
         dprintk(XENLOG_ERR, "Unable to map PMU\n");
@@ -98,15 +253,10 @@ static void exynos5_reset(void)
     }
 
     writel(1, pmu + EXYNOS5_SWRESET);
+
     iounmap(pmu);
 }
 
-static const char * const exynos5_dt_compat[] __initconst =
-{
-    "samsung,exynos5250",
-    NULL
-};
-
 static const struct dt_device_match exynos5_blacklist_dev[] __initconst =
 {
     /* Multi core Timer
@@ -117,12 +267,33 @@ static const struct dt_device_match 
exynos5_blacklist_dev[] __initconst =
     { /* sentinel */ },
 };
 
+static const char * const exynos5250_dt_compat[] __initconst =
+{
+    "samsung,exynos5250",
+    NULL
+};
+
+static const char * const exynos5_dt_compat[] __initconst =
+{
+    "samsung,exynos5410",
+    NULL
+};
+
+PLATFORM_START(exynos5250, "SAMSUNG EXYNOS5250")
+    .compatible = exynos5250_dt_compat,
+    .init_time = exynos5_init_time,
+    .specific_mapping = exynos5250_specific_mapping,
+    .smp_init = exynos5_smp_init,
+    .cpu_up = cpu_up_send_sgi,
+    .reset = exynos5_reset,
+    .blacklist_dev = exynos5_blacklist_dev,
+PLATFORM_END
+
 PLATFORM_START(exynos5, "SAMSUNG EXYNOS5")
     .compatible = exynos5_dt_compat,
     .init_time = exynos5_init_time,
-    .specific_mapping = exynos5_specific_mapping,
     .smp_init = exynos5_smp_init,
-    .cpu_up = cpu_up_send_sgi,
+    .cpu_up = exynos5_cpu_up,
     .reset = exynos5_reset,
     .blacklist_dev = exynos5_blacklist_dev,
 PLATFORM_END
diff --git a/xen/include/asm-arm/platforms/exynos5.h 
b/xen/include/asm-arm/platforms/exynos5.h
index ea941e7..c88455a 100644
--- a/xen/include/asm-arm/platforms/exynos5.h
+++ b/xen/include/asm-arm/platforms/exynos5.h
@@ -1,7 +1,6 @@
 #ifndef __ASM_ARM_PLATFORMS_EXYNOS5_H
 #define __ASM_ARM_PLATFORMS_EXYNOS5_H
 
-#define EXYNOS5_MCT_BASE            0x101c0000
 #define EXYNOS5_MCT_G_TCON          0x240       /* Relative to MCT_BASE */
 #define EXYNOS5_MCT_G_TCON_START    (1 << 8)
 
@@ -12,8 +11,6 @@
 
 #define EXYNOS5_SWRESET             0x0400      /* Relative to PA_PMU */
 
-#define S5P_PA_SYSRAM   0x02020000
-
 #endif /* __ASM_ARM_PLATFORMS_EXYNOS5_H */
 /*
  * Local variables:
--
generated by git-patchbot for /home/xen/git/xen.git#master

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.