summaryrefslogtreecommitdiffstats
path: root/firmware/target
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target')
-rw-r--r--firmware/target/arm/ata-as-arm.S32
-rw-r--r--firmware/target/arm/ata-nand-telechips.c2
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/system-gigabeat-s.c2
-rw-r--r--firmware/target/arm/imx31/i2c-imx31.c2
-rw-r--r--firmware/target/arm/imx31/i2c-imx31.h2
-rw-r--r--firmware/target/arm/ipod/button-target.h9
-rw-r--r--firmware/target/arm/ipod/video/lcd-as-video.S26
-rw-r--r--firmware/target/arm/pcm-telechips.c6
-rw-r--r--firmware/target/arm/pp/pcm-pp.c8
-rw-r--r--firmware/target/arm/s3c2440/i2c-s3c2440.h2
-rw-r--r--firmware/target/arm/s5l8700/ipodnano2g/button-target.h9
-rw-r--r--firmware/target/arm/s5l8702/ipod6g/button-target.h9
-rw-r--r--firmware/target/arm/tms320dm320/creative-zvm/ata-creativezvm.c2
-rw-r--r--firmware/target/arm/tms320dm320/i2c-dm320.h2
-rw-r--r--firmware/target/arm/tms320dm320/mrobe-500/lcd-mr500.c4
-rw-r--r--firmware/target/hosted/filesystem-app.c14
-rw-r--r--firmware/target/hosted/sdl/lcd-sdl.c6
-rw-r--r--firmware/target/hosted/sdl/thread-sdl.c2
-rw-r--r--firmware/target/mips/exception-mips.S181
-rw-r--r--firmware/target/mips/ingenic_jz47xx/app.lds34
-rw-r--r--firmware/target/mips/ingenic_jz47xx/boot.lds6
-rw-r--r--firmware/target/mips/ingenic_jz47xx/crt0.S184
-rw-r--r--firmware/target/mips/ingenic_jz47xx/debug-jz4760.c8
-rw-r--r--firmware/target/mips/ingenic_jz47xx/system-jz4740.c76
-rw-r--r--firmware/target/mips/ingenic_jz47xx/system-jz4760.c48
-rw-r--r--firmware/target/mips/ingenic_jz47xx/system-target.h1
-rw-r--r--firmware/target/mips/ingenic_jz47xx/usb-jz4760.c251
-rw-r--r--firmware/target/mips/ingenic_x1000/app.lds50
-rw-r--r--firmware/target/mips/ingenic_x1000/boot-x1000.c17
-rw-r--r--firmware/target/mips/ingenic_x1000/boot-x1000.h4
-rw-r--r--firmware/target/mips/ingenic_x1000/clk-x1000.h13
-rw-r--r--firmware/target/mips/ingenic_x1000/crt0.S158
-rw-r--r--firmware/target/mips/ingenic_x1000/debug-x1000.c13
-rw-r--r--firmware/target/mips/ingenic_x1000/dma-x1000.h2
-rw-r--r--firmware/target/mips/ingenic_x1000/erosqnative/audiohw-erosqnative.c117
-rw-r--r--firmware/target/mips/ingenic_x1000/erosqnative/button-erosqnative.c8
-rw-r--r--firmware/target/mips/ingenic_x1000/erosqnative/gpio-target.h30
-rw-r--r--firmware/target/mips/ingenic_x1000/erosqnative/i2c-target.h3
-rw-r--r--firmware/target/mips/ingenic_x1000/gpio-x1000.c10
-rw-r--r--firmware/target/mips/ingenic_x1000/gpio-x1000.h11
-rw-r--r--firmware/target/mips/ingenic_x1000/i2c-x1000.h2
-rw-r--r--firmware/target/mips/ingenic_x1000/installer-x1000.c25
-rw-r--r--firmware/target/mips/ingenic_x1000/installer-x1000.h1
-rw-r--r--firmware/target/mips/ingenic_x1000/lcd-x1000.c3
-rw-r--r--firmware/target/mips/ingenic_x1000/nand-x1000.c274
-rw-r--r--firmware/target/mips/ingenic_x1000/nand-x1000.h125
-rw-r--r--firmware/target/mips/ingenic_x1000/pcm-x1000.c19
-rw-r--r--firmware/target/mips/ingenic_x1000/spl-nand-x1000.c4
-rw-r--r--firmware/target/mips/ingenic_x1000/spl-start.S2
-rw-r--r--firmware/target/mips/ingenic_x1000/spl-x1000.c7
-rw-r--r--firmware/target/mips/ingenic_x1000/spl.lds3
-rw-r--r--firmware/target/mips/ingenic_x1000/system-target.h3
-rw-r--r--firmware/target/mips/ingenic_x1000/system-x1000.c48
-rw-r--r--firmware/target/mips/mmu-mips.h6
-rw-r--r--firmware/target/mips/system-mips.c175
-rw-r--r--firmware/target/mips/system-mips.h40
56 files changed, 1199 insertions, 902 deletions
diff --git a/firmware/target/arm/ata-as-arm.S b/firmware/target/arm/ata-as-arm.S
index 101bc4dcc1..16c2928bf1 100644
--- a/firmware/target/arm/ata-as-arm.S
+++ b/firmware/target/arm/ata-as-arm.S
@@ -139,9 +139,9 @@ copy_read_sectors:
.r_end2_u:
tst r1, #1 /* one halfword left? */
- ldrneh r4, [r2]
+ ldrhne r4, [r2]
orrne r3, r3, r4, lsl #8
- strneh r3, [r0], #2
+ strhne r3, [r0], #2
movne r3, r4, lsr #8
strb r3, [r0], #1 /* store final byte */
@@ -151,8 +151,8 @@ copy_read_sectors:
/* 16-bit aligned */
.r_aligned:
tst r0, #2 /* 32 bit aligned? */
- ldrneh r3, [r2] /* no: read first halfword */
- strneh r3, [r0], #2 /* store */
+ ldrhne r3, [r2] /* no: read first halfword */
+ strhne r3, [r0], #2 /* store */
subne r1, r1, #1 /* one halfword taken */
sub r1, r1, #8 /* adjust for zero-check and doing 8 halfwords/loop */
@@ -186,14 +186,14 @@ copy_read_sectors:
.r_end4_a:
tst r1, #2 /* 2 or more halfwords left? */
- ldrneh r3, [r2]
- ldrneh r4, [r2]
+ ldrhne r3, [r2]
+ ldrhne r4, [r2]
orrne r3, r3, r4, lsl #16
strne r3, [r0], #4
tst r1, #1 /* one halfword left? */
- ldrneh r3, [r2]
- strneh r3, [r0], #2
+ ldrhne r3, [r2]
+ strhne r3, [r0], #2
ldmpc regs=r4-r5
@@ -291,9 +291,9 @@ copy_write_sectors:
.w_end2_u:
tst r1, #1 /* one halfword left? */
- ldrneh r4, [r0], #2
+ ldrhne r4, [r0], #2
orrne r3, r3, r4, lsl #8
- strneh r3, [r2]
+ strhne r3, [r2]
movne r3, r3, lsr #16
ldrb r4, [r0], #1 /* load final byte */
@@ -305,8 +305,8 @@ copy_write_sectors:
/* 16-bit aligned */
.w_aligned:
tst r0, #2 /* 32 bit aligned? */
- ldrneh r3, [r0], #2 /* no: load first halfword */
- strneh r3, [r2] /* write */
+ ldrhne r3, [r0], #2 /* no: load first halfword */
+ strhne r3, [r2] /* write */
subne r1, r1, #1 /* one halfword taken */
sub r1, r1, #8 /* adjust for zero-check and doing 8 halfwords/loop */
@@ -341,13 +341,13 @@ copy_write_sectors:
tst r1, #2 /* 2 or more halfwords left? */
ldrne r3, [r0], #4
- strneh r3, [r2]
+ strhne r3, [r2]
movne r3, r3, lsr #16
- strneh r3, [r2]
+ strhne r3, [r2]
tst r1, #1 /* one halfword left? */
- ldrneh r3, [r0], #2
- strneh r3, [r2]
+ ldrhne r3, [r0], #2
+ strhne r3, [r2]
ldmpc regs=r4-r5
diff --git a/firmware/target/arm/ata-nand-telechips.c b/firmware/target/arm/ata-nand-telechips.c
index 55f6b1f3f7..d61c223219 100644
--- a/firmware/target/arm/ata-nand-telechips.c
+++ b/firmware/target/arm/ata-nand-telechips.c
@@ -915,7 +915,7 @@ int nand_init(void)
#ifndef BOOTLOADER
/* Use chip info to allocate the correct size LPT buffer */
lptbuf_size = sizeof(struct lpt_entry) * segments_per_bank * total_banks;
- lpt_handle = core_alloc("lpt lookup", lptbuf_size);
+ lpt_handle = core_alloc(lptbuf_size);
struct lpt_entry* lpt_lookup = core_get_data(lpt_handle);
#else
/* Use a static array in the bootloader */
diff --git a/firmware/target/arm/imx31/gigabeat-s/system-gigabeat-s.c b/firmware/target/arm/imx31/gigabeat-s/system-gigabeat-s.c
index d7ebeea024..22873bfef0 100644
--- a/firmware/target/arm/imx31/gigabeat-s/system-gigabeat-s.c
+++ b/firmware/target/arm/imx31/gigabeat-s/system-gigabeat-s.c
@@ -199,7 +199,7 @@ void system_exception_wait(void)
system_halt();
}
-void INIT_ATTR system_init(void)
+void system_init(void)
{
static const enum IMX31_CG_LIST disable_clocks[] INITDATA_ATTR =
{
diff --git a/firmware/target/arm/imx31/i2c-imx31.c b/firmware/target/arm/imx31/i2c-imx31.c
index 972c7d465b..ce5e4cc8f8 100644
--- a/firmware/target/arm/imx31/i2c-imx31.c
+++ b/firmware/target/arm/imx31/i2c-imx31.c
@@ -367,7 +367,7 @@ int i2c_write(struct i2c_node *node, const unsigned char *data,
return -1;
}
-void INIT_ATTR i2c_init(void)
+void i2c_init(void)
{
/* Do one-time inits for each module that will be used - leave
* module disabled and unclocked until something wants it. */
diff --git a/firmware/target/arm/imx31/i2c-imx31.h b/firmware/target/arm/imx31/i2c-imx31.h
index b7305931d1..dad5a3da00 100644
--- a/firmware/target/arm/imx31/i2c-imx31.h
+++ b/firmware/target/arm/imx31/i2c-imx31.h
@@ -76,7 +76,7 @@ struct i2c_sync_transfer_desc
};
/* One-time init of i2c driver */
-void i2c_init(void);
+void i2c_init(void) INIT_ATTR;
/* Enable or disable the node - modules will be switched on/off accordingly. */
void i2c_enable_node(struct i2c_node *node, bool enable);
diff --git a/firmware/target/arm/ipod/button-target.h b/firmware/target/arm/ipod/button-target.h
index 82f600d302..75bc191608 100644
--- a/firmware/target/arm/ipod/button-target.h
+++ b/firmware/target/arm/ipod/button-target.h
@@ -47,15 +47,20 @@ void ipod_4g_button_int(void);
/* Remote control's buttons */
#ifdef IPOD_ACCESSORY_PROTOCOL
+#define BUTTON_RC_DOWN 0x01000000
+#define BUTTON_RC_UP 0x00800000
+#define BUTTON_RC_SELECT 0x00400000
+#define BUTTON_RC_MENU 0x00200000
#define BUTTON_RC_PLAY 0x00100000
#define BUTTON_RC_STOP 0x00080000
-
#define BUTTON_RC_LEFT 0x00040000
#define BUTTON_RC_RIGHT 0x00020000
#define BUTTON_RC_VOL_UP 0x00010000
#define BUTTON_RC_VOL_DOWN 0x00008000
-#define BUTTON_REMOTE (BUTTON_RC_PLAY|BUTTON_RC_STOP\
+#define BUTTON_REMOTE (BUTTON_RC_UP|BUTTON_RC_DOWN \
+ |BUTTON_RC_SELECT|BUTTON_RC_PLAY \
+ |BUTTON_RC_PLAY|BUTTON_RC_STOP \
|BUTTON_RC_LEFT|BUTTON_RC_RIGHT\
|BUTTON_RC_VOL_UP|BUTTON_RC_VOL_DOWN)
#endif
diff --git a/firmware/target/arm/ipod/video/lcd-as-video.S b/firmware/target/arm/ipod/video/lcd-as-video.S
index 47155b8c75..7d6caef448 100644
--- a/firmware/target/arm/ipod/video/lcd-as-video.S
+++ b/firmware/target/arm/ipod/video/lcd-as-video.S
@@ -40,24 +40,24 @@ lcd_write_data: /* r1 = pixel count, must be even */
subs r1, r1, #16
.loop16:
- ldmgeia r0!, {r2-r3}
- stmgeia lr, {r2-r3}
- ldmgeia r0!, {r2-r3}
- stmgeia lr, {r2-r3}
- ldmgeia r0!, {r2-r3}
- stmgeia lr, {r2-r3}
- ldmgeia r0!, {r2-r3}
- stmgeia lr, {r2-r3}
- subges r1, r1, #16
+ ldmiage r0!, {r2-r3}
+ stmiage lr, {r2-r3}
+ ldmiage r0!, {r2-r3}
+ stmiage lr, {r2-r3}
+ ldmiage r0!, {r2-r3}
+ stmiage lr, {r2-r3}
+ ldmiage r0!, {r2-r3}
+ stmiage lr, {r2-r3}
+ subsge r1, r1, #16
bge .loop16
/* no need to correct the count, we're just checking bits from now */
tst r1, #8
- ldmneia r0!, {r2-r4, r12}
- stmneia lr, {r2-r4, r12}
+ ldmiane r0!, {r2-r4, r12}
+ stmiane lr, {r2-r4, r12}
tst r1, #4
- ldmneia r0!, {r2-r3}
- stmneia lr, {r2-r3}
+ ldmiane r0!, {r2-r3}
+ stmiane lr, {r2-r3}
tst r1, #2
ldrne r3, [r0], #4
strne r3, [lr]
diff --git a/firmware/target/arm/pcm-telechips.c b/firmware/target/arm/pcm-telechips.c
index 336b5626ca..45044bc664 100644
--- a/firmware/target/arm/pcm-telechips.c
+++ b/firmware/target/arm/pcm-telechips.c
@@ -218,6 +218,7 @@ void fiq_handler(void)
* r0-r3 and r12 is a working register.
*/
asm volatile (
+ BEGIN_ARM_ASM_SYNTAX_UNIFIED
"sub lr, lr, #4 \n"
"stmfd sp!, { r0-r3, lr } \n" /* stack scratch regs and lr */
"mov r14, #0 \n" /* Was the callback called? */
@@ -251,7 +252,7 @@ void fiq_handler(void)
"stmia r11, { r8-r9 } \n" /* save p and size */
"cmp r14, #0 \n" /* Callback called? */
- "ldmeqfd sp!, { r0-r3, pc }^ \n" /* no? -> exit */
+ "ldmfdeq sp!, { r0-r3, pc }^ \n" /* no? -> exit */
"ldr r1, =pcm_play_status_callback \n"
"ldr r1, [r1] \n"
@@ -268,11 +269,12 @@ void fiq_handler(void)
"mov lr, pc \n"
"ldr pc, =pcm_play_dma_complete_callback \n"
"cmp r0, #0 \n" /* any more to play? */
- "ldmneia r11, { r8-r9 } \n" /* load new p and size */
+ "ldmiane r11, { r8-r9 } \n" /* load new p and size */
"cmpne r9, #0x0f \n" /* did we actually get enough data? */
"bhi .fill_fifo \n" /* not stop and enough? refill */
"ldmfd sp!, { r0-r3, pc }^ \n" /* exit */
".ltorg \n"
+ END_ARM_ASM_SYNTAX_UNIFIED
: : "i"(PCM_DMAST_OK), "i"(PCM_DMAST_STARTED)
);
}
diff --git a/firmware/target/arm/pp/pcm-pp.c b/firmware/target/arm/pp/pcm-pp.c
index 0d61eb44ff..94b1c5ae10 100644
--- a/firmware/target/arm/pp/pcm-pp.c
+++ b/firmware/target/arm/pp/pcm-pp.c
@@ -327,6 +327,7 @@ void fiq_playback(void)
*/
asm volatile (
/* No external calls */
+ BEGIN_ARM_ASM_SYNTAX_UNIFIED
"sub lr, lr, #4 \n" /* Prepare return address */
"stmfd sp!, { lr } \n" /* stack lr so we can use it */
"ldr r12, =0xcf001040 \n" /* Some magic from iPodLinux ... */
@@ -349,8 +350,8 @@ void fiq_playback(void)
"bhi 0b \n" /* ... yes, continue */
"cmp r9, #0 \n" /* either FIFO full or size empty? */
- "stmneia r11, { r8-r9 } \n" /* save p and size, if not empty */
- "ldmnefd sp!, { pc }^ \n" /* RFE if not empty */
+ "stmiane r11, { r8-r9 } \n" /* save p and size, if not empty */
+ "ldmfdne sp!, { pc }^ \n" /* RFE if not empty */
/* Making external calls */
"1: \n"
@@ -363,7 +364,7 @@ void fiq_playback(void)
"mov lr, pc \n" /* long call (not in same section) */
"bx r3 \n"
"cmp r0, #0 \n" /* more data? */
- "ldmeqfd sp!, { r0-r3, pc }^ \n" /* no? -> exit */
+ "ldmfdeq sp!, { r0-r3, pc }^ \n" /* no? -> exit */
"ldr r14, [r10, #0x1c] \n" /* read IISFIFO_CFG to check FIFO status */
"ands r14, r14, #(0xe<<23) \n" /* r14 = (IIS_TX_FREE_COUNT & ~1) << 23 */
@@ -394,6 +395,7 @@ void fiq_playback(void)
"bne 3b \n" /* no? -> go return */
"b 2b \n" /* yes -> get even more */
".ltorg \n"
+ END_ARM_ASM_SYNTAX_UNIFIED
: /* These must only be integers! No regs */
: "i"(PCM_DMAST_OK), "i"(PCM_DMAST_STARTED));
}
diff --git a/firmware/target/arm/s3c2440/i2c-s3c2440.h b/firmware/target/arm/s3c2440/i2c-s3c2440.h
index 793ee213fd..8b739358af 100644
--- a/firmware/target/arm/s3c2440/i2c-s3c2440.h
+++ b/firmware/target/arm/s3c2440/i2c-s3c2440.h
@@ -41,6 +41,6 @@
/* IICLC */
#define I2C_FLT_ENB (1 << 2)
-void i2c_init(void);
+void i2c_init(void) INIT_ATTR;
void i2c_write(int addr, const unsigned char *data, int count);
diff --git a/firmware/target/arm/s5l8700/ipodnano2g/button-target.h b/firmware/target/arm/s5l8700/ipodnano2g/button-target.h
index 82f600d302..75bc191608 100644
--- a/firmware/target/arm/s5l8700/ipodnano2g/button-target.h
+++ b/firmware/target/arm/s5l8700/ipodnano2g/button-target.h
@@ -47,15 +47,20 @@ void ipod_4g_button_int(void);
/* Remote control's buttons */
#ifdef IPOD_ACCESSORY_PROTOCOL
+#define BUTTON_RC_DOWN 0x01000000
+#define BUTTON_RC_UP 0x00800000
+#define BUTTON_RC_SELECT 0x00400000
+#define BUTTON_RC_MENU 0x00200000
#define BUTTON_RC_PLAY 0x00100000
#define BUTTON_RC_STOP 0x00080000
-
#define BUTTON_RC_LEFT 0x00040000
#define BUTTON_RC_RIGHT 0x00020000
#define BUTTON_RC_VOL_UP 0x00010000
#define BUTTON_RC_VOL_DOWN 0x00008000
-#define BUTTON_REMOTE (BUTTON_RC_PLAY|BUTTON_RC_STOP\
+#define BUTTON_REMOTE (BUTTON_RC_UP|BUTTON_RC_DOWN \
+ |BUTTON_RC_SELECT|BUTTON_RC_PLAY \
+ |BUTTON_RC_PLAY|BUTTON_RC_STOP \
|BUTTON_RC_LEFT|BUTTON_RC_RIGHT\
|BUTTON_RC_VOL_UP|BUTTON_RC_VOL_DOWN)
#endif
diff --git a/firmware/target/arm/s5l8702/ipod6g/button-target.h b/firmware/target/arm/s5l8702/ipod6g/button-target.h
index ed17fc4baa..a5c4771b7c 100644
--- a/firmware/target/arm/s5l8702/ipod6g/button-target.h
+++ b/firmware/target/arm/s5l8702/ipod6g/button-target.h
@@ -47,15 +47,20 @@ void ipod_4g_button_int(void);
/* Remote control's buttons */
#ifdef IPOD_ACCESSORY_PROTOCOL
+#define BUTTON_RC_DOWN 0x01000000
+#define BUTTON_RC_UP 0x00800000
+#define BUTTON_RC_SELECT 0x00400000
+#define BUTTON_RC_MENU 0x00200000
#define BUTTON_RC_PLAY 0x00100000
#define BUTTON_RC_STOP 0x00080000
-
#define BUTTON_RC_LEFT 0x00040000
#define BUTTON_RC_RIGHT 0x00020000
#define BUTTON_RC_VOL_UP 0x00010000
#define BUTTON_RC_VOL_DOWN 0x00008000
-#define BUTTON_REMOTE (BUTTON_RC_PLAY|BUTTON_RC_STOP\
+#define BUTTON_REMOTE (BUTTON_RC_UP|BUTTON_RC_DOWN \
+ |BUTTON_RC_SELECT|BUTTON_RC_PLAY \
+ |BUTTON_RC_PLAY|BUTTON_RC_STOP \
|BUTTON_RC_LEFT|BUTTON_RC_RIGHT\
|BUTTON_RC_VOL_UP|BUTTON_RC_VOL_DOWN)
#endif
diff --git a/firmware/target/arm/tms320dm320/creative-zvm/ata-creativezvm.c b/firmware/target/arm/tms320dm320/creative-zvm/ata-creativezvm.c
index f13904628d..a1985472a0 100644
--- a/firmware/target/arm/tms320dm320/creative-zvm/ata-creativezvm.c
+++ b/firmware/target/arm/tms320dm320/creative-zvm/ata-creativezvm.c
@@ -303,7 +303,7 @@ static void cfs_init(void)
_ata_read_sectors(CFS_CLUSTER2CLUSTER(vfat_inodes_nr[1]), 1, &sector);
inode = (struct cfs_inode*)&sector;
#ifndef BOOTLOADER
- sectors_handle = core_alloc("ata sectors", VFAT_SECTOR_SIZE(inode->filesize));
+ sectors_handle = core_alloc(VFAT_SECTOR_SIZE(inode->filesize));
unsigned long *sectors = core_get_data(sectors_handle);
#else
static unsigned long _sector[VFAT_SECTOR_SIZE(1024*1024*1024)]; /* 1GB guess */
diff --git a/firmware/target/arm/tms320dm320/i2c-dm320.h b/firmware/target/arm/tms320dm320/i2c-dm320.h
index 43271692eb..89a8e6f1a4 100644
--- a/firmware/target/arm/tms320dm320/i2c-dm320.h
+++ b/firmware/target/arm/tms320dm320/i2c-dm320.h
@@ -24,7 +24,7 @@
#include "system.h"
-void i2c_init(void);
+void i2c_init(void) INIT_ATTR;
int i2c_write(unsigned short address, const unsigned char *data, int count);
int i2c_read(unsigned short address, unsigned char* buf, int count);
diff --git a/firmware/target/arm/tms320dm320/mrobe-500/lcd-mr500.c b/firmware/target/arm/tms320dm320/mrobe-500/lcd-mr500.c
index d952d3d40d..8620c672e1 100644
--- a/firmware/target/arm/tms320dm320/mrobe-500/lcd-mr500.c
+++ b/firmware/target/arm/tms320dm320/mrobe-500/lcd-mr500.c
@@ -38,7 +38,7 @@
#if CONFIG_ORIENTATION == SCREEN_PORTRAIT
#define LCD_USE_DMA
-#elif defined(LCD_STRIDEFORMAT) && LCD_STRIDEFORMAT == VERTICAL_STRIDE
+#elif LCD_STRIDEFORMAT == VERTICAL_STRIDE
#define LCD_USE_DMA
#endif
@@ -511,7 +511,7 @@ void lcd_update_rect(int x, int y, int width, int height)
#else
-#if defined(LCD_STRIDEFORMAT) && LCD_STRIDEFORMAT == VERTICAL_STRIDE
+#if LCD_STRIDEFORMAT == VERTICAL_STRIDE
#if defined(LCD_USE_DMA)
dma_start_transfer16( (char *)FBADDR(0,0), x, y, LCD_HEIGHT,
diff --git a/firmware/target/hosted/filesystem-app.c b/firmware/target/hosted/filesystem-app.c
index 2121af7752..09b3365a9e 100644
--- a/firmware/target/hosted/filesystem-app.c
+++ b/firmware/target/hosted/filesystem-app.c
@@ -43,6 +43,10 @@
#undef PIVOT_ROOT
#endif
+#if defined(DBTOOL)
+#define PIVOT_ROOT "."
+#endif
+
#if defined(__PCTOOL__)
/* We don't want this for tools */
#undef HAVE_SPECIAL_DIRS
@@ -222,7 +226,7 @@ const char * handle_special_dirs(const char *dir, unsigned flags,
#define PIVOT_ROOT_LEN (sizeof(PIVOT_ROOT)-1)
/* Prepend root prefix to find actual path */
if (strncmp(PIVOT_ROOT, dir, PIVOT_ROOT_LEN)
-#ifdef MULTIDRIVE_DIR
+#if defined(MULTIDRIVE_DIR) && defined(MULTIDRIVE_DIR_LEN)
/* Unless it's a MULTIDRIVE dir, in which case use as-is */
&& strncmp(MULTIDRIVE_DIR, dir, MULTIDRIVE_DIR_LEN)
#endif
@@ -580,10 +584,11 @@ ssize_t app_readlink(const char *path, char *buf, size_t bufsiz)
int os_volume_path(IF_MV(int volume, ) char *buffer, size_t bufsize)
{
-#ifdef HAVE_MULTIVOLUME
+#if defined(HAVE_MULTIVOLUME) && !(CONFIG_PLATFORM & PLATFORM_HOSTED)
char volname[VOL_MAX_LEN + 1];
get_volume_name(volume, volname);
#else
+ IF_MV((void)volume;)
const char *volname = "/";
#endif
@@ -595,3 +600,8 @@ int os_volume_path(IF_MV(int volume, ) char *buffer, size_t bufsize)
return 0;
}
+
+const char* app_root_realpath(void)
+{
+ return PATH_ROOTSTR;
+}
diff --git a/firmware/target/hosted/sdl/lcd-sdl.c b/firmware/target/hosted/sdl/lcd-sdl.c
index de19de365a..8cbb6c5651 100644
--- a/firmware/target/hosted/sdl/lcd-sdl.c
+++ b/firmware/target/hosted/sdl/lcd-sdl.c
@@ -31,9 +31,9 @@ void sdl_update_rect(SDL_Surface *surface, int x_start, int y_start, int width,
unsigned long (*getpixel)(int, int))
{
SDL_Rect dest;
-#if LCD_DEPTH >= 8 && (LCD_PIXELFORMAT == RGB565) \
- && !defined(LCD_STRIDEFORMAT) && !defined(HAVE_LCD_SPLIT) \
- && !defined(HAVE_REMOTE_LCD)
+#if LCD_DEPTH >= 8 && (LCD_PIXELFORMAT == RGB565) && \
+ (LCD_STRIDEFORMAT == HORIZONTAL_STRIDE) && \
+ !defined(HAVE_LCD_SPLIT) && !defined(HAVE_REMOTE_LCD)
SDL_Rect src;
(void)max_x;
(void)max_y;
diff --git a/firmware/target/hosted/sdl/thread-sdl.c b/firmware/target/hosted/sdl/thread-sdl.c
index a76941f103..17a0f847b5 100644
--- a/firmware/target/hosted/sdl/thread-sdl.c
+++ b/firmware/target/hosted/sdl/thread-sdl.c
@@ -215,7 +215,7 @@ void switch_thread(void)
} /* STATE_SLEEPING: */
}
-#ifdef DEBUG
+#ifdef BUFLIB_DEBUG_CHECK_VALID
core_check_valid();
#endif
__running_self_entry() = current;
diff --git a/firmware/target/mips/exception-mips.S b/firmware/target/mips/exception-mips.S
new file mode 100644
index 0000000000..605817c7d5
--- /dev/null
+++ b/firmware/target/mips/exception-mips.S
@@ -0,0 +1,181 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2022 Aidan MacDonald
+ *
+ * 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 "mips.h"
+
+ .text
+ .set push
+ .set mips32
+
+ .section .vectors.1, "ax", %progbits
+ la k1, tlb_refill_handler
+ j _exception_enter
+
+ .section .vectors.2, "ax", %progbits
+ la k1, cache_error_handler
+ j _exception_enter
+
+ .section .vectors.3, "ax", %progbits
+ li k1, M_CauseExcCode
+ mfc0 k0, C0_CAUSE
+ and k0, k1
+ beq zero, k0, 1f
+ la k1, exception_handler
+ j _exception_enter
+1:
+ la k1, intr_handler
+ j _exception_enter
+
+ .section .vectors.4, "ax", %progbits
+ /* same as above */
+ li k1, M_CauseExcCode
+ mfc0 k0, C0_CAUSE
+ and k0, k1
+ beq zero, k0, 1f
+ nop
+ la k1, exception_handler
+ j _exception_enter
+1:
+ la k1, intr_handler
+ j _exception_enter
+
+ .set push
+ .set noat
+ .set noreorder
+ .section .vectors, "ax", %progbits
+
+_exception_enter:
+ la k0, _irqstackend
+ addiu k0, -0x84
+
+ sw $1, 0x00(k0)
+ sw $2, 0x04(k0)
+ sw $3, 0x08(k0)
+ sw $4, 0x0c(k0)
+ sw $5, 0x10(k0)
+ sw $6, 0x14(k0)
+ sw $7, 0x18(k0)
+ sw $8, 0x1c(k0)
+ sw $9, 0x20(k0)
+ sw $10, 0x24(k0)
+ sw $11, 0x28(k0)
+ sw $12, 0x2c(k0)
+ sw $13, 0x30(k0)
+ sw $14, 0x34(k0)
+ sw $15, 0x38(k0)
+ sw $16, 0x3c(k0)
+ sw $17, 0x40(k0)
+ sw $18, 0x44(k0)
+ sw $19, 0x48(k0)
+ sw $20, 0x4c(k0)
+ sw $21, 0x50(k0)
+ sw $22, 0x54(k0)
+ sw $23, 0x58(k0)
+ sw $24, 0x5c(k0)
+ sw $25, 0x60(k0)
+ sw $28, 0x64(k0)
+ sw $29, 0x68(k0)
+ sw $30, 0x6c(k0)
+ sw $31, 0x70(k0)
+
+ mflo t0
+ ssnop
+ sw t0, 0x74(k0)
+
+ mfhi t0
+ ssnop
+ sw t0, 0x78(k0)
+
+ mfc0 t0, C0_STATUS
+ ssnop
+ ssnop
+ ssnop
+ sw t0, 0x7c(k0)
+
+ mfc0 a1, C0_EPC
+ ssnop
+ ssnop
+ ssnop
+ sw a1, 0x80(k0)
+
+ move sp, k0
+
+ jalr k1
+ move a0, sp
+
+_exception_return:
+ /* restore all GPRs except sp */
+ lw $1, 0x00(sp)
+ lw $2, 0x04(sp)
+ lw $3, 0x08(sp)
+ lw $4, 0x0c(sp)
+ lw $5, 0x10(sp)
+ lw $6, 0x14(sp)
+ lw $7, 0x18(sp)
+ lw $8, 0x1c(sp)
+ lw $9, 0x20(sp)
+ lw $10, 0x24(sp)
+ lw $11, 0x28(sp)
+ lw $12, 0x2c(sp)
+ lw $13, 0x30(sp)
+ lw $14, 0x34(sp)
+ lw $15, 0x38(sp)
+ lw $16, 0x3c(sp)
+ lw $17, 0x40(sp)
+ lw $18, 0x44(sp)
+ lw $19, 0x48(sp)
+ lw $20, 0x4c(sp)
+ lw $21, 0x50(sp)
+ lw $22, 0x54(sp)
+ lw $23, 0x58(sp)
+ lw $24, 0x5c(sp)
+ lw $25, 0x60(sp)
+ lw $28, 0x64(sp)
+ lw $30, 0x6c(sp)
+ lw $31, 0x70(sp)
+
+ lw k0, 0x74(sp)
+ mtlo k0
+ ssnop
+
+ lw k0, 0x78(sp)
+ mthi k0
+ ssnop
+
+ lw k0, 0x7c(sp)
+ mtc0 k0, C0_STATUS
+ ssnop
+ ssnop
+ ssnop
+
+ lw k0, 0x80(sp)
+ mtc0 k0, C0_EPC
+ ssnop
+ ssnop
+ ssnop
+
+ /* restore stack pointer last */
+ lw sp, 0x68(sp)
+ eret
+ ssnop
+
+ .set pop
+ .set pop
diff --git a/firmware/target/mips/ingenic_jz47xx/app.lds b/firmware/target/mips/ingenic_jz47xx/app.lds
index 89deb63f89..1d300fed82 100644
--- a/firmware/target/mips/ingenic_jz47xx/app.lds
+++ b/firmware/target/mips/ingenic_jz47xx/app.lds
@@ -1,9 +1,13 @@
#include "config.h"
+#define __ASSEMBLY__
+#include "cpu.h"
OUTPUT_FORMAT("elf32-littlemips")
OUTPUT_ARCH(MIPS)
ENTRY(_start)
STARTUP(target/mips/ingenic_jz47xx/crt0.o)
+INPUT(target/mips/exception-mips.o)
+INPUT(target/mips/system-mips.o)
#define STUBOFFSET 0x4000
@@ -18,22 +22,34 @@ STARTUP(target/mips/ingenic_jz47xx/crt0.o)
/* Where the codec buffer ends, and the plugin buffer starts */
#define ENDCODECADDR (ENDAUDIOADDR + CODEC_SIZE)
+/* Place init code in the codec buffer */
+#define INITBASE ENDAUDIOADDR
+#define INITSIZE CODEC_SIZE
+
MEMORY
{
DRAM : ORIGIN = DRAMORIG, LENGTH = DRAMSIZE
IRAM : ORIGIN = IRAMORIG, LENGTH = IRAMSIZE
+ INIT : ORIGIN = INITBASE, LENGTH = INITSIZE
}
SECTIONS
{
. = DRAMORIG;
- .text :
+ .startup :
{
loadaddress = .;
_loadaddress = .;
- *(.init.text);
+ *(.startup.text);
+ } > DRAM
+
+ .text :
+ {
*(.text*);
+#ifndef HAVE_INIT_ATTR
+ *(.init*);
+#endif
} > DRAM
. = ALIGN(4);
@@ -75,6 +91,16 @@ SECTIONS
} > IRAM
_iramcopy = LOADADDR(.iram);
+#ifdef HAVE_INIT_ATTR
+ .init :
+ {
+ _initstart = .;
+ *(.init*);
+ _initend = .;
+ } > INIT AT> DRAM
+ _initcopy = LOADADDR(.init);
+#endif
+
. = ALIGN(4);
.stack (NOLOAD):
@@ -83,9 +109,9 @@ SECTIONS
stackbegin = .;
. += 0x1d00;
stackend = .;
- irqstackbegin = .;
+ _irqstackbegin = .;
. += 0x400;
- irqstackend = .;
+ _irqstackend = .;
} > IRAM
.bss (NOLOAD):
diff --git a/firmware/target/mips/ingenic_jz47xx/boot.lds b/firmware/target/mips/ingenic_jz47xx/boot.lds
index b5a3f51c01..b1ea5ddf13 100644
--- a/firmware/target/mips/ingenic_jz47xx/boot.lds
+++ b/firmware/target/mips/ingenic_jz47xx/boot.lds
@@ -4,6 +4,8 @@ OUTPUT_FORMAT("elf32-littlemips")
OUTPUT_ARCH(MIPS)
ENTRY(_start)
STARTUP(target/mips/ingenic_jz47xx/crt0.o)
+INPUT(target/mips/exception-mips.o)
+INPUT(target/mips/system-mips.o)
#define DRAMSIZE ((MEMORYSIZE-4) * 0x100000)
@@ -87,9 +89,9 @@ SECTIONS
stackbegin = .;
. += 0x1d00;
stackend = .;
- irqstackbegin = .;
+ _irqstackbegin = .;
. += 0x400;
- irqstackend = .;
+ _irqstackend = .;
} > IRAM
/DISCARD/ :
diff --git a/firmware/target/mips/ingenic_jz47xx/crt0.S b/firmware/target/mips/ingenic_jz47xx/crt0.S
index 1652bea8e5..b73a43d8f2 100644
--- a/firmware/target/mips/ingenic_jz47xx/crt0.S
+++ b/firmware/target/mips/ingenic_jz47xx/crt0.S
@@ -40,11 +40,12 @@
.text
- .extern system_main
+ .extern system_early_init
.extern main
.global _start
- .section .init.text
+ .section .startup.text,"ax",%progbits
+ .set push
.set mips32
.set noreorder
.set noat
@@ -138,6 +139,19 @@ _iram_loop:
bne t1, t2, _iram_loop
sw t3, -4(t1)
+#ifdef HAVE_INIT_ATTR
+ /* Copy init code */
+ la t0, _initcopy
+ la t1, _initstart
+ la t2, _initend
+_init_loop:
+ lw t3, 0(t0)
+ addiu t1, 4
+ addiu t0, 4
+ bne t1, t2, _init_loop
+ sw t3, -4(t1)
+#endif
+
/*
----------------------------------------------------
Clear BSS section
@@ -169,8 +183,8 @@ _stack_loop:
Set up interrupt stack
----------------------------------------------------
*/
- la k0, irqstackend
- la t0, irqstackbegin
+ la k0, _irqstackend
+ la t0, _irqstackbegin
_irq_stack_loop:
addiu t0, 4
@@ -182,167 +196,9 @@ _irq_stack_loop:
Jump to C code
----------------------------------------------------
*/
- jal system_main /* Init clocks etc first */
+ jal system_early_init /* Init clocks etc first */
ssnop
j main
move ra, zero /* init backtrace root */
-
- /*
- * 0x0 - Simple TLB refill handler
- * 0x100 - Cache error handler
- * 0x180 - Exception/Interrupt handler
- * 0x200 - Special Exception Interrupt handler (when IV is set in CP0_CAUSE)
- */
-
- .section .vectors.1, "ax", %progbits
- j tlb_refill_handler
- ssnop
-
- .section .vectors.2, "ax", %progbits
- j real_exception_handler
- ssnop
-
- .section .vectors.3, "ax", %progbits
- j real_exception_handler
- ssnop
-
- .section .vectors.4, "ax", %progbits
- j real_exception_handler
- ssnop
-
- .section .vectors, "ax", %progbits
-real_exception_handler:
-
- /* Store stack pointer */
- move k0, sp
- /* jump to IRQ stack */
- la sp, irqstackend
-
- /* Push crap on frame */
- addiu sp, -0x84
- /* store current stack pointer */
- sw k0, 0x80(sp)
-
- sw ra, 0(sp)
- sw fp, 4(sp)
- sw gp, 8(sp)
- sw t9, 0xC(sp)
- sw t8, 0x10(sp)
- sw s7, 0x14(sp)
- sw s6, 0x18(sp)
- sw s5, 0x1C(sp)
- sw s4, 0x20(sp)
- sw s3, 0x24(sp)
- sw s2, 0x28(sp)
- sw s1, 0x2C(sp)
- sw s0, 0x30(sp)
- sw t7, 0x34(sp)
- sw t6, 0x38(sp)
- sw t5, 0x3C(sp)
- sw t4, 0x40(sp)
- sw t3, 0x44(sp)
- sw t2, 0x48(sp)
- sw t1, 0x4C(sp)
- sw t0, 0x50(sp)
- sw a3, 0x54(sp)
- sw a2, 0x58(sp)
- sw a1, 0x5C(sp)
- sw a0, 0x60(sp)
- sw v1, 0x64(sp)
- sw v0, 0x68(sp)
- sw $1, 0x6C(sp)
- mflo k0
- ssnop
- sw k0, 0x70(sp)
- mfhi k0
- ssnop
- sw k0, 0x74(sp)
- mfc0 k0, C0_STATUS
- ssnop
- ssnop
- ssnop
- sw k0, 0x78(sp)
- mfc0 k0, C0_EPC
- ssnop
- ssnop
- ssnop
- sw k0, 0x7C(sp)
-
- li k1, M_CauseExcCode
- mfc0 k0, C0_CAUSE
- and k0, k1
- beq zero, k0, _int
- ssnop
- j _exception
- ssnop
-
-_int:
- jal intr_handler
- ssnop
- j _exception_return
-
-_exception:
- move a0, sp
- mfc0 a1, C0_CAUSE
- ssnop
- ssnop
- ssnop
- mfc0 a2, C0_EPC
- ssnop
- ssnop
- ssnop
- jal exception_handler
- ssnop
-
-_exception_return:
- lw ra, 0(sp)
- lw fp, 4(sp)
- lw gp, 8(sp)
- lw t9, 0xC(sp)
- lw t8, 0x10(sp)
- lw s7, 0x14(sp)
- lw s6, 0x18(sp)
- lw s5, 0x1C(sp)
- lw s4, 0x20(sp)
- lw s3, 0x24(sp)
- lw s2, 0x28(sp)
- lw s1, 0x2C(sp)
- lw s0, 0x30(sp)
- lw t7, 0x34(sp)
- lw t6, 0x38(sp)
- lw t5, 0x3C(sp)
- lw t4, 0x40(sp)
- lw t3, 0x44(sp)
- lw t2, 0x48(sp)
- lw t1, 0x4C(sp)
- lw t0, 0x50(sp)
- lw a3, 0x54(sp)
- lw a2, 0x58(sp)
- lw a1, 0x5C(sp)
- lw a0, 0x60(sp)
- lw v1, 0x64(sp)
- lw v0, 0x68(sp)
- lw $1, 0x6C(sp)
- lw k0, 0x70(sp)
- mtlo k0
- ssnop
- lw k0, 0x74(sp)
- mthi k0
- ssnop
- lw k0, 0x78(sp)
- mtc0 k0, C0_STATUS
- ssnop
- ssnop
- ssnop
- lw k0, 0x7C(sp)
- mtc0 k0, C0_EPC
- ssnop
- ssnop
- ssnop
- /* Restore previous stack pointer */
- lw sp, 0x80(sp)
- eret
- ssnop
- .set reorder
- .set at
+ .set pop
diff --git a/firmware/target/mips/ingenic_jz47xx/debug-jz4760.c b/firmware/target/mips/ingenic_jz47xx/debug-jz4760.c
index 65b5e93887..f5624cf469 100644
--- a/firmware/target/mips/ingenic_jz47xx/debug-jz4760.c
+++ b/firmware/target/mips/ingenic_jz47xx/debug-jz4760.c
@@ -537,7 +537,7 @@ static const char* hw_info_menu_get_name(int item, void * data,
(void)data;
struct tm *cur_time;
uint32_t *stackptr;
- extern uint32_t irqstackend,irqstackbegin;
+ extern uint32_t _irqstackend,_irqstackbegin;
int btn;
#ifdef HAVE_TOUCHSCREEN
int touch;
@@ -557,10 +557,10 @@ static const char* hw_info_menu_get_name(int item, void * data,
read_cp0_15(), (REG_CPM_CLKGR0 & BIT31) >> 31);
return buffer;
case 2: /*IRQstack*/
- stackptr = &irqstackbegin;
- for ( ; stackptr < &irqstackend && *stackptr == 0xDEADBEEF; stackptr++) {}
+ stackptr = &_irqstackbegin;
+ for ( ; stackptr < &_irqstackend && *stackptr == 0xDEADBEEF; stackptr++) {}
snprintf(buffer, buffer_len, "IRQ stack max: %lu",
- (uint32_t)&irqstackend - (uint32_t)stackptr);
+ (uint32_t)&_irqstackend - (uint32_t)stackptr);
return buffer;
case 5: /*Touch/BTN*/
#ifdef HAVE_TOUCHSCREEN
diff --git a/firmware/target/mips/ingenic_jz47xx/system-jz4740.c b/firmware/target/mips/ingenic_jz47xx/system-jz4740.c
index fdc335ad21..5aff144327 100644
--- a/firmware/target/mips/ingenic_jz47xx/system-jz4740.c
+++ b/firmware/target/mips/ingenic_jz47xx/system-jz4740.c
@@ -219,80 +219,6 @@ void intr_handler(void)
irqvector[irq-1]();
}
-#define EXC(x,y) case (x): return (y);
-static char* parse_exception(unsigned int cause)
-{
- switch(cause & M_CauseExcCode)
- {
- EXC(EXC_INT, "Interrupt");
- EXC(EXC_MOD, "TLB Modified");
- EXC(EXC_TLBL, "TLB Exception (Load or Ifetch)");
- EXC(EXC_ADEL, "Address Error (Load or Ifetch)");
- EXC(EXC_ADES, "Address Error (Store)");
- EXC(EXC_TLBS, "TLB Exception (Store)");
- EXC(EXC_IBE, "Instruction Bus Error");
- EXC(EXC_DBE, "Data Bus Error");
- EXC(EXC_SYS, "Syscall");
- EXC(EXC_BP, "Breakpoint");
- EXC(EXC_RI, "Reserved Instruction");
- EXC(EXC_CPU, "Coprocessor Unusable");
- EXC(EXC_OV, "Overflow");
- EXC(EXC_TR, "Trap Instruction");
- EXC(EXC_FPE, "Floating Point Exception");
- EXC(EXC_C2E, "COP2 Exception");
- EXC(EXC_MDMX, "MDMX Exception");
- EXC(EXC_WATCH, "Watch Exception");
- EXC(EXC_MCHECK, "Machine Check Exception");
- EXC(EXC_CacheErr, "Cache error caused re-entry to Debug Mode");
- default:
- return NULL;
- }
-}
-
-void exception_handler(void* stack_ptr, unsigned int cause, unsigned int epc)
-{
-#if EXTENDED_EXCEPTION_DESC
- (void)epc;
-
- /* Depends on crt0.S ! */
- char *registers[] = { "ra", "fp", "gp", "t9", "t8", "s7", "s6", "s5", "s4",
- "s3", "s2", "s1", "s0", "t7", "t6", "t5", "t4", "t3",
- "t2", "t1", "t0", "a3", "a2", "a1", "a0", "v1", "v0",
- "$1", "LO", "HI", "STATUS", "EPC" };
- int i;
-
-#if LCD_DEPTH > 1
- lcd_set_backdrop(NULL);
- lcd_set_drawmode(DRMODE_SOLID);
- lcd_set_foreground(LCD_BLACK);
- lcd_set_background(LCD_WHITE);
-#endif
- lcd_setfont(FONT_SYSFIXED);
- lcd_set_viewport(NULL);
-
- lcd_clear_display();
- backlight_hw_on();
-
- lcd_puts(0, 0, parse_exception(cause));
- lcd_putsf(0, 1, "0x%08x at 0x%08x", read_c0_badvaddr(), epc);
- for(i=0; i< 0x80/4; i+=2)
- {
- unsigned int* ptr = (unsigned int*)(stack_ptr + i*4);
- lcd_putsf(0, 3 + i/2, "%s: 0x%08x %s: 0x%08x", registers[i], *ptr, registers[i+1], *(ptr+1));
- }
- lcd_update();
-
- system_exception_wait();
-#else
- panicf("Exception occurred: %s [0x%08x] at 0x%08x (stack at 0x%08x)", parse_exception(cause), read_c0_badvaddr(), epc, (unsigned int)stack_ptr);
-#endif
-}
-
-void tlb_refill_handler(void)
-{
- panicf("TLB refill handler at 0x%08lx! [0x%x]", read_c0_epc(), read_c0_badvaddr());
-}
-
void udelay(unsigned int usec)
{
unsigned int i = usec * (__cpm_get_cclk() / 2000000);
@@ -508,7 +434,7 @@ static void sdram_init(void)
}
/* Gets called *before* main */
-void ICODE_ATTR system_main(void)
+void ICODE_ATTR system_early_init(void)
{
int i;
diff --git a/firmware/target/mips/ingenic_jz47xx/system-jz4760.c b/firmware/target/mips/ingenic_jz47xx/system-jz4760.c
index 10973f3e2b..3a1321b992 100644
--- a/firmware/target/mips/ingenic_jz47xx/system-jz4760.c
+++ b/firmware/target/mips/ingenic_jz47xx/system-jz4760.c
@@ -301,46 +301,6 @@ top:
goto top;
}
-#define EXC(x,y) case (x): return (y);
-static char* parse_exception(unsigned int cause)
-{
- switch(cause & M_CauseExcCode)
- {
- EXC(EXC_INT, "Interrupt");
- EXC(EXC_MOD, "TLB Modified");
- EXC(EXC_TLBL, "TLB Exception (Load or Ifetch)");
- EXC(EXC_ADEL, "Address Error (Load or Ifetch)");
- EXC(EXC_ADES, "Address Error (Store)");
- EXC(EXC_TLBS, "TLB Exception (Store)");
- EXC(EXC_IBE, "Instruction Bus Error");
- EXC(EXC_DBE, "Data Bus Error");
- EXC(EXC_SYS, "Syscall");
- EXC(EXC_BP, "Breakpoint");
- EXC(EXC_RI, "Reserved Instruction");
- EXC(EXC_CPU, "Coprocessor Unusable");
- EXC(EXC_OV, "Overflow");
- EXC(EXC_TR, "Trap Instruction");
- EXC(EXC_FPE, "Floating Point Exception");
- EXC(EXC_C2E, "COP2 Exception");
- EXC(EXC_MDMX, "MDMX Exception");
- EXC(EXC_WATCH, "Watch Exception");
- EXC(EXC_MCHECK, "Machine Check Exception");
- EXC(EXC_CacheErr, "Cache error caused re-entry to Debug Mode");
- default:
- return NULL;
- }
-}
-
-void exception_handler(void* stack_ptr, unsigned int cause, unsigned int epc)
-{
- panicf("Exception occurred: %s [0x%08x] at 0x%08x (stack at 0x%08x)", parse_exception(cause), read_c0_badvaddr(), epc, (unsigned int)stack_ptr);
-}
-
-void tlb_refill_handler(void)
-{
- panicf("TLB refill handler at 0x%08lx! [0x%x]", read_c0_epc(), read_c0_badvaddr());
-}
-
#ifdef HW_UDELAY_TIMER
/* This enables the HW timer, set to EXT_XTAL / 4 (so @ 12/4 = 3MHz, 1 us = 3 ticks) */
static void init_delaytimer(void)
@@ -573,7 +533,7 @@ static void serial_setbrg(void)
*uart_lcr = tmp;
}
-int serial_preinit(void)
+static int serial_preinit(void)
{
volatile u8 *uart_fcr = (volatile u8 *)(CFG_UART_BASE + OFF_FCR);
volatile u8 *uart_lcr = (volatile u8 *)(CFG_UART_BASE + OFF_LCR);
@@ -609,7 +569,7 @@ int serial_preinit(void)
#define cpu_frequency CPU_FREQ
#endif
-void usb_preinit(void)
+static void usb_preinit(void)
{
/* Clear ECS bit of CPCCR, 0:clock source is EXCLK, 1:clock source is EXCLK/2 */
REG_CPM_CPCCR &= ~CPCCR_ECS;
@@ -661,7 +621,7 @@ void usb_preinit(void)
udelay(300);
}
-void dma_preinit(void)
+static void dma_preinit(void)
{
__cpm_start_mdma();
__cpm_start_dmac();
@@ -676,7 +636,7 @@ void dma_preinit(void)
}
/* Gets called *before* main */
-void ICODE_ATTR system_main(void)
+void ICODE_ATTR system_early_init(void)
{
int i;
diff --git a/firmware/target/mips/ingenic_jz47xx/system-target.h b/firmware/target/mips/ingenic_jz47xx/system-target.h
index 2725944452..1db0ee4671 100644
--- a/firmware/target/mips/ingenic_jz47xx/system-target.h
+++ b/firmware/target/mips/ingenic_jz47xx/system-target.h
@@ -27,6 +27,7 @@
#include "config.h"
#include "cpu.h"
#include "mipsregs.h"
+#include "system-mips.h"
#define CACHE_SIZE 16*1024
#define CACHEALIGN_BITS 5
diff --git a/firmware/target/mips/ingenic_jz47xx/usb-jz4760.c b/firmware/target/mips/ingenic_jz47xx/usb-jz4760.c
index 474d45edee..8ff6d4bc1e 100644
--- a/firmware/target/mips/ingenic_jz47xx/usb-jz4760.c
+++ b/firmware/target/mips/ingenic_jz47xx/usb-jz4760.c
@@ -54,16 +54,14 @@
OUT = HOST->DEV, (ie we recv)
*/
-enum ep_type
-{
+enum ep_type {
ep_control,
ep_bulk,
ep_interrupt,
ep_isochronous
};
-struct usb_endpoint
-{
+struct usb_endpoint {
const enum ep_type type;
const long fifo_addr;
unsigned short fifo_size;
@@ -76,8 +74,7 @@ struct usb_endpoint
volatile void *buf;
volatile size_t length;
- union
- {
+ union {
volatile size_t sent;
volatile size_t received;
};
@@ -94,8 +91,7 @@ struct usb_endpoint
#define short_not_ok 1 /* only works for mass storage.. */
#define ep_doublebuf(__ep) 0
-static union
-{
+static union {
int buf[64 / sizeof(int)];
struct usb_ctrlrequest request;
} ep0_rx;
@@ -106,7 +102,7 @@ static volatile bool ep0_data_requested = false;
static struct usb_endpoint endpoints[] =
{
EP_INIT(ep_control, USB_FIFO_EP(0), 64, NULL),
- EP_INIT(ep_control, USB_FIFO_EP(0), 64, ep0_rx.buf),
+ EP_INIT(ep_control, USB_FIFO_EP(0), 64, NULL),
EP_INIT(ep_bulk, USB_FIFO_EP(1), 512, NULL),
EP_INIT(ep_bulk, USB_FIFO_EP(1), 512, NULL),
EP_INIT(ep_interrupt, USB_FIFO_EP(2), 512, NULL),
@@ -127,19 +123,14 @@ static void readFIFO(struct usb_endpoint *ep, unsigned int size)
register unsigned int s = size >> 2;
register unsigned int x;
- if(size > 0)
- {
- if( ((unsigned int)ptr & 3) == 0 )
- {
- while(s--)
+ if(size > 0) {
+ if (((unsigned int)ptr & 3) == 0) {
+ while(s--) {
*ptr32++ = REG32(ep->fifo_addr);
-
+ }
ptr = (unsigned char*)ptr32;
- }
- else
- {
- while(s--)
- {
+ } else {
+ while(s--) {
x = REG32(ep->fifo_addr);
*ptr++ = x & 0xFF; x >>= 8;
*ptr++ = x & 0xFF; x >>= 8;
@@ -147,10 +138,10 @@ static void readFIFO(struct usb_endpoint *ep, unsigned int size)
*ptr++ = x;
}
}
-
s = size & 3;
- while(s--)
+ while(s--) {
*ptr++ = REG8(ep->fifo_addr);
+ }
}
}
@@ -163,18 +154,14 @@ static void writeFIFO(struct usb_endpoint *ep, size_t size)
register size_t s = size >> 2;
register unsigned int x;
- if(size > 0)
- {
- if( ((unsigned int)d8 & 3) == 0 )
- {
- while (s--)
+ if (size > 0) {
+ if (((unsigned int)d8 & 3) == 0) {
+ while (s--) {
REG32(ep->fifo_addr) = *d32++;
+ }
d8 = (unsigned char *)d32;
- }
- else
- {
- while (s--)
- {
+ } else {
+ while (s--) {
x = (unsigned int)(*d8++) & 0xff;
x |= ((unsigned int)(*d8++) & 0xff) << 8;
x |= ((unsigned int)(*d8++) & 0xff) << 16;
@@ -182,11 +169,9 @@ static void writeFIFO(struct usb_endpoint *ep, size_t size)
REG32(ep->fifo_addr) = x;
}
}
-
- if( (s = size & 3) )
- {
- while (s--)
- REG8(ep->fifo_addr) = *d8++;
+ s = size & 3;
+ while (s--) {
+ REG8(ep->fifo_addr) = *d8++;
}
}
}
@@ -195,18 +180,17 @@ static void flushFIFO(struct usb_endpoint *ep)
{
logf("%s(%d)", __func__, EP_NUMBER(ep));
- switch (ep->type)
- {
- case ep_control:
+ switch (ep->type) {
+ case ep_control:
break;
-
- case ep_bulk:
- case ep_interrupt:
- case ep_isochronous:
- if(EP_IS_IN(ep))
- REG_USB_INCSR |= (USB_INCSR_FF | USB_INCSR_CDT);
- else
- REG_USB_OUTCSR |= (USB_OUTCSR_FF | USB_OUTCSR_CDT);
+ case ep_bulk:
+ case ep_interrupt:
+ case ep_isochronous:
+ if (EP_IS_IN(ep)) {
+ REG_USB_INCSR |= (USB_INCSR_FF | USB_INCSR_CDT);
+ } else {
+ REG_USB_OUTCSR |= (USB_OUTCSR_FF | USB_OUTCSR_CDT);
+ }
break;
}
}
@@ -217,8 +201,9 @@ static inline void ep_transfer_completed(struct usb_endpoint* ep)
ep->length = 0;
ep->buf = NULL;
ep->busy = false;
- if(ep->wait)
+ if (ep->wait) {
semaphore_release(&ep->complete);
+ }
}
static void EP0_send(void)
@@ -232,27 +217,26 @@ static void EP0_send(void)
logf("%s(): 0x%x %d %d", __func__, csr0, ep->sent, ep->length);
- if(ep->sent == 0)
- {
+ if (ep->sent == 0) {
length = MIN(ep->length, ep->fifo_size);
REG_USB_CSR0 = (csr0 | USB_CSR0_FLUSHFIFO);
- }
- else
+ } else {
length = MIN(EP_BUF_LEFT(ep), ep->fifo_size);
+ }
writeFIFO(ep, length);
ep->sent += length;
- if(ep->sent >= ep->length)
- {
+ if (ep->sent >= ep->length) {
REG_USB_CSR0 = (csr0 | USB_CSR0_INPKTRDY | USB_CSR0_DATAEND); /* Set data end! */
- if (!ep->wait)
+ if (!ep->wait) {
usb_core_transfer_complete(EP_CONTROL, USB_DIR_IN, 0, ep->sent);
+ }
ep->rc = 0;
ep_transfer_completed(ep);
- }
- else
+ } else {
REG_USB_CSR0 = (csr0 | USB_CSR0_INPKTRDY);
+ }
}
static void EP0_handler(void)
@@ -270,8 +254,7 @@ static void EP0_handler(void)
/* Check for SentStall:
This bit is set when a STALL handshake is transmitted. The CPU should clear this bit.
*/
- if(csr0 & USB_CSR0_SENTSTALL)
- {
+ if (csr0 & USB_CSR0_SENTSTALL) {
REG_USB_CSR0 = csr0 & ~USB_CSR0_SENTSTALL;
return;
}
@@ -281,68 +264,62 @@ static void EP0_handler(void)
An interrupt will be generated and the FIFO flushed at this time.
The bit is cleared by the CPU writing a 1 to the ServicedSetupEnd bit.
*/
- if(csr0 & USB_CSR0_SETUPEND)
- {
+ if (csr0 & USB_CSR0_SETUPEND) {
csr0 |= USB_CSR0_SVDSETUPEND;
REG_USB_CSR0 = csr0;
ep0_data_supplied = false;
ep0_data_requested = false;
- if (ep_send->busy)
- {
+ if (ep_send->busy) {
if (!ep_send->wait)
usb_core_transfer_complete(EP_CONTROL, USB_DIR_IN, -1, 0);
ep_transfer_completed(ep_send);
}
- if (ep_recv->busy)
- {
+ if (ep_recv->busy) {
usb_core_transfer_complete(EP_CONTROL, USB_DIR_OUT, -1, 0);
ep_transfer_completed(ep_recv);
}
}
/* Call relevant routines for endpoint 0 state */
- if(csr0 & USB_CSR0_OUTPKTRDY) /* There is a packet in the fifo */
- {
- if (ep_send->busy)
- {
- if (!ep_send->wait)
+ if (csr0 & USB_CSR0_OUTPKTRDY) { /* There is a packet in the fifo */
+ if (ep_send->busy) {
+ if (!ep_send->wait) {
usb_core_transfer_complete(EP_CONTROL, USB_DIR_IN, -1, 0);
+ }
ep_transfer_completed(ep_send);
}
- if (ep_recv->busy && ep_recv->buf && ep_recv->length)
- {
+ if (ep_recv->busy && ep_recv->buf && ep_recv->length) {
unsigned int size = REG_USB_COUNT0;
readFIFO(ep_recv, size);
ep_recv->received += size;
- if (size < ep_recv->fifo_size || ep_recv->received >= ep_recv->length)
- {
+ if (size < ep_recv->fifo_size || ep_recv->received >= ep_recv->length) {
REG_USB_CSR0 = csr0 | USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND; /* Set data end! */
usb_core_transfer_complete(EP_CONTROL, USB_DIR_OUT, 0, ep_recv->received);
ep_transfer_completed(ep_recv);
+ } else {
+ REG_USB_CSR0 = csr0 | USB_CSR0_SVDOUTPKTRDY; /* clear OUTPKTRDY bit */
}
- else REG_USB_CSR0 = csr0 | USB_CSR0_SVDOUTPKTRDY; /* clear OUTPKTRDY bit */
- }
- else if (!ep0_data_supplied)
- {
+ } else if (!ep0_data_supplied) {
ep_recv->buf = ep0_rx.buf;
readFIFO(ep_recv, REG_USB_COUNT0);
csr0 |= USB_CSR0_SVDOUTPKTRDY;
- if (!ep0_rx.request.wLength)
- {
+ if (!ep0_rx.request.wLength) {
csr0 |= USB_CSR0_DATAEND; /* Set data end! */
ep0_data_requested = false;
ep0_data_supplied = false;
- }
- else if (ep0_rx.request.bRequestType & USB_DIR_IN)
+ } else if (ep0_rx.request.bRequestType & USB_DIR_IN) {
ep0_data_requested = true;
- else ep0_data_supplied = true;
+ } else {
+ ep0_data_supplied = true;
+ }
REG_USB_CSR0 = csr0;
usb_core_legacy_control_request(&ep0_rx.request);
ep_transfer_completed(ep_recv);
}
}
- else if (ep_send->busy)
+ else if (ep_send->busy) {
EP0_send();
+ }
}
/* Does new work */
@@ -429,7 +406,7 @@ static void EPIN_send(unsigned int endpoint)
#endif
/* Non-DMA code */
- if(ep->sent == 0)
+ if (ep->sent == 0)
length = MIN(ep->length, ep->fifo_size);
else
length = MIN(EP_BUF_LEFT(ep), ep->fifo_size);
@@ -494,7 +471,7 @@ static void EPIN_complete(unsigned int endpoint)
logf("EP%d: %d -> %d", endpoint, ep->sent, ep->length);
- if(ep->sent >= ep->length) {
+ if (ep->sent >= ep->length) {
if (!ep->wait)
usb_core_transfer_complete(endpoint, USB_DIR_IN, 0, ep->sent);
ep->rc = 0;
@@ -516,9 +493,9 @@ static void EPOUT_handler(unsigned int endpoint)
}
select_endpoint(endpoint);
- while((csr = REG_USB_OUTCSR) & (USB_OUTCSR_SENTSTALL|USB_OUTCSR_OUTPKTRDY)) {
+ while ((csr = REG_USB_OUTCSR) & (USB_OUTCSR_SENTSTALL|USB_OUTCSR_OUTPKTRDY)) {
logf("%s(%d): 0x%x", __func__, endpoint, csr);
- if(csr & USB_OUTCSR_SENTSTALL) {
+ if (csr & USB_OUTCSR_SENTSTALL) {
logf("stall sent, flushing fifo..");
flushFIFO(ep);
REG_USB_OUTCSR = csr & ~USB_OUTCSR_SENTSTALL;
@@ -593,7 +570,7 @@ static void EPOUT_handler(unsigned int endpoint)
logf("received: %d max length: %d", ep->received, ep->length);
- if(size < ep->fifo_size || ep->received >= ep->length) {
+ if (size < ep->fifo_size || ep->received >= ep->length) {
usb_core_transfer_complete(endpoint, USB_DIR_OUT, 0, ep->received);
ep_transfer_completed(ep);
logf("receive transfer_complete");
@@ -613,8 +590,7 @@ static void EPOUT_ready(unsigned int endpoint)
select_endpoint(endpoint);
csr = REG_USB_OUTCSR;
- if(!ep->busy)
- {
+ if (!ep->busy) {
logf("Entered EPOUT handler without work!");
return;
}
@@ -717,15 +693,15 @@ static void setup_endpoint(struct usb_endpoint *ep)
select_endpoint(endpoint);
- if (ep->busy)
- {
- if(EP_IS_IN(ep))
- {
+ if (ep->busy) {
+ if (EP_IS_IN(ep)) {
if (ep->wait)
semaphore_release(&ep->complete);
- else usb_core_transfer_complete(endpoint, USB_DIR_IN, -1, 0);
+ else
+ usb_core_transfer_complete(endpoint, USB_DIR_IN, -1, 0);
+ } else {
+ usb_core_transfer_complete(endpoint, USB_DIR_OUT, -1, 0);
}
- else usb_core_transfer_complete(endpoint, USB_DIR_OUT, -1, 0);
}
ep->busy = false;
@@ -733,17 +709,16 @@ static void setup_endpoint(struct usb_endpoint *ep)
ep->sent = 0;
ep->length = 0;
- if(ep->type != ep_control)
+ if (ep->type != ep_control)
ep->fifo_size = usb_drv_port_speed() ? 512 : 64;
ep->config = REG_USB_CONFIGDATA;
- if(EP_IS_IN(ep))
- {
+ if(EP_IS_IN(ep)) {
csr = (USB_INCSR_FF | USB_INCSR_CDT);
csrh = USB_INCSRH_MODE;
- if(ep->type == ep_interrupt)
+ if (ep->type == ep_interrupt)
csrh |= USB_INCSRH_FRCDATATOG;
REG_USB_INMAXP = ep->fifo_size;
@@ -754,9 +729,7 @@ static void setup_endpoint(struct usb_endpoint *ep)
if (ep->allocated)
REG_USB_INTRINE |= USB_INTR_EP(EP_NUMBER2(ep));
- }
- else
- {
+ } else {
csr = (USB_OUTCSR_FF | USB_OUTCSR_CDT);
csrh = 0;
@@ -813,8 +786,7 @@ static void udc_reset(void)
endpoints[0].config = REG_USB_CONFIGDATA;
endpoints[1].config = REG_USB_CONFIGDATA;
- if (endpoints[0].busy)
- {
+ if (endpoints[0].busy) {
if (endpoints[0].wait)
semaphore_release(&endpoints[0].complete);
else
@@ -837,7 +809,7 @@ static void udc_reset(void)
endpoints[1].allocated = true;
/* Reset other endpoints */
- for(i=2; i<TOTAL_EP(); i++)
+ for (i=2; i<TOTAL_EP(); i++)
setup_endpoint(&endpoints[i]);
ep0_data_supplied = false;
@@ -864,26 +836,26 @@ void OTG(void)
logf("IRQ %x %x %x %x", intrUSB, intrIn, intrOut, intrDMA);
/* EPIN & EPOUT are all handled in DMA */
- if(intrIn & USB_INTR_EP(0))
+ if (intrIn & USB_INTR_EP(0))
EP0_handler();
- if(intrIn & USB_INTR_EP(1))
+ if (intrIn & USB_INTR_EP(1))
EPIN_complete(1);
- if(intrIn & USB_INTR_EP(2))
+ if (intrIn & USB_INTR_EP(2))
EPIN_complete(2);
- if(intrOut & USB_INTR_EP(1))
+ if (intrOut & USB_INTR_EP(1))
EPOUT_ready(1);
- if(intrOut & USB_INTR_EP(2))
+ if (intrOut & USB_INTR_EP(2))
EPOUT_ready(2);
- if(intrUSB & USB_INTR_RESET)
+ if (intrUSB & USB_INTR_RESET)
udc_reset();
- if(intrUSB & USB_INTR_SUSPEND)
+ if (intrUSB & USB_INTR_SUSPEND)
logf("USB suspend");
- if(intrUSB & USB_INTR_RESUME)
+ if (intrUSB & USB_INTR_RESUME)
logf("USB resume");
#ifdef USE_USB_DMA
- if(intrDMA & (1<<USB_INTR_DMA_BULKIN))
+ if (intrDMA & (1<<USB_INTR_DMA_BULKIN))
EPDMA_handler(USB_INTR_DMA_BULKIN);
- if(intrDMA & (1<<USB_INTR_DMA_BULKOUT))
+ if (intrDMA & (1<<USB_INTR_DMA_BULKOUT))
EPDMA_handler(USB_INTR_DMA_BULKOUT);
#endif
}
@@ -896,11 +868,10 @@ bool usb_drv_stalled(int endpoint, bool in)
select_endpoint(endpoint);
- if(endpoint == EP_CONTROL)
+ if (endpoint == EP_CONTROL) {
return (REG_USB_CSR0 & USB_CSR0_SENDSTALL) != 0;
- else
- {
- if(in)
+ } else {
+ if (in)
return (REG_USB_INCSR & USB_INCSR_SENDSTALL) != 0;
else
return (REG_USB_OUTCSR & USB_OUTCSR_SENDSTALL) != 0;
@@ -915,24 +886,18 @@ void usb_drv_stall(int endpoint, bool stall, bool in)
select_endpoint(endpoint);
- if(endpoint == EP_CONTROL)
- {
+ if(endpoint == EP_CONTROL) {
if(stall)
REG_USB_CSR0 |= USB_CSR0_SENDSTALL;
else
REG_USB_CSR0 &= ~USB_CSR0_SENDSTALL;
- }
- else
- {
- if(in)
- {
+ } else {
+ if(in) {
if(stall)
REG_USB_INCSR |= USB_INCSR_SENDSTALL;
else
REG_USB_INCSR = (REG_USB_INCSR & ~USB_INCSR_SENDSTALL) | USB_INCSR_CDT;
- }
- else
- {
+ } else {
if(stall)
REG_USB_OUTCSR |= USB_OUTCSR_SENDSTALL;
else
@@ -965,7 +930,7 @@ void usb_init_device(void)
system_enable_irq(IRQ_OTG);
- for(unsigned i=0; i<TOTAL_EP(); i++)
+ for (unsigned i=0; i<TOTAL_EP(); i++)
semaphore_init(&endpoints[i].complete, 1, 0);
}
@@ -979,7 +944,7 @@ static int usb_oneshot_callback(struct timeout *tmo)
* and post appropriate event. */
usb_status_event(state);
- if(state == USB_EXTRACTED)
+ if (state == USB_EXTRACTED)
__gpio_as_irq_rise_edge(PIN_USB_DET);
else
__gpio_as_irq_fall_edge(PIN_USB_DET);
@@ -996,7 +961,7 @@ void GPIO_USB_DET(void)
void usb_enable(bool on)
{
- if(on)
+ if (on)
usb_core_init();
else
usb_core_exit();
@@ -1070,7 +1035,7 @@ static void usb_drv_send_internal(struct usb_endpoint* ep, void* ptr, int length
ep->sent = 0;
ep->length = length;
ep->busy = true;
- if(blocking) {
+ if (blocking) {
ep->rc = -1;
ep->wait = true;
} else {
@@ -1085,7 +1050,7 @@ static void usb_drv_send_internal(struct usb_endpoint* ep, void* ptr, int length
restore_irq(flags);
- if(blocking) {
+ if (blocking) {
semaphore_wait(&ep->complete, HZ);
ep->wait = false;
}
@@ -1097,8 +1062,7 @@ int usb_drv_send_nonblocking(int endpoint, void* ptr, int length)
logf("%s(%d, 0x%x, %d)", __func__, endpoint, (int)ptr, length);
- if (ep->allocated)
- {
+ if (ep->allocated) {
usb_drv_send_internal(ep, ptr, length, false);
return 0;
}
@@ -1112,8 +1076,7 @@ int usb_drv_send(int endpoint, void* ptr, int length)
logf("%s(%d, 0x%x, %d)", __func__, endpoint, (int)ptr, length);
- if (ep->allocated)
- {
+ if (ep->allocated) {
usb_drv_send_internal(ep, ptr, length, true);
return ep->rc;
}
@@ -1188,7 +1151,8 @@ void usb_drv_cancel_all_transfers(void)
{
logf("%s()", __func__);
- unsigned int i, flags = disable_irq_save();
+ unsigned int i;
+ unsigned int flags = disable_irq_save();
#ifdef USE_USB_DMA
/* Disable DMA */
@@ -1204,7 +1168,8 @@ void usb_drv_cancel_all_transfers(void)
usb_core_transfer_complete(i >> 1, USB_DIR_OUT, -1, 0);
else if (endpoints[i].wait)
semaphore_release(&endpoints[i].complete);
- else usb_core_transfer_complete(i >> 1, USB_DIR_IN, -1, 0);
+ else
+ usb_core_transfer_complete(i >> 1, USB_DIR_IN, -1, 0);
}
if(i != 1) /* ep0 out needs special handling */
diff --git a/firmware/target/mips/ingenic_x1000/app.lds b/firmware/target/mips/ingenic_x1000/app.lds
index 2943329ba7..fe06e1cd8d 100644
--- a/firmware/target/mips/ingenic_x1000/app.lds
+++ b/firmware/target/mips/ingenic_x1000/app.lds
@@ -5,12 +5,18 @@ OUTPUT_FORMAT("elf32-littlemips")
OUTPUT_ARCH(MIPS)
ENTRY(_start)
STARTUP(target/mips/ingenic_x1000/crt0.o)
+INPUT(target/mips/exception-mips.o)
+INPUT(target/mips/system-mips.o)
#ifdef BOOTLOADER
# undef PLUGIN_BUFFER_SIZE
# undef CODEC_SIZE
# define PLUGIN_BUFFER_SIZE 0
# define CODEC_SIZE 0
+# if defined(HAVE_INIT_ATTR)
+/* This needs to be fixed for the bootloader */
+# error "bootloader does not support INIT_ATTR"
+# endif
#endif
/* End of the audio buffer, where the codec buffer starts */
@@ -19,21 +25,33 @@ STARTUP(target/mips/ingenic_x1000/crt0.o)
/* Where the codec buffer ends, and the plugin buffer starts */
#define ENDCODECADDR (ENDAUDIOADDR + CODEC_SIZE)
+/* Place init code in the codec buffer */
+#define INIT_BASE ENDAUDIOADDR
+#define INIT_SIZE CODEC_SIZE
+
MEMORY
{
IRAM : ORIGIN = X1000_IRAM_BASE, LENGTH = X1000_IRAM_SIZE
DRAM : ORIGIN = X1000_DRAM_BASE, LENGTH = X1000_DRAM_SIZE
TCSM : ORIGIN = X1000_TCSM_BASE, LENGTH = X1000_TCSM_SIZE
+ INIT : ORIGIN = INIT_BASE, LENGTH = INIT_SIZE
}
SECTIONS
{
- .text :
+ .startup :
{
loadaddress = .;
_loadaddress = .;
- *(.init.text);
+ *(.startup.text);
+ } > DRAM
+
+ .text :
+ {
*(.text*);
+#ifndef HAVE_INIT_ATTR
+ *(.init*);
+#endif
} > DRAM
. = ALIGN(4);
@@ -49,7 +67,13 @@ SECTIONS
*(.sdata*);
} > DRAM
- .iram X1000_IRAM_BASE: AT (_bssbegin)
+ /*
+ * The following sections are loaded after normal DRAM sections
+ * but are copied elsewhere by the startup code.
+ */
+ _noloaddram = .;
+
+ .iram :
{
_iramstart = .;
. = 0x000; /* TLB refill */
@@ -66,17 +90,29 @@ SECTIONS
*(.irodata);
*(.idata);
_iramend = .;
- } > IRAM
+ } > IRAM AT> DRAM
_iramcopy = LOADADDR(.iram);
- .tcsm X1000_TCSM_BASE: AT (_bssbegin + SIZEOF(.iram))
+ .tcsm :
{
_tcsmstart = .;
KEEP(*(.tcsm*));
_tcsmend = .;
- } > TCSM
+ } > TCSM AT> DRAM
_tcsmcopy = LOADADDR(.tcsm);
+#ifdef HAVE_INIT_ATTR
+ .init :
+ {
+ _initstart = .;
+ *(.init*);
+ _initend = .;
+ } > INIT AT> DRAM
+ _initcopy = LOADADDR(.init);
+#endif
+
+ /* Sections below have no data. */
+
. = ALIGN(4);
.stack (NOLOAD) :
{
@@ -89,7 +125,7 @@ SECTIONS
_irqstackend = .;
} > IRAM
- .bss (NOLOAD) :
+ .bss _noloaddram (NOLOAD) :
{
_bssbegin = .;
*(.sbss*);
diff --git a/firmware/target/mips/ingenic_x1000/boot-x1000.c b/firmware/target/mips/ingenic_x1000/boot-x1000.c
index aa97bfcd85..2f2714c67a 100644
--- a/firmware/target/mips/ingenic_x1000/boot-x1000.c
+++ b/firmware/target/mips/ingenic_x1000/boot-x1000.c
@@ -20,6 +20,7 @@
****************************************************************************/
#include "system.h"
+#include "usb.h"
#include "boot-x1000.h"
#include "nand-x1000.h"
#include "gpio-x1000.h"
@@ -113,6 +114,14 @@ void x1000_boot_linux(const void* source, size_t length,
{
size_t args_len = strlen(args);
+ /* Shut off USB to avoid "irq 21 nobody cared" error */
+ usb_close();
+ usb_enable(false);
+
+ /* clear USB PHY voodoo bits, not all kernels use them */
+ jz_writef(CPM_OPCR, GATE_USBPHY_CLK(0));
+ jz_writef(CPM_USBCDR, PHY_GATE(0));
+
disable_irq();
/* --- Beyond this point, do not call into DRAM --- */
@@ -121,7 +130,7 @@ void x1000_boot_linux(const void* source, size_t length,
/* copy argument string to a safe location */
char* args_copy = safe_mem + 32;
- iram_memmove(args_copy, args, args_len);
+ iram_memmove(args_copy, args, args_len+1);
/* generate argv array */
char** argv = safe_mem;
@@ -151,10 +160,6 @@ void x1000_dualboot_cleanup(void)
jz_writef(LCD_CTRL, BEDN(0), EOFM(0), SOFM(0), IFUM(0), QDM(0));
jz_writef(CPM_CLKGR, LCD(1));
- /* clear USB PHY voodoo bits, not all kernels use them */
- jz_writef(CPM_OPCR, GATE_USBPHY_CLK(0));
- jz_writef(CPM_USBCDR, PHY_GATE(0));
-
#if defined(FIIO_M3K) || defined(EROS_QN)
/*
* Need to bring up MPLL before booting Linux
@@ -262,7 +267,7 @@ void x1000_dualboot_init_uart2(void)
int x1000_dualboot_load_pdma_fw(void)
{
- nand_drv* n = nand_init();
+ struct nand_drv* n = nand_init();
nand_lock(n);
int ret = nand_open(n);
diff --git a/firmware/target/mips/ingenic_x1000/boot-x1000.h b/firmware/target/mips/ingenic_x1000/boot-x1000.h
index 1b7a0db1e9..eb476c513d 100644
--- a/firmware/target/mips/ingenic_x1000/boot-x1000.h
+++ b/firmware/target/mips/ingenic_x1000/boot-x1000.h
@@ -36,10 +36,10 @@ enum {
};
void x1000_boot_rockbox(const void* source, size_t length)
- __attribute__((section(".icode")));
+ __attribute__((section(".icode.x1000_boot_rockbox")));
void x1000_boot_linux(const void* source, size_t length,
void* load, void* entry, const char* args)
- __attribute__((section(".icode")));
+ __attribute__((section(".icode.x1000_boot_linux")));
/* dual boot support code */
void x1000_dualboot_cleanup(void);
diff --git a/firmware/target/mips/ingenic_x1000/clk-x1000.h b/firmware/target/mips/ingenic_x1000/clk-x1000.h
index f7153da564..4b1d4ef838 100644
--- a/firmware/target/mips/ingenic_x1000/clk-x1000.h
+++ b/firmware/target/mips/ingenic_x1000/clk-x1000.h
@@ -22,8 +22,9 @@
#ifndef __CLK_X1000_H__
#define __CLK_X1000_H__
-#include <stdint.h>
+#include "config.h"
#include "x1000/cpm.h"
+#include <stdint.h>
/* Used as arguments to clk_set_ccr_mux() */
#define CLKMUX_SCLK_A(x) jz_orf(CPM_CCR, SEL_SRC_V(x))
@@ -67,17 +68,17 @@ extern uint32_t clk_get(x1000_clk_t clk);
extern const char* clk_get_name(x1000_clk_t clk);
/* Clock initialization */
-extern void clk_init_early(void);
-extern void clk_init(void);
+extern void clk_init_early(void) INIT_ATTR;
+extern void clk_init(void) INIT_ATTR;
/* Sets system clock multiplexers */
-extern void clk_set_ccr_mux(uint32_t muxbits);
+extern void clk_set_ccr_mux(uint32_t muxbits) INIT_ATTR;
/* Sets system clock dividers */
-extern void clk_set_ccr_div(uint32_t divbits);
+extern void clk_set_ccr_div(uint32_t divbits) INIT_ATTR;
/* Sets DDR clock source and divider */
-extern void clk_set_ddr(x1000_clk_t src, uint32_t div);
+extern void clk_set_ddr(x1000_clk_t src, uint32_t div) INIT_ATTR;
/* Returns the smallest n such that infreq/n <= outfreq */
static inline uint32_t clk_calc_div(uint32_t infreq, uint32_t outfreq)
diff --git a/firmware/target/mips/ingenic_x1000/crt0.S b/firmware/target/mips/ingenic_x1000/crt0.S
index 9d89ac1227..6c0942b0db 100644
--- a/firmware/target/mips/ingenic_x1000/crt0.S
+++ b/firmware/target/mips/ingenic_x1000/crt0.S
@@ -34,7 +34,7 @@
.set noreorder
.set noat
- .section .init.text
+ .section .startup.text,"ax",%progbits
_start:
b _realstart
@@ -55,6 +55,12 @@ _header:
#endif
_realstart:
+ /* Save bootloader arguments. */
+ move s0, a0
+ move s1, a1
+ move s2, a2
+ move s3, a3
+
/* Copy IRAM from BSS to low memory. */
la a0, _iramcopy
la a1, _iramstart
@@ -69,6 +75,15 @@ _realstart:
bal _copy
nop
+#ifdef HAVE_INIT_ATTR
+ /* Copy init code */
+ la a0, _initcopy
+ la a1, _initstart
+ la a2, _initend
+ bal _copy
+ nop
+#endif
+
/* Clear the BSS segment (needed to zero-initialize C static values) */
la a0, _bssbegin
la a1, _bssend
@@ -109,6 +124,13 @@ _realstart:
/* Jump to C code */
jal system_early_init
nop
+
+ /* Restore bootloader arguments, jump to main. */
+ move a0, s0
+ move a1, s1
+ move a2, s2
+ move a3, s3
+
j main
move ra, zero /* init backtrace root */
@@ -134,138 +156,4 @@ _clear:
jr ra
nop
- /* Exception entry points */
- .section .vectors.1, "ax", %progbits
- j tlb_refill_handler
- nop
-
- .section .vectors.2, "ax", %progbits
- j real_exception_handler
- nop
-
- .section .vectors.3, "ax", %progbits
- j real_exception_handler
- nop
-
- .section .vectors.4, "ax", %progbits
- j real_exception_handler
- nop
-
- .section .vectors, "ax", %progbits
-real_exception_handler:
- move k0, sp
- la sp, _irqstackend
- addiu sp, -0x84
- sw k0, 0x80(sp)
- sw ra, 0x00(sp)
- sw fp, 0x04(sp)
- sw gp, 0x08(sp)
- sw t9, 0x0c(sp)
- sw t8, 0x10(sp)
- sw s7, 0x14(sp)
- sw s6, 0x18(sp)
- sw s5, 0x1c(sp)
- sw s4, 0x20(sp)
- sw s3, 0x24(sp)
- sw s2, 0x28(sp)
- sw s1, 0x2c(sp)
- sw s0, 0x30(sp)
- sw t7, 0x34(sp)
- sw t6, 0x38(sp)
- sw t5, 0x3c(sp)
- sw t4, 0x40(sp)
- sw t3, 0x44(sp)
- sw t2, 0x48(sp)
- sw t1, 0x4c(sp)
- sw t0, 0x50(sp)
- sw a3, 0x54(sp)
- sw a2, 0x58(sp)
- sw a1, 0x5c(sp)
- sw a0, 0x60(sp)
- sw v1, 0x64(sp)
- sw v0, 0x68(sp)
- sw $1, 0x6c(sp)
- mflo k0
- nop
- sw k0, 0x70(sp)
- mfhi k0
- nop
- sw k0, 0x74(sp)
- mfc0 k0, C0_STATUS
- nop
- nop
- nop
- sw k0, 0x78(sp)
- mfc0 k0, C0_EPC
- nop
- nop
- nop
- sw k0, 0x7c(sp)
-
- li k1, M_CauseExcCode
- mfc0 a0, C0_CAUSE
- and k0, a0, k1
- bnez k0, _exception
- nop
- jal intr_handler
- nop
- j _exception_return
-
-_exception:
- mfc0 a1, C0_EPC
- nop
- nop
- nop
- jal exception_handler
- move a2, sp
-
-_exception_return:
- lw ra, 0x00(sp)
- lw fp, 0x04(sp)
- lw gp, 0x08(sp)
- lw t9, 0x0c(sp)
- lw t8, 0x10(sp)
- lw s7, 0x14(sp)
- lw s6, 0x18(sp)
- lw s5, 0x1c(sp)
- lw s4, 0x20(sp)
- lw s3, 0x24(sp)
- lw s2, 0x28(sp)
- lw s1, 0x2c(sp)
- lw s0, 0x30(sp)
- lw t7, 0x34(sp)
- lw t6, 0x38(sp)
- lw t5, 0x3c(sp)
- lw t4, 0x40(sp)
- lw t3, 0x44(sp)
- lw t2, 0x48(sp)
- lw t1, 0x4c(sp)
- lw t0, 0x50(sp)
- lw a3, 0x54(sp)
- lw a2, 0x58(sp)
- lw a1, 0x5c(sp)
- lw a0, 0x60(sp)
- lw v1, 0x64(sp)
- lw v0, 0x68(sp)
- lw $1, 0x6c(sp)
- lw k0, 0x70(sp)
- mtlo k0
- nop
- lw k0, 0x74(sp)
- mthi k0
- nop
- lw k0, 0x78(sp)
- mtc0 k0, C0_STATUS
- nop
- nop
- nop
- lw k0, 0x7c(sp)
- mtc0 k0, C0_EPC
- nop
- nop
- nop
- lw sp, 0x80(sp)
- eret
- nop
-
.set pop
diff --git a/firmware/target/mips/ingenic_x1000/debug-x1000.c b/firmware/target/mips/ingenic_x1000/debug-x1000.c
index 236442a880..827bb37855 100644
--- a/firmware/target/mips/ingenic_x1000/debug-x1000.c
+++ b/firmware/target/mips/ingenic_x1000/debug-x1000.c
@@ -121,6 +121,9 @@ extern volatile unsigned aic_tx_underruns;
#ifdef HAVE_RECORDING
extern volatile unsigned aic_rx_overruns;
#endif
+#ifdef HAVE_EROS_QN_CODEC
+extern int es9018k2m_present_flag;
+#endif
static bool dbg_audio(void)
{
@@ -130,6 +133,16 @@ static bool dbg_audio(void)
#ifdef HAVE_RECORDING
lcd_putsf(0, 1, "RX overruns: %u", aic_rx_overruns);
#endif
+#ifdef HAVE_EROS_QN_CODEC
+ if (es9018k2m_present_flag)
+ {
+ lcd_putsf(0, 2, "(%d) ES9018K2M HWVOL", es9018k2m_present_flag);
+ }
+ else
+ {
+ lcd_putsf(0, 2, "(%d) SWVOL", es9018k2m_present_flag);
+ }
+#endif
lcd_update();
} while(get_action(CONTEXT_STD, HZ) != ACTION_STD_CANCEL);
diff --git a/firmware/target/mips/ingenic_x1000/dma-x1000.h b/firmware/target/mips/ingenic_x1000/dma-x1000.h
index 8bb5f1ddaa..4a526cec02 100644
--- a/firmware/target/mips/ingenic_x1000/dma-x1000.h
+++ b/firmware/target/mips/ingenic_x1000/dma-x1000.h
@@ -64,7 +64,7 @@ typedef struct dma_desc dma_desc;
typedef void(*dma_cb_func)(int event);
-extern void dma_init(void);
+extern void dma_init(void) INIT_ATTR;
extern void dma_set_callback(int chn, dma_cb_func cb);
#endif /* __DMA_X1000_H__ */
diff --git a/firmware/target/mips/ingenic_x1000/erosqnative/audiohw-erosqnative.c b/firmware/target/mips/ingenic_x1000/erosqnative/audiohw-erosqnative.c
index b32a32a3a3..df97aba0c8 100644
--- a/firmware/target/mips/ingenic_x1000/erosqnative/audiohw-erosqnative.c
+++ b/firmware/target/mips/ingenic_x1000/erosqnative/audiohw-erosqnative.c
@@ -19,28 +19,36 @@
*
****************************************************************************/
-#include "audiohw.h"
#include "system.h"
+#include "audiohw.h"
+#include "pcm_sw_volume.h"
#include "pcm_sampr.h"
+#include "i2c-target.h"
+#include "button.h"
+
+// #define LOGF_ENABLE
+#include "logf.h"
+
#include "aic-x1000.h"
#include "i2c-x1000.h"
#include "gpio-x1000.h"
-#include "logf.h"
-/* Audio path appears to be:
- * DAC --> HP Amp --> Stereo Switch --> HP OUT
- * \--> LO OUT
+/*
+ * Earlier devices audio path appears to be:
+ * DAC \--> HP Amp --> Stereo Switch --> HP OUT
+ * \-> LO OUT
*
- * The real purpose of the Stereo Switch is not clear.
- * It appears to switch sources between the HP amp and something,
- * likely something unimplemented. */
+ * Recent devices, the audio path seems to have changed to:
+ * DAC --> HP Amp --> Stereo Switch \--> HP OUT
+ * \-> LO OUT
+ */
void audiohw_init(void)
{
/* explicitly mute everything */
- gpio_set_level(GPIO_MAX97220_SHDN, 0);
- gpio_set_level(GPIO_ISL54405_MUTE, 1);
- gpio_set_level(GPIO_PCM5102A_XMIT, 0);
+ gpio_set_level(GPIO_HPAMP_SHDN, 0);
+ gpio_set_level(GPIO_STEREOSW_MUTE, 1);
+ gpio_set_level(GPIO_DAC_PWR, 0);
aic_set_play_last_sample(true);
aic_set_external_codec(true);
@@ -53,8 +61,8 @@ void audiohw_init(void)
mdelay(10);
/* power on DAC and HP Amp */
- gpio_set_level(GPIO_PCM5102A_ANALOG_PWR, 1);
- gpio_set_level(GPIO_MAX97220_POWER, 1);
+ gpio_set_level(GPIO_DAC_ANALOG_PWR, 1);
+ gpio_set_level(GPIO_HPAMP_POWER, 1);
}
void audiohw_postinit(void)
@@ -76,23 +84,39 @@ void audiohw_postinit(void)
jz_writef(AIC_CCR, ERPL(0));
/* unmute - attempt to make power-on pop-free */
- gpio_set_level(GPIO_ISL54405_SEL, 0);
- gpio_set_level(GPIO_MAX97220_SHDN, 1);
+ gpio_set_level(GPIO_STEREOSW_SEL, 0);
+ gpio_set_level(GPIO_HPAMP_SHDN, 1);
mdelay(10);
- gpio_set_level(GPIO_PCM5102A_XMIT, 1);
+ gpio_set_level(GPIO_DAC_PWR, 1);
mdelay(10);
- gpio_set_level(GPIO_ISL54405_MUTE, 0);
+ gpio_set_level(GPIO_STEREOSW_MUTE, 0);
+
+ i2c_x1000_set_freq(ES9018K2M_BUS, I2C_FREQ_400K);
+
+ int ret = es9018k2m_read_reg(ES9018K2M_REG0_SYSTEM_SETTINGS);
+ if (ret >= 0) /* Detected ES9018K2M DAC */
+ {
+ logf("ES9018K2M found: ret=%d", ret);
+ es9018k2m_present_flag = 1;
+
+ /* Default is 32-bit data, and it works ok. Enabling the following
+ * causes issue. Which is weird, I definitely thought AIC was configured
+ * for 24-bit data... */
+ // es9018k2m_write_reg(ES9018K2M_REG1_INPUT_CONFIG, 0b01001100); // 24-bit data
+
+ } else { /* Default to SWVOL for PCM5102A DAC */
+ logf("Default to SWVOL: ret=%d", ret);
+ }
}
-/* TODO: get shutdown just right according to dac datasheet */
void audiohw_close(void)
{
/* mute - attempt to make power-off pop-free */
- gpio_set_level(GPIO_ISL54405_MUTE, 1);
+ gpio_set_level(GPIO_STEREOSW_MUTE, 1);
mdelay(10);
- gpio_set_level(GPIO_PCM5102A_XMIT, 0);
+ gpio_set_level(GPIO_DAC_PWR, 0);
mdelay(10);
- gpio_set_level(GPIO_MAX97220_SHDN, 0);
+ gpio_set_level(GPIO_HPAMP_SHDN, 0);
}
void audiohw_set_frequency(int fsel)
@@ -105,3 +129,54 @@ void audiohw_set_frequency(int fsel)
aic_enable_i2s_bit_clock(true);
}
+void audiohw_set_volume(int vol_l, int vol_r)
+{
+ int l, r;
+
+ eros_qn_set_last_vol(vol_l, vol_r);
+
+ l = vol_l;
+ r = vol_r;
+
+#if (defined(HAVE_HEADPHONE_DETECTION) && defined(HAVE_LINEOUT_DETECTION))
+ /* make sure headphones aren't present - don't want to
+ * blow out our eardrums cranking it to full */
+ if (lineout_inserted() && !headphones_inserted())
+ {
+ eros_qn_switch_output(1);
+
+ l = r = eros_qn_get_volume_limit();
+ }
+ else
+ {
+ eros_qn_switch_output(0);
+ }
+#endif
+
+ if (es9018k2m_present_flag) /* ES9018K2M */
+ {
+ /* Same volume range and mute point for both DACs, so use PCM5102A_VOLUME_MIN */
+ l = l <= PCM5102A_VOLUME_MIN ? PCM_MUTE_LEVEL : l;
+ r = r <= PCM5102A_VOLUME_MIN ? PCM_MUTE_LEVEL : r;
+
+ /* set software volume just below unity due to
+ * DAC offset. We don't want to overflow the PCM system. */
+ pcm_set_master_volume(-1, -1);
+ es9018k2m_set_volume_async(l, r);
+ }
+ else /* PCM5102A */
+ {
+ l = l <= PCM5102A_VOLUME_MIN ? PCM_MUTE_LEVEL : (l / 20);
+ r = r <= PCM5102A_VOLUME_MIN ? PCM_MUTE_LEVEL : (r / 20);
+
+ pcm_set_master_volume(l, r);
+ }
+}
+
+void audiohw_set_filter_roll_off(int value)
+{
+ if (es9018k2m_present_flag)
+ {
+ es9018k2m_set_filter_roll_off(value);
+ }
+} \ No newline at end of file
diff --git a/firmware/target/mips/ingenic_x1000/erosqnative/button-erosqnative.c b/firmware/target/mips/ingenic_x1000/erosqnative/button-erosqnative.c
index 1583db175a..0d2207af2a 100644
--- a/firmware/target/mips/ingenic_x1000/erosqnative/button-erosqnative.c
+++ b/firmware/target/mips/ingenic_x1000/erosqnative/button-erosqnative.c
@@ -127,7 +127,7 @@ bool headphones_inserted(void)
{
hp_detect_reg_old = hp_detect_reg;
#if !defined(BOOTLOADER)
- pcm5102_set_outputs();
+ eros_qn_set_outputs();
#endif
}
return hp_detect_reg & 0x10 ? false : true;
@@ -140,7 +140,7 @@ bool lineout_inserted(void)
{
hp_detect_reg_old = hp_detect_reg;
#if !defined(BOOTLOADER)
- pcm5102_set_outputs();
+ eros_qn_set_outputs();
#endif
}
return hp_detect_reg & 0x20 ? false : true;
@@ -233,6 +233,8 @@ int button_read_device(void)
* Rockbox treats these buttons differently. */
queue_post(&button_queue, BUTTON_SCROLL_FWD, 0);
enc_position = 0;
+ reset_poweroff_timer();
+ backlight_on();
}
else if (enc_position < -1)
{
@@ -240,6 +242,8 @@ int button_read_device(void)
* Rockbox treats these buttons differently. */
queue_post(&button_queue, BUTTON_SCROLL_BACK, 0);
enc_position = 0;
+ reset_poweroff_timer();
+ backlight_on();
}
return r;
diff --git a/firmware/target/mips/ingenic_x1000/erosqnative/gpio-target.h b/firmware/target/mips/ingenic_x1000/erosqnative/gpio-target.h
index 376eae136e..72052c261f 100644
--- a/firmware/target/mips/ingenic_x1000/erosqnative/gpio-target.h
+++ b/firmware/target/mips/ingenic_x1000/erosqnative/gpio-target.h
@@ -15,35 +15,39 @@
/* ---------------------------------------------- */
+
/* Name Port Pins Function */
DEFINE_PINGROUP(LCD_DATA, GPIO_A, 0xffff << 0, GPIOF_DEVICE(1))
DEFINE_PINGROUP(LCD_CONTROL, GPIO_B, 0x1a << 16, GPIOF_DEVICE(1))
DEFINE_PINGROUP(MSC0, GPIO_A, 0x3f << 20, GPIOF_DEVICE(1))
DEFINE_PINGROUP(SFC, GPIO_A, 0x3f << 26, GPIOF_DEVICE(1))
DEFINE_PINGROUP(I2S, GPIO_B, 0x1f << 0, GPIOF_DEVICE(1))
+DEFINE_PINGROUP(I2C1, GPIO_C, 3 << 26, GPIOF_DEVICE(0))
DEFINE_PINGROUP(I2C2, GPIO_D, 3 << 0, GPIOF_DEVICE(1))
/* Name Pin Function */
-/* mute DAC - 0 - mute, 1 - play. Affects both HP and LO. */
-DEFINE_GPIO(PCM5102A_XMIT, GPIO_PB(12), GPIOF_OUTPUT(0))
+/* mute DAC: 0 - mute, 1 - play */
+/* Note: This seems to actually be power to the DAC in general,
+ * at least on the ES9018K2M devices. Was "DAC_XMIT". */
+DEFINE_GPIO(DAC_PWR, GPIO_PB(12), GPIOF_OUTPUT(0))
-/* mute HP amp, no effect on LO. 0 - mute, 1 - play */
-DEFINE_GPIO(MAX97220_SHDN, GPIO_PB(8), GPIOF_OUTPUT(0))
+/* mute HP amp: 0 - mute, 1 - play */
+DEFINE_GPIO(HPAMP_SHDN, GPIO_PB(8), GPIOF_OUTPUT(0))
-/* mute audio mux, only affects Headphone out.
- * 0 - play, 1 - mute */
-DEFINE_GPIO(ISL54405_MUTE, GPIO_PB(15), GPIOF_OUTPUT(1))
+/* mute audio mux: 0 - play, 1 - mute */
+DEFINE_GPIO(STEREOSW_MUTE, GPIO_PB(15), GPIOF_OUTPUT(1))
-/* switches HP on/off - 0 HP on, 1 hp off, has no effect on LO.
- * As best I can tell, it switches HP Out sources between HP amp and something
- * not implemented - there seem to be resistors missing. */
-DEFINE_GPIO(ISL54405_SEL, GPIO_PB(5), GPIOF_OUTPUT(0))
+/*
+ * Original devices: switches HP on/off - 0 HP on, 1 HP off, no effect on LO.
+ * Newer devices: switches between HP and LO - 0 HP, 1 LO.
+ */
+DEFINE_GPIO(STEREOSW_SEL, GPIO_PB(5), GPIOF_OUTPUT(0))
/* DAC AVDD */
-DEFINE_GPIO(PCM5102A_ANALOG_PWR, GPIO_PB(9), GPIOF_OUTPUT(0))
+DEFINE_GPIO(DAC_ANALOG_PWR, GPIO_PB(9), GPIOF_OUTPUT(0))
/* Headphone Amp power */
-DEFINE_GPIO(MAX97220_POWER, GPIO_PB(6), GPIOF_OUTPUT(0))
+DEFINE_GPIO(HPAMP_POWER, GPIO_PB(6), GPIOF_OUTPUT(0))
/* SD card */
DEFINE_GPIO(MSC0_CD, GPIO_PB(11), GPIOF_INPUT)
diff --git a/firmware/target/mips/ingenic_x1000/erosqnative/i2c-target.h b/firmware/target/mips/ingenic_x1000/erosqnative/i2c-target.h
index 8d0b8a6e20..89d995f33a 100644
--- a/firmware/target/mips/ingenic_x1000/erosqnative/i2c-target.h
+++ b/firmware/target/mips/ingenic_x1000/erosqnative/i2c-target.h
@@ -25,6 +25,9 @@
#define I2C_ASYNC_BUS_COUNT 3
#define I2C_ASYNC_QUEUE_SIZE 4
+#define ES9018K2M_BUS 1
+#define ES9018K2M_ADDR 0x48
+
#define AXP_PMU_BUS 2
#define AXP_PMU_ADDR 0x34
diff --git a/firmware/target/mips/ingenic_x1000/gpio-x1000.c b/firmware/target/mips/ingenic_x1000/gpio-x1000.c
index 14195359df..0ebe424566 100644
--- a/firmware/target/mips/ingenic_x1000/gpio-x1000.c
+++ b/firmware/target/mips/ingenic_x1000/gpio-x1000.c
@@ -21,7 +21,7 @@
#include "gpio-x1000.h"
-const struct gpio_setting gpio_settings[PIN_COUNT] = {
+static const struct gpio_setting gpio_settings[PIN_COUNT] INITDATA_ATTR = {
#define DEFINE_GPIO(_name, _gpio, _func) \
{.gpio = _gpio, .func = _func},
#define DEFINE_PINGROUP(...)
@@ -30,7 +30,7 @@ const struct gpio_setting gpio_settings[PIN_COUNT] = {
#undef DEFINE_PINGROUP
};
-const struct pingroup_setting pingroup_settings[PINGROUP_COUNT] = {
+static const struct pingroup_setting pingroup_settings[PINGROUP_COUNT] INITDATA_ATTR = {
#define DEFINE_GPIO(...)
#define DEFINE_PINGROUP(_name, _port, _pins, _func) \
{.port = _port, .pins = _pins, .func = _func},
@@ -39,7 +39,8 @@ const struct pingroup_setting pingroup_settings[PINGROUP_COUNT] = {
#undef DEFINE_PINGROUP
};
-const char* const gpio_names[PIN_COUNT] = {
+#if 0 /* not needed for the time being */
+static const char* const gpio_names[PIN_COUNT] = {
#define DEFINE_GPIO(_name, ...) #_name,
#define DEFINE_PINGROUP(...)
#include "gpio-target.h"
@@ -47,13 +48,14 @@ const char* const gpio_names[PIN_COUNT] = {
#undef DEFINE_PINGROUP
};
-const char* const pingroup_names[PINGROUP_COUNT] = {
+static const char* const pingroup_names[PINGROUP_COUNT] = {
#define DEFINE_GPIO(...)
#define DEFINE_PINGROUP(_name, ...) #_name,
#include "gpio-target.h"
#undef DEFINE_GPIO
#undef DEFINE_PINGROUP
};
+#endif
void gpio_init(void)
{
diff --git a/firmware/target/mips/ingenic_x1000/gpio-x1000.h b/firmware/target/mips/ingenic_x1000/gpio-x1000.h
index eac5f8651f..310a457ab5 100644
--- a/firmware/target/mips/ingenic_x1000/gpio-x1000.h
+++ b/firmware/target/mips/ingenic_x1000/gpio-x1000.h
@@ -23,6 +23,7 @@
#define __GPIO_X1000_H__
#include "x1000/gpio.h"
+#include "config.h"
/* GPIO port numbers */
#define GPIO_A 0
@@ -103,16 +104,8 @@ enum {
PINGROUP_COUNT,
};
-/* arrays which define the target's GPIO settings */
-extern const struct gpio_setting gpio_settings[PIN_COUNT];
-extern const struct pingroup_setting pingroup_settings[PINGROUP_COUNT];
-
-/* stringified names for use in debug menus */
-extern const char* const gpio_names[PIN_COUNT];
-extern const char* const pingroup_names[PINGROUP_COUNT];
-
/* called at early init to set up GPIOs */
-extern void gpio_init(void);
+extern void gpio_init(void) INIT_ATTR;
/* Use GPIO Z to reconfigure several pins atomically */
extern void gpioz_configure(int port, uint32_t pins, int func);
diff --git a/firmware/target/mips/ingenic_x1000/i2c-x1000.h b/firmware/target/mips/ingenic_x1000/i2c-x1000.h
index e76624d511..9b9ba5e088 100644
--- a/firmware/target/mips/ingenic_x1000/i2c-x1000.h
+++ b/firmware/target/mips/ingenic_x1000/i2c-x1000.h
@@ -27,7 +27,7 @@
#define I2C_FREQ_100K 100000
#define I2C_FREQ_400K 400000
-extern void i2c_init(void);
+extern void i2c_init(void) INIT_ATTR;
/* Configure the I2C controller prior to use.
*
diff --git a/firmware/target/mips/ingenic_x1000/installer-x1000.c b/firmware/target/mips/ingenic_x1000/installer-x1000.c
index 66aa42d4a1..d2f9e4e5e0 100644
--- a/firmware/target/mips/ingenic_x1000/installer-x1000.c
+++ b/firmware/target/mips/ingenic_x1000/installer-x1000.c
@@ -62,10 +62,13 @@ static const struct update_part updates[] = {
static const int num_updates = sizeof(updates) / sizeof(struct update_part);
+static const uint8_t flash_sig_magic[8] =
+ {0x06, 0x05, 0x04, 0x03, 0x02, 0x55, 0xaa, 0x55};
+
/* calculate the offset and length of the update image; this is constant
* for a given target, based on the update parts and the NAND chip geometry.
*/
-static void get_image_loc(nand_drv* ndrv, size_t* offptr, size_t* lenptr)
+static void get_image_loc(struct nand_drv* ndrv, size_t* offptr, size_t* lenptr)
{
size_t blk_size = ndrv->chip->page_size << ndrv->chip->log2_ppb;
size_t img_off = 0;
@@ -119,7 +122,7 @@ struct updater {
size_t img_len; /* image length in flash = size of the buffer */
mtar_t* tar;
- nand_drv* ndrv;
+ struct nand_drv* ndrv;
};
static int updater_init(struct updater* u)
@@ -148,7 +151,7 @@ static int updater_init(struct updater* u)
/* buf_len is a bit oversized here, but it's not really important */
u->buf_len = u->img_len + sizeof(mtar_t) + 2*CACHEALIGN_SIZE;
- u->buf_hnd = core_alloc_ex("boot_image", u->buf_len, &buflib_ops_locked);
+ u->buf_hnd = core_alloc_ex(u->buf_len, &buflib_ops_locked);
if(u->buf_hnd < 0) {
rc = IERR_OUT_OF_MEMORY;
goto error;
@@ -178,8 +181,7 @@ static void updater_cleanup(struct updater* u)
if(u->tar && mtar_is_open(u->tar))
mtar_close(u->tar);
- if(u->buf_hnd >= 0)
- core_free(u->buf_hnd);
+ core_free(u->buf_hnd);
if(u->ndrv) {
nand_close(u->ndrv);
@@ -250,6 +252,12 @@ int backup_bootloader(const char* filename)
goto error;
}
+ /* bail if we're backing up something that looks like garbage */
+ if (memcmp(u.img_buf, flash_sig_magic, 8)) {
+ rc = IERR_CORRUPTED_BACKUP;
+ goto error;
+ }
+
/* write to file */
fd = open(filename, O_CREAT|O_TRUNC|O_WRONLY);
if(fd < 0) {
@@ -294,6 +302,12 @@ int restore_bootloader(const char* filename)
goto error;
}
+ /* safety check to reduce risk of flashing complete garbage */
+ if (memcmp(u.img_buf, flash_sig_magic, 8)) {
+ rc = IERR_CORRUPTED_BACKUP;
+ goto error;
+ }
+
/* write image */
rc = nand_write_bytes(u.ndrv, u.img_off, u.img_len, u.img_buf);
if(rc != NAND_SUCCESS) {
@@ -321,6 +335,7 @@ const char* installer_strerror(int rc)
case IERR_NAND_OPEN: return "NAND open error";
case IERR_NAND_READ: return "NAND read error";
case IERR_NAND_WRITE: return "NAND write error";
+ case IERR_CORRUPTED_BACKUP: return "Backup is corrupt";
default: return "Unknown error!?";
}
}
diff --git a/firmware/target/mips/ingenic_x1000/installer-x1000.h b/firmware/target/mips/ingenic_x1000/installer-x1000.h
index b71839a907..9b0f1e4bd6 100644
--- a/firmware/target/mips/ingenic_x1000/installer-x1000.h
+++ b/firmware/target/mips/ingenic_x1000/installer-x1000.h
@@ -45,6 +45,7 @@ enum {
IERR_NAND_OPEN,
IERR_NAND_READ,
IERR_NAND_WRITE,
+ IERR_CORRUPTED_BACKUP,
};
extern int install_bootloader(const char* filename);
diff --git a/firmware/target/mips/ingenic_x1000/lcd-x1000.c b/firmware/target/mips/ingenic_x1000/lcd-x1000.c
index b66359a598..979febf066 100644
--- a/firmware/target/mips/ingenic_x1000/lcd-x1000.c
+++ b/firmware/target/mips/ingenic_x1000/lcd-x1000.c
@@ -428,7 +428,10 @@ void lcd_enable(bool en)
/* Handle turning the LCD back on */
if(!bit && en)
+ {
+ send_event(LCD_EVENT_ACTIVATION, NULL);
lcd_dma_start();
+ }
}
#endif
diff --git a/firmware/target/mips/ingenic_x1000/nand-x1000.c b/firmware/target/mips/ingenic_x1000/nand-x1000.c
index 5838b21b39..af0f972eae 100644
--- a/firmware/target/mips/ingenic_x1000/nand-x1000.c
+++ b/firmware/target/mips/ingenic_x1000/nand-x1000.c
@@ -22,76 +22,98 @@
#include "nand-x1000.h"
#include "sfc-x1000.h"
#include "system.h"
+#include "logf.h"
#include <string.h>
-/* cmd mode a d phase format has data */
-#define NANDCMD_RESET SFC_CMD(0xff, SFC_TMODE_1_1_1, 0, 0, SFC_PFMT_ADDR_FIRST, 0)
-#define NANDCMD_READID(x,y) SFC_CMD(0x9f, SFC_TMODE_1_1_1, x, y, SFC_PFMT_ADDR_FIRST, 1)
-#define NANDCMD_WR_EN SFC_CMD(0x06, SFC_TMODE_1_1_1, 0, 0, SFC_PFMT_ADDR_FIRST, 0)
-#define NANDCMD_GET_FEATURE SFC_CMD(0x0f, SFC_TMODE_1_1_1, 1, 0, SFC_PFMT_ADDR_FIRST, 1)
-#define NANDCMD_SET_FEATURE SFC_CMD(0x1f, SFC_TMODE_1_1_1, 1, 0, SFC_PFMT_ADDR_FIRST, 1)
-#define NANDCMD_PAGE_READ(x) SFC_CMD(0x13, SFC_TMODE_1_1_1, x, 0, SFC_PFMT_ADDR_FIRST, 0)
-#define NANDCMD_READ_CACHE(x) SFC_CMD(0x0b, SFC_TMODE_1_1_1, x, 8, SFC_PFMT_ADDR_FIRST, 1)
-#define NANDCMD_READ_CACHE_x4(x) SFC_CMD(0x6b, SFC_TMODE_1_1_4, x, 8, SFC_PFMT_ADDR_FIRST, 1)
-#define NANDCMD_PROGRAM_LOAD(x) SFC_CMD(0x02, SFC_TMODE_1_1_1, x, 0, SFC_PFMT_ADDR_FIRST, 1)
-#define NANDCMD_PROGRAM_LOAD_x4(x) SFC_CMD(0x32, SFC_TMODE_1_1_4, x, 0, SFC_PFMT_ADDR_FIRST, 1)
-#define NANDCMD_PROGRAM_EXECUTE(x) SFC_CMD(0x10, SFC_TMODE_1_1_1, x, 0, SFC_PFMT_ADDR_FIRST, 0)
-#define NANDCMD_BLOCK_ERASE(x) SFC_CMD(0xd8, SFC_TMODE_1_1_1, x, 0, SFC_PFMT_ADDR_FIRST, 0)
-
-/* Feature registers are found in linux/mtd/spinand.h,
- * apparently these are pretty standardized */
-#define FREG_PROT 0xa0
-#define FREG_PROT_UNLOCK 0x00
-
-#define FREG_CFG 0xb0
-#define FREG_CFG_OTP_ENABLE (1 << 6)
-#define FREG_CFG_ECC_ENABLE (1 << 4)
-#define FREG_CFG_QUAD_ENABLE (1 << 0)
-
-#define FREG_STATUS 0xc0
-#define FREG_STATUS_BUSY (1 << 0)
-#define FREG_STATUS_EFAIL (1 << 2)
-#define FREG_STATUS_PFAIL (1 << 3)
-#define FREG_STATUS_ECC_MASK (3 << 4)
-#define FREG_STATUS_ECC_NO_FLIPS (0 << 4)
-#define FREG_STATUS_ECC_HAS_FLIPS (1 << 4)
-#define FREG_STATUS_ECC_UNCOR_ERR (2 << 4)
-
-const nand_chip supported_nand_chips[] = {
-#if defined(FIIO_M3K) || defined(SHANLING_Q1) || defined(EROS_QN)
- {
- /* ATO25D1GA */
- .mf_id = 0x9b,
- .dev_id = 0x12,
- .row_cycles = 3,
- .col_cycles = 2,
- .log2_ppb = 6, /* 64 pages */
- .page_size = 2048,
- .oob_size = 64,
- .nr_blocks = 1024,
- .bbm_pos = 2048,
- .clock_freq = 150000000,
- .dev_conf = jz_orf(SFC_DEV_CONF,
- CE_DL(1), HOLD_DL(1), WP_DL(1),
- CPHA(0), CPOL(0),
- TSH(7), TSETUP(0), THOLD(0),
- STA_TYPE_V(1BYTE), CMD_TYPE_V(8BITS),
- SMP_DELAY(1)),
- .flags = NAND_CHIPFLAG_QUAD | NAND_CHIPFLAG_HAS_QE_BIT,
- },
-#else
- { 0 },
-#endif
+static void winbond_setup_chip(struct nand_drv* drv);
+
+static const struct nand_chip chip_ato25d1ga = {
+ .log2_ppb = 6, /* 64 pages */
+ .page_size = 2048,
+ .oob_size = 64,
+ .nr_blocks = 1024,
+ .bbm_pos = 2048,
+ .clock_freq = 150000000,
+ .dev_conf = jz_orf(SFC_DEV_CONF,
+ CE_DL(1), HOLD_DL(1), WP_DL(1),
+ CPHA(0), CPOL(0),
+ TSH(7), TSETUP(0), THOLD(0),
+ STA_TYPE_V(1BYTE), CMD_TYPE_V(8BITS),
+ SMP_DELAY(1)),
+ .flags = NAND_CHIPFLAG_QUAD | NAND_CHIPFLAG_HAS_QE_BIT,
+ .cmd_page_read = NANDCMD_PAGE_READ,
+ .cmd_program_execute = NANDCMD_PROGRAM_EXECUTE,
+ .cmd_block_erase = NANDCMD_BLOCK_ERASE,
+ .cmd_read_cache = NANDCMD_READ_CACHE_x4,
+ .cmd_program_load = NANDCMD_PROGRAM_LOAD_x4,
};
-const size_t nr_supported_nand_chips =
- sizeof(supported_nand_chips) / sizeof(nand_chip);
+static const struct nand_chip chip_w25n01gvxx = {
+ .log2_ppb = 6, /* 64 pages */
+ .page_size = 2048,
+ .oob_size = 64,
+ .nr_blocks = 1024,
+ .bbm_pos = 2048,
+ .clock_freq = 150000000,
+ .dev_conf = jz_orf(SFC_DEV_CONF,
+ CE_DL(1), HOLD_DL(1), WP_DL(1),
+ CPHA(0), CPOL(0),
+ TSH(11), TSETUP(0), THOLD(0),
+ STA_TYPE_V(1BYTE), CMD_TYPE_V(8BITS),
+ SMP_DELAY(1)),
+ .flags = NAND_CHIPFLAG_ON_DIE_ECC,
+ /* TODO: quad mode? */
+ .cmd_page_read = NANDCMD_PAGE_READ,
+ .cmd_program_execute = NANDCMD_PROGRAM_EXECUTE,
+ .cmd_block_erase = NANDCMD_BLOCK_ERASE,
+ .cmd_read_cache = NANDCMD_READ_CACHE_SLOW,
+ .cmd_program_load = NANDCMD_PROGRAM_LOAD,
+ .setup_chip = winbond_setup_chip,
+};
+
+static const struct nand_chip chip_gd5f1gq4xexx = {
+ .log2_ppb = 6, /* 64 pages */
+ .page_size = 2048,
+ .oob_size = 64, /* 128B when hardware ECC is disabled */
+ .nr_blocks = 1024,
+ .bbm_pos = 2048,
+ .clock_freq = 150000000,
+ .dev_conf = jz_orf(SFC_DEV_CONF,
+ CE_DL(1), HOLD_DL(1), WP_DL(1),
+ CPHA(0), CPOL(0),
+ TSH(7), TSETUP(0), THOLD(0),
+ STA_TYPE_V(1BYTE), CMD_TYPE_V(8BITS),
+ SMP_DELAY(1)),
+ .flags = NAND_CHIPFLAG_QUAD | NAND_CHIPFLAG_HAS_QE_BIT |
+ NAND_CHIPFLAG_ON_DIE_ECC,
+ .cmd_page_read = NANDCMD_PAGE_READ,
+ .cmd_program_execute = NANDCMD_PROGRAM_EXECUTE,
+ .cmd_block_erase = NANDCMD_BLOCK_ERASE,
+ .cmd_read_cache = NANDCMD_READ_CACHE_x4,
+ .cmd_program_load = NANDCMD_PROGRAM_LOAD_x4,
+};
-static nand_drv static_nand_drv;
+#define chip_ds35x1gaxxx chip_gd5f1gq4xexx
+#define chip_gd5f1gq5xexxg chip_gd5f1gq4xexx
+
+const struct nand_chip_id supported_nand_chips[] = {
+ NAND_CHIP_ID(&chip_ato25d1ga, NAND_READID_ADDR, 0x9b, 0x12),
+ NAND_CHIP_ID(&chip_w25n01gvxx, NAND_READID_ADDR, 0xef, 0xaa, 0x21),
+ NAND_CHIP_ID(&chip_gd5f1gq4xexx, NAND_READID_ADDR, 0xc8, 0xd1),
+ NAND_CHIP_ID(&chip_gd5f1gq4xexx, NAND_READID_ADDR, 0xc8, 0xc1),
+ NAND_CHIP_ID(&chip_ds35x1gaxxx, NAND_READID_ADDR, 0xe5, 0x71), /* 3.3 V */
+ NAND_CHIP_ID(&chip_ds35x1gaxxx, NAND_READID_ADDR, 0xe5, 0x21), /* 1.8 V */
+ NAND_CHIP_ID(&chip_gd5f1gq5xexxg, NAND_READID_ADDR, 0xc8, 0x51), /* 3.3 V */
+ NAND_CHIP_ID(&chip_gd5f1gq5xexxg, NAND_READID_ADDR, 0xc8, 0x41), /* 1.8 V */
+};
+
+const size_t nr_supported_nand_chips = ARRAYLEN(supported_nand_chips);
+
+static struct nand_drv static_nand_drv;
static uint8_t static_scratch_buf[NAND_DRV_SCRATCHSIZE] CACHEALIGN_ATTR;
static uint8_t static_page_buf[NAND_DRV_MAXPAGESIZE] CACHEALIGN_ATTR;
-nand_drv* nand_init(void)
+struct nand_drv* nand_init(void)
{
static bool inited = false;
if(!inited) {
@@ -104,19 +126,19 @@ nand_drv* nand_init(void)
return &static_nand_drv;
}
-static uint8_t nand_get_reg(nand_drv* drv, uint8_t reg)
+static uint8_t nand_get_reg(struct nand_drv* drv, uint8_t reg)
{
sfc_exec(NANDCMD_GET_FEATURE, reg, drv->scratch_buf, 1|SFC_READ);
return drv->scratch_buf[0];
}
-static void nand_set_reg(nand_drv* drv, uint8_t reg, uint8_t val)
+static void nand_set_reg(struct nand_drv* drv, uint8_t reg, uint8_t val)
{
drv->scratch_buf[0] = val;
sfc_exec(NANDCMD_SET_FEATURE, reg, drv->scratch_buf, 1|SFC_WRITE);
}
-static void nand_upd_reg(nand_drv* drv, uint8_t reg, uint8_t msk, uint8_t val)
+static void nand_upd_reg(struct nand_drv* drv, uint8_t reg, uint8_t msk, uint8_t val)
{
uint8_t x = nand_get_reg(drv, reg);
x &= ~msk;
@@ -124,56 +146,50 @@ static void nand_upd_reg(nand_drv* drv, uint8_t reg, uint8_t msk, uint8_t val)
nand_set_reg(drv, reg, x);
}
-static bool identify_chip(nand_drv* drv)
+static const struct nand_chip* identify_chip_method(uint8_t method,
+ const uint8_t* id_buf)
+{
+ for (size_t i = 0; i < nr_supported_nand_chips; ++i) {
+ const struct nand_chip_id* chip_id = &supported_nand_chips[i];
+ if (chip_id->method == method &&
+ !memcmp(chip_id->id_bytes, id_buf, chip_id->num_id_bytes))
+ return chip_id->chip;
+ }
+
+ return NULL;
+}
+
+static bool identify_chip(struct nand_drv* drv)
{
/* Read ID command has some variations; Linux handles these 3:
* - no address or dummy bytes
* - 1 byte address, no dummy byte
* - no address byte, 1 byte dummy
*
- * Right now there is only a need for the 2nd variation, as that is
- * the method used by the ATO25D1GA.
- *
- * Some chips also output more than 2 ID bytes.
+ * Currently we use the 2nd method, aka. address read ID, the
+ * other methods can be added when needed.
*/
- sfc_exec(NANDCMD_READID(1, 0), 0, drv->scratch_buf, 2|SFC_READ);
- drv->mf_id = drv->scratch_buf[0];
- drv->dev_id = drv->scratch_buf[1];
-
- for(size_t i = 0; i < nr_supported_nand_chips; ++i) {
- const nand_chip* chip = &supported_nand_chips[i];
- if(chip->mf_id == drv->mf_id && chip->dev_id == drv->dev_id) {
- drv->chip = chip;
- return true;
- }
- }
+ sfc_exec(NANDCMD_READID_ADDR, 0, drv->scratch_buf, 4|SFC_READ);
+ drv->chip = identify_chip_method(NAND_READID_ADDR, drv->scratch_buf);
+ if (drv->chip)
+ return true;
return false;
}
-static void setup_chip_data(nand_drv* drv)
+static void setup_chip_data(struct nand_drv* drv)
{
drv->ppb = 1 << drv->chip->log2_ppb;
drv->fpage_size = drv->chip->page_size + drv->chip->oob_size;
}
-static void setup_chip_commands(nand_drv* drv)
+static void winbond_setup_chip(struct nand_drv* drv)
{
- /* Select commands appropriate for the chip */
- drv->cmd_page_read = NANDCMD_PAGE_READ(drv->chip->row_cycles);
- drv->cmd_program_execute = NANDCMD_PROGRAM_EXECUTE(drv->chip->row_cycles);
- drv->cmd_block_erase = NANDCMD_BLOCK_ERASE(drv->chip->row_cycles);
-
- if(drv->chip->flags & NAND_CHIPFLAG_QUAD) {
- drv->cmd_read_cache = NANDCMD_READ_CACHE_x4(drv->chip->col_cycles);
- drv->cmd_program_load = NANDCMD_PROGRAM_LOAD_x4(drv->chip->col_cycles);
- } else {
- drv->cmd_read_cache = NANDCMD_READ_CACHE(drv->chip->col_cycles);
- drv->cmd_program_load = NANDCMD_PROGRAM_LOAD(drv->chip->col_cycles);
- }
+ /* Ensure we are in buffered read mode. */
+ nand_upd_reg(drv, FREG_CFG, FREG_CFG_WINBOND_BUF, FREG_CFG_WINBOND_BUF);
}
-static void setup_chip_registers(nand_drv* drv)
+static void setup_chip_registers(struct nand_drv* drv)
{
/* Set chip registers to enter normal operation */
if(drv->chip->flags & NAND_CHIPFLAG_HAS_QE_BIT) {
@@ -182,14 +198,23 @@ static void setup_chip_registers(nand_drv* drv)
en ? FREG_CFG_QUAD_ENABLE : 0);
}
+ if(drv->chip->flags & NAND_CHIPFLAG_ON_DIE_ECC) {
+ /* Enable on-die ECC */
+ nand_upd_reg(drv, FREG_CFG, FREG_CFG_ECC_ENABLE, FREG_CFG_ECC_ENABLE);
+ }
+
/* Clear OTP bit to access the main data array */
nand_upd_reg(drv, FREG_CFG, FREG_CFG_OTP_ENABLE, 0);
/* Clear write protection bits */
nand_set_reg(drv, FREG_PROT, FREG_PROT_UNLOCK);
+
+ /* Call any chip-specific hooks */
+ if(drv->chip->setup_chip)
+ drv->chip->setup_chip(drv);
}
-int nand_open(nand_drv* drv)
+int nand_open(struct nand_drv* drv)
{
if(drv->refcount > 0) {
drv->refcount++;
@@ -198,8 +223,13 @@ int nand_open(nand_drv* drv)
/* Initialize the controller */
sfc_open();
- sfc_set_dev_conf(supported_nand_chips[0].dev_conf);
- sfc_set_clock(supported_nand_chips[0].clock_freq);
+ sfc_set_dev_conf(jz_orf(SFC_DEV_CONF,
+ CE_DL(1), HOLD_DL(1), WP_DL(1),
+ CPHA(0), CPOL(0),
+ TSH(15), TSETUP(0), THOLD(0),
+ STA_TYPE_V(1BYTE), CMD_TYPE_V(8BITS),
+ SMP_DELAY(0)));
+ sfc_set_clock(X1000_EXCLK_FREQ);
/* Send the software reset command */
sfc_exec(NANDCMD_RESET, 0, NULL, 0);
@@ -210,7 +240,6 @@ int nand_open(nand_drv* drv)
return NAND_ERR_UNKNOWN_CHIP;
setup_chip_data(drv);
- setup_chip_commands(drv);
/* Set new SFC parameters */
sfc_set_dev_conf(drv->chip->dev_conf);
@@ -223,7 +252,7 @@ int nand_open(nand_drv* drv)
return NAND_SUCCESS;
}
-void nand_close(nand_drv* drv)
+void nand_close(struct nand_drv* drv)
{
--drv->refcount;
if(drv->refcount > 0)
@@ -237,7 +266,13 @@ void nand_close(nand_drv* drv)
sfc_close();
}
-static uint8_t nand_wait_busy(nand_drv* drv)
+void nand_enable_otp(struct nand_drv* drv, bool enable)
+{
+ nand_upd_reg(drv, FREG_CFG, FREG_CFG_OTP_ENABLE,
+ enable ? FREG_CFG_OTP_ENABLE : 0);
+}
+
+static uint8_t nand_wait_busy(struct nand_drv* drv)
{
uint8_t reg;
do {
@@ -246,10 +281,10 @@ static uint8_t nand_wait_busy(nand_drv* drv)
return reg;
}
-int nand_block_erase(nand_drv* drv, nand_block_t block)
+int nand_block_erase(struct nand_drv* drv, nand_block_t block)
{
sfc_exec(NANDCMD_WR_EN, 0, NULL, 0);
- sfc_exec(drv->cmd_block_erase, block, NULL, 0);
+ sfc_exec(drv->chip->cmd_block_erase, block, NULL, 0);
uint8_t status = nand_wait_busy(drv);
if(status & FREG_STATUS_EFAIL)
@@ -258,11 +293,12 @@ int nand_block_erase(nand_drv* drv, nand_block_t block)
return NAND_SUCCESS;
}
-int nand_page_program(nand_drv* drv, nand_page_t page, const void* buffer)
+int nand_page_program(struct nand_drv* drv, nand_page_t page, const void* buffer)
{
sfc_exec(NANDCMD_WR_EN, 0, NULL, 0);
- sfc_exec(drv->cmd_program_load, 0, (void*)buffer, drv->fpage_size|SFC_WRITE);
- sfc_exec(drv->cmd_program_execute, page, NULL, 0);
+ sfc_exec(drv->chip->cmd_program_load,
+ 0, (void*)buffer, drv->fpage_size|SFC_WRITE);
+ sfc_exec(drv->chip->cmd_program_execute, page, NULL, 0);
uint8_t status = nand_wait_busy(drv);
if(status & FREG_STATUS_PFAIL)
@@ -271,15 +307,29 @@ int nand_page_program(nand_drv* drv, nand_page_t page, const void* buffer)
return NAND_SUCCESS;
}
-int nand_page_read(nand_drv* drv, nand_page_t page, void* buffer)
+int nand_page_read(struct nand_drv* drv, nand_page_t page, void* buffer)
{
- sfc_exec(drv->cmd_page_read, page, NULL, 0);
+ sfc_exec(drv->chip->cmd_page_read, page, NULL, 0);
nand_wait_busy(drv);
- sfc_exec(drv->cmd_read_cache, 0, buffer, drv->fpage_size|SFC_READ);
+ sfc_exec(drv->chip->cmd_read_cache, 0, buffer, drv->fpage_size|SFC_READ);
+
+ if(drv->chip->flags & NAND_CHIPFLAG_ON_DIE_ECC) {
+ uint8_t status = nand_get_reg(drv, FREG_STATUS);
+
+ if(status & FREG_STATUS_ECC_UNCOR_ERR) {
+ logf("ecc uncorrectable error on page %08lx", (unsigned long)page);
+ return NAND_ERR_ECC_FAIL;
+ }
+
+ if(status & FREG_STATUS_ECC_HAS_FLIPS) {
+ logf("ecc corrected bitflips on page %08lx", (unsigned long)page);
+ }
+ }
+
return NAND_SUCCESS;
}
-int nand_read_bytes(nand_drv* drv, uint32_t byte_addr, uint32_t byte_len, void* buffer)
+int nand_read_bytes(struct nand_drv* drv, uint32_t byte_addr, uint32_t byte_len, void* buffer)
{
if(byte_len == 0)
return NAND_SUCCESS;
@@ -307,7 +357,7 @@ int nand_read_bytes(nand_drv* drv, uint32_t byte_addr, uint32_t byte_len, void*
return NAND_SUCCESS;
}
-int nand_write_bytes(nand_drv* drv, uint32_t byte_addr, uint32_t byte_len, const void* buffer)
+int nand_write_bytes(struct nand_drv* drv, uint32_t byte_addr, uint32_t byte_len, const void* buffer)
{
if(byte_len == 0)
return NAND_SUCCESS;
diff --git a/firmware/target/mips/ingenic_x1000/nand-x1000.h b/firmware/target/mips/ingenic_x1000/nand-x1000.h
index 668b3e3f82..0ccd075079 100644
--- a/firmware/target/mips/ingenic_x1000/nand-x1000.h
+++ b/firmware/target/mips/ingenic_x1000/nand-x1000.h
@@ -32,6 +32,7 @@
#define NAND_ERR_PROGRAM_FAIL (-2)
#define NAND_ERR_ERASE_FAIL (-3)
#define NAND_ERR_UNALIGNED (-4)
+#define NAND_ERR_ECC_FAIL (-5)
/* keep max page size in sync with the NAND chip table in the .c file */
#define NAND_DRV_SCRATCHSIZE 32
@@ -41,6 +42,47 @@
#define NAND_CHIPFLAG_QUAD 0x0001
/* Chip requires QE bit set to enable quad I/O mode */
#define NAND_CHIPFLAG_HAS_QE_BIT 0x0002
+/* True if the chip has on-die ECC */
+#define NAND_CHIPFLAG_ON_DIE_ECC 0x0004
+
+/* cmd mode a d phase format has data */
+#define NANDCMD_RESET SFC_CMD(0xff, SFC_TMODE_1_1_1, 0, 0, SFC_PFMT_ADDR_FIRST, 0)
+#define NANDCMD_READID_OPCODE SFC_CMD(0x9f, SFC_TMODE_1_1_1, 0, 0, SFC_PFMT_ADDR_FIRST, 1)
+#define NANDCMD_READID_ADDR SFC_CMD(0x9f, SFC_TMODE_1_1_1, 1, 0, SFC_PFMT_ADDR_FIRST, 1)
+#define NANDCMD_READID_DUMMY SFC_CMD(0x9f, SFC_TMODE_1_1_1, 0, 8, SFC_PFMT_ADDR_FIRST, 1)
+#define NANDCMD_WR_EN SFC_CMD(0x06, SFC_TMODE_1_1_1, 0, 0, SFC_PFMT_ADDR_FIRST, 0)
+#define NANDCMD_GET_FEATURE SFC_CMD(0x0f, SFC_TMODE_1_1_1, 1, 0, SFC_PFMT_ADDR_FIRST, 1)
+#define NANDCMD_SET_FEATURE SFC_CMD(0x1f, SFC_TMODE_1_1_1, 1, 0, SFC_PFMT_ADDR_FIRST, 1)
+#define NANDCMD_PAGE_READ SFC_CMD(0x13, SFC_TMODE_1_1_1, 3, 0, SFC_PFMT_ADDR_FIRST, 0)
+#define NANDCMD_READ_CACHE_SLOW SFC_CMD(0x03, SFC_TMODE_1_1_1, 2, 8, SFC_PFMT_ADDR_FIRST, 1)
+#define NANDCMD_READ_CACHE SFC_CMD(0x0b, SFC_TMODE_1_1_1, 2, 8, SFC_PFMT_ADDR_FIRST, 1)
+#define NANDCMD_READ_CACHE_x4 SFC_CMD(0x6b, SFC_TMODE_1_1_4, 2, 8, SFC_PFMT_ADDR_FIRST, 1)
+#define NANDCMD_PROGRAM_EXECUTE SFC_CMD(0x10, SFC_TMODE_1_1_1, 3, 0, SFC_PFMT_ADDR_FIRST, 0)
+#define NANDCMD_PROGRAM_LOAD SFC_CMD(0x02, SFC_TMODE_1_1_1, 2, 0, SFC_PFMT_ADDR_FIRST, 1)
+#define NANDCMD_PROGRAM_LOAD_x4 SFC_CMD(0x32, SFC_TMODE_1_1_4, 2, 0, SFC_PFMT_ADDR_FIRST, 1)
+#define NANDCMD_BLOCK_ERASE SFC_CMD(0xd8, SFC_TMODE_1_1_1, 3, 0, SFC_PFMT_ADDR_FIRST, 0)
+
+/* Feature registers are found in linux/mtd/spinand.h,
+ * apparently these are pretty standardized */
+#define FREG_PROT 0xa0
+#define FREG_PROT_UNLOCK 0x00
+
+#define FREG_CFG 0xb0
+#define FREG_CFG_OTP_ENABLE (1 << 6)
+#define FREG_CFG_ECC_ENABLE (1 << 4)
+#define FREG_CFG_QUAD_ENABLE (1 << 0)
+
+/* Winbond-specific bit used on the W25N01GVxx */
+#define FREG_CFG_WINBOND_BUF (1 << 3)
+
+#define FREG_STATUS 0xc0
+#define FREG_STATUS_BUSY (1 << 0)
+#define FREG_STATUS_EFAIL (1 << 2)
+#define FREG_STATUS_PFAIL (1 << 3)
+#define FREG_STATUS_ECC_MASK (3 << 4)
+#define FREG_STATUS_ECC_NO_FLIPS (0 << 4)
+#define FREG_STATUS_ECC_HAS_FLIPS (1 << 4)
+#define FREG_STATUS_ECC_UNCOR_ERR (2 << 4)
/* Types to distinguish between block & page addresses in the API.
*
@@ -59,15 +101,9 @@
typedef uint32_t nand_block_t;
typedef uint32_t nand_page_t;
-typedef struct nand_chip {
- /* Manufacturer and device ID bytes */
- uint8_t mf_id;
- uint8_t dev_id;
-
- /* Row/column address width */
- uint8_t row_cycles;
- uint8_t col_cycles;
+struct nand_drv;
+struct nand_chip {
/* Base2 logarithm of the number of pages per block */
unsigned log2_ppb;
@@ -89,9 +125,38 @@ typedef struct nand_chip {
/* Chip specific flags */
uint32_t flags;
-} nand_chip;
-typedef struct nand_drv {
+ /* SFC commands for issuing I/O ops */
+ uint32_t cmd_page_read;
+ uint32_t cmd_program_execute;
+ uint32_t cmd_block_erase;
+ uint32_t cmd_read_cache;
+ uint32_t cmd_program_load;
+
+ /* Chip-specific setup routine */
+ void(*setup_chip)(struct nand_drv* drv);
+};
+
+enum nand_readid_method {
+ NAND_READID_OPCODE,
+ NAND_READID_ADDR,
+ NAND_READID_DUMMY,
+};
+
+struct nand_chip_id {
+ uint8_t method;
+ uint8_t num_id_bytes;
+ uint8_t id_bytes[4];
+ const struct nand_chip* chip;
+};
+
+#define NAND_CHIP_ID(_chip, _method, ...) \
+ { .method = _method, \
+ .num_id_bytes = ARRAYLEN(((uint8_t[]){__VA_ARGS__})), \
+ .id_bytes = {__VA_ARGS__}, \
+ .chip = _chip }
+
+struct nand_drv {
/* NAND access lock. Needs to be held during any operations. */
struct mutex mutex;
@@ -113,27 +178,16 @@ typedef struct nand_drv {
uint8_t* page_buf;
/* Pointer to the chip data. */
- const nand_chip* chip;
+ const struct nand_chip* chip;
/* Pages per block = 1 << chip->log2_ppb */
unsigned ppb;
/* Full page size = chip->page_size + chip->oob_size */
unsigned fpage_size;
+};
- /* Probed mf_id / dev_id for debugging, in case identification fails. */
- uint8_t mf_id;
- uint8_t dev_id;
-
- /* SFC commands used for I/O, these are set based on chip data */
- uint32_t cmd_page_read;
- uint32_t cmd_read_cache;
- uint32_t cmd_program_load;
- uint32_t cmd_program_execute;
- uint32_t cmd_block_erase;
-} nand_drv;
-
-extern const nand_chip supported_nand_chips[];
+extern const struct nand_chip_id supported_nand_chips[];
extern const size_t nr_supported_nand_chips;
/* Return the static NAND driver instance.
@@ -141,14 +195,14 @@ extern const size_t nr_supported_nand_chips;
* ALL normal Rockbox code should use this instance. The SPL does not
* use it, because it needs to manually place buffers in external RAM.
*/
-extern nand_drv* nand_init(void);
+extern struct nand_drv* nand_init(void);
-static inline void nand_lock(nand_drv* drv)
+static inline void nand_lock(struct nand_drv* drv)
{
mutex_lock(&drv->mutex);
}
-static inline void nand_unlock(nand_drv* drv)
+static inline void nand_unlock(struct nand_drv* drv)
{
mutex_unlock(&drv->mutex);
}
@@ -162,8 +216,11 @@ static inline void nand_unlock(nand_drv* drv)
*
* These functions require the lock to be held.
*/
-extern int nand_open(nand_drv* drv);
-extern void nand_close(nand_drv* drv);
+extern int nand_open(struct nand_drv* drv);
+extern void nand_close(struct nand_drv* drv);
+
+/* Enable/disable OTP access. OTP data pages are usually vendor-specific. */
+void nand_enable_otp(struct nand_drv* drv, bool enable);
/* Read / program / erase operations. Buffer needs to be cache-aligned for DMA.
* Read and program operate on full page data, ie. including OOB data areas.
@@ -171,15 +228,15 @@ extern void nand_close(nand_drv* drv);
* NOTE: ECC is not implemented. If it ever needs to be, these functions will
* probably use ECC transparently. All code should be written to expect this.
*/
-extern int nand_block_erase(nand_drv* drv, nand_block_t block);
-extern int nand_page_program(nand_drv* drv, nand_page_t page, const void* buffer);
-extern int nand_page_read(nand_drv* drv, nand_page_t page, void* buffer);
+extern int nand_block_erase(struct nand_drv* drv, nand_block_t block);
+extern int nand_page_program(struct nand_drv* drv, nand_page_t page, const void* buffer);
+extern int nand_page_read(struct nand_drv* drv, nand_page_t page, void* buffer);
/* Wrappers to read/write bytes. For simple access to the main data area only.
* The write address / length must align to a block boundary. Reads do not have
* any alignment requirement. OOB data is never read, and is written as 0xff.
*/
-extern int nand_read_bytes(nand_drv* drv, uint32_t byte_addr, uint32_t byte_len, void* buffer);
-extern int nand_write_bytes(nand_drv* drv, uint32_t byte_addr, uint32_t byte_len, const void* buffer);
+extern int nand_read_bytes(struct nand_drv* drv, uint32_t byte_addr, uint32_t byte_len, void* buffer);
+extern int nand_write_bytes(struct nand_drv* drv, uint32_t byte_addr, uint32_t byte_len, const void* buffer);
#endif /* __NAND_X1000_H__ */
diff --git a/firmware/target/mips/ingenic_x1000/pcm-x1000.c b/firmware/target/mips/ingenic_x1000/pcm-x1000.c
index 7d1c83a35a..4b9cb85b57 100644
--- a/firmware/target/mips/ingenic_x1000/pcm-x1000.c
+++ b/firmware/target/mips/ingenic_x1000/pcm-x1000.c
@@ -168,8 +168,23 @@ void pcm_play_dma_start(const void* addr, size_t size)
void pcm_play_dma_stop(void)
{
- jz_writef(AIC_CCR, TDMS(0), ETUR(0), ERPL(0));
- jz_writef(AIC_CCR, TFLUSH(1));
+ /* disable DMA and underrun interrupts */
+ jz_writef(AIC_CCR, TDMS(0), ETUR(0));
+
+ /*
+ * wait for FIFO to be empty - on targets
+ * with >16bit samples, flushing the fifo
+ * may result in swapping l and r channels!
+ * (ensure bit clock is running first)
+ */
+ if (jz_readf(AIC_I2SCR, STPBK) == 0) {
+ while(jz_readf(AIC_SR, TFL) != 0);
+ } else {
+ panicf("pcm_play_dma_stop: No bit clock running!");
+ }
+
+ /* disable playback */
+ jz_writef(AIC_CCR, ERPL(0));
play_dma_pending_event = DMA_EVENT_NONE;
aic_state &= ~AIC_STATE_PLAYING;
diff --git a/firmware/target/mips/ingenic_x1000/spl-nand-x1000.c b/firmware/target/mips/ingenic_x1000/spl-nand-x1000.c
index 82a05abf75..24eb42081e 100644
--- a/firmware/target/mips/ingenic_x1000/spl-nand-x1000.c
+++ b/firmware/target/mips/ingenic_x1000/spl-nand-x1000.c
@@ -23,7 +23,7 @@
#include "gpio-x1000.h"
#include "nand-x1000.h"
-static nand_drv* ndrv = NULL;
+static struct nand_drv* ndrv = NULL;
int spl_storage_open(void)
{
@@ -31,7 +31,7 @@ int spl_storage_open(void)
gpioz_configure(GPIO_A, 0x3f << 26, GPIOF_DEVICE(1));
/* Allocate NAND driver manually in DRAM */
- ndrv = spl_alloc(sizeof(nand_drv));
+ ndrv = spl_alloc(sizeof(struct nand_drv));
ndrv->page_buf = spl_alloc(NAND_DRV_MAXPAGESIZE);
ndrv->scratch_buf = spl_alloc(NAND_DRV_SCRATCHSIZE);
ndrv->refcount = 0;
diff --git a/firmware/target/mips/ingenic_x1000/spl-start.S b/firmware/target/mips/ingenic_x1000/spl-start.S
index 58346fe750..ecdc47f283 100644
--- a/firmware/target/mips/ingenic_x1000/spl-start.S
+++ b/firmware/target/mips/ingenic_x1000/spl-start.S
@@ -31,7 +31,7 @@
.set noreorder
.set noat
- .section .init.spl
+ .section .startup.spl
_spl_start:
/* Clear data watchpoint */
diff --git a/firmware/target/mips/ingenic_x1000/spl-x1000.c b/firmware/target/mips/ingenic_x1000/spl-x1000.c
index b9ee6cc1c1..08f88f506c 100644
--- a/firmware/target/mips/ingenic_x1000/spl-x1000.c
+++ b/firmware/target/mips/ingenic_x1000/spl-x1000.c
@@ -317,6 +317,9 @@ void spl_main(void)
REG_CPM_PSWC2ST = 0x18;
REG_CPM_PSWC3ST = 0x08;
+ /* Save this, it's needed on some targets */
+ uint32_t saved_cpm_scratch = REG_CPM_SCRATCH;
+
/* set up boot flags */
init_boot_flags();
@@ -361,8 +364,8 @@ void spl_main(void)
spl_storage_close();
/* jump to the entry point */
- typedef void(*entry_fn)(void);
+ typedef void(*entry_fn)(uint32_t);
entry_fn fn = (entry_fn)BOOT_EXEC_ADDR;
commit_discard_idcache();
- fn();
+ fn(saved_cpm_scratch);
}
diff --git a/firmware/target/mips/ingenic_x1000/spl.lds b/firmware/target/mips/ingenic_x1000/spl.lds
index 09ab75d520..b3e508e9c3 100644
--- a/firmware/target/mips/ingenic_x1000/spl.lds
+++ b/firmware/target/mips/ingenic_x1000/spl.lds
@@ -15,9 +15,10 @@ SECTIONS
{
.text :
{
- *(.init.spl);
+ *(.startup.spl);
*(.text*);
*(.icode*);
+ *(.init*);
} > TCSM
. = ALIGN(4);
diff --git a/firmware/target/mips/ingenic_x1000/system-target.h b/firmware/target/mips/ingenic_x1000/system-target.h
index 7cea654865..ed077a3cce 100644
--- a/firmware/target/mips/ingenic_x1000/system-target.h
+++ b/firmware/target/mips/ingenic_x1000/system-target.h
@@ -31,6 +31,7 @@
#include "mmu-mips.h"
#include "mipsregs.h"
#include "mipsr2-endian.h"
+#include "system-mips.h"
#include <stdint.h>
/* Rockbox API */
@@ -96,6 +97,8 @@ extern irq_handler_t system_set_irq_handler(int irq, irq_handler_t handler);
extern void system_enable_irq(int irq);
extern void system_disable_irq(int irq);
+extern void system_early_init(void) INIT_ATTR;
+
/* Simple delay API */
#define OST_FREQUENCY (X1000_EXCLK_FREQ / 4)
#define OST_TICKS_PER_US (OST_FREQUENCY / 1000000)
diff --git a/firmware/target/mips/ingenic_x1000/system-x1000.c b/firmware/target/mips/ingenic_x1000/system-x1000.c
index 7542b97a3d..64890a6c3a 100644
--- a/firmware/target/mips/ingenic_x1000/system-x1000.c
+++ b/firmware/target/mips/ingenic_x1000/system-x1000.c
@@ -44,6 +44,7 @@ uint32_t __cpu_idle_reftick = 0;
#endif
/* Prepare the CPU to process interrupts, but don't enable them yet */
+static void system_init_irq(void) INIT_ATTR;
static void system_init_irq(void)
{
/* Mask all interrupts */
@@ -343,8 +344,10 @@ static int vector_irq(void)
return n;
}
-void intr_handler(unsigned cause)
+void intr_handler(void)
{
+ unsigned long cause = read_c0_cause();
+
/* OST interrupt is handled separately */
if(cause & M_CauseIP3) {
OST();
@@ -363,49 +366,6 @@ void intr_handler(unsigned cause)
irqvector[irq]();
}
-void tlb_refill_handler(void)
-{
- panicf("TLB refill handler at 0x%08lx! [0x%x]",
- read_c0_epc(), read_c0_badvaddr());
-}
-
-#define EXC(x,y) case (x): return (y);
-static char* parse_exception(unsigned cause)
-{
- switch(cause & M_CauseExcCode)
- {
- EXC(EXC_INT, "Interrupt");
- EXC(EXC_MOD, "TLB Modified");
- EXC(EXC_TLBL, "TLB Exception (Load or Ifetch)");
- EXC(EXC_ADEL, "Address Error (Load or Ifetch)");
- EXC(EXC_ADES, "Address Error (Store)");
- EXC(EXC_TLBS, "TLB Exception (Store)");
- EXC(EXC_IBE, "Instruction Bus Error");
- EXC(EXC_DBE, "Data Bus Error");
- EXC(EXC_SYS, "Syscall");
- EXC(EXC_BP, "Breakpoint");
- EXC(EXC_RI, "Reserved Instruction");
- EXC(EXC_CPU, "Coprocessor Unusable");
- EXC(EXC_OV, "Overflow");
- EXC(EXC_TR, "Trap Instruction");
- EXC(EXC_FPE, "Floating Point Exception");
- EXC(EXC_C2E, "COP2 Exception");
- EXC(EXC_MDMX, "MDMX Exception");
- EXC(EXC_WATCH, "Watch Exception");
- EXC(EXC_MCHECK, "Machine Check Exception");
- EXC(EXC_CacheErr, "Cache error caused re-entry to Debug Mode");
- default:
- return 0;
- }
-}
-#undef EXC
-
-void exception_handler(unsigned cause, unsigned epc, unsigned stack_ptr)
-{
- panicf("Exception occurred: %s [0x%08x] at 0x%08x (stack at 0x%08x)",
- parse_exception(cause), read_c0_badvaddr(), epc, stack_ptr);
-}
-
void system_exception_wait(void)
{
#ifdef FIIO_M3K
diff --git a/firmware/target/mips/mmu-mips.h b/firmware/target/mips/mmu-mips.h
index b8f5ff0143..ca865f9909 100644
--- a/firmware/target/mips/mmu-mips.h
+++ b/firmware/target/mips/mmu-mips.h
@@ -36,7 +36,11 @@ void map_address(unsigned long virtual, unsigned long physical,
void mmu_init(void);
/* Commits entire DCache */
-MIPS_CACHEFUNC_API(void, commit_dcache, (void));
+#if 0 /* NOTE: This is currently aliased to commit_discard_dcache. Causes compilation errors with newer GCC if we try to assign it to a section here */
+//MIPS_CACHEFUNC_API(void, commit_dcache, (void));
+#else
+void commit_dcache(void);
+#endif
/* Commit and discard entire DCache, will do writeback */
MIPS_CACHEFUNC_API(void, commit_discard_dcache, (void));
diff --git a/firmware/target/mips/system-mips.c b/firmware/target/mips/system-mips.c
new file mode 100644
index 0000000000..e6bb2d8ea6
--- /dev/null
+++ b/firmware/target/mips/system-mips.c
@@ -0,0 +1,175 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2022 Aidan MacDonald
+ *
+ * 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 "system.h"
+#include "backtrace.h"
+#include "lcd.h"
+#include "backlight-target.h"
+#include "font.h"
+#include "logf.h"
+#include "mips.h"
+#undef sp /* breaks backtrace lib */
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+
+/* copies exception frame info and error pc to the backtrace context */
+static void setup_exception_bt(struct mips_exception_frame* frame,
+ unsigned long epc, struct mips_bt_context* ctx)
+{
+ ctx->pc = (void*)epc;
+ ctx->sp = (void*)frame->gpr[29 - 3];
+ ctx->depth = 0;
+ ctx->valid = (1 << MIPSBT_RA);
+ ctx->reg[MIPSBT_RA] = frame->gpr[31 - 3];
+}
+
+/* dump backtrace for an exception */
+static void exception_bt(void* frame, unsigned long epc, unsigned* line)
+{
+ struct mips_bt_context ctx;
+ setup_exception_bt(frame, epc, &ctx);
+ rb_backtrace_ctx(&ctx, line);
+}
+
+/*
+ * TODO: This should be converted into a generic panic routine that accepts
+ * a backtrace context argument but the ARM backtrace setup will need to be
+ * refactored in order to do that
+ */
+static void exception_dump(void* frame, unsigned long epc,
+ const char* fmt, ...)
+{
+ extern char panic_buf[128];
+ va_list ap;
+
+ set_irq_level(DISABLE_INTERRUPTS);
+
+ va_start(ap, fmt);
+ vsnprintf(panic_buf, sizeof(panic_buf), fmt, ap);
+ va_end(ap);
+
+ lcd_set_viewport(NULL);
+#if LCD_DEPTH > 1
+ lcd_set_backdrop(NULL);
+ lcd_set_drawmode(DRMODE_SOLID);
+ lcd_set_foreground(LCD_BLACK);
+ lcd_set_background(LCD_WHITE);
+#endif
+
+ lcd_clear_display();
+ lcd_setfont(FONT_SYSFIXED);
+
+ unsigned y = 1;
+ lcd_puts(1, y++, "*EXCEPTION*");
+
+ /* wrap panic message */
+ {
+ const int linechars = (LCD_WIDTH / SYSFONT_WIDTH) - 2;
+
+ int pos = 0, len = strlen(panic_buf);
+ while(len > 0) {
+ int idx = pos + MIN(len, linechars);
+ char c = panic_buf[idx];
+ panic_buf[idx] = 0;
+ lcd_puts(1, y++, &panic_buf[pos]);
+ panic_buf[idx] = c;
+
+ len -= linechars;
+ pos += linechars;
+ }
+ }
+
+ exception_bt(frame, epc, &y);
+#ifdef ROCKBOX_HAS_LOGF
+ logf_panic_dump(&y);
+#endif
+
+ lcd_update();
+ backlight_hw_on();
+
+#ifdef HAVE_ADJUSTABLE_CPU_FREQ
+ if (cpu_boost_lock())
+ {
+ set_cpu_frequency(0);
+ cpu_boost_unlock();
+ }
+#endif
+
+#ifdef HAVE_ATA_POWER_OFF
+ ide_power_enable(false);
+#endif
+
+ system_exception_wait();
+ system_reboot();
+ while(1);
+}
+
+#define EXC(x,y) case (x): return (y);
+static char* parse_exception(unsigned long cause)
+{
+ switch(cause & M_CauseExcCode)
+ {
+ EXC(EXC_INT, "Interrupt");
+ EXC(EXC_MOD, "TLB Modified");
+ EXC(EXC_TLBL, "TLB Exception (Load or Ifetch)");
+ EXC(EXC_ADEL, "Address Error (Load or Ifetch)");
+ EXC(EXC_ADES, "Address Error (Store)");
+ EXC(EXC_TLBS, "TLB Exception (Store)");
+ EXC(EXC_IBE, "Instruction Bus Error");
+ EXC(EXC_DBE, "Data Bus Error");
+ EXC(EXC_SYS, "Syscall");
+ EXC(EXC_BP, "Breakpoint");
+ EXC(EXC_RI, "Reserved Instruction");
+ EXC(EXC_CPU, "Coprocessor Unusable");
+ EXC(EXC_OV, "Overflow");
+ EXC(EXC_TR, "Trap Instruction");
+ EXC(EXC_FPE, "Floating Point Exception");
+ EXC(EXC_C2E, "COP2 Exception");
+ EXC(EXC_MDMX, "MDMX Exception");
+ EXC(EXC_WATCH, "Watch Exception");
+ EXC(EXC_MCHECK, "Machine Check Exception");
+ EXC(EXC_CacheErr, "Cache error caused re-entry to Debug Mode");
+ default:
+ return 0;
+ }
+}
+#undef EXC
+
+void exception_handler(void* frame, unsigned long epc)
+{
+ unsigned long cause = read_c0_cause();
+
+ exception_dump(frame, epc, "%s [0x%08x] at %08lx",
+ parse_exception(cause), read_c0_badvaddr(), epc);
+}
+
+void cache_error_handler(void* frame, unsigned long epc)
+{
+ exception_dump(frame, epc, "Cache Error [0x%08x] at %08lx",
+ read_c0_cacheerr(), epc);
+}
+
+void tlb_refill_handler(void* frame, unsigned long epc)
+{
+ exception_dump(frame, epc, "TLB refill at %08lx [0x%x]",
+ epc, read_c0_badvaddr());
+}
diff --git a/firmware/target/mips/system-mips.h b/firmware/target/mips/system-mips.h
new file mode 100644
index 0000000000..d9108ef7c2
--- /dev/null
+++ b/firmware/target/mips/system-mips.h
@@ -0,0 +1,40 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2022 Aidan MacDonald
+ *
+ * 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 SYSTEM_MIPS_H
+#define SYSTEM_MIPS_H
+
+#include <stdint.h>
+
+struct mips_exception_frame {
+ uint32_t gpr[29]; /* GPRs $1-$25, $28-$31 */
+ uint32_t lo;
+ uint32_t hi;
+ uint32_t c0_status;
+ uint32_t c0_epc;
+};
+
+void intr_handler(void);
+void exception_handler(void* frame, unsigned long epc);
+void cache_error_handler(void* frame, unsigned long epc);
+void tlb_refill_handler(void* frame, unsigned long epc);
+
+#endif /* SYSTEM_MIPS_H */