[444] | 1 | /* |
---|
| 2 | * cma101.c -- lo-level support for Cogent CMA101 development board. |
---|
| 3 | * |
---|
| 4 | * Copyright (c) 1996, 2001, 2002 Cygnus Support |
---|
| 5 | * |
---|
| 6 | * The authors hereby grant permission to use, copy, modify, distribute, |
---|
| 7 | * and license this software and its documentation for any purpose, provided |
---|
| 8 | * that existing copyright notices are retained in all copies and that this |
---|
| 9 | * notice is included verbatim in any distributions. No written agreement, |
---|
| 10 | * license, or royalty fee is required for any of the authorized uses. |
---|
| 11 | * Modifications to this software may be copyrighted by their authors |
---|
| 12 | * and need not follow the licensing terms described here, provided that |
---|
| 13 | * the new terms are clearly indicated on the first page of each file where |
---|
| 14 | * they apply. |
---|
| 15 | */ |
---|
| 16 | |
---|
| 17 | #ifdef __mips16 |
---|
| 18 | /* The assembler portions of this file need to be re-written to |
---|
| 19 | support mips16, if and when that seems useful. |
---|
| 20 | */ |
---|
| 21 | #error cma101.c can not be compiled -mips16 |
---|
| 22 | #endif |
---|
| 23 | |
---|
| 24 | |
---|
| 25 | #include <time.h> /* standard ANSI time routines */ |
---|
| 26 | |
---|
| 27 | /* Normally these would appear in a header file for external |
---|
| 28 | use. However, we are only building a simple example world at the |
---|
| 29 | moment: */ |
---|
| 30 | |
---|
| 31 | #include "regs.S" |
---|
| 32 | |
---|
| 33 | #if defined(MIPSEB) |
---|
| 34 | #define BYTEREG(b,o) ((volatile unsigned char *)(PHYS_TO_K1((b) + (o) + 7))) |
---|
| 35 | #endif /* MIPSEB */ |
---|
| 36 | #if defined(MIPSEL) |
---|
| 37 | #define BYTEREG(b,o) ((volatile unsigned char *)(PHYS_TO_K1((b) + (o)))) |
---|
| 38 | #endif /* MIPSEL */ |
---|
| 39 | |
---|
| 40 | /* I/O addresses: */ |
---|
| 41 | #define RTCLOCK_BASE (0x0E800000) /* Mk48T02 NVRAM/RTC */ |
---|
| 42 | #define UART_BASE (0x0E900000) /* NS16C552 DUART */ |
---|
| 43 | #define LCD_BASE (0x0EB00000) /* Alphanumeric display */ |
---|
| 44 | |
---|
| 45 | /* LCD panel manifests: */ |
---|
| 46 | #define LCD_DATA BYTEREG(LCD_BASE,0) |
---|
| 47 | #define LCD_CMD BYTEREG(LCD_BASE,8) |
---|
| 48 | |
---|
| 49 | #define LCD_STAT_BUSY (0x80) |
---|
| 50 | #define LCD_SET_DDADDR (0x80) |
---|
| 51 | |
---|
| 52 | /* RTC manifests */ |
---|
| 53 | /* The lo-offsets are the NVRAM locations (0x7F8 bytes) */ |
---|
| 54 | #define RTC_CONTROL BYTEREG(RTCLOCK_BASE,0x3FC0) |
---|
| 55 | #define RTC_SECS BYTEREG(RTCLOCK_BASE,0x3FC8) |
---|
| 56 | #define RTC_MINS BYTEREG(RTCLOCK_BASE,0x3FD0) |
---|
| 57 | #define RTC_HOURS BYTEREG(RTCLOCK_BASE,0x3FD8) |
---|
| 58 | #define RTC_DAY BYTEREG(RTCLOCK_BASE,0x3FE0) |
---|
| 59 | #define RTC_DATE BYTEREG(RTCLOCK_BASE,0x3FE8) |
---|
| 60 | #define RTC_MONTH BYTEREG(RTCLOCK_BASE,0x3FF0) |
---|
| 61 | #define RTC_YEAR BYTEREG(RTCLOCK_BASE,0x3FF8) |
---|
| 62 | |
---|
| 63 | #define RTC_CTL_LOCK_READ (0x40) /* lock RTC whilst reading */ |
---|
| 64 | #define RTC_CTL_LOCK_WRITE (0x80) /* lock RTC whilst writing */ |
---|
| 65 | |
---|
| 66 | /* Macro to force out-standing memory transfers to complete before |
---|
| 67 | next sequence. For the moment we assume that the processor in the |
---|
| 68 | CMA101 board supports at least ISA II. */ |
---|
| 69 | #define DOSYNC() asm(" .set mips2 ; sync ; .set mips0") |
---|
| 70 | |
---|
| 71 | /* We disable interrupts by writing zero to all of the masks, and the |
---|
| 72 | global interrupt enable bit: */ |
---|
| 73 | #define INTDISABLE(sr,tmp) asm("\ |
---|
| 74 | .set mips2 ; \ |
---|
| 75 | mfc0 %0,$12 ; \ |
---|
| 76 | lui %1,0xffff ; \ |
---|
| 77 | ori %1,%1,0xfffe ; \ |
---|
| 78 | and %1, %0, %1 ; \ |
---|
| 79 | mtc0 %1,$12 ; \ |
---|
| 80 | .set mips0" : "=d" (sr), "=d" (tmp)) |
---|
| 81 | #define INTRESTORE(sr) asm("\ |
---|
| 82 | .set mips2 ; \ |
---|
| 83 | mtc0 %0,$12 ; \ |
---|
| 84 | .set mips0" : : "d" (sr)) |
---|
| 85 | |
---|
| 86 | /* TODO:FIXME: The CPU card support should be in separate source file |
---|
| 87 | from the standard CMA101 support provided in this file. */ |
---|
| 88 | |
---|
| 89 | /* The CMA101 board being used contains a CMA257 Vr4300 CPU: |
---|
| 90 | MasterClock is at 33MHz. PClock is derived from MasterClock by |
---|
| 91 | multiplying by the ratio defined by the DivMode pins: |
---|
| 92 | DivMode(1:0) MasterClock PClock Ratio |
---|
| 93 | 00 100MHz 100MHz 1:1 |
---|
| 94 | 01 100MHz 150MHz 1.5:1 |
---|
| 95 | 10 100MHz 200MHz 2:1 |
---|
| 96 | 11 100Mhz 300MHz 3:1 |
---|
| 97 | |
---|
| 98 | Are these pins reflected in the EC bits in the CONFIG register? or |
---|
| 99 | is that talking about a different clock multiplier? |
---|
| 100 | 110 = 1 |
---|
| 101 | 111 = 1.5 |
---|
| 102 | 000 = 2 |
---|
| 103 | 001 = 3 |
---|
| 104 | (all other values are undefined) |
---|
| 105 | */ |
---|
| 106 | |
---|
| 107 | #define MASTERCLOCK (33) /* ticks per uS */ |
---|
| 108 | unsigned int pclock; /* number of PClock ticks per uS */ |
---|
| 109 | void |
---|
| 110 | set_pclock (void) |
---|
| 111 | { |
---|
| 112 | unsigned int config; |
---|
| 113 | asm volatile ("mfc0 %0,$16 ; nop ; nop" : "=r" (config)); /* nasty CP0 register constant */ |
---|
| 114 | switch ((config >> 28) & 0x7) { |
---|
| 115 | case 0x7 : /* 1.5:1 */ |
---|
| 116 | pclock = (MASTERCLOCK + (MASTERCLOCK / 2)); |
---|
| 117 | break; |
---|
| 118 | |
---|
| 119 | case 0x0 : /* 2:1 */ |
---|
| 120 | pclock = (2 * MASTERCLOCK); |
---|
| 121 | break; |
---|
| 122 | |
---|
| 123 | case 0x1 : /* 3:1 */ |
---|
| 124 | pclock = (3 * MASTERCLOCK); |
---|
| 125 | break; |
---|
| 126 | |
---|
| 127 | case 0x6 : /* 1:1 */ |
---|
| 128 | default : /* invalid configuration, so assume the lowest */ |
---|
| 129 | pclock = MASTERCLOCK; |
---|
| 130 | break; |
---|
| 131 | } |
---|
| 132 | |
---|
| 133 | return; |
---|
| 134 | } |
---|
| 135 | |
---|
| 136 | #define PCLOCK_WAIT(x) __cpu_timer_poll((x) * pclock) |
---|
| 137 | |
---|
| 138 | /* NOTE: On the Cogent CMA101 board the LCD controller will sometimes |
---|
| 139 | return not-busy, even though it is. The work-around is to perform a |
---|
| 140 | ~50uS delay before checking the busy signal. */ |
---|
| 141 | |
---|
| 142 | static int |
---|
| 143 | lcd_busy (void) |
---|
| 144 | { |
---|
| 145 | PCLOCK_WAIT(50); /* 50uS delay */ |
---|
| 146 | return(*LCD_CMD & LCD_STAT_BUSY); |
---|
| 147 | } |
---|
| 148 | |
---|
| 149 | /* Note: This code *ASSUMES* that the LCD has already been initialised |
---|
| 150 | by the monitor. It only provides code to write to the LCD, and is |
---|
| 151 | not a complete device driver. */ |
---|
| 152 | |
---|
| 153 | void |
---|
| 154 | lcd_display (int line, const char *msg) |
---|
| 155 | { |
---|
| 156 | int n; |
---|
| 157 | |
---|
| 158 | if (lcd_busy ()) |
---|
| 159 | return; |
---|
| 160 | |
---|
| 161 | *LCD_CMD = (LCD_SET_DDADDR | (line == 1 ? 0x40 : 0x00)); |
---|
| 162 | |
---|
| 163 | for (n = 0; n < 16; n++) { |
---|
| 164 | if (lcd_busy ()) |
---|
| 165 | return; |
---|
| 166 | if (*msg) |
---|
| 167 | *LCD_DATA = *msg++; |
---|
| 168 | else |
---|
| 169 | *LCD_DATA = ' '; |
---|
| 170 | } |
---|
| 171 | |
---|
| 172 | return; |
---|
| 173 | } |
---|
| 174 | |
---|
| 175 | #define SM_PATTERN (0x55AA55AA) |
---|
| 176 | #define SM_INCR ((256 << 10) / sizeof(unsigned int)) /* 64K words */ |
---|
| 177 | |
---|
| 178 | extern unsigned int __buserr_count(void); |
---|
| 179 | extern void __default_buserr_handler(void); |
---|
| 180 | extern void __restore_buserr_handler(void); |
---|
| 181 | |
---|
| 182 | /* Allow the user to provide his/her own defaults. */ |
---|
| 183 | unsigned int __sizemem_default; |
---|
| 184 | |
---|
| 185 | unsigned int |
---|
| 186 | __sizemem () |
---|
| 187 | { |
---|
| 188 | volatile unsigned int *base; |
---|
| 189 | volatile unsigned int *probe; |
---|
| 190 | unsigned int baseorig; |
---|
| 191 | unsigned int sr; |
---|
| 192 | extern char end[]; |
---|
| 193 | char *endptr = (char *)&end; |
---|
| 194 | int extra; |
---|
| 195 | |
---|
| 196 | /* If the linker script provided a value for the memory size (or the user |
---|
| 197 | overrode it in a debugger), use that. */ |
---|
| 198 | if (__sizemem_default) |
---|
| 199 | return __sizemem_default; |
---|
| 200 | |
---|
| 201 | /* If we are running in kernel segment 0 (possibly cached), try sizing memory |
---|
| 202 | in kernel segment 1 (uncached) to avoid some problems with monitors. */ |
---|
| 203 | if (endptr >= K0BASE_ADDR && endptr < K1BASE_ADDR) |
---|
| 204 | endptr = (endptr - K0BASE_ADDR) + K1BASE_ADDR; |
---|
| 205 | |
---|
| 206 | INTDISABLE(sr,baseorig); /* disable all interrupt masks */ |
---|
| 207 | |
---|
| 208 | __default_buserr_handler(); |
---|
| 209 | __cpu_flush(); |
---|
| 210 | |
---|
| 211 | DOSYNC(); |
---|
| 212 | |
---|
| 213 | /* _end is the end of the user program. _end may not be properly aligned |
---|
| 214 | for an int pointer, so we adjust the address to make sure it is safe. |
---|
| 215 | We use void * arithmetic to avoid accidentally truncating the pointer. */ |
---|
| 216 | |
---|
| 217 | extra = ((int) endptr & (sizeof (int) - 1)); |
---|
| 218 | base = ((void *) endptr + sizeof (int) - extra); |
---|
| 219 | baseorig = *base; |
---|
| 220 | |
---|
| 221 | *base = SM_PATTERN; |
---|
| 222 | /* This assumes that the instructions fetched between the store, and |
---|
| 223 | the following read will have changed the data bus contents: */ |
---|
| 224 | if (*base == SM_PATTERN) { |
---|
| 225 | probe = base; |
---|
| 226 | for (;;) { |
---|
| 227 | unsigned int probeorig; |
---|
| 228 | probe += SM_INCR; |
---|
| 229 | probeorig = *probe; |
---|
| 230 | /* Check if a bus error occurred: */ |
---|
| 231 | if (!__buserr_count()) { |
---|
| 232 | *probe = SM_PATTERN; |
---|
| 233 | DOSYNC(); |
---|
| 234 | if (*probe == SM_PATTERN) { |
---|
| 235 | *probe = ~SM_PATTERN; |
---|
| 236 | DOSYNC(); |
---|
| 237 | if (*probe == ~SM_PATTERN) { |
---|
| 238 | if (*base == SM_PATTERN) { |
---|
| 239 | *probe = probeorig; |
---|
| 240 | continue; |
---|
| 241 | } |
---|
| 242 | } |
---|
| 243 | } |
---|
| 244 | *probe = probeorig; |
---|
| 245 | } |
---|
| 246 | break; |
---|
| 247 | } |
---|
| 248 | } |
---|
| 249 | |
---|
| 250 | *base = baseorig; |
---|
| 251 | __restore_buserr_handler(); |
---|
| 252 | __cpu_flush(); |
---|
| 253 | |
---|
| 254 | DOSYNC(); |
---|
| 255 | |
---|
| 256 | INTRESTORE(sr); /* restore interrupt mask to entry state */ |
---|
| 257 | |
---|
| 258 | return((probe - base) * sizeof(unsigned int)); |
---|
| 259 | } |
---|
| 260 | |
---|
| 261 | /* Provided as a function, so as to avoid reading the I/O location |
---|
| 262 | multiple times: */ |
---|
| 263 | static int |
---|
| 264 | convertbcd(byte) |
---|
| 265 | unsigned char byte; |
---|
| 266 | { |
---|
| 267 | return ((((byte >> 4) & 0xF) * 10) + (byte & 0xF)); |
---|
| 268 | } |
---|
| 269 | |
---|
| 270 | time_t |
---|
| 271 | time (_timer) |
---|
| 272 | time_t *_timer; |
---|
| 273 | { |
---|
| 274 | time_t result = 0; |
---|
| 275 | struct tm tm; |
---|
| 276 | *RTC_CONTROL |= RTC_CTL_LOCK_READ; |
---|
| 277 | DOSYNC(); |
---|
| 278 | |
---|
| 279 | tm.tm_sec = convertbcd(*RTC_SECS); |
---|
| 280 | tm.tm_min = convertbcd(*RTC_MINS); |
---|
| 281 | tm.tm_hour = convertbcd(*RTC_HOURS); |
---|
| 282 | tm.tm_mday = convertbcd(*RTC_DATE); |
---|
| 283 | tm.tm_mon = convertbcd(*RTC_MONTH); |
---|
| 284 | tm.tm_year = convertbcd(*RTC_YEAR); |
---|
| 285 | |
---|
| 286 | DOSYNC(); |
---|
| 287 | *RTC_CONTROL &= ~(RTC_CTL_LOCK_READ | RTC_CTL_LOCK_WRITE); |
---|
| 288 | |
---|
| 289 | tm.tm_isdst = 0; |
---|
| 290 | |
---|
| 291 | /* Check for invalid time information */ |
---|
| 292 | if ((tm.tm_sec < 60) && (tm.tm_min < 60) && (tm.tm_hour < 24) |
---|
| 293 | && (tm.tm_mday < 32) && (tm.tm_mon < 13)) { |
---|
| 294 | |
---|
| 295 | /* Get the correct year number, but keep it in YEAR-1900 form: */ |
---|
| 296 | if (tm.tm_year < 70) |
---|
| 297 | tm.tm_year += 100; |
---|
| 298 | |
---|
| 299 | #if 0 /* NOTE: mon_printf() can only accept 4 arguments (format string + 3 fields) */ |
---|
| 300 | mon_printf("[DBG: s=%d m=%d h=%d]", tm.tm_sec, tm.tm_min, tm.tm_hour); |
---|
| 301 | mon_printf("[DBG: d=%d m=%d y=%d]", tm.tm_mday, tm.tm_mon, tm.tm_year); |
---|
| 302 | #endif |
---|
| 303 | |
---|
| 304 | /* Convert the time-structure into a second count */ |
---|
| 305 | result = mktime (&tm); |
---|
| 306 | } |
---|
| 307 | |
---|
| 308 | if (_timer != NULL) |
---|
| 309 | *_timer = result; |
---|
| 310 | |
---|
| 311 | return (result); |
---|
| 312 | } |
---|
| 313 | |
---|
| 314 | /*> EOF cma101.c <*/ |
---|