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 | * |
Wolfgang Denk | 1a45966 | 2013-07-08 09:37:19 +0200 | [diff] [blame] | 5 | * SPDX-License-Identifier: GPL-2.0+ |
Stefan Kristiansson | 272f84b | 2011-11-26 19:04:51 +0000 | [diff] [blame] | 6 | */ |
| 7 | |
| 8 | #include <common.h> |
| 9 | #include <asm/system.h> |
| 10 | #include <asm/openrisc_exc.h> |
| 11 | |
| 12 | static volatile int illegal_instruction; |
| 13 | |
| 14 | static void illegal_instruction_handler(void) |
| 15 | { |
| 16 | ulong *epcr = (ulong *)mfspr(SPR_EPCR_BASE); |
| 17 | |
| 18 | /* skip over the illegal instruction */ |
| 19 | mtspr(SPR_EPCR_BASE, (ulong)(++epcr)); |
| 20 | illegal_instruction = 1; |
| 21 | } |
| 22 | |
| 23 | static void checkinstructions(void) |
| 24 | { |
| 25 | ulong ra = 1, rb = 1, rc; |
| 26 | |
| 27 | exception_install_handler(EXC_ILLEGAL_INSTR, |
| 28 | illegal_instruction_handler); |
| 29 | |
| 30 | illegal_instruction = 0; |
| 31 | asm volatile("l.mul %0,%1,%2" : "=r" (rc) : "r" (ra), "r" (rb)); |
| 32 | printf(" Hardware multiplier: %s\n", |
| 33 | illegal_instruction ? "no" : "yes"); |
| 34 | |
| 35 | illegal_instruction = 0; |
| 36 | asm volatile("l.div %0,%1,%2" : "=r" (rc) : "r" (ra), "r" (rb)); |
| 37 | printf(" Hardware divider: %s\n", |
| 38 | illegal_instruction ? "no" : "yes"); |
| 39 | |
| 40 | exception_free_handler(EXC_ILLEGAL_INSTR); |
| 41 | } |
| 42 | |
| 43 | int checkcpu(void) |
| 44 | { |
| 45 | ulong upr = mfspr(SPR_UPR); |
| 46 | ulong vr = mfspr(SPR_VR); |
| 47 | ulong iccfgr = mfspr(SPR_ICCFGR); |
| 48 | ulong dccfgr = mfspr(SPR_DCCFGR); |
| 49 | ulong immucfgr = mfspr(SPR_IMMUCFGR); |
| 50 | ulong dmmucfgr = mfspr(SPR_DMMUCFGR); |
| 51 | ulong cpucfgr = mfspr(SPR_CPUCFGR); |
| 52 | uint ver = (vr & SPR_VR_VER) >> 24; |
| 53 | uint rev = vr & SPR_VR_REV; |
| 54 | uint block_size; |
| 55 | uint ways; |
| 56 | uint sets; |
| 57 | |
| 58 | printf("CPU: OpenRISC-%x00 (rev %d) @ %d MHz\n", |
| 59 | ver, rev, (CONFIG_SYS_CLK_FREQ / 1000000)); |
| 60 | |
| 61 | if (upr & SPR_UPR_DCP) { |
| 62 | block_size = (dccfgr & SPR_DCCFGR_CBS) ? 32 : 16; |
| 63 | ways = 1 << (dccfgr & SPR_DCCFGR_NCW); |
| 64 | printf(" D-Cache: %d bytes, %d bytes/line, %d way(s)\n", |
| 65 | checkdcache(), block_size, ways); |
| 66 | } else { |
| 67 | printf(" D-Cache: no\n"); |
| 68 | } |
| 69 | |
| 70 | if (upr & SPR_UPR_ICP) { |
| 71 | block_size = (iccfgr & SPR_ICCFGR_CBS) ? 32 : 16; |
| 72 | ways = 1 << (iccfgr & SPR_ICCFGR_NCW); |
| 73 | printf(" I-Cache: %d bytes, %d bytes/line, %d way(s)\n", |
| 74 | checkicache(), block_size, ways); |
| 75 | } else { |
| 76 | printf(" I-Cache: no\n"); |
| 77 | } |
| 78 | |
| 79 | if (upr & SPR_UPR_DMP) { |
| 80 | sets = 1 << ((dmmucfgr & SPR_DMMUCFGR_NTS) >> 2); |
| 81 | ways = (dmmucfgr & SPR_DMMUCFGR_NTW) + 1; |
| 82 | printf(" DMMU: %d sets, %d way(s)\n", |
| 83 | sets, ways); |
| 84 | } else { |
| 85 | printf(" DMMU: no\n"); |
| 86 | } |
| 87 | |
| 88 | if (upr & SPR_UPR_IMP) { |
| 89 | sets = 1 << ((immucfgr & SPR_IMMUCFGR_NTS) >> 2); |
| 90 | ways = (immucfgr & SPR_IMMUCFGR_NTW) + 1; |
| 91 | printf(" IMMU: %d sets, %d way(s)\n", |
| 92 | sets, ways); |
| 93 | } else { |
| 94 | printf(" IMMU: no\n"); |
| 95 | } |
| 96 | |
| 97 | printf(" MAC unit: %s\n", |
| 98 | (upr & SPR_UPR_MP) ? "yes" : "no"); |
| 99 | printf(" Debug unit: %s\n", |
| 100 | (upr & SPR_UPR_DUP) ? "yes" : "no"); |
| 101 | printf(" Performance counters: %s\n", |
| 102 | (upr & SPR_UPR_PCUP) ? "yes" : "no"); |
| 103 | printf(" Power management: %s\n", |
| 104 | (upr & SPR_UPR_PMP) ? "yes" : "no"); |
| 105 | printf(" Interrupt controller: %s\n", |
| 106 | (upr & SPR_UPR_PICP) ? "yes" : "no"); |
| 107 | printf(" Timer: %s\n", |
| 108 | (upr & SPR_UPR_TTP) ? "yes" : "no"); |
| 109 | printf(" Custom unit(s): %s\n", |
| 110 | (upr & SPR_UPR_CUP) ? "yes" : "no"); |
| 111 | |
| 112 | printf(" Supported instructions:\n"); |
| 113 | printf(" ORBIS32: %s\n", |
| 114 | (cpucfgr & SPR_CPUCFGR_OB32S) ? "yes" : "no"); |
| 115 | printf(" ORBIS64: %s\n", |
| 116 | (cpucfgr & SPR_CPUCFGR_OB64S) ? "yes" : "no"); |
| 117 | printf(" ORFPX32: %s\n", |
| 118 | (cpucfgr & SPR_CPUCFGR_OF32S) ? "yes" : "no"); |
| 119 | printf(" ORFPX64: %s\n", |
| 120 | (cpucfgr & SPR_CPUCFGR_OF64S) ? "yes" : "no"); |
| 121 | |
| 122 | checkinstructions(); |
| 123 | |
| 124 | return 0; |
| 125 | } |
| 126 | |
| 127 | int cleanup_before_linux(void) |
| 128 | { |
| 129 | disable_interrupts(); |
| 130 | return 0; |
| 131 | } |
| 132 | |
| 133 | extern void __reset(void); |
| 134 | |
| 135 | int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) |
| 136 | { |
| 137 | disable_interrupts(); |
Julius Baxter | 3874a37 | 2012-05-05 12:32:11 +0000 | [diff] [blame] | 138 | /* Code the jump to __reset here as the compiler is prone to |
| 139 | emitting a bad jump instruction if the function is in flash */ |
| 140 | __asm__("l.movhi r1,hi(__reset); \ |
Wolfgang Denk | 93e1459 | 2013-10-04 17:43:24 +0200 | [diff] [blame] | 141 | l.ori r1,r1,lo(__reset); \ |
| 142 | l.jr r1"); |
Stefan Kristiansson | 272f84b | 2011-11-26 19:04:51 +0000 | [diff] [blame] | 143 | /* not reached, __reset does not return */ |
| 144 | return 0; |
| 145 | } |