Stefan Kristiansson | 272f84b | 2011-11-26 19:04:51 +0000 | [diff] [blame] | 1 | /* |
| 2 | * (C) Copyright 2011, Stefan Kristiansson <stefan.kristiansson@saunalahti.fi> |
| 3 | * (C) Copyright 2011, Julius Baxter <julius@opencores.org> |
| 4 | * |
| 5 | * See file CREDITS for list of people who contributed to this |
| 6 | * project. |
| 7 | * |
| 8 | * This program is free software; you can redistribute it and/or |
| 9 | * modify it under the terms of the GNU General Public License as |
| 10 | * published by the Free Software Foundation; either version 2 of |
| 11 | * the License, or (at your option) any later version. |
| 12 | * |
| 13 | * This program is distributed in the hope that it will be useful, |
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 16 | * GNU General Public License for more details. |
| 17 | * |
| 18 | * You should have received a copy of the GNU General Public License |
| 19 | * along with this program; if not, write to the Free Software |
| 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, |
| 21 | * MA 02111-1307 USA |
| 22 | */ |
| 23 | |
| 24 | #include <common.h> |
| 25 | #include <asm/system.h> |
| 26 | #include <asm/openrisc_exc.h> |
| 27 | |
| 28 | static volatile int illegal_instruction; |
| 29 | |
| 30 | static void illegal_instruction_handler(void) |
| 31 | { |
| 32 | ulong *epcr = (ulong *)mfspr(SPR_EPCR_BASE); |
| 33 | |
| 34 | /* skip over the illegal instruction */ |
| 35 | mtspr(SPR_EPCR_BASE, (ulong)(++epcr)); |
| 36 | illegal_instruction = 1; |
| 37 | } |
| 38 | |
| 39 | static void checkinstructions(void) |
| 40 | { |
| 41 | ulong ra = 1, rb = 1, rc; |
| 42 | |
| 43 | exception_install_handler(EXC_ILLEGAL_INSTR, |
| 44 | illegal_instruction_handler); |
| 45 | |
| 46 | illegal_instruction = 0; |
| 47 | asm volatile("l.mul %0,%1,%2" : "=r" (rc) : "r" (ra), "r" (rb)); |
| 48 | printf(" Hardware multiplier: %s\n", |
| 49 | illegal_instruction ? "no" : "yes"); |
| 50 | |
| 51 | illegal_instruction = 0; |
| 52 | asm volatile("l.div %0,%1,%2" : "=r" (rc) : "r" (ra), "r" (rb)); |
| 53 | printf(" Hardware divider: %s\n", |
| 54 | illegal_instruction ? "no" : "yes"); |
| 55 | |
| 56 | exception_free_handler(EXC_ILLEGAL_INSTR); |
| 57 | } |
| 58 | |
| 59 | int checkcpu(void) |
| 60 | { |
| 61 | ulong upr = mfspr(SPR_UPR); |
| 62 | ulong vr = mfspr(SPR_VR); |
| 63 | ulong iccfgr = mfspr(SPR_ICCFGR); |
| 64 | ulong dccfgr = mfspr(SPR_DCCFGR); |
| 65 | ulong immucfgr = mfspr(SPR_IMMUCFGR); |
| 66 | ulong dmmucfgr = mfspr(SPR_DMMUCFGR); |
| 67 | ulong cpucfgr = mfspr(SPR_CPUCFGR); |
| 68 | uint ver = (vr & SPR_VR_VER) >> 24; |
| 69 | uint rev = vr & SPR_VR_REV; |
| 70 | uint block_size; |
| 71 | uint ways; |
| 72 | uint sets; |
| 73 | |
| 74 | printf("CPU: OpenRISC-%x00 (rev %d) @ %d MHz\n", |
| 75 | ver, rev, (CONFIG_SYS_CLK_FREQ / 1000000)); |
| 76 | |
| 77 | if (upr & SPR_UPR_DCP) { |
| 78 | block_size = (dccfgr & SPR_DCCFGR_CBS) ? 32 : 16; |
| 79 | ways = 1 << (dccfgr & SPR_DCCFGR_NCW); |
| 80 | printf(" D-Cache: %d bytes, %d bytes/line, %d way(s)\n", |
| 81 | checkdcache(), block_size, ways); |
| 82 | } else { |
| 83 | printf(" D-Cache: no\n"); |
| 84 | } |
| 85 | |
| 86 | if (upr & SPR_UPR_ICP) { |
| 87 | block_size = (iccfgr & SPR_ICCFGR_CBS) ? 32 : 16; |
| 88 | ways = 1 << (iccfgr & SPR_ICCFGR_NCW); |
| 89 | printf(" I-Cache: %d bytes, %d bytes/line, %d way(s)\n", |
| 90 | checkicache(), block_size, ways); |
| 91 | } else { |
| 92 | printf(" I-Cache: no\n"); |
| 93 | } |
| 94 | |
| 95 | if (upr & SPR_UPR_DMP) { |
| 96 | sets = 1 << ((dmmucfgr & SPR_DMMUCFGR_NTS) >> 2); |
| 97 | ways = (dmmucfgr & SPR_DMMUCFGR_NTW) + 1; |
| 98 | printf(" DMMU: %d sets, %d way(s)\n", |
| 99 | sets, ways); |
| 100 | } else { |
| 101 | printf(" DMMU: no\n"); |
| 102 | } |
| 103 | |
| 104 | if (upr & SPR_UPR_IMP) { |
| 105 | sets = 1 << ((immucfgr & SPR_IMMUCFGR_NTS) >> 2); |
| 106 | ways = (immucfgr & SPR_IMMUCFGR_NTW) + 1; |
| 107 | printf(" IMMU: %d sets, %d way(s)\n", |
| 108 | sets, ways); |
| 109 | } else { |
| 110 | printf(" IMMU: no\n"); |
| 111 | } |
| 112 | |
| 113 | printf(" MAC unit: %s\n", |
| 114 | (upr & SPR_UPR_MP) ? "yes" : "no"); |
| 115 | printf(" Debug unit: %s\n", |
| 116 | (upr & SPR_UPR_DUP) ? "yes" : "no"); |
| 117 | printf(" Performance counters: %s\n", |
| 118 | (upr & SPR_UPR_PCUP) ? "yes" : "no"); |
| 119 | printf(" Power management: %s\n", |
| 120 | (upr & SPR_UPR_PMP) ? "yes" : "no"); |
| 121 | printf(" Interrupt controller: %s\n", |
| 122 | (upr & SPR_UPR_PICP) ? "yes" : "no"); |
| 123 | printf(" Timer: %s\n", |
| 124 | (upr & SPR_UPR_TTP) ? "yes" : "no"); |
| 125 | printf(" Custom unit(s): %s\n", |
| 126 | (upr & SPR_UPR_CUP) ? "yes" : "no"); |
| 127 | |
| 128 | printf(" Supported instructions:\n"); |
| 129 | printf(" ORBIS32: %s\n", |
| 130 | (cpucfgr & SPR_CPUCFGR_OB32S) ? "yes" : "no"); |
| 131 | printf(" ORBIS64: %s\n", |
| 132 | (cpucfgr & SPR_CPUCFGR_OB64S) ? "yes" : "no"); |
| 133 | printf(" ORFPX32: %s\n", |
| 134 | (cpucfgr & SPR_CPUCFGR_OF32S) ? "yes" : "no"); |
| 135 | printf(" ORFPX64: %s\n", |
| 136 | (cpucfgr & SPR_CPUCFGR_OF64S) ? "yes" : "no"); |
| 137 | |
| 138 | checkinstructions(); |
| 139 | |
| 140 | return 0; |
| 141 | } |
| 142 | |
| 143 | int cleanup_before_linux(void) |
| 144 | { |
| 145 | disable_interrupts(); |
| 146 | return 0; |
| 147 | } |
| 148 | |
| 149 | extern void __reset(void); |
| 150 | |
| 151 | int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) |
| 152 | { |
| 153 | disable_interrupts(); |
Julius Baxter | 3874a37 | 2012-05-05 12:32:11 +0000 | [diff] [blame] | 154 | /* Code the jump to __reset here as the compiler is prone to |
| 155 | emitting a bad jump instruction if the function is in flash */ |
| 156 | __asm__("l.movhi r1,hi(__reset); \ |
| 157 | l.ori r1,r1,lo(__reset); \ |
| 158 | l.jr r1"); |
Stefan Kristiansson | 272f84b | 2011-11-26 19:04:51 +0000 | [diff] [blame] | 159 | /* not reached, __reset does not return */ |
| 160 | return 0; |
| 161 | } |