blob: e17075c0813fab926d0e721d3cc356d0f7386658 [file] [log] [blame]
Ionela Voinescu8fa8f4b2014-12-01 18:31:48 +00001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2014 Imagination Technologies
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
Ionela Voinescu8fa8f4b2014-12-01 18:31:48 +000014 */
15
16#include <arch/cache.h>
Ionela Voinescuef4e87b2015-02-18 13:32:28 +000017#include <arch/cpu.h>
Ionela Voinescudeaaab22015-01-21 01:51:25 +000018#include <console/console.h>
Ionela Voinescu1a1a8262015-05-20 17:03:23 +010019#include <program_loading.h>
Ionela Voinescuef4e87b2015-02-18 13:32:28 +000020#include <symbols.h>
Ionela Voinescu8fa8f4b2014-12-01 18:31:48 +000021
22/* cache_op: issues cache operation for specified address */
23#define cache_op(op, addr) \
24({ \
25 __asm__ __volatile__( \
26 ".set push\n\t" \
27 ".set noreorder\n\t" \
28 ".set mips32\n\t" \
29 "cache %0, %1\n\t" \
30 ".set mips0\n\t" \
31 ".set pop\n\t" \
32 : \
33 : "i" (op), "R" (*(unsigned char *)(addr))); \
34})
35
Ionela Voinescuef4e87b2015-02-18 13:32:28 +000036#define MIPS_CONFIG1_DL_SHIFT 10
37#define MIPS_CONFIG1_DL_MASK (0x00000007)
38#define MIPS_CONFIG1_IL_SHIFT 19
39#define MIPS_CONFIG1_IL_MASK (0x00000007)
40#define MIPS_CONFIG2_SL_SHIFT 4
41#define MIPS_CONFIG2_SL_MASK (0x0000000F)
42
43/*
44 * get_cache_line_size:
45 * Read config register
46 * Isolate instruction cache line size
47 * Interpret value as per MIPS manual: 2 << value
48 * Return cache line size
49 */
50static int get_cache_line_size(uint8_t type)
Ionela Voinescudeaaab22015-01-21 01:51:25 +000051{
52 switch (type) {
Ionela Voinescuef4e87b2015-02-18 13:32:28 +000053 case ICACHE:
54 return 2 << ((read_c0_config1() >> MIPS_CONFIG1_IL_SHIFT) &
55 MIPS_CONFIG1_IL_MASK);
56 case DCACHE:
57 return 2 << ((read_c0_config1() >> MIPS_CONFIG1_DL_SHIFT) &
58 MIPS_CONFIG1_DL_MASK);
59 case L2CACHE:
60 return 2 << ((read_c0_config2() >> MIPS_CONFIG2_SL_SHIFT) &
61 MIPS_CONFIG2_SL_MASK);
Ionela Voinescudeaaab22015-01-21 01:51:25 +000062 default:
63 printk(BIOS_ERR, "%s: Error: unsupported cache type.\n",
64 __func__);
65 return 0;
66 }
67 return 0;
68}
69
Ionela Voinescu8fa8f4b2014-12-01 18:31:48 +000070void perform_cache_operation(uintptr_t start, size_t size, uint8_t operation)
71{
72 u32 line_size, line_mask;
73 uintptr_t end;
74
Ionela Voinescuef4e87b2015-02-18 13:32:28 +000075 line_size = get_cache_line_size((operation >> CACHE_TYPE_SHIFT) &
Ionela Voinescudeaaab22015-01-21 01:51:25 +000076 CACHE_TYPE_MASK);
77 if (!line_size)
78 return;
Ionela Voinescu8fa8f4b2014-12-01 18:31:48 +000079 line_mask = ~(line_size-1);
80 end = (start + (line_size - 1) + size) & line_mask;
81 start &= line_mask;
82 if ((operation & L2CACHE) == L2CACHE)
Ionela Voinescuef4e87b2015-02-18 13:32:28 +000083 write_c0_l23taglo(0);
Ionela Voinescu8fa8f4b2014-12-01 18:31:48 +000084 while (start < end) {
85 switch (operation) {
86 case CACHE_CODE(ICACHE, WB_INVD):
87 cache_op(CACHE_CODE(ICACHE, WB_INVD), start);
88 break;
89 case CACHE_CODE(DCACHE, WB_INVD):
90 cache_op(CACHE_CODE(DCACHE, WB_INVD), start);
91 break;
92 case CACHE_CODE(L2CACHE, WB_INVD):
93 cache_op(CACHE_CODE(L2CACHE, WB_INVD), start);
94 break;
95 default:
96 return;
97 }
98 start += line_size;
99 }
100 asm("sync");
101}
102
103void cache_invalidate_all(uintptr_t start, size_t size)
104{
105 perform_cache_operation(start, size, CACHE_CODE(ICACHE, WB_INVD));
106 perform_cache_operation(start, size, CACHE_CODE(DCACHE, WB_INVD));
107 perform_cache_operation(start, size, CACHE_CODE(L2CACHE, WB_INVD));
Ionela Voinescu8fa8f4b2014-12-01 18:31:48 +0000108}
Ionela Voinescu1a1a8262015-05-20 17:03:23 +0100109
110void arch_segment_loaded(uintptr_t start, size_t size, int flags)
111{
112 cache_invalidate_all(start, size);
113 if (flags & SEG_FINAL)
114 cache_invalidate_all((uintptr_t)_cbfs_cache, _cbfs_cache_size);
115}