summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libcpu/bfin/cache/cache.c
blob: 4ac67545e2e7911ad27140fafe0e040bc00d35e6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
/*  Blackfin Cache Support
 *
 *  Copyright (c) 2008 Kallisti Labs, Los Gatos, CA, USA
 *             written by Allan Hessenflow <allanh@kallisti.com>
 *
 *  The license and distribution terms for this file may be
 *  found in the file LICENSE in this distribution or at
 *  http://www.rtems.com/license/LICENSE.
 */


#include <rtems.h>
#include <bsp.h>
#include <libcpu/memoryRegs.h>
#include "cache_.h"


/* There are many syncs in the following code because they should be
   harmless except for wasting time, and this is easier than figuring out
   exactly where they're needed to protect from the effects of write
   buffers and queued reads.  Many of them are likely unnecessary. */


void _CPU_cache_flush_1_data_line(const void *d_addr) {

  __asm__ __volatile__ ("ssync; flush [%0]; ssync" :: "a" (d_addr));
}

/* Blackfins can't just invalidate cache; they can only do flush +
   invalidate.  If the line isn't dirty then this is equivalent to
   just an invalidate.  Even if it is dirty, this should still be
   okay since with a pure invalidate method the caller would have no
   way to insure the dirty line hadn't been written out anyway prior
   to the invalidate. */
void _CPU_cache_invalidate_1_data_line(const void *d_addr) {

  __asm__ __volatile__ ("ssync; flushinv [%0]; ssync" :: "a" (d_addr));
}

void _CPU_cache_freeze_data(void) {
}

void _CPU_cache_unfreeze_data(void) {
}

void _CPU_cache_invalidate_1_instruction_line(const void *d_addr) {

  __asm__ __volatile__ ("ssync; iflush [%0]; ssync" :: "a" (d_addr));
}

void _CPU_cache_freeze_instruction(void) {
}

void _CPU_cache_unfreeze_instruction(void) {
}

/* incredibly inefficient...  It would be better to make use of the
   DTEST_COMMAND/DTEST_DATAx registers to find the addresses in each
   cache line and flush just those.  However the documentation I've
   seen on those is a bit sketchy, and I sure wouldn't want to get it
   wrong. */
void _CPU_cache_flush_entire_data(void) {
  uint32_t i;

  i = 0;
  __asm__ __volatile__ ("ssync");
  do {
      __asm__ __volatile__ ("flush [%0]" :: "a" (i));
      i += CPU_DATA_CACHE_ALIGNMENT;
  } while (i);
  __asm__ __volatile__ ("ssync");
}

void _CPU_cache_invalidate_entire_data(void) {
  uint32_t dmemControl;

  __asm__ __volatile__ ("ssync");
  dmemControl = *(uint32_t volatile *) DMEM_CONTROL;
  *(uint32_t volatile *) DMEM_CONTROL = dmemControl & ~DMEM_CONTROL_DMC_MASK;
  *(uint32_t volatile *) DMEM_CONTROL = dmemControl;
  __asm__ __volatile__ ("ssync");
}

/* this does not actually enable data cache unless CPLBs are also enabled.
   LIBCPU_DATA_CACHE_CONFIG contains the DMEM_CONTROL_DMC bits to set. */
void _CPU_cache_enable_data(void) {

  __asm__ __volatile__ ("ssync");
  *(uint32_t volatile *) DMEM_CONTROL |= LIBCPU_DATA_CACHE_CONFIG;
  __asm__ __volatile__ ("ssync");
}

void _CPU_cache_disable_data(void) {

  __asm__ __volatile__ ("ssync");
  *(uint32_t volatile *) DMEM_CONTROL &= ~DMEM_CONTROL_DMC_MASK;
  __asm__ __volatile__ ("ssync");
}

void _CPU_cache_invalidate_entire_instruction(void) {
  uint32_t imemControl;

  __asm__ __volatile__ ("ssync");
  imemControl = *(uint32_t volatile *) IMEM_CONTROL;
  *(uint32_t volatile *) IMEM_CONTROL = imemControl & ~IMEM_CONTROL_IMC;
  *(uint32_t volatile *) IMEM_CONTROL = imemControl;
  __asm__ __volatile__ ("ssync");
}

/* this only actually enables the instruction cache if the CPLBs are also
   enabled. */
void _CPU_cache_enable_instruction(void) {

  __asm__ __volatile__ ("ssync");
  *(uint32_t volatile *) IMEM_CONTROL |= IMEM_CONTROL_IMC;
  __asm__ __volatile__ ("ssync");
}

void _CPU_cache_disable_instruction(void) {

  __asm__ __volatile__ ("ssync");
  *(uint32_t volatile *) IMEM_CONTROL &= ~IMEM_CONTROL_IMC;
  __asm__ __volatile__ ("ssync");
}