blob: defcf719f2e84eb5cae2b6be57fed58227eeb6ec [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * arch/sh/mm/cache-sh2.c
3 *
4 * Copyright (C) 2002 Paul Mundt
Yoshinori Satocce2d452008-08-04 16:33:47 +09005 * Copyright (C) 2008 Yoshinori Sato
Linus Torvalds1da177e2005-04-16 15:20:36 -07006 *
7 * Released under the terms of the GNU GPL v2.0.
8 */
Yoshinori Sato9d4436a2006-11-05 15:40:13 +09009
Linus Torvalds1da177e2005-04-16 15:20:36 -070010#include <linux/init.h>
11#include <linux/mm.h>
12
13#include <asm/cache.h>
14#include <asm/addrspace.h>
15#include <asm/processor.h>
16#include <asm/cacheflush.h>
17#include <asm/io.h>
18
Paul Mundt109b44a2009-08-15 12:35:15 +090019static void sh2__flush_wback_region(void *start, int size)
Linus Torvalds1da177e2005-04-16 15:20:36 -070020{
Yoshinori Sato9d4436a2006-11-05 15:40:13 +090021 unsigned long v;
22 unsigned long begin, end;
Linus Torvalds1da177e2005-04-16 15:20:36 -070023
Yoshinori Sato9d4436a2006-11-05 15:40:13 +090024 begin = (unsigned long)start & ~(L1_CACHE_BYTES-1);
25 end = ((unsigned long)start + size + L1_CACHE_BYTES-1)
26 & ~(L1_CACHE_BYTES-1);
27 for (v = begin; v < end; v+=L1_CACHE_BYTES) {
Yoshinori Satocce2d452008-08-04 16:33:47 +090028 unsigned long addr = CACHE_OC_ADDRESS_ARRAY | (v & 0x00000ff0);
29 int way;
30 for (way = 0; way < 4; way++) {
Paul Mundt9d56dd32010-01-26 12:58:40 +090031 unsigned long data = __raw_readl(addr | (way << 12));
Yoshinori Satocce2d452008-08-04 16:33:47 +090032 if ((data & CACHE_PHYSADDR_MASK) == (v & CACHE_PHYSADDR_MASK)) {
33 data &= ~SH_CACHE_UPDATED;
Paul Mundt9d56dd32010-01-26 12:58:40 +090034 __raw_writel(data, addr | (way << 12));
Yoshinori Satocce2d452008-08-04 16:33:47 +090035 }
36 }
Yoshinori Sato9d4436a2006-11-05 15:40:13 +090037 }
38}
Linus Torvalds1da177e2005-04-16 15:20:36 -070039
Paul Mundt109b44a2009-08-15 12:35:15 +090040static void sh2__flush_purge_region(void *start, int size)
Yoshinori Sato9d4436a2006-11-05 15:40:13 +090041{
42 unsigned long v;
43 unsigned long begin, end;
Linus Torvalds1da177e2005-04-16 15:20:36 -070044
Yoshinori Sato9d4436a2006-11-05 15:40:13 +090045 begin = (unsigned long)start & ~(L1_CACHE_BYTES-1);
46 end = ((unsigned long)start + size + L1_CACHE_BYTES-1)
47 & ~(L1_CACHE_BYTES-1);
Yoshinori Satocce2d452008-08-04 16:33:47 +090048
49 for (v = begin; v < end; v+=L1_CACHE_BYTES)
Paul Mundt9d56dd32010-01-26 12:58:40 +090050 __raw_writel((v & CACHE_PHYSADDR_MASK),
Yoshinori Satocce2d452008-08-04 16:33:47 +090051 CACHE_OC_ADDRESS_ARRAY | (v & 0x00000ff0) | 0x00000008);
Yoshinori Sato9d4436a2006-11-05 15:40:13 +090052}
Linus Torvalds1da177e2005-04-16 15:20:36 -070053
Paul Mundt109b44a2009-08-15 12:35:15 +090054static void sh2__flush_invalidate_region(void *start, int size)
Yoshinori Sato9d4436a2006-11-05 15:40:13 +090055{
Yoshinori Satocce2d452008-08-04 16:33:47 +090056#ifdef CONFIG_CACHE_WRITEBACK
57 /*
58 * SH-2 does not support individual line invalidation, only a
59 * global invalidate.
60 */
61 unsigned long ccr;
62 unsigned long flags;
63 local_irq_save(flags);
64 jump_to_uncached();
65
Paul Mundt9d56dd32010-01-26 12:58:40 +090066 ccr = __raw_readl(CCR);
Yoshinori Satocce2d452008-08-04 16:33:47 +090067 ccr |= CCR_CACHE_INVALIDATE;
Paul Mundt9d56dd32010-01-26 12:58:40 +090068 __raw_writel(ccr, CCR);
Yoshinori Satocce2d452008-08-04 16:33:47 +090069
70 back_to_cached();
71 local_irq_restore(flags);
72#else
Yoshinori Sato9d4436a2006-11-05 15:40:13 +090073 unsigned long v;
74 unsigned long begin, end;
75
76 begin = (unsigned long)start & ~(L1_CACHE_BYTES-1);
77 end = ((unsigned long)start + size + L1_CACHE_BYTES-1)
78 & ~(L1_CACHE_BYTES-1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070079
Yoshinori Satocce2d452008-08-04 16:33:47 +090080 for (v = begin; v < end; v+=L1_CACHE_BYTES)
Paul Mundt9d56dd32010-01-26 12:58:40 +090081 __raw_writel((v & CACHE_PHYSADDR_MASK),
Yoshinori Satocce2d452008-08-04 16:33:47 +090082 CACHE_OC_ADDRESS_ARRAY | (v & 0x00000ff0) | 0x00000008);
83#endif
84}
Paul Mundt109b44a2009-08-15 12:35:15 +090085
86void __init sh2_cache_init(void)
87{
88 __flush_wback_region = sh2__flush_wback_region;
89 __flush_purge_region = sh2__flush_purge_region;
90 __flush_invalidate_region = sh2__flush_invalidate_region;
91}