MDIO R/W working
[mw/milkymist.git] / software / demo / shell.c
1 /*
2  * Milkymist VJ SoC (Software)
3  * Copyright (C) 2007, 2008, 2009, 2010 Sebastien Bourdeauducq
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, version 3 of the License.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <console.h>
22 #include <uart.h>
23 #include <cffat.h>
24 #include <system.h>
25 #include <math.h>
26 #include <irq.h>
27 #include <board.h>
28 #include <hw/pfpu.h>
29 #include <hw/tmu.h>
30 #include <hw/sysctl.h>
31 #include <hw/gpio.h>
32 #include <hw/interrupts.h>
33
34 #include <hal/vga.h>
35 #include <hal/snd.h>
36 #include <hal/tmu.h>
37 #include <hal/time.h>
38 #include <hal/brd.h>
39
40 #include <net/mdio.h>
41
42 #include "line.h"
43 #include "wave.h"
44 #include "rpipe.h"
45 #include "cpustats.h"
46 #include "shell.h"
47 #include "ui.h"
48
49 #define NUMBER_OF_BYTES_ON_A_LINE 16
50 static void dump_bytes(unsigned int *ptr, int count, unsigned addr)
51 {
52         char *data = (char *)ptr;
53         int line_bytes = 0, i = 0;
54
55         putsnonl("Memory dump:");
56         while(count > 0){
57                 line_bytes =
58                         (count > NUMBER_OF_BYTES_ON_A_LINE)?
59                                 NUMBER_OF_BYTES_ON_A_LINE : count;
60
61                 printf("\n0x%08x  ", addr);
62                 for(i=0;i<line_bytes;i++)
63                         printf("%02x ", *(unsigned char *)(data+i));
64
65                 for(;i<NUMBER_OF_BYTES_ON_A_LINE;i++)
66                         printf("   ");
67
68                 printf(" ");
69
70                 for(i=0;i<line_bytes;i++) {
71                         if((*(data+i) < 0x20) || (*(data+i) > 0x7e))
72                                 printf(".");
73                         else
74                                 printf("%c", *(data+i));
75                 }
76
77                 for(;i<NUMBER_OF_BYTES_ON_A_LINE;i++)
78                         printf(" ");
79
80                 data += (char)line_bytes;
81                 count -= line_bytes;
82                 addr += line_bytes;
83         }
84         printf("\n");
85 }
86
87 static void mr(char *startaddr, char *len)
88 {
89         char *c;
90         unsigned *addr;
91         unsigned length;
92
93         if(*startaddr == 0) {
94                 printf("mr <address> [length]\n");
95                 return;
96         }
97         addr = (unsigned *)strtoul(startaddr, &c, 0);
98         if(*c != 0) {
99                 printf("incorrect address\n");
100                 return;
101         }
102         if(*len == 0) {
103                 length = 1;
104         } else {
105                 length = strtoul(len, &c, 0);
106                 if(*c != 0) {
107                         printf("incorrect length\n");
108                         return;
109                 }
110         }
111
112         dump_bytes(addr, length, (unsigned)addr);
113 }
114
115 static void mw(char *addr, char *value, char *count)
116 {
117         char *c;
118         unsigned *addr2;
119         unsigned value2;
120         unsigned count2;
121         unsigned i;
122
123         if((*addr == 0) || (*value == 0)) {
124                 printf("mw <address> <value>\n");
125                 return;
126         }
127         addr2 = (unsigned *)strtoul(addr, &c, 0);
128         if(*c != 0) {
129                 printf("incorrect address\n");
130                 return;
131         }
132         value2 = strtoul(value, &c, 0);
133         if(*c != 0) {
134                 printf("incorrect value\n");
135                 return;
136         }
137         if(*count == 0) {
138                 count2 = 1;
139         } else {
140                 count2 = strtoul(count, &c, 0);
141                 if(*c != 0) {
142                         printf("incorrect count\n");
143                         return;
144                 }
145         }
146         for (i=0;i<count2;i++) *addr2++ = value2;
147 }
148
149 static int lscb(const char *filename, const char *longname, void *param)
150 {
151         printf("%12s [%s]\n", filename, longname);
152         return 1;
153 }
154
155 static void ls()
156 {
157         cffat_init();
158         cffat_list_files(lscb, NULL);
159         cffat_done();
160 }
161
162 static void render(const char *filename)
163 {
164         if(*filename == 0) {
165                 printf("render <filename>\n");
166                 return;
167         }
168
169         ui_render_from_file(filename, 0);
170 }
171
172 static void spam()
173 {
174         spam_enabled = !spam_enabled;
175         if(spam_enabled)
176                 printf("Advertising enabled\n");
177         else
178                 printf("Advertising disabled\n");
179 }
180
181 static void stats()
182 {
183         int hours, mins, secs;
184         struct timestamp ts;
185
186         time_get(&ts);
187         secs = ts.sec;
188         mins = secs/60;
189         secs -= mins*60;
190         hours = mins/60;
191         mins -= hours*60;
192         printf("Uptime: %02d:%02d:%02d  FPS: %d  CPU:%3d%%\n", hours, mins, secs,
193                 rpipe_fps(),
194                 cpustats_load());
195 }
196
197 static void help()
198 {
199         puts("Milkymist demo firmware\n");
200         puts("Available commands :");
201         puts("mr         - read address space");
202         puts("mw         - write address space");
203         puts("flush      - flush FML bridge cache");
204         puts("ls         - list files on the memory card");
205         puts("render     - start rendering a preset");
206         puts("stop       - stop renderer");
207         puts("spam       - start/stop advertising");
208         puts("stats      - print system stats");
209         puts("reboot     - system reset");
210         puts("mdior      - read MDIO register");
211         puts("mdiow      - write MDIO register");
212 }
213
214 static void mdior(char *reg)
215 {
216         char *c;
217         int reg2;
218
219         if(*reg == 0) {
220                 printf("mdior <register>\n");
221                 return;
222         }
223         reg2 = strtoul(reg, &c, 0);
224         if(*c != 0) {
225                 printf("incorrect register\n");
226                 return;
227         }
228
229         printf("%02x\n", mdio_read(0, reg2));
230 }
231
232 static void mdiow(char *reg, char *value)
233 {
234         char *c;
235         int reg2;
236         int value2;
237
238         if((*reg == 0) || (*value == 0)) {
239                 printf("mdiow <register> <value>\n");
240                 return;
241         }
242         reg2 = strtoul(reg, &c, 0);
243         if(*c != 0) {
244                 printf("incorrect address\n");
245                 return;
246         }
247         value2 = strtoul(value, &c, 0);
248         if(*c != 0) {
249                 printf("incorrect value\n");
250                 return;
251         }
252
253         mdio_write(0, reg2, value2);
254 }
255
256
257 static void loadpic(const char *filename)
258 {
259         int size;
260         
261         if(*filename == 0) {
262                 printf("loadpic <filename>\n");
263                 return;
264         }
265
266         if(!cffat_init()) return;
267         if(!cffat_load(filename, (void *)vga_backbuffer, vga_hres*vga_vres*2, &size)) return;
268         cffat_done();
269
270         vga_swap_buffers();
271 }
272
273 static void checker()
274 {
275         int x, y;
276
277         for(y=0;y<vga_vres;y++)
278                 for(x=0;x<vga_hres;x++)
279                         if((x/4+y/4) & 1)
280                                 vga_backbuffer[y*vga_hres+x] = 0x0000;
281                         else
282                                 vga_backbuffer[y*vga_hres+x] = 0xffff;
283         vga_swap_buffers();
284 }
285
286 /*
287  * Low-level PFPU test, bypassing driver.
288  * This test should only be run when the driver task queue
289  * is empty.
290  */
291 static struct tmu_vertex mesh[128][128] __attribute__((aligned(8)));
292 static void pfputest()
293 {
294         unsigned int *pfpu_regs = (unsigned int *)CSR_PFPU_DREGBASE;
295         unsigned int *pfpu_code = (unsigned int *)CSR_PFPU_CODEBASE;
296         int x, y;
297         int timeout;
298         unsigned int oldmask;
299
300         /* Do not let the driver get our interrupt */
301         oldmask = irq_getmask();
302         irq_setmask(oldmask & (~IRQ_PFPU));
303
304         for(y=0;y<128;y++)
305                 for(x=0;x<128;x++) {
306                         mesh[y][x].x = 0xdeadbeef;
307                         mesh[y][x].y = 0xdeadbeef;
308                 }
309
310         CSR_PFPU_MESHBASE = (unsigned int)&mesh;
311         //CSR_PFPU_HMESHLAST = 6;
312         //CSR_PFPU_VMESHLAST = 9;
313
314         CSR_PFPU_HMESHLAST = 11;
315         CSR_PFPU_VMESHLAST = 9;
316
317         pfpu_regs[3] = 0x41300000;
318         pfpu_regs[4] = 0x41100000;
319
320         pfpu_code[ 0] = 0x00000300;
321         pfpu_code[ 1] = 0x00040300;
322         pfpu_code[ 2] = 0x00000000;
323         pfpu_code[ 3] = 0x00000003;
324         pfpu_code[ 4] = 0x00000004;
325         pfpu_code[ 5] = 0x000c2080;
326         pfpu_code[ 6] = 0x00000000;
327         pfpu_code[ 7] = 0x00000000;
328         pfpu_code[ 8] = 0x00000000;
329         pfpu_code[ 9] = 0x00000005;
330         pfpu_code[10] = 0x00142b80;
331
332         CSR_PFPU_CTL = PFPU_CTL_START;
333         printf("Waiting for PFPU...\n");
334         timeout = 30;
335         do {
336                 printf("%08x vertices:%d collisions:%d strays:%d last:%08x pc:%04x\n",
337                         CSR_PFPU_CTL, CSR_PFPU_VERTICES, CSR_PFPU_COLLISIONS, CSR_PFPU_STRAYWRITES, CSR_PFPU_LASTDMA, 4*CSR_PFPU_PC);
338         } while((timeout--) && (CSR_PFPU_CTL & PFPU_CTL_BUSY));
339         if(timeout > 0)
340                 printf("OK\n");
341         else
342                 printf("Timeout\n");
343
344         asm volatile( /* Invalidate Level-1 data cache */
345                 "wcsr DCC, r0\n"
346                 "nop\n"
347         );
348
349         printf("Result:\n");
350         for(y=0;y<10;y++) {
351                 for(x=0;x<12;x++)
352                         printf("%08x ", mesh[y][x].x);
353                 printf("\n");
354         }
355         printf("\n");
356         for(y=0;y<10;y++) {
357                 for(x=0;x<12;x++)
358                         printf("%08x ", mesh[y][x].y);
359                 printf("\n");
360         }
361
362         printf("Program:\n");
363         for(x=0;x<11;x++)
364                 printf("%08x ", pfpu_code[x]);
365         printf("\n");
366
367         CSR_PFPU_CTL = 0; /* Ack interrupt */
368         irq_ack(IRQ_PFPU);
369         irq_setmask(oldmask);
370 }
371
372 static void tmutest_callback(struct tmu_td *td)
373 {
374         int *complete;
375         complete = (int *)td->user;
376         *complete = 1;
377 }
378
379 static void tmutest()
380 {
381         int x, y;
382         static struct tmu_vertex srcmesh[TMU_MESH_MAXSIZE][TMU_MESH_MAXSIZE] __attribute__((aligned(8)));
383         struct tmu_td td;
384         volatile int complete;
385
386         for(y=0;y<=32;y++)
387                 for(x=0;x<=32;x++) {
388                         srcmesh[y][x].x = (10*x) << TMU_FIXEDPOINT_SHIFT;
389                         srcmesh[y][x].y = (7*y) << TMU_FIXEDPOINT_SHIFT;
390                 }
391
392         td.flags = 0;
393         td.hmeshlast = 32;
394         td.vmeshlast = 32;
395         td.brightness = TMU_BRIGHTNESS_MAX;
396         td.chromakey = 0;
397         td.vertices = &srcmesh[0][0];
398         td.texfbuf = vga_frontbuffer;
399         td.texhres = vga_hres;
400         td.texvres = vga_vres;
401         td.texhmask = TMU_MASK_FULL;
402         td.texvmask = TMU_MASK_FULL;
403         td.dstfbuf = vga_backbuffer;
404         td.dsthres = vga_hres;
405         td.dstvres = vga_vres;
406         td.dsthoffset = 0;
407         td.dstvoffset = 0;
408         td.dstsquarew = vga_hres/32;
409         td.dstsquareh = vga_vres/32;
410         
411         td.callback = tmutest_callback;
412         td.user = (void *)&complete;
413
414         complete = 0;
415         flush_bridge_cache();
416         tmu_submit_task(&td);
417         while(!complete);
418         vga_swap_buffers();
419 }
420
421 static unsigned short original[640*480*2] __attribute__((aligned(2)));
422
423 static void tmudemo()
424 {
425         int size;
426         unsigned int oldmask;
427         static struct tmu_vertex srcmesh[TMU_MESH_MAXSIZE][TMU_MESH_MAXSIZE] __attribute__((aligned(8)));
428         struct tmu_td td;
429         volatile int complete;
430         int w, speed;
431         int mindelta, xdelta, ydelta;
432
433         if(!cffat_init()) return;
434         if(!cffat_load("lena.raw", (void *)original, vga_hres*vga_vres*2, &size)) return;
435         cffat_done();
436
437         printf("done\n");
438         
439         /* Disable UI keys and slowout */
440         oldmask = irq_getmask();
441         irq_setmask(oldmask & (~IRQ_GPIO) & (~IRQ_TIMER1));
442         
443         speed = 0;
444         w = 512 << TMU_FIXEDPOINT_SHIFT;
445
446         xdelta = 0;
447         ydelta = 0;
448         while(1) {
449                 srcmesh[0][0].x = xdelta;
450                 srcmesh[0][0].y = ydelta;
451                 srcmesh[0][1].x = w+xdelta;
452                 srcmesh[0][1].y = ydelta;
453                 srcmesh[1][0].x = xdelta;
454                 srcmesh[1][0].y = w+ydelta;
455                 srcmesh[1][1].x = w+xdelta;
456                 srcmesh[1][1].y = w+ydelta;
457
458                 if(CSR_GPIO_IN & GPIO_DIP6) {
459                         if(CSR_GPIO_IN & GPIO_PBN)
460                                 ydelta += 16;
461                         if(CSR_GPIO_IN & GPIO_PBS)
462                                 ydelta -= 16;
463                         if(CSR_GPIO_IN & GPIO_PBE)
464                                 xdelta += 16;
465                         if(CSR_GPIO_IN & GPIO_PBW)
466                                 xdelta -= 16;
467                 } else {
468                         if(CSR_GPIO_IN & GPIO_PBN)
469                                 speed += 2;
470                         if(CSR_GPIO_IN & GPIO_PBS)
471                                 speed -= 2;
472                 }
473                 w += speed;
474                 if(w < 1) {
475                         w = 1;
476                         speed = 0;
477                 }
478                 if(xdelta > ydelta)
479                         mindelta = ydelta;
480                 else
481                         mindelta = xdelta;
482                 if(w > ((TMU_MASK_FULL >> 1)+mindelta)) {
483                         w = (TMU_MASK_FULL >> 1)+mindelta;
484                         speed = 0;
485                 }
486                 if(speed > 0) speed--;
487                 if(speed < 0) speed++;
488                 
489
490                 td.flags = 0;
491                 td.hmeshlast = 1;
492                 td.vmeshlast = 1;
493                 td.brightness = TMU_BRIGHTNESS_MAX;
494                 td.chromakey = 0;
495                 td.vertices = &srcmesh[0][0];
496                 td.texfbuf = original;
497                 td.texhres = vga_hres;
498                 td.texvres = vga_vres;
499                 td.texhmask = CSR_GPIO_IN & GPIO_DIP7 ? 0x7FFF : TMU_MASK_FULL;
500                 td.texvmask = CSR_GPIO_IN & GPIO_DIP8 ? 0x7FFF : TMU_MASK_FULL;
501                 td.dstfbuf = vga_backbuffer;
502                 td.dsthres = vga_hres;
503                 td.dstvres = vga_vres;
504                 td.dsthoffset = 0;
505                 td.dstvoffset = 0;
506                 td.dstsquarew = vga_hres;
507                 td.dstsquareh = vga_vres;
508
509                 td.callback = tmutest_callback;
510                 td.user = (void *)&complete;
511
512                 complete = 0;
513                 flush_bridge_cache();
514                 CSR_TIMER1_CONTROL = 0;
515                 CSR_TIMER1_COUNTER = 0;
516                 CSR_TIMER1_COMPARE = 0xffffffff;
517                 CSR_TIMER1_CONTROL = TIMER_ENABLE;
518                 tmu_submit_task(&td);
519                 while(!complete);
520                 CSR_TIMER1_CONTROL = 0;
521
522                 if(readchar_nonblock()) {
523                         char c;
524                         c = readchar();
525                         if(c == 'q') break;
526                         if(c == 's') {
527                                 unsigned int t;
528                                 t = CSR_TIMER1_COUNTER;
529                                 printf("Processing cycles: %d (%d Mpixels/s)\n", t, 640*480*100/t);
530                         }
531                 }
532                 vga_swap_buffers();
533         }
534         irq_ack(IRQ_GPIO);
535         irq_setmask(oldmask);
536 }
537
538 static short audio_buffer1[SND_MAX_NSAMPLES*2];
539 static short audio_buffer2[SND_MAX_NSAMPLES*2];
540 static short audio_buffer3[SND_MAX_NSAMPLES*2];
541 static short audio_buffer4[SND_MAX_NSAMPLES*2];
542
543 static void record_callback(short *buffer, void *user)
544 {
545         snd_play_refill(buffer);
546 }
547
548 static void play_callback(short *buffer, void *user)
549 {
550         snd_record_refill(buffer);
551 }
552
553 static void echo()
554 {
555         if(snd_play_active()) {
556                 snd_record_stop();
557                 snd_play_stop();
558                 printf("Digital Echo demo stopped\n");
559         } else {
560                 int i;
561
562                 snd_play_empty();
563                 for(i=0;i<AC97_MAX_DMASIZE/2;i++) {
564                         audio_buffer1[i] = 0;
565                         audio_buffer2[i] = 0;
566                 }
567                 snd_play_refill(audio_buffer1);
568                 snd_play_refill(audio_buffer2);
569                 snd_play_start(play_callback, SND_MAX_NSAMPLES, NULL);
570
571                 snd_record_empty();
572                 snd_record_refill(audio_buffer3);
573                 snd_record_refill(audio_buffer4);
574                 snd_record_start(record_callback, SND_MAX_NSAMPLES, NULL);
575                 printf("Digital Echo demo started\n");
576         }
577 }
578
579 static char *get_token(char **str)
580 {
581         char *c, *d;
582
583         c = (char *)strchr(*str, ' ');
584         if(c == NULL) {
585                 d = *str;
586                 *str = *str+strlen(*str);
587                 return d;
588         }
589         *c = 0;
590         d = *str;
591         *str = c+1;
592         return d;
593 }
594
595 static void do_command(char *c)
596 {
597         char *command, *param1, *param2, *param3;
598
599         command = get_token(&c);
600         param1 = get_token(&c);
601         param2 = get_token(&c);
602         param3 = get_token(&c);
603
604         if(strcmp(command, "mr") == 0) mr(param1, param2);
605         else if(strcmp(command, "mw") == 0) mw(param1, param2, param3);
606         else if(strcmp(command, "ls") == 0) ls();
607         else if(strcmp(command, "flush") == 0) flush_bridge_cache();
608         else if(strcmp(command, "render") == 0) render(param1);
609         else if(strcmp(command, "stop") == 0) ui_render_stop();
610         else if(strcmp(command, "spam") == 0) spam();
611         else if(strcmp(command, "stats") == 0) stats();
612         else if(strcmp(command, "reboot") == 0) reboot();
613         else if(strcmp(command, "help") == 0) help();
614
615         /* Networking */
616         else if(strcmp(command, "mdior") == 0) mdior(param1);
617         else if(strcmp(command, "mdiow") == 0) mdiow(param1, param2);
618
619         /* Test functions and hacks */
620         else if(strcmp(command, "loadpic") == 0) loadpic(param1);
621         else if(strcmp(command, "checker") == 0) checker();
622         else if(strcmp(command, "pfputest") == 0) pfputest();
623         else if(strcmp(command, "tmutest") == 0) tmutest();
624         else if(strcmp(command, "tmudemo") == 0) tmudemo();
625         else if(strcmp(command, "echo") == 0) echo();
626
627         else if(strcmp(command, "") != 0) printf("Command not found: '%s'\n", command);
628 }
629
630 static char command_buffer[64];
631 static unsigned int command_index;
632
633 static void prompt()
634 {
635         putsnonl("\e[1m% \e[0m");
636 }
637
638 void shell_init()
639 {
640         prompt();
641         command_index = 0;
642 }
643
644 void shell_input(char c)
645 {
646         cpustats_enter();
647         switch(c) {
648                 case 0x7f:
649                 case 0x08:
650                         if(command_index > 0) {
651                                 command_index--;
652                                 putsnonl("\x08 \x08");
653                         }
654                         break;
655                 case '\r':
656                 case '\n':
657                         command_buffer[command_index] = 0x00;
658                         putsnonl("\n");
659                         command_index = 0;
660                         do_command(command_buffer);
661                         prompt();
662                         break;
663                 default:
664                         if(command_index < (sizeof(command_buffer)-1)) {
665                                 writechar(c);
666                                 command_buffer[command_index] = c;
667                                 command_index++;
668                         }
669                         break;
670         }
671         cpustats_leave();
672 }