/* | |
* (C) Copyright 2007 | |
* Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com> | |
* | |
* (C) Copyright 2007 | |
* Nobobuhiro Iwamatsu <iwamatsu@nigauri.org> | |
* | |
* SPDX-License-Identifier: GPL-2.0+ | |
*/ | |
#include <common.h> | |
#include <command.h> | |
#include <asm/processor.h> | |
#include <asm/io.h> | |
/* | |
* Jump to P2 area. | |
* When handling TLB or caches, we need to do it from P2 area. | |
*/ | |
#define jump_to_P2() \ | |
do { \ | |
unsigned long __dummy; \ | |
__asm__ __volatile__( \ | |
"mov.l 1f, %0\n\t" \ | |
"or %1, %0\n\t" \ | |
"jmp @%0\n\t" \ | |
" nop\n\t" \ | |
".balign 4\n" \ | |
"1: .long 2f\n" \ | |
"2:" \ | |
: "=&r" (__dummy) \ | |
: "r" (0x20000000)); \ | |
} while (0) | |
/* | |
* Back to P1 area. | |
*/ | |
#define back_to_P1() \ | |
do { \ | |
unsigned long __dummy; \ | |
__asm__ __volatile__( \ | |
"nop;nop;nop;nop;nop;nop;nop\n\t" \ | |
"mov.l 1f, %0\n\t" \ | |
"jmp @%0\n\t" \ | |
" nop\n\t" \ | |
".balign 4\n" \ | |
"1: .long 2f\n" \ | |
"2:" \ | |
: "=&r" (__dummy)); \ | |
} while (0) | |
#define CACHE_VALID 1 | |
#define CACHE_UPDATED 2 | |
static inline void cache_wback_all(void) | |
{ | |
unsigned long addr, data, i, j; | |
jump_to_P2(); | |
for (i = 0; i < CACHE_OC_NUM_ENTRIES; i++) { | |
for (j = 0; j < CACHE_OC_NUM_WAYS; j++) { | |
addr = CACHE_OC_ADDRESS_ARRAY | |
| (j << CACHE_OC_WAY_SHIFT) | |
| (i << CACHE_OC_ENTRY_SHIFT); | |
data = inl(addr); | |
if (data & CACHE_UPDATED) { | |
data &= ~CACHE_UPDATED; | |
outl(data, addr); | |
} | |
} | |
} | |
back_to_P1(); | |
} | |
#define CACHE_ENABLE 0 | |
#define CACHE_DISABLE 1 | |
int cache_control(unsigned int cmd) | |
{ | |
unsigned long ccr; | |
jump_to_P2(); | |
ccr = inl(CCR); | |
if (ccr & CCR_CACHE_ENABLE) | |
cache_wback_all(); | |
if (cmd == CACHE_DISABLE) | |
outl(CCR_CACHE_STOP, CCR); | |
else | |
outl(CCR_CACHE_INIT, CCR); | |
back_to_P1(); | |
return 0; | |
} |