From ebb612fbcc87a9547a3603ef6188a26b0760a9aa Mon Sep 17 00:00:00 2001 From: Maurus Cuelenaere Date: Tue, 15 Jul 2008 17:17:01 +0000 Subject: Onda VX747: 1) Improve touchscreen handling 2) Add RTC driver 4) Add NAND Flash ID scanning 3) Other minor fixes Nand_ID: Add a generic NAND ID database (currently only containg Samsung chips) git-svn-id: svn://svn.rockbox.org/rockbox/trunk@18052 a1c6a512-1295-4272-9138-f99709370657 --- firmware/SOURCES | 5 +- firmware/common/timefuncs.c | 9 +- firmware/drivers/nand_id.c | 73 +++++ firmware/drivers/rtc/rtc_jz4740.c | 307 +++++++++++++++++++++ firmware/export/config-ondavx747.h | 8 +- firmware/export/nand_id.h | 38 +++ firmware/target/mips/ingenic_jz47xx/ata-jz4740.c | 40 --- .../target/mips/ingenic_jz47xx/ata-nand-jz4740.c | 68 +++++ .../ingenic_jz47xx/onda_vx747/button-onda_vx747.c | 33 ++- .../target/mips/ingenic_jz47xx/system-jz4740.c | 8 +- 10 files changed, 524 insertions(+), 65 deletions(-) create mode 100644 firmware/drivers/nand_id.c create mode 100644 firmware/drivers/rtc/rtc_jz4740.c create mode 100644 firmware/export/nand_id.h delete mode 100644 firmware/target/mips/ingenic_jz47xx/ata-jz4740.c create mode 100644 firmware/target/mips/ingenic_jz47xx/ata-nand-jz4740.c (limited to 'firmware') diff --git a/firmware/SOURCES b/firmware/SOURCES index 89f5a26c78..99e880c19a 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES @@ -155,6 +155,8 @@ drivers/rtc/rtc_mr100.c drivers/rtc/rtc_mc13783.c #elif (CONFIG_RTC == RTC_TCC77X) drivers/rtc/rtc_tcc77x.c +#elif (CONFIG_RTC == RTC_JZ47XX) +drivers/rtc/rtc_jz4740.c #endif /* (CONFIG_RTC == RTC_) */ #endif /* SIMULATOR */ @@ -1073,9 +1075,10 @@ target/arm/s5l8700/meizu-m6sl/lcd-m6sl.c #endif /* MEIZU_M6SL */ #if CONFIG_CPU==JZ4732 -target/mips/ingenic_jz47xx/ata-jz4740.c +target/mips/ingenic_jz47xx/ata-nand-jz4740.c target/mips/ingenic_jz47xx/lcd-jz4740.c target/mips/ingenic_jz47xx/system-jz4740.c +drivers/nand_id.c #endif #ifdef ONDA_VX747 diff --git a/firmware/common/timefuncs.c b/firmware/common/timefuncs.c index 1bf29d203c..d46b961a8c 100644 --- a/firmware/common/timefuncs.c +++ b/firmware/common/timefuncs.c @@ -52,10 +52,12 @@ struct tm *get_time(void) static long timeout = 0; /* Don't read the RTC more than once per second */ - if (current_tick > timeout) { - char rtcbuf[7]; + if (current_tick > timeout) + { /* Once per second, 1/10th of a second off */ timeout = HZ * (current_tick / HZ + 1) + HZ / 5; +#if CONFIG_RTC != RTC_JZ47XX + char rtcbuf[7]; rtc_read_datetime(rtcbuf); tm.tm_sec = ((rtcbuf[0] & 0x70) >> 4) * 10 + (rtcbuf[0] & 0x0f); @@ -76,6 +78,9 @@ struct tm *get_time(void) tm.tm_yday = 0; /* Not implemented for now */ tm.tm_isdst = -1; /* Not implemented for now */ +#else + rtc_read_datetime((unsigned char*)&tm); +#endif } #else tm.tm_sec = 0; diff --git a/firmware/drivers/nand_id.c b/firmware/drivers/nand_id.c new file mode 100644 index 0000000000..ab10ecec07 --- /dev/null +++ b/firmware/drivers/nand_id.c @@ -0,0 +1,73 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2008 by Maurus Cuelenaere + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include +#include "nand_id.h" + +struct nand_manufacturer +{ + unsigned char id; + struct nand_info* info; + unsigned short total; +}; + +/* { pages_per_block, blocks_per_bank, page_size, spare_size, col_cycles, row_cycles } */ + +static const struct nand_info samsung[] = +{ + /* K9K8G08UOM */ + {0xD3, 0x51, 64, 8192, 2048, 64, 2, 3}, + /* K9LAG08UOM */ + {0xD5, 0x55, 128, 8192, 2048, 64, 2, 3}, + /* K9LBG08UOM, K9HBG08U1M, K9MCG08U5M */ + {0xD7, 0x55, 128, 8192, 4096, 128, 2, 3}, +}; + +#define M(id, x) {id, (struct nand_info*)x, (sizeof(x)/sizeof(struct nand_info))} +static const struct nand_manufacturer all[] = +{ + M(0xEC, samsung), +}; + +struct nand_info* nand_identify(unsigned char data[5]) + { + unsigned int i; + int found = -1; + for(i = 0; i < (sizeof(all)/sizeof(struct nand_manufacturer)); i++) + { + if(data[0] == all[i].id) + { + found = i; + break; + } + } + if(found < 0) + return NULL; + + for(i = 0; i < all[found].total; i++) + { + if(data[1] == all[found].info[i].dev_id && + data[2] == all[found].info[i].dev_id2) + return &all[found].info[i]; + } + + return NULL; +} diff --git a/firmware/drivers/rtc/rtc_jz4740.c b/firmware/drivers/rtc/rtc_jz4740.c new file mode 100644 index 0000000000..b9cceec9af --- /dev/null +++ b/firmware/drivers/rtc/rtc_jz4740.c @@ -0,0 +1,307 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2008 by Maurus Cuelenaere + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +/* + * Jz OnChip Real Time Clock interface for Linux + * + */ + +#include "config.h" +#include "jz4740.h" +#include "rtc.h" +#include "timefuncs.h" + +static unsigned int epoch = 1900; +static const unsigned char days_in_mo[] = { + 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 +}; + +static const unsigned int yearday[5] = {0, 366, 366+365, 366+365*2, 366+365*3}; +static const unsigned int sweekday = 6; +static const unsigned int sum_monthday[13] = { + 0, + 31, + 31+28, + 31+28+31, + 31+28+31+30, + 31+28+31+30+31, + 31+28+31+30+31+30, + 31+28+31+30+31+30+31, + 31+28+31+30+31+30+31+31, + 31+28+31+30+31+30+31+31+30, + 31+28+31+30+31+30+31+31+30+31, + 31+28+31+30+31+30+31+31+30+31+30, + 365 +}; + +static unsigned int jz_mktime(int year, int mon, int day, int hour, int min, int sec) +{ + unsigned int seccounter; + + if (year < 2000) + year = 2000; + year -= 2000; + seccounter = (year/4)*(365*3+366); + seccounter += yearday[year%4]; + if (year%4) + seccounter += sum_monthday[mon-1]; + else + if (mon >= 3) + seccounter += sum_monthday[mon-1]+1; + else + seccounter += sum_monthday[mon-1]; + seccounter += day-1; + seccounter *= 24; + seccounter += hour; + seccounter *= 60; + seccounter += min; + seccounter *= 60; + seccounter += sec; + + return seccounter; +} + +static void jz_gettime(unsigned int rtc, int *year, int *mon, int *day, int *hour, + int *min, int *sec, int *weekday) +{ + unsigned int tday, tsec, i, tmp; + + tday = rtc/(24*3600); + *weekday = ((tday % 7) + sweekday) % 7; + *year = (tday/(366+365*3)) * 4; + tday = tday%(366+365*3); + for (i=0;i<5;i++) + { + if (tday=2)) + tmp += 1; + if (tday=2)) + tmp += 1; + *day = tday - tmp + 1; + break; + } + } + tsec = rtc % (24 * 3600); + *hour = tsec / 3600; + *min = (tsec / 60) % 60; + *sec = tsec - *hour*3600 - *min*60; + *year += 2000; +} + +int rtc_read_datetime(unsigned char* buf) +{ + struct tm rtc_tm; + unsigned int sec,mon,mday,wday,year,hour,min; + + /* + * Only the values that we read from the RTC are set. We leave + * tm_wday, tm_yday and tm_isdst untouched. Even though the + * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated + * by the RTC when initially set to a non-zero value. + */ + jz_gettime(REG_RTC_RSR, &year, &mon, &mday, &hour, &min, &sec, &wday); + + year -= 2000; + + rtc_tm.tm_sec = sec; + rtc_tm.tm_min = min; + rtc_tm.tm_hour = hour; + rtc_tm.tm_mday = mday; + rtc_tm.tm_wday = wday; + /* Don't use centry, but start from year 1970 */ + rtc_tm.tm_mon = mon; + if ((year += (epoch - 1900)) <= 69) + year += 100; + rtc_tm.tm_year = year + 1900; + + rtc_tm.tm_yday = 0; /* Not implemented for now */ + rtc_tm.tm_isdst = -1; /* Not implemented for now */ + + (*((struct tm*)buf)) = rtc_tm; + return 1; +} + +#if 0 +void get_rtc_alm_time(struct rtc_time *alm_tm) +{ + unsigned int sec,mon,mday,wday,year,hour,min; + unsigned int lval; + unsigned long flags; + /* + * Only the values that we read from the RTC are set. That + * means only tm_hour, tm_min, and tm_sec. + */ + lval = REG_RTC_RSAR; + jz_gettime(lval, &year, &mon, &mday, &hour, &min, &sec, &wday); + + alm_tm->tm_sec = sec; + alm_tm->tm_min = min; + alm_tm->tm_hour = hour; +} + + +int rtc_ioctl(unsigned int cmd,struct rtc_time *val,unsigned int epo) +{ + struct rtc_time wtime; + switch (cmd) { + case RTC_ALM_READ: /* Read the present alarm time */ + /* + * This returns a struct rtc_time. Reading >= 0xc0 + * means "don't care" or "match all". Only the tm_hour, + * tm_min, and tm_sec values are filled in. + */ + get_rtc_alm_time(val); + break; + case RTC_ALM_SET: /* Store a time into the alarm */ + { + unsigned char ahrs, amin, asec; + unsigned int sec,mon,mday,wday,year,hour,min; + unsigned int lval; + unsigned long flags; + struct rtc_time alm_tm; + + alm_tm = *val; + ahrs = alm_tm.tm_hour; + amin = alm_tm.tm_min; + asec = alm_tm.tm_sec; + + + + if (ahrs >= 24) + return -1; + + if (amin >= 60) + return -1; + + if (asec >= 60) + return -1; + + flags = spin_lock_irqsave(); + lval = REG_RTC_RSR; + jz_gettime(lval, &year, &mon, &mday, &hour, &min, &sec, &wday); + hour = ahrs; + min = amin; + sec = asec; + lval = jz_mktime(year, mon, mday, hour, min, sec); + REG_RTC_RSAR = lval; + spin_unlock_irqrestore(flags); + break; + } + case RTC_RD_TIME: /* Read the time/date from RTC */ + get_rtc_time(val); + break; + case RTC_SET_TIME: /* Set the RTC */ + { + struct rtc_time rtc_tm; + unsigned int mon, day, hrs, min, sec, leap_yr, date; + unsigned int yrs; + unsigned int lval; + unsigned long flags; + + rtc_tm = *val; + yrs = rtc_tm.tm_year;// + 1900; + mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */ + day = rtc_tm.tm_wday; + date = rtc_tm.tm_mday; + hrs = rtc_tm.tm_hour; + min = rtc_tm.tm_min; + sec = rtc_tm.tm_sec; + + + if (yrs < 1970) + return -EINVAL; + leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400)); + + if ((mon > 12) || (date == 0)) + return -EINVAL; + + if (date > (days_in_mo[mon] + ((mon == 2) && leap_yr))) + return -EINVAL; + + if ((hrs >= 24) || (min >= 60) || (sec >= 60)) + return -EINVAL; + + if ((yrs -= epoch) > 255) /* They are unsigned */ + return -EINVAL; + + flags = spin_lock_irqsave(); + /* These limits and adjustments are independant of + * whether the chip is in binary mode or not. + */ + + if (yrs > 169) { + spin_unlock_irqrestore(flags); + return -EINVAL; + } + + yrs += epoch; + lval = jz_mktime(yrs, mon, date, hrs, min, sec); + REG_RTC_RSR = lval; + /* FIXME: maybe we need to write alarm register here. */ + spin_unlock_irqrestore(flags); + + return 0; + } + break; + case RTC_EPOCH_READ: /* Read the epoch. */ + epo = epoch; + return 0; + case RTC_EPOCH_SET: /* Set the epoch. */ + /* + * There were no RTC clocks before 1900. + */ + if (epo < 1900) + return -EINVAL; + + epoch = epo; + return 0; + default: + return -EINVAL; + } + return -EINVAL; +} +#endif + +#define udelay(x) for(i=0; i ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id: ata.h 17847 2008-06-28 18:10:04Z bagder $ + * + * Copyright (C) 2002 by Alan Korr + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#ifndef __NAND_ID_H__ +#define __NAND_ID_H__ + +struct nand_info +{ + unsigned char dev_id; + unsigned char dev_id2; + unsigned short pages_per_block; + unsigned short blocks_per_bank; + unsigned short page_size; + unsigned short spare_size; + unsigned short col_cycles; + unsigned short row_cycles; +}; + +struct nand_info* nand_identify(unsigned char data[5]); + +#endif /* __NAND_ID_H__ */ diff --git a/firmware/target/mips/ingenic_jz47xx/ata-jz4740.c b/firmware/target/mips/ingenic_jz47xx/ata-jz4740.c deleted file mode 100644 index b907bb86df..0000000000 --- a/firmware/target/mips/ingenic_jz47xx/ata-jz4740.c +++ /dev/null @@ -1,40 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2008 by Maurus Cuelenaere - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ - -#include "config.h" -#include "jz4740.h" -#include "ata.h" - -int ata_read_sectors(IF_MV2(int drive,) unsigned long start, int count, void* buf) -{ - (void)start; - (void)count; - (void)buf; - return 0; -} - -int ata_write_sectors(IF_MV2(int drive,) unsigned long start, int count, const void* buf) -{ - (void)start; - (void)count; - (void)buf; - return 0; -} diff --git a/firmware/target/mips/ingenic_jz47xx/ata-nand-jz4740.c b/firmware/target/mips/ingenic_jz47xx/ata-nand-jz4740.c new file mode 100644 index 0000000000..ad053c7deb --- /dev/null +++ b/firmware/target/mips/ingenic_jz47xx/ata-nand-jz4740.c @@ -0,0 +1,68 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2008 by Maurus Cuelenaere + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include "config.h" +#include "jz4740.h" +#include "ata.h" + +#define NAND_CMD_READ1_00 0x00 +#define NAND_CMD_READ1_01 0x01 +#define NAND_CMD_READ2 0x50 +#define NAND_CMD_READ_ID1 0x90 +#define NAND_CMD_READ_ID2 0x91 +#define NAND_CMD_RESET 0xFF +#define NAND_CMD_PAGE_PROGRAM_START 0x80 +#define NAND_CMD_PAGE_PROGRAM_STOP 0x10 +#define NAND_CMD_BLOCK_ERASE_START 0x60 +#define NAND_CMD_BLOCK_ERASE_CONFIRM 0xD0 +#define NAND_CMD_READ_STATUS 0x70 + +#define NANDFLASH_CLE 0x00008000 //PA[15] +#define NANDFLASH_ALE 0x00010000 //PA[16] + +#define NANDFLASH_BASE 0xB8000000 +#define REG_NAND_DATA (*((volatile unsigned char *) NANDFLASH_BASE)) +#define REG_NAND_CMD (*((volatile unsigned char *) (NANDFLASH_BASE + NANDFLASH_CLE))) +#define REG_NAND_ADDR (*((volatile unsigned char *) (NANDFLASH_BASE + NANDFLASH_ALE))) + +#define JZ_NAND_SET_CLE (NANDFLASH_BASE |= NANDFLASH_CLE) +#define JZ_NAND_CLR_CLE (NANDFLASH_BASE &= ~NANDFLASH_CLE) +#define JZ_NAND_SET_ALE (NANDFLASH_BASE |= NANDFLASH_ALE) +#define JZ_NAND_CLR_ALE (NANDFLASH_BASE &= ~NANDFLASH_ALE) + +#define JZ_NAND_SELECT (REG_EMC_NFCSR |= EMC_NFCSR_NFCE1 ) +#define JZ_NAND_DESELECT (REG_EMC_NFCSR &= ~(EMC_NFCSR_NFCE1)) + +int ata_read_sectors(IF_MV2(int drive,) unsigned long start, int count, void* buf) +{ + (void)start; + (void)count; + (void)buf; + return 0; +} + +int ata_write_sectors(IF_MV2(int drive,) unsigned long start, int count, const void* buf) +{ + (void)start; + (void)count; + (void)buf; + return 0; +} diff --git a/firmware/target/mips/ingenic_jz47xx/onda_vx747/button-onda_vx747.c b/firmware/target/mips/ingenic_jz47xx/onda_vx747/button-onda_vx747.c index 90dc0b83fb..950fc51d69 100644 --- a/firmware/target/mips/ingenic_jz47xx/onda_vx747/button-onda_vx747.c +++ b/firmware/target/mips/ingenic_jz47xx/onda_vx747/button-onda_vx747.c @@ -32,16 +32,16 @@ | BTN_MENU | BTN_OFF ) #define SADC_CFG_INIT ( \ - (2 << SADC_CFG_CLKOUT_NUM_BIT) | \ - SADC_CFG_XYZ1Z2 | \ - SADC_CFG_SNUM_5 | \ - (1 << SADC_CFG_CLKDIV_BIT) | \ - SADC_CFG_PBAT_HIGH | \ - SADC_CFG_CMD_INT_PEN ) + (2 << SADC_CFG_CLKOUT_NUM_BIT) | \ + SADC_CFG_XYZ1Z2 | \ + SADC_CFG_SNUM_5 | \ + (1 << SADC_CFG_CLKDIV_BIT) | \ + SADC_CFG_PBAT_HIGH | \ + SADC_CFG_CMD_INT_PEN ) bool button_hold(void) { - return (REG_GPIO_PXPIN(3) ^ BTN_HOLD ? 1 : 0); + return (~REG_GPIO_PXPIN(3) & BTN_HOLD ? 1 : 0); } void button_init_device(void) @@ -54,7 +54,7 @@ void button_init_device(void) REG_SADC_CFG = SADC_CFG_INIT; REG_SADC_SAMETIME = 1; - REG_SADC_WAITTIME = 1000; //per 100 HZ + REG_SADC_WAITTIME = 1000; /* per 100 HZ */ REG_SADC_STATE &= (~REG_SADC_STATE); REG_SADC_CTRL &= (~(SADC_CTRL_PENDM | SADC_CTRL_TSRDYM)); REG_SADC_ENA = SADC_ENA_TSEN; // | REG_SADC_ENA;//SADC_ENA_TSEN | SADC_ENA_PBATEN | SADC_ENA_SADCINEN; @@ -66,14 +66,21 @@ static int touch_to_pixels(short x, short y) x -= 300; y -= 300; - x /= 3200 / LCD_WIDTH; - y /= 3600 / LCD_HEIGHT; - - return (x << 16) | y; + /* X & Y are switched */ + x /= 3200 / LCD_HEIGHT; + y /= 3600 / LCD_WIDTH; + + x = LCD_HEIGHT - x; + y = LCD_WIDTH - y; + + return (y << 16) | x; } int button_read_device(int *data) { + if(button_hold()) + return 0; + unsigned int key = ~REG_GPIO_PXPIN(3); int ret = 0; if(key & BTN_MASK) @@ -114,6 +121,8 @@ int button_read_device(int *data) REG_SADC_STATE = 0; //__intc_unmask_irq(IRQ_SADC); } + else + *data = 0; return ret; } diff --git a/firmware/target/mips/ingenic_jz47xx/system-jz4740.c b/firmware/target/mips/ingenic_jz47xx/system-jz4740.c index 4963cac517..ee50520243 100644 --- a/firmware/target/mips/ingenic_jz47xx/system-jz4740.c +++ b/firmware/target/mips/ingenic_jz47xx/system-jz4740.c @@ -22,19 +22,17 @@ #include "config.h" #include "jz4740.h" #include "mipsregs.h" +#include "panic.h" void intr_handler(void) { + _printf("Interrupt!"); return; } void except_handler(void* stack_ptr, unsigned int cause, unsigned int epc) { - (void)stack_ptr; - (void)cause; - (void)epc; - REG8(USB_REG_POWER) &= ~USB_POWER_SOFTCONN; - while(1); + panicf("Exception occurred: [0x%x] at 0x%x (stack at 0x%x)", cause, epc, (unsigned int)stack_ptr); } void system_reboot(void) -- cgit v1.2.3