1 /* $NetBSD: switch.c,v 1.2 2014/08/10 07:40:50 isaki Exp $ */
2
3 /*
4 * Copyright (c) 2014 Tetsuya Isaki. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
20 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
22 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28 #include <sys/param.h>
29 #include <lib/libsa/stand.h>
30 #include <lib/libkern/libkern.h>
31
32 #include "switch.h"
33
34 #define SRAM_MEMSIZE (*((volatile uint32_t *)0x00ed0008))
35 #define SRAM_ROMADDR (*((volatile uint32_t *)0x00ed000c))
36 #define SRAM_RAMADDR (*((volatile uint32_t *)0x00ed0010))
37 #define SRAM_BOOTDEV (*((volatile uint16_t *)0x00ed0018))
38
39 #define SYSPORT_SRAM_WP (*((volatile uint8_t *)0x00e8e00d))
40
41 static int hextoi(const char *);
42 static void cmd_switch_help(void);
43 static void cmd_switch_show(void);
44 static void cmd_switch_show_boot(void);
45 static void cmd_switch_show_rom(void);
46 static void cmd_switch_show_memory(void);
47 static const char *romaddr_tostr(uint32_t);
48 static const char *get_romaddr_name(uint32_t);
49 static void cmd_switch_boot(const char *);
50 static void cmd_switch_rom(const char *);
51 static void cmd_switch_memory(const char *);
52
53 static inline void
sram_write_enable(void)54 sram_write_enable(void)
55 {
56 SYSPORT_SRAM_WP = 0x31;
57 }
58
59 static inline void
sram_write_disable(void)60 sram_write_disable(void)
61 {
62 SYSPORT_SRAM_WP = 0;
63 }
64
65 static int
hextoi(const char * in)66 hextoi(const char *in)
67 {
68 char *c;
69 int ret;
70
71 ret = 0;
72 c = (char *)in;
73 for (; isxdigit(*c); c++) {
74 ret = (ret * 16) +
75 (*c > '9' ? ((*c | 0x20) - 'a' + 10) : *c - '0');
76 }
77 return ret;
78 }
79
80 static void
cmd_switch_help(void)81 cmd_switch_help(void)
82 {
83 printf(
84 "usage: switch <key>=<val>\n"
85 " boot=[std | inscsi<N> | exscsi<N> | fd<N> | rom ]\n"
86 " rom=[ inscsi<N> | exscsi<N> | $<addr> ]\n"
87 " memory=<1..12> (unit:MB)\n"
88 " switch show\n"
89 );
90 }
91
92 void
cmd_switch(char * arg)93 cmd_switch(char *arg)
94 {
95 char *val;
96
97 if (strcmp(arg, "show") == 0) {
98 cmd_switch_show();
99 return;
100 }
101
102 val = strchr(arg, '=');
103 if (val == NULL) {
104 cmd_switch_help();
105 return;
106 }
107 *val++ = '\0';
108
109 if (strcmp(arg, "boot") == 0) {
110 cmd_switch_boot(val);
111 } else if (strcmp(arg, "rom") == 0) {
112 cmd_switch_rom(val);
113 } else if (strcmp(arg, "memory") == 0) {
114 cmd_switch_memory(val);
115 } else {
116 cmd_switch_help();
117 }
118 }
119
120 static void
cmd_switch_show(void)121 cmd_switch_show(void)
122 {
123 cmd_switch_show_boot();
124 cmd_switch_show_rom();
125 cmd_switch_show_memory();
126 }
127
128 static void
cmd_switch_show_boot(void)129 cmd_switch_show_boot(void)
130 {
131 uint32_t romaddr;
132 uint16_t bootdev;
133 const char *name;
134
135 bootdev = SRAM_BOOTDEV;
136 romaddr = SRAM_ROMADDR;
137
138 /*
139 * $0000: std
140 * $8n00: sasi<N>
141 * $9n70: fd<N>
142 * $a000: ROM
143 * $b000: RAM
144 */
145 printf("boot=");
146 switch (bootdev >> 12) {
147 default:
148 case 0x0:
149 /*
150 * The real order is fd->sasi->rom->ram
151 * but it is a bit redundant..
152 */
153 printf("std (fd -> ");
154 name = get_romaddr_name(romaddr);
155 if (name)
156 printf("%s)", name);
157 else
158 printf("rom$%x)", romaddr);
159 break;
160 case 0x8:
161 printf("sasi%d", (bootdev >> 8) & 15);
162 break;
163 case 0x9:
164 printf("fd%d", (bootdev >> 8) & 3);
165 break;
166 case 0xa:
167 printf("rom%s", romaddr_tostr(romaddr));
168 break;
169 case 0xb:
170 printf("ram$%x", SRAM_RAMADDR);
171 break;
172 }
173 printf("\n");
174 }
175
176 static void
cmd_switch_show_rom(void)177 cmd_switch_show_rom(void)
178 {
179 uint32_t romaddr;
180
181 romaddr = SRAM_ROMADDR;
182 printf("rom=%s\n", romaddr_tostr(romaddr));
183 }
184
185 static void
cmd_switch_show_memory(void)186 cmd_switch_show_memory(void)
187 {
188 printf("memory=%d MB\n", SRAM_MEMSIZE / (1024 * 1024));
189 }
190
191 /* return rom address as string with name if any */
192 static const char *
romaddr_tostr(uint32_t addr)193 romaddr_tostr(uint32_t addr)
194 {
195 static char buf[32];
196 const char *name;
197
198 name = get_romaddr_name(addr);
199 if (name)
200 snprintf(buf, sizeof(buf), "$%x (%s)", addr, name);
201 else
202 snprintf(buf, sizeof(buf), "$%x", addr);
203
204 return buf;
205 }
206
207 /*
208 * return "inscsiN" / "exscsiN" if addr is in range of SCSI boot.
209 * Otherwise return NULL.
210 */
211 static const char *
get_romaddr_name(uint32_t addr)212 get_romaddr_name(uint32_t addr)
213 {
214 static char buf[8];
215
216 if (0xfc0000 <= addr && addr < 0xfc0020 && addr % 4 == 0) {
217 snprintf(buf, sizeof(buf), "inscsi%d", (addr >> 2) & 7);
218 } else if (0xea0020 <= addr && addr < 0xea0040 && addr % 4 == 0) {
219 snprintf(buf, sizeof(buf), "exscsi%d", (addr >> 2) & 7);
220 } else {
221 return NULL;
222 }
223 return buf;
224 }
225
226 static void
cmd_switch_boot(const char * arg)227 cmd_switch_boot(const char *arg)
228 {
229 int id;
230 uint32_t romaddr;
231 uint16_t bootdev;
232
233 romaddr = 0xffffffff;
234
235 if (strcmp(arg, "std") == 0) {
236 bootdev = 0x0000;
237
238 } else if (strcmp(arg, "rom") == 0) {
239 bootdev = 0xa000;
240
241 } else if (strncmp(arg, "inscsi", 6) == 0) {
242 id = (arg[6] - '0') & 7;
243 bootdev = 0xa000;
244 romaddr = 0xfc0000 + id * 4;
245
246 } else if (strncmp(arg, "exscsi", 6) == 0) {
247 id = (arg[6] - '0') & 7;
248 bootdev = 0xa000;
249 romaddr = 0xea0020 + id * 4;
250
251 } else if (strncmp(arg, "fd", 2) == 0) {
252 id = (arg[2] - '0') & 3;
253 bootdev = 0x9070 | (id << 8);
254
255 } else {
256 cmd_switch_help();
257 return;
258 }
259
260 sram_write_enable();
261 SRAM_BOOTDEV = bootdev;
262 if (romaddr != 0xffffffff)
263 SRAM_ROMADDR = romaddr;
264 sram_write_disable();
265
266 cmd_switch_show_boot();
267 }
268
269 static void
cmd_switch_rom(const char * arg)270 cmd_switch_rom(const char *arg)
271 {
272 int id;
273 uint32_t romaddr;
274
275 if (strncmp(arg, "inscsi", 6) == 0) {
276 id = (arg[6] - '0') & 7;
277 romaddr = 0xfc0000 + id * 4;
278
279 } else if (strncmp(arg, "exscsi", 6) == 0) {
280 id = (arg[6] - '0') & 7;
281 romaddr = 0xea0020 + id * 4;
282
283 } else if (*arg == '$') {
284 romaddr = hextoi(arg + 1);
285
286 } else {
287 cmd_switch_help();
288 return;
289 }
290
291 sram_write_enable();
292 SRAM_ROMADDR = romaddr;
293 sram_write_disable();
294
295 cmd_switch_show_rom();
296 }
297
298 static void
cmd_switch_memory(const char * arg)299 cmd_switch_memory(const char *arg)
300 {
301 int num;
302
303 num = atoi(arg);
304 if (num < 1 || num > 12) {
305 cmd_switch_help();
306 return;
307 }
308
309 sram_write_enable();
310 SRAM_MEMSIZE = num * (1024 * 1024);
311 sram_write_disable();
312
313 cmd_switch_show_memory();
314 }
315