blob: 4dfc78d58cc052bfe381d5958066ee916b89f843 [file] [log] [blame]
Maurus Cuelenaere0709f0a2008-07-14 15:03:10 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2008 by Maurus Cuelenaere
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
Maurus Cuelenaere0709f0a2008-07-14 15:03:10 +000022#include "config.h"
23#include "jz4740.h"
24#include "backlight.h"
25#include "font.h"
26#include "lcd.h"
Nils Wallménius304c6222009-08-19 22:36:39 +000027#include "file.h"
Maurus Cuelenaere40ec5432008-12-19 11:13:58 +000028#include "usb.h"
Maurus Cuelenaere0709f0a2008-07-14 15:03:10 +000029#include "system.h"
Maurus Cuelenaere0709f0a2008-07-14 15:03:10 +000030#include "button.h"
Maurus Cuelenaere975261f2008-07-16 15:25:35 +000031#include "common.h"
Maurus Cuelenaere9da24562008-12-19 11:29:18 +000032#include "storage.h"
Maurus Cuelenaere04c73792009-02-09 10:02:38 +000033#include "disk.h"
34#include "string.h"
Maurus Cuelenaerebe8a27a2009-04-20 18:28:51 +000035#include "adc.h"
Rafaël Carré5d236b22010-05-27 09:41:46 +000036#include "version.h"
Maurus Cuelenaere0709f0a2008-07-14 15:03:10 +000037
Maurus Cuelenaerecf9935d2009-07-17 14:30:42 +000038extern int show_logo(void);
Maurus Cuelenaerecaf20112009-08-19 00:26:06 +000039extern void power_off(void);
Maurus Cuelenaerecf9935d2009-07-17 14:30:42 +000040
Maurus Cuelenaere04c73792009-02-09 10:02:38 +000041static void show_splash(int timeout, const char *msg)
42{
43 reset_screen();
44 lcd_putsxy( (LCD_WIDTH - (SYSFONT_WIDTH * strlen(msg))) / 2,
45 (LCD_HEIGHT - SYSFONT_HEIGHT) / 2, msg);
46 lcd_update();
47
48 sleep(timeout);
49}
50
Maurus Cuelenaere04c73792009-02-09 10:02:38 +000051static void usb_mode(void)
52{
53 int button;
Maurus Cuelenaerec4682732009-07-01 14:39:39 +000054
Maurus Cuelenaere04c73792009-02-09 10:02:38 +000055 /* Init USB */
56 usb_init();
57 usb_start_monitoring();
58
59 /* Wait for threads to connect */
60 show_splash(HZ/2, "Waiting for USB");
61
62 while (1)
63 {
64 button = button_get_w_tmo(HZ/2);
65
66 if (button == SYS_USB_CONNECTED)
67 break; /* Hit */
68 }
69
70 if (button == SYS_USB_CONNECTED)
71 {
72 /* Got the message - wait for disconnect */
73 show_splash(0, "Bootloader USB mode");
74
75 usb_acknowledge(SYS_USB_CONNECTED_ACK);
76
77 while (1)
78 {
79 button = button_get(true);
80 if (button == SYS_USB_DISCONNECTED)
81 {
82 usb_acknowledge(SYS_USB_DISCONNECTED_ACK);
83 break;
84 }
85 }
86 }
Maurus Cuelenaere04c73792009-02-09 10:02:38 +000087}
88
Maurus Cuelenaerecf9935d2009-07-17 14:30:42 +000089static int boot_of(void)
Maurus Cuelenaere04c73792009-02-09 10:02:38 +000090{
Maurus Cuelenaerecf9935d2009-07-17 14:30:42 +000091 int fd, rc, len, i, checksum = 0;
92 void (*kernel_entry)(int, void*, void*);
93
Maurus Cuelenaeref7b4ed32009-08-21 22:37:27 +000094 printf("Mounting disk...");
95 rc = disk_mount_all();
96 if (rc <= 0)
97 error(EDISK,rc);
98
Maurus Cuelenaerecf9935d2009-07-17 14:30:42 +000099 /* TODO: get this from the NAND flash instead of SD */
100 fd = open("/ccpmp.bin", O_RDONLY);
101 if(fd < 0)
102 return EFILE_NOT_FOUND;
103
104 lseek(fd, 4, SEEK_SET);
105 rc = read(fd, (char*)&len, 4); /* CPU is LE */
106 if(rc < 4)
107 return EREAD_IMAGE_FAILED;
108
109 len += 8;
110 printf("Reading %d bytes...", len);
111
112 lseek(fd, 0, SEEK_SET);
113 rc = read(fd, (void*)0x80004000, len);
114 if(rc < len)
115 return EREAD_IMAGE_FAILED;
116
117 close(fd);
118
119 for(i=0; i<len; i++)
120 checksum += ((unsigned char*)0x80004000)[i];
121
122 *((unsigned int*)0x80004000) = checksum;
123
124 printf("Starting the OF...");
125
126 /* OF requires all clocks on */
127 __cpm_start_all();
128
129 disable_interrupt();
130 __dcache_writeback_all();
131 __icache_invalidate_all();
132
133 for(i=8000; i>0; i--)
134 asm volatile("nop\n");
135
136 kernel_entry = (void*) 0x80004008;
137 kernel_entry(0, "Jan 10 2008", "15:34:42"); /* Reversed from the SPL */
138
Maurus Cuelenaerecaf20112009-08-19 00:26:06 +0000139 return 0; /* Shouldn't happen */
140}
141
142static int boot_rockbox(void)
143{
144 int rc;
145 void (*kernel_entry)(void);
146
Maurus Cuelenaeref7b4ed32009-08-21 22:37:27 +0000147 printf("Mounting disk...");
148 rc = disk_mount_all();
149 if (rc <= 0)
150 error(EDISK,rc);
151
152 printf("Loading firmware...");
Maurus Cuelenaerecaf20112009-08-19 00:26:06 +0000153 rc = load_firmware((unsigned char *)CONFIG_SDRAM_START, BOOTFILE, 0x400000);
154 if(rc < 0)
155 return rc;
156 else
157 {
158 printf("Starting Rockbox...");
159 adc_close(); /* Disable SADC, seems to fix the re-init Rockbox does */
160
161 disable_interrupt();
162 kernel_entry = (void*) CONFIG_SDRAM_START;
163 kernel_entry();
164
165 return 0; /* Shouldn't happen */
166 }
167}
168
Maurus Cuelenaeref7b4ed32009-08-21 22:37:27 +0000169static void reset_configuration(void)
170{
171 int rc;
172
173 rc = disk_mount_all();
174 if (rc <= 0)
175 error(EDISK,rc);
176
177 if(rename(ROCKBOX_DIR "/config.cfg", ROCKBOX_DIR "/config.old") == 0)
178 show_splash(HZ/2, "Configuration reset successfully!");
179 else
180 show_splash(HZ/2, "Couldn't reset configuration!");
181}
182
Maurus Cuelenaerecaf20112009-08-19 00:26:06 +0000183#define RECT_X (LCD_WIDTH/8)
184#define RECT_Y(i) (LCD_HEIGHT/20 + LCD_HEIGHT/10*i + RECT_HEIGHT*i)
185#define RECT_WIDTH (LCD_WIDTH*3/4)
186#define RECT_HEIGHT (LCD_HEIGHT/ARRAYLEN(strings) - LCD_HEIGHT/10)
187#define TEXT_X(i) (RECT_X + RECT_WIDTH/2 - strlen(strings[i])*SYSFONT_WIDTH/2)
188#define TEXT_Y(i) (RECT_Y(i) + RECT_HEIGHT/2 - SYSFONT_HEIGHT/2)
189static int boot_menu(void)
190{
Maurus Cuelenaeref7b4ed32009-08-21 22:37:27 +0000191 const char* strings[] = {"Boot Rockbox", "Boot OF", "USB mode", "Reset Rockbox configuration"};
Maurus Cuelenaerebfd42d62009-09-01 07:57:56 +0000192 int button, touch, poweroff_repeat = 0;
Maurus Cuelenaerecaf20112009-08-19 00:26:06 +0000193 unsigned int i;
194
Maurus Cuelenaeref7b4ed32009-08-21 22:37:27 +0000195 verbose = true;
Maurus Cuelenaerecaf20112009-08-19 00:26:06 +0000196 adc_init();
197
198redraw:
199 lcd_clear_display();
200 for(i=0; i<ARRAYLEN(strings); i++)
201 {
202 lcd_drawrect(RECT_X, RECT_Y(i), RECT_WIDTH, RECT_HEIGHT);
203 lcd_putsxy(TEXT_X(i), TEXT_Y(i), strings[i]);
204 }
205 lcd_update();
206
207 while(1)
208 {
209 button = button_get_w_tmo(HZ/4);
Maurus Cuelenaerebfd42d62009-09-01 07:57:56 +0000210 if(button & BUTTON_TOUCHSCREEN)
Maurus Cuelenaerecaf20112009-08-19 00:26:06 +0000211 {
212 touch = button_get_data();
213 unsigned int x = touch & 0xFFFF, y = touch >> 16;
214 int found = -1;
215 for(i=0; i<ARRAYLEN(strings); i++)
216 {
217 if(x > RECT_X && x < RECT_X+RECT_WIDTH &&
218 y > RECT_Y(i) && y < RECT_Y(i)+RECT_HEIGHT)
219 {
220 found = i;
221 break;
222 }
223 }
224
225 switch(found)
226 {
227 case 0:
Maurus Cuelenaeref7b4ed32009-08-21 22:37:27 +0000228 reset_screen();
229 boot_rockbox();
230 break;
Maurus Cuelenaerecaf20112009-08-19 00:26:06 +0000231 case 1:
Maurus Cuelenaeref7b4ed32009-08-21 22:37:27 +0000232 reset_screen();
233 boot_of();
234 break;
Maurus Cuelenaerecaf20112009-08-19 00:26:06 +0000235 case 2:
236 usb_mode();
237 break;
Maurus Cuelenaeref7b4ed32009-08-21 22:37:27 +0000238 case 3:
239 reset_configuration();
240 break;
Maurus Cuelenaerecaf20112009-08-19 00:26:06 +0000241 }
242
243 if(found != -1)
244 goto redraw;
245 }
Maurus Cuelenaerebfd42d62009-09-01 07:57:56 +0000246 else if(button & BUTTON_POWER)
Andree Buschmann5cebdcd2010-01-03 11:12:31 +0000247 {
248 if(poweroff_repeat++ > 8)
249 power_off();
250 }
251 else
252 poweroff_repeat = 0;
Maurus Cuelenaerecaf20112009-08-19 00:26:06 +0000253 }
Maurus Cuelenaere04c73792009-02-09 10:02:38 +0000254}
Maurus Cuelenaere0709f0a2008-07-14 15:03:10 +0000255
Maurus Cuelenaere0709f0a2008-07-14 15:03:10 +0000256int main(void)
Maurus Cuelenaere4bf4d2b2008-08-10 21:44:48 +0000257{
Maurus Cuelenaere3369a742009-04-21 15:47:39 +0000258 int rc;
259#ifdef HAVE_TOUCHSCREEN
260 int dummy;
261#endif
Maurus Cuelenaerec4682732009-07-01 14:39:39 +0000262
Maurus Cuelenaere0709f0a2008-07-14 15:03:10 +0000263 kernel_init();
264 lcd_init();
265 font_init();
266 lcd_setfont(FONT_SYSFIXED);
267 button_init();
Maurus Cuelenaerec4682732009-07-01 14:39:39 +0000268 backlight_init();
Maurus Cuelenaere0709f0a2008-07-14 15:03:10 +0000269
Maurus Cuelenaerecf9935d2009-07-17 14:30:42 +0000270 show_logo();
Maurus Cuelenaerec4682732009-07-01 14:39:39 +0000271
272 rc = storage_init();
273 if(rc)
274 error(EATA, rc);
275
Maurus Cuelenaeref7b4ed32009-08-21 22:37:27 +0000276 /* Don't mount the disks yet, there could be file system/partition errors
277 which are fixable in USB mode */
278
Maurus Cuelenaere04c73792009-02-09 10:02:38 +0000279#ifdef HAVE_TOUCHSCREEN
Maurus Cuelenaere4532d142009-02-13 00:45:49 +0000280 rc = button_read_device(&dummy);
Maurus Cuelenaere9407ae82008-09-17 21:44:47 +0000281#else
Maurus Cuelenaere04c73792009-02-09 10:02:38 +0000282 rc = button_read_device();
Maurus Cuelenaeree1446382008-09-05 15:09:40 +0000283#endif
Maurus Cuelenaerec4682732009-07-01 14:39:39 +0000284
Maurus Cuelenaerecf9935d2009-07-17 14:30:42 +0000285 if(rc)
286 verbose = true;
287
Maurus Cuelenaerecaf20112009-08-19 00:26:06 +0000288#ifdef BUTTON_VOL_UP
289 if(rc & BUTTON_VOL_UP ||
290#endif
Maurus Cuelenaeref7b4ed32009-08-21 22:37:27 +0000291#ifdef BUTTON_POWER
292 rc & BUTTON_POWER ||
293#endif
Maurus Cuelenaerecaf20112009-08-19 00:26:06 +0000294 0)
295 rc = boot_menu();
Maurus Cuelenaerecf9935d2009-07-17 14:30:42 +0000296
297 if(verbose)
298 reset_screen();
299 printf(MODEL_NAME" Rockbox Bootloader");
Rafaël Carré5d236b22010-05-27 09:41:46 +0000300 printf("Version " RBVERSION);
Maurus Cuelenaere04c73792009-02-09 10:02:38 +0000301
Maurus Cuelenaerecaf20112009-08-19 00:26:06 +0000302#ifdef HAS_BUTTON_HOLD
Maurus Cuelenaerecf9935d2009-07-17 14:30:42 +0000303 if(button_hold())
Maurus Cuelenaerecf9935d2009-07-17 14:30:42 +0000304 rc = boot_of();
Maurus Cuelenaerecaf20112009-08-19 00:26:06 +0000305 else
306#endif
307 rc = boot_rockbox();
Maurus Cuelenaerecf9935d2009-07-17 14:30:42 +0000308
Maurus Cuelenaere04c73792009-02-09 10:02:38 +0000309 if(rc < 0)
310 printf("Error: %s", strerror(rc));
311
Maurus Cuelenaere04c73792009-02-09 10:02:38 +0000312 /* Halt */
313 while (1)
314 core_idle();
Maurus Cuelenaerec4682732009-07-01 14:39:39 +0000315
Maurus Cuelenaere0709f0a2008-07-14 15:03:10 +0000316 return 0;
317}