2 * Copyright (C) 2013 Spreadtrum Communications Inc.
4 * This software is licensed under the terms of the GNU General Public
5 * License version 2, as published by the Free Software Foundation, and
6 * may be copied, distributed, and modified under those terms.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
14 #include "normal_mode.h"
18 #include <asm/sizes.h>
19 #include <boot_mode.h>
22 #include <linux/keypad.h>
23 #include <linux/key_code.h>
25 #include <linux/mtd/mtd.h>
26 #include <asm/global_data.h>
28 extern PUBLIC phys_size_t get_dram_size_from_gd(void);
30 extern void MMU_DisableIDCM(void);
31 extern int lcd_display_bitmap(ulong bmp_image, int x, int y);
32 extern lcd_display(void);
33 extern void set_backlight(uint32_t value);
34 extern void lcd_setfgcolor(int color);
36 void display_writing_sysdump(void)
38 debugf("%s\n", __FUNCTION__);
39 #ifdef CONFIG_SPLASH_SCREEN
43 //read boot image header
45 char * bmp_img = malloc(size);
47 debugf("not enough memory for splash image\n");
50 int ret = read_logoimg(bmp_img,size);
55 lcd_display_bitmap((ulong)bmp_img, 0, 0);
56 lcd_printf(" ------------------------------- \n"
57 " Sysdumpping now, keep power on. \n"
58 " ------------------------------- \n");
66 void display_special_mode(void)
68 debugf("%s\n", __FUNCTION__);
69 #ifdef CONFIG_SPLASH_SCREEN
73 //read boot image header
75 char * bmp_img = malloc(size);
77 debugf("not enough memory for splash image\n");
80 int ret = read_logoimg(bmp_img,size);
85 lcd_display_bitmap((ulong)bmp_img, 0, 0);
86 lcd_printf(" ------------------------------- \n"
87 " Restart now, keep power on. \n"
88 " ------------------------------- \n");
96 static void wait_for_keypress()
102 key_code = board_key_scan();
103 //printf("key_code: %d, (vd:%d,vu:%d,p:%d)\n", key_code, KEY_VOLUMEDOWN, KEY_VOLUMEUP, KEY_POWER);
104 if (key_code == KEY_VOLUMEDOWN || key_code == KEY_VOLUMEUP || key_code == KEY_HOME)
107 debugf("Pressed key: %d\n", key_code);
108 lcd_printf("Pressed key: %d\n", key_code);
112 int init_mmc_fat(void)
115 block_dev_desc_t *dev_desc = NULL;
119 mmc = find_mmc_device(0);
123 debugf("mmc init failed %d\n", ret);
127 debugf("no mmc card found\n");
131 dev_desc = &mmc->block_dev;
133 debugf("no mmc block device found\n");
137 ret = fat_register_device(dev_desc, 1);
139 debugf("fat regist fail %d\n", ret);
143 ret = file_fat_detectfs();
145 debugf("detect fs failed\n");
152 void write_mem_to_mmc(char *path, char *filename,
153 void *memaddr, unsigned long memsize)
158 do {} while (0); /* TODO: jianjun.he */
161 debugf("writing 0x%lx bytes to sd file %s\n",
163 lcd_printf("writing 0x%lx bytes to sd file %s\n", memsize, filename);
165 ret = file_fat_write(filename, memaddr, memsize);
167 debugf("sd file write error %d\n", ret);
173 extern unsigned check_reboot_mode(void);
176 static size_t get_elfhdr_size(int nphdr)
180 elfhdr_len = sizeof(struct elfhdr) +
181 (nphdr + 1) * sizeof(struct elf_phdr);
183 elfhdr_len += ((sizeof(struct elf_note)) +
184 roundup(sizeof(CORE_STR), 4)) * 3 +
185 roundup(sizeof(struct elf_prstatus), 4) +
186 roundup(sizeof(struct elf_prpsinfo), 4) +
187 roundup(sizeof(struct task_struct), 4);
189 elfhdr_len = PAGE_ALIGN(elfhdr_len); //why?
195 static int notesize(struct memelfnote *en)
199 sz = sizeof(struct elf_note);
200 sz += roundup((strlen(en->name) + 1), 4);
201 sz += roundup(en->datasz, 4);
206 static char *storenote(struct memelfnote *men, char *bufp)
210 #define DUMP_WRITE(addr,nr) do { memcpy(bufp,addr,nr); bufp += nr; } while(0)
212 en.n_namesz = strlen(men->name) + 1;
213 en.n_descsz = men->datasz;
214 en.n_type = men->type;
216 DUMP_WRITE(&en, sizeof(en));
217 DUMP_WRITE(men->name, en.n_namesz);
219 /* XXX - cast from long long to long to avoid need for libgcc.a */
220 bufp = (char*) roundup((unsigned long)bufp,4);
221 DUMP_WRITE(men->data, men->datasz);
222 bufp = (char*) roundup((unsigned long)bufp,4);
231 static void sysdump_fill_core_hdr(struct pt_regs *regs,
232 struct sysdump_mem *sysmem, int mem_num,
233 char *bufp, int nphdr, int dataoff)
236 struct elf_prstatus prstatus; /* NT_PRSTATUS */
237 struct elf_prpsinfo prpsinfo; /* NT_PRPSINFO */
239 struct elf_phdr *nhdr, *phdr;
241 struct memelfnote notes[3];
245 /* setup ELF header */
246 elf = (struct elfhdr *) bufp;
247 bufp += sizeof(struct elfhdr); //printk("sizeof(struct elfhdr): %d\n");
248 offset += sizeof(struct elfhdr); //printk("sizeof(struct elfhdr): %d\n");
249 memcpy(elf->e_ident, ELFMAG, SELFMAG); //printk("ELFMAG: %s, SELFMAG:%d\n", ELFMAG, SELFMAG);
250 elf->e_ident[EI_CLASS] = ELF_CLASS;//printk("EI_CLASS:%d, ELF_CLASS: %d", EI_CLASS, ELF_CLASS);
251 elf->e_ident[EI_DATA] = ELF_DATA;//printk("EI_DATA:%");
252 elf->e_ident[EI_VERSION]= EV_CURRENT;
253 elf->e_ident[EI_OSABI] = ELF_OSABI;
254 memset(elf->e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD);
255 elf->e_type = ET_CORE;
256 elf->e_machine = ELF_ARCH;
257 elf->e_version = EV_CURRENT;
259 elf->e_phoff = sizeof(struct elfhdr);
261 elf->e_flags = ELF_CORE_EFLAGS;
262 elf->e_ehsize = sizeof(struct elfhdr);
263 elf->e_phentsize= sizeof(struct elf_phdr);
264 elf->e_phnum = nphdr;
269 /* setup ELF PT_NOTE program header */
270 nhdr = (struct elf_phdr *) bufp;
271 bufp += sizeof(struct elf_phdr);
272 offset += sizeof(struct elf_phdr);
273 nhdr->p_type = PT_NOTE;
282 /* setup ELF PT_LOAD program header for every area */
283 for (i = 0; i < mem_num; i++) {
284 phdr = (struct elf_phdr *) bufp;
285 bufp += sizeof(struct elf_phdr);
286 offset += sizeof(struct elf_phdr);
288 phdr->p_type = PT_LOAD;
289 phdr->p_flags = PF_R|PF_W|PF_X;
290 phdr->p_offset = dataoff;
291 phdr->p_vaddr = sysmem[i].vaddr;
292 phdr->p_paddr = sysmem[i].paddr;
293 phdr->p_filesz = phdr->p_memsz = sysmem[i].size;
294 phdr->p_align = 0;//PAGE_SIZE;
295 dataoff += sysmem[i].size;
299 * Set up the notes in similar form to SVR4 core dumps made
300 * with info from their /proc.
302 nhdr->p_offset = offset;
304 /* set up the process status */
305 notes[0].name = CORE_STR;
306 notes[0].type = NT_PRSTATUS;
307 notes[0].datasz = sizeof(struct elf_prstatus);
308 notes[0].data = &prstatus;
310 memset(&prstatus, 0, sizeof(struct elf_prstatus));
311 //fill_prstatus(&prstatus, current, 0);
313 // memcpy(&prstatus.pr_reg, regs, sizeof(*regs));
315 // crash_setup_regs((struct pt_regs *)&prstatus.pr_reg, NULL);
317 nhdr->p_filesz = notesize(¬es[0]);
318 bufp = storenote(¬es[0], bufp);
320 /* set up the process info */
321 notes[1].name = CORE_STR;
322 notes[1].type = NT_PRPSINFO;
323 notes[1].datasz = sizeof(struct elf_prpsinfo);
324 notes[1].data = &prpsinfo;
326 memset(&prpsinfo, 0, sizeof(struct elf_prpsinfo));
327 //fill_psinfo(&prpsinfo, current, current->mm);
329 strcpy(prpsinfo.pr_fname, "vmlinux");
330 //strncpy(prpsinfo.pr_psargs, saved_command_line, ELF_PRARGSZ);
332 nhdr->p_filesz += notesize(¬es[1]);
333 bufp = storenote(¬es[1], bufp);
335 /* set up the task structure */
336 notes[2].name = CORE_STR;
337 notes[2].type = NT_TASKSTRUCT;
338 notes[2].datasz = sizeof(struct task_struct);
339 notes[2].data = current;
341 printk("%s: data size is %d, data addr is %p",__func__,notes[2].datasz,notes[2].data);
343 nhdr->p_filesz += notesize(¬es[2]);
344 bufp = storenote(¬es[2], bufp);
347 } /* end elf_kcore_store_hdr() */
349 #define PROD_PART "prodnv"
350 int sysdump_flag_check(void)
352 char sysdump_buf[200]={0};
354 memset(sysdump_buf,0x0,200);
355 if(!do_fs_file_read(PROD_PART, "sysdump_flag", sysdump_buf,200))
356 debugf("file: sysdump_flag is exist\n");
358 debugf("file: sysdump_flag is not exist\n");
359 #ifdef SYSDUMP_BYPASS
366 if(!strncmp(sysdump_buf, "on", 2))
372 "fastboot", // 0x77665500 FASTBOOT_MODE
373 "manual dump", // 0x01 UNDEFINE_MODE
374 "recovery", // 0x77665502 RECOVERY_MODE
375 "normal", // 0x77665503 NORMAL_MODE
376 "alarm", // 0x77665504 ALARM_MODE
377 "sleep", // 0x77665505 SLEEP_MODE
378 "watchdogtimeout", // 0x77665506 WATCHDOG_REBOOT
379 "framework crash", // 0x77665507 SPECIAL_MODE
380 "manual dump", // 0x77665508 UNKNOW_REBOOT_MODE
381 "kernel crash", // 0x77665509 PANIC_REBOOT
382 "calibration", // 0x7766550a CALIBRATION_MODE
385 #define GET_RST_MODE(x) rstmode[(((x)&0x0F) < 0x0b) ? ((x)&0x0F) : 1]
387 #ifndef CONFIG_EMMC_BOOT
388 /*Copy the data saved in nand flash to ram*/
389 int read_nand_to_ram( struct mtd_info *mtd, loff_t paddr, unsigned int size, unsigned char *buf)
392 unsigned int retlen = 0;
393 loff_t read_addr = 0;
394 unsigned char *read_buf = NULL;
395 unsigned int readsize = 0;
397 debugf("%s, read 0x%.8x:0x%.8x buf: 0x%.8x\n", __func__, (unsigned int)paddr, size, buf);
398 for(read_addr = paddr, read_buf = buf; read_addr < (paddr + size); read_addr += readsize, read_buf += readsize) {
399 readsize = (paddr + size - read_addr) > mtd->erasesize ? mtd->erasesize : (paddr + size - read_addr);
400 if(mtd->block_isbad(mtd, read_addr) == 1) {//if met bad block, we just fill it with 0x5a
401 memset(read_buf, 0x5a, readsize);
405 ret = mtd->read(mtd, read_addr, readsize, &retlen, read_buf);
406 if(ret != 0 && retlen != readsize) {
407 printf("%s, read addr: 0x%.8x len: 0x%.8x 's value err, ret: %d, retlen: 0x%.8x\n",\
408 __func__, (unsigned int)read_addr, readsize, ret, retlen);
409 lcd_printf("\nRead nand flash 0x%.8x error, you can dump it use download tools again!\n", read_addr);
417 /*dump the data saved in nand flash to sdcard when needed*/
421 unsigned int write_len = 0, write_addr = 0;
423 unsigned int part_len = 0x8000000;//The size of each ubipac-part file
426 struct mtd_info *mtd = NULL;
428 buf = SCRATCH_ADDR;//After dump memory to sdcard, we suppose the whole memory except u-boot used are avaliable.
429 mtd = get_mtd_device_nm(UBIPAC_PART);
431 printf("Can't get the mtd part: %s\n", UBIPAC_PART);
435 debugf("Begin to dump 0x%.8x ubipac to sdcard!\n", mtd->size);
436 for(write_addr = 0; write_addr < mtd->size; write_addr += write_len, loop++)
438 write_len = (mtd->size - write_addr) > part_len ? part_len : (mtd->size - write_addr);
439 debugf("begin to read 0x%.8x value to ubipac%d\n", write_len, loop);
440 memset(buf, 0, write_len);
441 ret = read_nand_to_ram(mtd, (loff_t)(write_addr), write_len, buf);
443 printf("%s, read ubipac%d error, the ret is %d\n", __func__, loop, ret);
446 debugf("read ubipac%d end\n", loop);
448 memset(fname, 0, 72);
449 sprintf(fname, "ubipac%d", loop);
450 write_mem_to_mmc(NULL, fname, buf, write_len);
451 debugf("write ubipac%d end\n", loop);
458 void write_sysdump_before_boot(int rst_mode)
461 char fnbuf[72], *path;
464 struct sysdump_mem *mem;
465 struct sysdump_info *infop = (struct sysdump_info *)SPRD_SYSDUMP_MAGIC;
467 struct sysdump_mem sprd_dump_mem[] = {
469 .paddr = CONFIG_PHYS_OFFSET,
470 .vaddr = PAGE_OFFSET,
472 .size = REAL_SDRAM_SIZE,
477 int sprd_dump_mem_num = 1;
479 debugf("rst_mode:0x%x, Check if need to write sysdump info of 0x%08lx to file...\t", rst_mode,
482 if ((rst_mode == WATCHDOG_REBOOT) || (rst_mode == UNKNOW_REBOOT_MODE) || (rst_mode == EXT_RSTN_REBOOT_MODE) || \
483 ((rst_mode == PANIC_REBOOT) && !memcmp(infop->magic, SYSDUMP_MAGIC, sizeof(infop->magic))) || (rst_mode == SPECIAL_MODE) ) {
486 memset(infop->magic, 0, sizeof(infop->magic));
488 if(-1 == sysdump_flag_check()) {
489 debugf("skip sysdump because sysdump_flag is close.\n");
496 /* display on screen */
497 display_writing_sysdump();
498 #define CONSOLE_COLOR_RED (0x1f<<11)
499 #define CONSOLE_COLOR_GREEN 0x07e0
500 lcd_setfgcolor(CONSOLE_COLOR_GREEN);
501 lcd_printf("\nReset mode: %s\n\n",GET_RST_MODE(rst_mode));
502 lcd_setfgcolor(CONSOLE_COLOR_RED);
505 if ((rst_mode == WATCHDOG_REBOOT) || (rst_mode == UNKNOW_REBOOT_MODE) || (rst_mode == EXT_RSTN_REBOOT_MODE) || (rst_mode == SPECIAL_MODE)) {
506 infop->dump_path[0] = '\0';
507 infop->mem_num = sprd_dump_mem_num;
508 infop->dump_mem_paddr = (unsigned long)sprd_dump_mem;
509 strcpy(infop->time, "hw_watchdog");
510 infop->elfhdr_size = get_elfhdr_size(infop->mem_num);
511 infop->crash_key = 0;
513 sysdump_fill_core_hdr(NULL,
516 (char *)infop + sizeof(*infop),
521 if (strlen(infop->dump_path))
522 path = infop->dump_path;
526 sprintf(fnbuf, SYSDUMP_CORE_NAME_FMT, 0);
527 write_mem_to_mmc(path, fnbuf,
528 (char *)infop + sizeof(*infop), infop->elfhdr_size);
530 #if 1 /* TODO: jianjun.he */
531 mem = (struct sysdump_mem *)infop->dump_mem_paddr;
532 for (i = 0; i < infop->mem_num; i++) {
533 if (0xffffffff != mem[i].soff)
534 waddr = (char *)infop + sizeof(*infop) +
535 infop->elfhdr_size + mem[i].soff;
537 waddr = mem[i].paddr;
539 #ifdef CONFIG_RAMDUMP_NO_SPLIT
540 sprintf(fnbuf, SYSDUMP_CORE_NAME_FMT"_0x%8.8x-0x%8.8x_dump.lst", i + 1, mem[i].paddr, mem[i].paddr + mem[i].size -1);
541 write_mem_to_mmc(path, fnbuf, waddr, mem[i].size);
543 if (mem[i].size <= SZ_8M) {
544 sprintf(fnbuf, SYSDUMP_CORE_NAME_FMT, /*infop->time,*/ i + 1);
545 write_mem_to_mmc(path, fnbuf, waddr, mem[i].size);
547 for (j = 0; j < mem[i].size / SZ_8M; j++) {
548 sprintf(fnbuf, SYSDUMP_CORE_NAME_FMT"_%03d",
549 /*infop->time,*/ i + 1, j);
550 write_mem_to_mmc(path, fnbuf, waddr + j * SZ_8M, SZ_8M);
553 if (mem[i].size % SZ_8M) {
554 sprintf(fnbuf, SYSDUMP_CORE_NAME_FMT"_%03d",
555 /*infop->time,*/ i + 1, j);
556 write_mem_to_mmc(path, fnbuf, waddr + j * SZ_8M,
557 (mem[i].size % SZ_8M));
563 for (i = 0; i < infop->mem_num; i++) {
564 sprintf(fnbuf, SYSDUMP_CORE_NAME_FMT, /*infop->time,*/ i + 1);
565 write_mem_to_mmc(path, fnbuf, mem[i].paddr, mem[i].size);
569 #ifndef CONFIG_EMMC_BOOT
570 lcd_printf("\nBegin to dump nand flash:\n");
574 debugf("\nwriting done.\nPress any key to continue...");
575 lcd_printf("\nWriting done.\nPress any key (Exp power key) to continue...");
579 debugf("no need.\n");