#include <stdio.h>
#include <stdlib.h>
#include <sys/neutrino.h>
#include <sys/syspage.h>
#include <sys/mman.h>
#include <sys/types.h>

#define SH4_MAX_LINES_PER	0x64
#define MIN(_a,_b)		((_a) < (_b) ? (_a) : (_b))

unsigned cache_control( paddr32_t base, unsigned num_lines, int flags,
                   struct cacheattr_entry *cache, volatile struct syspage_entry *sysp ) {
	register unsigned line_size = cache->line_size;
	register unsigned do_num_lines = MIN(num_lines, SH4_MAX_LINES_PER);
	register unsigned nlines;
	register paddr32_t addr;

#ifdef SMARTER_FLUSH
#define DCACHE_FLUSH_MULTI	3
#define SH4_DCACHE_ENTRY_OFF 5
#define SH4_DCACHE_ENTRY_ADDR(_n)	(SH4_DCACHE_ADDRESS_ARRAY | (((_n) << SH4_DCACHE_ENTRY_OFF) & 0x7fe0))

	if(num_lines > (DCACHE_FLUSH_MULTI*cache->num_lines)) {
		nlines = cache->num_lines;
		do {
			addr=SH4_DCACHE_ENTRY_ADDR(nlines-1);
			*(uint32_t*)addr |= 0x3; /* write down U+V bits to force flush */
		while (--nlines);
		
		return 0; /* indicate the whole cache is done to the kernel */
	}
#endif

	/* original call out code */
	if(flags & (MS_SYNC|MS_ASYNC)) {
		addr = base;
		nlines = do_num_lines;
		do {
			__asm__ __volatile__ (
				"ocbwb @%0;"
				: :"r"(addr)
			);
			addr+=line_size;
		} while(--nlines);
	}

	if (flags & MS_INVALIDATE) {
		addr = base;
		nlines = do_num_lines;
		do {
			__asm__ __volatile__(
				"ocbi @%0;"
				: :"r"(addr)
			);
			addr+=line_size;
		} while(--nlines);
	}

	return do_num_lines;

}

