arch: arm: Add support to clean and invalidate cache at unaligned addresses.

Change-Id: I2006160a4486685525092b78b1cb138ffea1ec68
diff --git a/arch/arm/cache.c b/arch/arm/cache.c
index 0a403b5..b024d37 100644
--- a/arch/arm/cache.c
+++ b/arch/arm/cache.c
@@ -1,22 +1,43 @@
-/*
- * Copyright (c) 2008 Travis Geiselbrecht
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
  *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files
- * (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
  *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
- * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
- * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
+
+ #include <debug.h>
+ #include <arch/defines.h>
+ #include <stdlib.h>
+ #include <arch/ops.h>
+
+ void cache_clean_invalidate_unaligned_start_addr(addr_t start, size_t size)
+ {
+	addr_t actual_start;
+	size_t actual_size;
+
+	actual_start = GET_CAHE_LINE_START_ADDR(start);
+	actual_size = start - actual_start + size;
+
+	arch_clean_invalidate_cache_range(actual_start, actual_size);
+ }
diff --git a/arch/arm/include/arch/defines.h b/arch/arm/include/arch/defines.h
index d08988e..f1e5228 100644
--- a/arch/arm/include/arch/defines.h
+++ b/arch/arm/include/arch/defines.h
@@ -48,5 +48,6 @@
 #define dsb() __asm__ volatile ("mcr p15, 0, %0, c7, c10, 4" : : "r" (0): "memory");
 #endif
 
-#endif
+#define GET_CAHE_LINE_START_ADDR(addr) ROUNDDOWN(addr, CACHE_LINE)
 
+#endif
diff --git a/include/arch/ops.h b/include/arch/ops.h
index 26d0642..9f95e2b 100644
--- a/include/arch/ops.h
+++ b/include/arch/ops.h
@@ -53,6 +53,7 @@
 void arch_clean_invalidate_cache_range(addr_t start, size_t len);
 void arch_invalidate_cache_range(addr_t start, size_t len);
 void arch_sync_cache_range(addr_t start, size_t len);
+void cache_clean_invalidate_unaligned_start_addr(addr_t start, size_t size);
 	
 void arch_idle(void);