OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [arch/] [sh/] [mm/] [cache-sh3.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/* $Id: cache-sh3.c,v 1.1.1.1 2004-04-15 01:17:16 phoenix Exp $
2
 *
3
 *  linux/arch/sh/mm/cache-sh3.c
4
 *
5
 * Copyright (C) 1999, 2000  Niibe Yutaka
6
 *
7
 */
8
 
9
#include <linux/init.h>
10
#include <linux/mman.h>
11
#include <linux/mm.h>
12
#include <linux/threads.h>
13
#include <asm/addrspace.h>
14
#include <asm/page.h>
15
#include <asm/pgtable.h>
16
#include <asm/processor.h>
17
#include <asm/cache.h>
18
#include <asm/io.h>
19
#include <asm/uaccess.h>
20
#include <asm/pgalloc.h>
21
#include <asm/mmu_context.h>
22
 
23
 
24
#define CCR             0xffffffec      /* Address of Cache Control Register */
25
 
26
#define CCR_CACHE_CE    0x01    /* Cache Enable */
27
#define CCR_CACHE_WT    0x02    /* Write-Through (for P0,U0,P3) (else writeback) */
28
#define CCR_CACHE_CB    0x04    /* Write-Back (for P1) (else writethrough) */
29
#define CCR_CACHE_CF    0x08    /* Cache Flush */
30
#define CCR_CACHE_RA    0x20    /* RAM mode */
31
 
32
#define CCR_CACHE_VAL   (CCR_CACHE_CB|CCR_CACHE_CE)     /* 8k-byte cache, P1-wb, enable */
33
#define CCR_CACHE_INIT  (CCR_CACHE_CF|CCR_CACHE_VAL)    /* 8k-byte cache, CF, P1-wb, enable */
34
 
35
#define CACHE_OC_ADDRESS_ARRAY 0xf0000000
36
#define CACHE_VALID       1
37
#define CACHE_UPDATED     2
38
#define CACHE_PHYSADDR_MASK 0x1ffffc00
39
 
40
/* 7709A/7729 has 16K cache (256-entry), while 7702 has only 2K(direct)
41
   7702 is not supported (yet) */
42
struct _cache_system_info {
43
        int way_shift;
44
        int entry_mask;
45
        int num_entries;
46
};
47
 
48
/* Data at BSS is cleared after setting this variable.
49
   So, we Should not placed this variable at BSS section.
50
   Initialize this, it is placed at data section. */
51
static struct _cache_system_info cache_system_info = {0,};
52
 
53
#define CACHE_OC_WAY_SHIFT      (cache_system_info.way_shift)
54
#define CACHE_OC_ENTRY_SHIFT    4
55
#define CACHE_OC_ENTRY_MASK     (cache_system_info.entry_mask)
56
#define CACHE_OC_NUM_ENTRIES    (cache_system_info.num_entries)
57
#define CACHE_OC_NUM_WAYS       4
58
#define CACHE_OC_ASSOC_BIT    (1<<3)
59
 
60
 
61
/*
62
 * Write back all the cache.
63
 *
64
 * For SH-4, we only need to flush (write back) Operand Cache,
65
 * as Instruction Cache doesn't have "updated" data.
66
 *
67
 * Assumes that this is called in interrupt disabled context, and P2.
68
 * Shuld be INLINE function.
69
 */
70
static inline void cache_wback_all(void)
71
{
72
        unsigned long addr, data, i, j;
73
 
74
        for (i=0; i<CACHE_OC_NUM_ENTRIES; i++) {
75
                for (j=0; j<CACHE_OC_NUM_WAYS; j++) {
76
                        addr = CACHE_OC_ADDRESS_ARRAY|(j<<CACHE_OC_WAY_SHIFT)|
77
                                (i<<CACHE_OC_ENTRY_SHIFT);
78
                        data = ctrl_inl(addr);
79
                        if ((data & (CACHE_UPDATED|CACHE_VALID))
80
                            == (CACHE_UPDATED|CACHE_VALID))
81
                                ctrl_outl(data & ~CACHE_UPDATED, addr);
82
                }
83
        }
84
}
85
 
86
static void __init
87
detect_cpu_and_cache_system(void)
88
{
89
        unsigned long addr0, addr1, data0, data1, data2, data3;
90
 
91
        jump_to_P2();
92
        /*
93
         * Check if the entry shadows or not.
94
         * When shadowed, it's 128-entry system.
95
         * Otherwise, it's 256-entry system.
96
         */
97
        addr0 = CACHE_OC_ADDRESS_ARRAY + (3 << 12);
98
        addr1 = CACHE_OC_ADDRESS_ARRAY + (1 << 12);
99
 
100
        /* First, write back & invalidate */
101
        data0  = ctrl_inl(addr0);
102
        ctrl_outl(data0&~(CACHE_VALID|CACHE_UPDATED), addr0);
103
        data1  = ctrl_inl(addr1);
104
        ctrl_outl(data1&~(CACHE_VALID|CACHE_UPDATED), addr1);
105
 
106
        /* Next, check if there's shadow or not */
107
        data0 = ctrl_inl(addr0);
108
        data0 ^= CACHE_VALID;
109
        ctrl_outl(data0, addr0);
110
        data1 = ctrl_inl(addr1);
111
        data2 = data1 ^ CACHE_VALID;
112
        ctrl_outl(data2, addr1);
113
        data3 = ctrl_inl(addr0);
114
 
115
        /* Lastly, invaliate them. */
116
        ctrl_outl(data0&~CACHE_VALID, addr0);
117
        ctrl_outl(data2&~CACHE_VALID, addr1);
118
        back_to_P1();
119
 
120
        if (data0 == data1 && data2 == data3) { /* Shadow */
121
                cache_system_info.way_shift = 11;
122
                cache_system_info.entry_mask = 0x7f0;
123
                cache_system_info.num_entries = 128;
124
                cpu_data->type = CPU_SH7708;
125
        } else {                                /* 7709A or 7729  */
126
                cache_system_info.way_shift = 12;
127
                cache_system_info.entry_mask = 0xff0;
128
                cache_system_info.num_entries = 256;
129
                cpu_data->type = CPU_SH7729;
130
        }
131
}
132
 
133
void __init cache_init(void)
134
{
135
        unsigned long ccr;
136
 
137
        detect_cpu_and_cache_system();
138
 
139
        jump_to_P2();
140
        ccr = ctrl_inl(CCR);
141
        if (ccr & CCR_CACHE_CE)
142
                /*
143
                 * XXX: Should check RA here.
144
                 * If RA was 1, we only need to flush the half of the caches.
145
                 */
146
                cache_wback_all();
147
 
148
        ctrl_outl(CCR_CACHE_INIT, CCR);
149
        back_to_P1();
150
}
151
 
152
/*
153
 * Write back the dirty D-caches, but not invalidate them.
154
 *
155
 * Is this really worth it, or should we just alias this routine
156
 * to __flush_purge_region too?
157
 *
158
 * START: Virtual Address (U0, P1, or P3)
159
 * SIZE: Size of the region.
160
 */
161
 
162
void __flush_wback_region(void *start, int size)
163
{
164
        unsigned long v, j;
165
        unsigned long begin, end;
166
        unsigned long flags;
167
 
168
        begin = (unsigned long)start & ~(L1_CACHE_BYTES-1);
169
        end = ((unsigned long)start + size + L1_CACHE_BYTES-1)
170
                & ~(L1_CACHE_BYTES-1);
171
 
172
        for (v = begin; v < end; v+=L1_CACHE_BYTES) {
173
                for (j=0; j<CACHE_OC_NUM_WAYS; j++) {
174
                        unsigned long data, addr, p;
175
 
176
                        p = __pa(v);
177
                        addr = CACHE_OC_ADDRESS_ARRAY|(j<<CACHE_OC_WAY_SHIFT)|
178
                                (v&CACHE_OC_ENTRY_MASK);
179
                        save_and_cli(flags);
180
                        data = ctrl_inl(addr);
181
 
182
                        if ((data & CACHE_PHYSADDR_MASK) ==
183
                            (p & CACHE_PHYSADDR_MASK)) {
184
                                data &= ~CACHE_UPDATED;
185
                                ctrl_outl(data, addr);
186
                                restore_flags(flags);
187
                                break;
188
                        }
189
                        restore_flags(flags);
190
                }
191
        }
192
}
193
 
194
/*
195
 * Write back the dirty D-caches and invalidate them.
196
 *
197
 * START: Virtual Address (U0, P1, or P3)
198
 * SIZE: Size of the region.
199
 */
200
void __flush_purge_region(void *start, int size)
201
{
202
        unsigned long v;
203
        unsigned long begin, end;
204
 
205
        begin = (unsigned long)start & ~(L1_CACHE_BYTES-1);
206
        end = ((unsigned long)start + size + L1_CACHE_BYTES-1)
207
                & ~(L1_CACHE_BYTES-1);
208
 
209
        for (v = begin; v < end; v+=L1_CACHE_BYTES) {
210
                unsigned long data, addr;
211
 
212
                data = (v & 0xfffffc00); /* _Virtual_ address, ~U, ~V */
213
                addr = CACHE_OC_ADDRESS_ARRAY | (v&CACHE_OC_ENTRY_MASK) |
214
                        CACHE_OC_ASSOC_BIT;
215
                ctrl_outl(data, addr);
216
        }
217
}
218
 
219
/*
220
 * No write back please
221
 *
222
 * Except I don't think there's any way to avoid the writeback. So we
223
 * just alias it to __flush_purge_region(). dwmw2.
224
 */
225
void __flush_invalidate_region(void *start, int size)
226
        __attribute__((alias("__flush_purge_region")));

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.