boards which do not use the full malloc in SPL (which is
enabled with CONFIG_SYS_SPL_MALLOC_START).
+- CONFIG_SYS_NONCACHED_MEMORY:
+ Size of non-cached memory area. This area of memory will be
+ typically located right below the malloc() area and mapped
+ uncached in the MMU. This is useful for drivers that would
+ otherwise require a lot of explicit cache maintenance. For
+ some drivers it's also impossible to properly maintain the
+ cache. For example if the regions that need to be flushed
+ are not a multiple of the cache-line size, *and* padding
+ cannot be allocated between the regions to align them (i.e.
+ if the HW requires a contiguous array of regions, and the
+ size of each region is not cache-aligned), then a flush of
+ one region may result in overwriting data that hardware has
+ written to another region in the same cache-line. This can
+ happen for example in network drivers where descriptors for
+ buffers are typically smaller than the CPU cache-line (e.g.
+ 16 bytes vs. 32 or 64 bytes).
+
+ Non-cached memory is only supported on 32-bit ARM at present.
+
- CONFIG_SYS_BOOTM_LEN:
Normally compressed uImages are limited to an
uncompressed size of 8 MBytes. If this is not enough,
*/
void mmu_page_table_flush(unsigned long start, unsigned long stop);
+#ifdef CONFIG_SYS_NONCACHED_MEMORY
+void noncached_init(void);
+phys_addr_t noncached_alloc(size_t size, size_t align);
+#endif /* CONFIG_SYS_NONCACHED_MEMORY */
+
#endif /* __ASSEMBLY__ */
#define arch_align_stack(x) (x)
/* for now: just dummy functions to satisfy the linker */
#include <common.h>
+#include <malloc.h>
__weak void flush_cache(unsigned long start, unsigned long size)
{
{
puts("WARNING: Caches not enabled\n");
}
+
+#ifdef CONFIG_SYS_NONCACHED_MEMORY
+/*
+ * Reserve one MMU section worth of address space below the malloc() area that
+ * will be mapped uncached.
+ */
+static unsigned long noncached_start;
+static unsigned long noncached_end;
+static unsigned long noncached_next;
+
+void noncached_init(void)
+{
+ phys_addr_t start, end;
+ size_t size;
+
+ end = ALIGN(mem_malloc_start, MMU_SECTION_SIZE) - MMU_SECTION_SIZE;
+ size = ALIGN(CONFIG_SYS_NONCACHED_MEMORY, MMU_SECTION_SIZE);
+ start = end - size;
+
+ debug("mapping memory %pa-%pa non-cached\n", &start, &end);
+
+ noncached_start = start;
+ noncached_end = end;
+ noncached_next = start;
+
+#ifndef CONFIG_SYS_DCACHE_OFF
+ mmu_set_region_dcache_behaviour(noncached_start, size, DCACHE_OFF);
+#endif
+}
+
+phys_addr_t noncached_alloc(size_t size, size_t align)
+{
+ phys_addr_t next = ALIGN(noncached_next, align);
+
+ if (next >= noncached_end || (noncached_end - next) < size)
+ return 0;
+
+ debug("allocated %zu bytes of uncached memory @%pa\n", size, &next);
+ noncached_next = next + size;
+
+ return next;
+}
+#endif /* CONFIG_SYS_NONCACHED_MEMORY */
return 0;
}
+#ifdef CONFIG_SYS_NONCACHED_MEMORY
+static int initr_noncached(void)
+{
+ noncached_init();
+ return 0;
+}
+#endif
+
#ifdef CONFIG_DM
static int initr_dm(void)
{
#endif
initr_barrier,
initr_malloc,
+#ifdef CONFIG_SYS_NONCACHED_MEMORY
+ initr_noncached,
+#endif
bootstage_relocate,
#ifdef CONFIG_DM
initr_dm,