From 4af26e7e98b6d4b2e1c94a54ad7ca02d55bb04cc Mon Sep 17 00:00:00 2001 From: Maurus Cuelenaere Date: Wed, 5 Nov 2008 00:24:46 +0000 Subject: [PATCH] Onda VX747: * Commit (premature) SD, USB & audio drivers * Fix ramdisk.c mistake * Add battery readout git-svn-id: svn://svn.rockbox.org/rockbox/trunk@19011 a1c6a512-1295-4272-9138-f99709370657 --- firmware/SOURCES | 6 +- firmware/drivers/ramdisk.c | 2 +- firmware/export/config-ondavx747.h | 6 +- .../target/mips/ingenic_jz47xx/ata-jz4740.c | 104 ++ .../mips/ingenic_jz47xx/ata-nand-jz4740.c | 156 +- .../mips/ingenic_jz47xx/ata-nand-target.h | 28 + .../mips/ingenic_jz47xx/ata-sd-jz4740.c | 1168 ++++++++++++ .../mips/ingenic_jz47xx/ata-sd-target.h | 39 + .../target/mips/ingenic_jz47xx/codec-jz4740.c | 280 +++ .../onda_vx747/sadc-onda_vx747.c | 54 +- .../target/mips/ingenic_jz47xx/pcm-jz4740.c | 164 ++ .../target/mips/ingenic_jz47xx/usb-jz4740.c | 1617 ++++++++++------- 12 files changed, 2927 insertions(+), 697 deletions(-) create mode 100644 firmware/target/mips/ingenic_jz47xx/ata-jz4740.c create mode 100644 firmware/target/mips/ingenic_jz47xx/ata-nand-target.h create mode 100644 firmware/target/mips/ingenic_jz47xx/ata-sd-jz4740.c create mode 100644 firmware/target/mips/ingenic_jz47xx/ata-sd-target.h create mode 100644 firmware/target/mips/ingenic_jz47xx/codec-jz4740.c create mode 100644 firmware/target/mips/ingenic_jz47xx/pcm-jz4740.c diff --git a/firmware/SOURCES b/firmware/SOURCES index f299d51a53..33386f8f82 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES @@ -1157,9 +1157,13 @@ drivers/qt1106.c #endif /* MEIZU_M3 */ #if CONFIG_CPU==JZ4732 +target/mips/ingenic_jz47xx/ata-jz4740.c target/mips/ingenic_jz47xx/ata-nand-jz4740.c -target/mips/ingenic_jz47xx/lcd-jz4740.c +target/mips/ingenic_jz47xx/ata-sd-jz4740.c +target/mips/ingenic_jz47xx/codec-jz4740.c target/mips/ingenic_jz47xx/kernel-jz4740.c +target/mips/ingenic_jz47xx/lcd-jz4740.c +target/mips/ingenic_jz47xx/pcm-jz4740.c target/mips/ingenic_jz47xx/system-jz4740.c target/mips/ingenic_jz47xx/usb-jz4740.c drivers/nand_id.c diff --git a/firmware/drivers/ramdisk.c b/firmware/drivers/ramdisk.c index 0a3e991382..266d3ea225 100644 --- a/firmware/drivers/ramdisk.c +++ b/firmware/drivers/ramdisk.c @@ -84,7 +84,7 @@ void ramdisk_spindown(int seconds) (void)seconds; } #ifdef STORAGE_GET_INFO -void ramdisk_get_info(struct storage_info *info) +void ramdisk_get_info(IF_MV2(int drive,) struct storage_info *info) { /* firmware version */ info->revision="0.00"; diff --git a/firmware/export/config-ondavx747.h b/firmware/export/config-ondavx747.h index e52b38700c..3d7628fa8f 100644 --- a/firmware/export/config-ondavx747.h +++ b/firmware/export/config-ondavx747.h @@ -37,7 +37,7 @@ #define HAVE_HOTSWAP //#define CONFIG_STORAGE (STORAGE_NAND | STORAGE_SD) -#define CONFIG_STORAGE STORAGE_NAND /* Multivolume currently handled at firmware/target/ level */ +#define CONFIG_STORAGE STORAGE_RAMDISK /* Multivolume currently handled at firmware/target/ level */ #define CONFIG_NAND NAND_CC @@ -156,10 +156,10 @@ #define BOOTFILE "rockbox." BOOTFILE_EXT #define BOOTDIR "/.rockbox" -/*#define CONFIG_USBOTG USBOTG_INGENIC +#define CONFIG_USBOTG USBOTG_INGENIC #define HAVE_USBSTACK #define USB_VENDOR_ID 0x041e -#define USB_PRODUCT_ID 0x4133*/ +#define USB_PRODUCT_ID 0x4133 #include /* HACKY */ diff --git a/firmware/target/mips/ingenic_jz47xx/ata-jz4740.c b/firmware/target/mips/ingenic_jz47xx/ata-jz4740.c new file mode 100644 index 0000000000..dd14a4c651 --- /dev/null +++ b/firmware/target/mips/ingenic_jz47xx/ata-jz4740.c @@ -0,0 +1,104 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2008 by Maurus Cuelenaere + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include "config.h" +#include "ata.h" +#include "ata-sd-target.h" +#include "ata-nand-target.h" +#include "panic.h" + +int ata_read_sectors(IF_MV2(int drive,) unsigned long start, int count, void* buf) +{ + switch(drive) + { + case 0: + return nand_read_sectors(start, count, buf); + case 1: + return sd_read_sectors(start, count, buf); + default: + panicf("ata_read_sectors: Drive %d unhandled!", drive); + return -1; + } +} + +int ata_write_sectors(IF_MV2(int drive,) unsigned long start, int count, const void* buf) +{ + switch(drive) + { + case 0: + return nand_write_sectors(start, count, buf); + case 1: + return sd_write_sectors(start, count, buf); + default: + panicf("ata_write_sectors: Drive %d unhandled!", drive); + return -1; + } +} + +int ata_init(void) +{ + if(sd_init() != 0) + return -1; + if(nand_init() != 0) + return -2; + + return 0; +} + +void ata_spindown(int seconds) +{ + /* null */ + (void)seconds; +} + +bool ata_disk_is_active(void) +{ + /* null */ + return false; +} + +void ata_sleep(void) +{ + /* null */ +} + +void ata_spin(void) +{ + /* null */ +} + +int ata_hard_reset(void) +{ + /* null */ + return 0; +} + +int ata_soft_reset(void) +{ + /* null */ + return 0; +} + +void ata_enable(bool on) +{ + /* null - flash controller is enabled/disabled as needed. */ + (void)on; +} diff --git a/firmware/target/mips/ingenic_jz47xx/ata-nand-jz4740.c b/firmware/target/mips/ingenic_jz47xx/ata-nand-jz4740.c index a41a62294a..7a937bf7cf 100644 --- a/firmware/target/mips/ingenic_jz47xx/ata-nand-jz4740.c +++ b/firmware/target/mips/ingenic_jz47xx/ata-nand-jz4740.c @@ -22,6 +22,7 @@ #include "config.h" #include "jz4740.h" #include "ata.h" +#include "ata-nand-target.h" #include "nand_id.h" #include "system.h" #include "panic.h" @@ -29,31 +30,31 @@ /* * Standard NAND flash commands */ -#define NAND_CMD_READ0 0 -#define NAND_CMD_READ1 1 +#define NAND_CMD_READ0 0 +#define NAND_CMD_READ1 1 #define NAND_CMD_RNDOUT 5 -#define NAND_CMD_PAGEPROG 0x10 -#define NAND_CMD_READOOB 0x50 +#define NAND_CMD_PAGEPROG 0x10 +#define NAND_CMD_READOOB 0x50 #define NAND_CMD_ERASE1 0x60 #define NAND_CMD_STATUS 0x70 -#define NAND_CMD_STATUS_MULTI 0x71 -#define NAND_CMD_SEQIN 0x80 -#define NAND_CMD_RNDIN 0x85 +#define NAND_CMD_STATUS_MULTI 0x71 +#define NAND_CMD_SEQIN 0x80 +#define NAND_CMD_RNDIN 0x85 #define NAND_CMD_READID 0x90 #define NAND_CMD_ERASE2 0xd0 -#define NAND_CMD_RESET 0xff +#define NAND_CMD_RESET 0xff /* Extended commands for large page devices */ #define NAND_CMD_READSTART 0x30 -#define NAND_CMD_RNDOUTSTART 0xE0 -#define NAND_CMD_CACHEDPROG 0x15 +#define NAND_CMD_RNDOUTSTART 0xE0 +#define NAND_CMD_CACHEDPROG 0x15 /* Status bits */ -#define NAND_STATUS_FAIL 0x01 +#define NAND_STATUS_FAIL 0x01 #define NAND_STATUS_FAIL_N1 0x02 -#define NAND_STATUS_TRUE_READY 0x20 -#define NAND_STATUS_READY 0x40 -#define NAND_STATUS_WP 0x80 +#define NAND_STATUS_TRUE_READY 0x20 +#define NAND_STATUS_READY 0x40 +#define NAND_STATUS_WP 0x80 /* * NAND parameter struct @@ -81,21 +82,21 @@ struct nand_param #define NAND_COMMPORT 0xb8008000 #define ECC_BLOCK 512 -#define ECC_POS 6 -#define PAR_SIZE 9 +#define ECC_POS 6 +#define PAR_SIZE 9 -#define __nand_cmd(n) (REG8(NAND_COMMPORT) = (n)) -#define __nand_addr(n) (REG8(NAND_ADDRPORT) = (n)) -#define __nand_data8() REG8(NAND_DATAPORT) -#define __nand_data16() REG16(NAND_DATAPORT) +#define __nand_cmd(n) (REG8(NAND_COMMPORT) = (n)) +#define __nand_addr(n) (REG8(NAND_ADDRPORT) = (n)) +#define __nand_data8() REG8(NAND_DATAPORT) +#define __nand_data16() REG16(NAND_DATAPORT) #define __nand_enable() (REG_EMC_NFCSR |= EMC_NFCSR_NFE1 | EMC_NFCSR_NFCE1) -#define __nand_disable() (REG_EMC_NFCSR &= ~(EMC_NFCSR_NFCE1)) +#define __nand_disable() (REG_EMC_NFCSR &= ~(EMC_NFCSR_NFCE1)) #define __nand_ecc_rs_encoding() \ (REG_EMC_NFECR = EMC_NFECR_ECCE | EMC_NFECR_ERST | EMC_NFECR_RS | EMC_NFECR_RS_ENCODING) #define __nand_ecc_rs_decoding() \ (REG_EMC_NFECR = EMC_NFECR_ECCE | EMC_NFECR_ERST | EMC_NFECR_RS | EMC_NFECR_RS_DECODING) -#define __nand_ecc_disable() (REG_EMC_NFECR &= ~EMC_NFECR_ECCE) +#define __nand_ecc_disable() (REG_EMC_NFECR &= ~EMC_NFECR_ECCE) #define __nand_ecc_encode_sync() while (!(REG_EMC_NFINTS & EMC_NFINTS_ENCF)) #define __nand_ecc_decode_sync() while (!(REG_EMC_NFINTS & EMC_NFINTS_DECF)) @@ -104,14 +105,14 @@ struct nand_param static struct nand_info* chip_info = NULL; static struct nand_param internal_param; -static inline void nand_wait_ready(void) +static inline void jz_nand_wait_ready(void) { unsigned int timeout = 1000; while ((REG_GPIO_PXPIN(2) & 0x40000000) && timeout--); while (!(REG_GPIO_PXPIN(2) & 0x40000000)); } -static inline void nand_read_buf16(void *buf, int count) +static inline void jz_nand_read_buf16(void *buf, int count) { int i; unsigned short *p = (unsigned short *)buf; @@ -120,7 +121,7 @@ static inline void nand_read_buf16(void *buf, int count) *p++ = __nand_data16(); } -static inline void nand_read_buf8(void *buf, int count) +static inline void jz_nand_read_buf8(void *buf, int count) { int i; unsigned char *p = (unsigned char *)buf; @@ -129,18 +130,53 @@ static inline void nand_read_buf8(void *buf, int count) *p++ = __nand_data8(); } -static inline void nand_read_buf(void *buf, int count, int bw) +static void jz_nand_write_dma(void *source, unsigned int len, int bw) +{ + if(((unsigned int)source < 0xa0000000) && len) + dma_cache_wback_inv((unsigned long)source, len); + + REG_DMAC_DCCSR(DMA_NAND_CHANNEL) = 0; + REG_DMAC_DSAR(DMA_NAND_CHANNEL) = PHYSADDR((unsigned long)source); + REG_DMAC_DTAR(DMA_NAND_CHANNEL) = PHYSADDR((unsigned long)NAND_DATAPORT); + REG_DMAC_DTCR(DMA_NAND_CHANNEL) = len / 16; + REG_DMAC_DRSR(DMA_NAND_CHANNEL) = DMAC_DRSR_RS_AUTO; + REG_DMAC_DCMD(DMA_NAND_CHANNEL) = (DMAC_DCMD_SAI| DMAC_DCMD_DAI | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DS_16BYTE | + (bw == 8 ? DMAC_DCMD_DWDH_8 : DMAC_DCMD_DWDH_16)); + + REG_DMAC_DCCSR(DMA_NAND_CHANNEL) = (DMAC_DCCSR_EN | DMAC_DCCSR_NDES); + while( REG_DMAC_DTCR(DMA_NAND_CHANNEL) ) + yield(); +} + +static void jz_nand_read_dma(void *target, unsigned int len, int bw) +{ + if(((unsigned int)target < 0xa0000000) && len) + dma_cache_wback_inv((unsigned long)target, len); + + REG_DMAC_DCCSR(DMA_NAND_CHANNEL) = 0; + REG_DMAC_DSAR(DMA_NAND_CHANNEL) = PHYSADDR((unsigned long)NAND_DATAPORT); + REG_DMAC_DTAR(DMA_NAND_CHANNEL) = PHYSADDR((unsigned long)target); + REG_DMAC_DTCR(DMA_NAND_CHANNEL) = len / 4; + REG_DMAC_DRSR(DMA_NAND_CHANNEL) = DMAC_DRSR_RS_AUTO; + REG_DMAC_DCMD(DMA_NAND_CHANNEL) = (DMAC_DCMD_SAI| DMAC_DCMD_DAI | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BIT | + (bw == 8 ? DMAC_DCMD_SWDH_8 : DMAC_DCMD_SWDH_16)); + REG_DMAC_DCCSR(DMA_NAND_CHANNEL) = (DMAC_DCCSR_EN | DMAC_DCCSR_NDES); + while( REG_DMAC_DTCR(DMA_NAND_CHANNEL) ) + yield(); +} + +static inline void jz_nand_read_buf(void *buf, int count, int bw) { if (bw == 8) - nand_read_buf8(buf, count); + jz_nand_read_dma(buf, count, 8); else - nand_read_buf16(buf, count); + jz_nand_read_dma(buf, count, 16); } /* * Correct 1~9-bit errors in 512-bytes data */ -static void rs_correct(unsigned char *dat, int idx, int mask) +static void jz_rs_correct(unsigned char *dat, int idx, int mask) { int i, j; unsigned short d, d1, dm; @@ -172,7 +208,7 @@ static void rs_correct(unsigned char *dat, int idx, int mask) /* * Read oob */ -static int nand_read_oob(int page_addr, unsigned char *buf, int size) +static int jz_nand_read_oob(int page_addr, unsigned char *buf, int size) { struct nand_param *nandp = &internal_param; int page_size, row_cycle, bus_width; @@ -210,10 +246,10 @@ static int nand_read_oob(int page_addr, unsigned char *buf, int size) __nand_cmd(NAND_CMD_READSTART); /* Wait for device ready */ - nand_wait_ready(); + jz_nand_wait_ready(); /* Read oob data */ - nand_read_buf(buf, size, bus_width); + jz_nand_read_buf(buf, size, bus_width); return 0; } @@ -228,7 +264,7 @@ static int nand_read_oob(int page_addr, unsigned char *buf, int size) * page - page number within a block: 0, 1, 2, ... * dst - pointer to target buffer */ -static int nand_read_page(int block, int page, unsigned char *dst) +static int jz_nand_read_page(int block, int page, unsigned char *dst) { struct nand_param *nandp = &internal_param; int page_size, oob_size, page_per_block; @@ -248,7 +284,7 @@ static int nand_read_page(int block, int page, unsigned char *dst) /* * Read oob data */ - nand_read_oob(page_addr, oob_buf, oob_size); + jz_nand_read_oob(page_addr, oob_buf, oob_size); /* * Read page data @@ -273,7 +309,7 @@ static int nand_read_page(int block, int page, unsigned char *dst) __nand_cmd(NAND_CMD_READSTART); /* Wait for device ready */ - nand_wait_ready(); + jz_nand_wait_ready(); /* Read page data */ data_buf = dst; @@ -290,7 +326,7 @@ static int nand_read_page(int block, int page, unsigned char *dst) __nand_ecc_rs_decoding(); /* Read data */ - nand_read_buf((void *)data_buf, ECC_BLOCK, bus_width); + jz_nand_read_buf((void *)data_buf, ECC_BLOCK, bus_width); /* Set PAR values */ for (j = 0; j < PAR_SIZE; j++) @@ -310,8 +346,10 @@ static int nand_read_page(int block, int page, unsigned char *dst) if (stat & EMC_NFINTS_ERR) { /* Error occurred */ - if (stat & EMC_NFINTS_UNCOR) { + if (stat & EMC_NFINTS_UNCOR) + { /* Uncorrectable error occurred */ + panicf("Uncorrectable ECC error at NAND page 0x%x block 0x%x", page, block); } else { @@ -323,19 +361,19 @@ static int nand_read_page(int block, int page, unsigned char *dst) case 4: index = (REG_EMC_NFERR3 & EMC_NFERR_INDEX_MASK) >> EMC_NFERR_INDEX_BIT; mask = (REG_EMC_NFERR3 & EMC_NFERR_MASK_MASK) >> EMC_NFERR_MASK_BIT; - rs_correct(data_buf, index, mask); + jz_rs_correct(data_buf, index, mask); case 3: index = (REG_EMC_NFERR2 & EMC_NFERR_INDEX_MASK) >> EMC_NFERR_INDEX_BIT; mask = (REG_EMC_NFERR2 & EMC_NFERR_MASK_MASK) >> EMC_NFERR_MASK_BIT; - rs_correct(data_buf, index, mask); + jz_rs_correct(data_buf, index, mask); case 2: index = (REG_EMC_NFERR1 & EMC_NFERR_INDEX_MASK) >> EMC_NFERR_INDEX_BIT; mask = (REG_EMC_NFERR1 & EMC_NFERR_MASK_MASK) >> EMC_NFERR_MASK_BIT; - rs_correct(data_buf, index, mask); + jz_rs_correct(data_buf, index, mask); case 1: index = (REG_EMC_NFERR0 & EMC_NFERR_INDEX_MASK) >> EMC_NFERR_INDEX_BIT; mask = (REG_EMC_NFERR0 & EMC_NFERR_MASK_MASK) >> EMC_NFERR_MASK_BIT; - rs_correct(data_buf, index, mask); + jz_rs_correct(data_buf, index, mask); break; default: break; @@ -352,7 +390,7 @@ static int nand_read_page(int block, int page, unsigned char *dst) /* * Enable NAND controller */ -static void nand_enable(void) +static void jz_nand_enable(void) { __nand_enable(); @@ -362,16 +400,16 @@ static void nand_enable(void) /* * Disable NAND controller */ -static void nand_disable(void) +static void jz_nand_disable(void) { __nand_disable(); } -int nand_init(void) +static int jz_nand_init(void) { unsigned char cData[5]; - nand_enable(); + jz_nand_enable(); __nand_cmd(NAND_CMD_READID); __nand_addr(NAND_CMD_READ0); @@ -386,7 +424,7 @@ int nand_init(void) { panicf("Unknown NAND flash chip: 0x%x 0x%x 0x%x 0x%x 0x%x", cData[0], cData[1], cData[2], cData[3], cData[4]); - return -1; + return -1; /* panicf() doesn't return though */ } internal_param.bus_width = 8; @@ -400,23 +438,39 @@ int nand_init(void) void jz_nand_read(int block, int page, unsigned char *buf) { - nand_read_page(block, page, buf); + jz_nand_read_page(block, page, buf); } -int nand_read_sectors(IF_MV2(int drive,) unsigned long start, int count, void* buf) +static bool inited = false; +int nand_init(void) +{ + int res = 0; + + if(!inited) + { + res = jz_nand_init(); + inited = true; + } + + return res; +} + +/* TODO */ +int nand_read_sectors(unsigned long start, int count, void* buf) { (void)start; (void)count; (void)buf; - return 0; + return -1; } -int nand_write_sectors(IF_MV2(int drive,) unsigned long start, int count, const void* buf) +/* TODO */ +int nand_write_sectors(unsigned long start, int count, const void* buf) { (void)start; (void)count; (void)buf; - return 0; + return -1; } void nand_spindown(int seconds) diff --git a/firmware/target/mips/ingenic_jz47xx/ata-nand-target.h b/firmware/target/mips/ingenic_jz47xx/ata-nand-target.h new file mode 100644 index 0000000000..c8b2376e41 --- /dev/null +++ b/firmware/target/mips/ingenic_jz47xx/ata-nand-target.h @@ -0,0 +1,28 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2008 by Maurus Cuelenaere + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#ifndef ATA_NAND_TARGET_H +#define ATA_NAND_TARGET_H + +int nand_read_sectors(unsigned long start, int count, void* buf); +int nand_write_sectors(unsigned long start, int count, const void* buf); +int nand_init(void); + +#endif diff --git a/firmware/target/mips/ingenic_jz47xx/ata-sd-jz4740.c b/firmware/target/mips/ingenic_jz47xx/ata-sd-jz4740.c new file mode 100644 index 0000000000..ccd71630a6 --- /dev/null +++ b/firmware/target/mips/ingenic_jz47xx/ata-sd-jz4740.c @@ -0,0 +1,1168 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2008 by Maurus Cuelenaere + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include "config.h" +#include "jz4740.h" +#include "ata.h" +#include "ata-sd-target.h" +#include "system.h" +#include "kernel.h" +#include "panic.h" +#include "debug.h" + +static struct wakeup sd_wakeup; + +//#define MMC_DMA_ENABLE +#define MMC_DMA_INTERRUPT 0 + +//#define DEBUG(x...) DEBUGF(x); +#define DEBUG(x...) printf(x); + +#define MMC_CD_PIN (29 + 1 * 32) /* Pin to check card insertion */ +#define MMC_POWER_PIN (30 + 1 * 32) /* Pin to enable/disable card power */ +//#define MMC_PW_PIN (14 + 3 * 32) /* Pin to check protect card */ + +#define MMC_POWER_OFF() \ +do { \ + __gpio_set_pin(MMC_POWER_PIN); \ +} while (0) + +#define MMC_POWER_ON() \ +do { \ + __gpio_clear_pin(MMC_POWER_PIN); \ +} while (0) + +#define MMC_INSERT_STATUS() __gpio_get_pin(MMC_CD_PIN) + +#define MMC_RESET() __msc_reset() + +#define MMC_IRQ_MASK() \ +do { \ + REG_MSC_IMASK = 0xffff; \ + REG_MSC_IREG = 0xffff; \ +} while (0) + +static inline void mmc_init_gpio(void) +{ + __gpio_as_msc(); +#ifdef MMC_POWER_PIN + __gpio_as_output(MMC_POWER_PIN); + __gpio_disable_pull(MMC_POWER_PIN); + __gpio_set_pin(MMC_POWER_PIN); +#endif +#ifdef MMC_CD_PIN + __gpio_as_input(MMC_CD_PIN); + __gpio_disable_pull(MMC_CD_PIN); +#endif +#ifdef MMC_PW_PIN + __gpio_as_input(MMC_PW_PIN); + __gpio_disable_pull(MMC_PW_PIN); +#endif +} + +/* Error codes */ +enum mmc_result_t +{ + MMC_NO_RESPONSE = -1, + MMC_NO_ERROR = 0, + MMC_ERROR_OUT_OF_RANGE, + MMC_ERROR_ADDRESS, + MMC_ERROR_BLOCK_LEN, + MMC_ERROR_ERASE_SEQ, + MMC_ERROR_ERASE_PARAM, + MMC_ERROR_WP_VIOLATION, + MMC_ERROR_CARD_IS_LOCKED, + MMC_ERROR_LOCK_UNLOCK_FAILED, + MMC_ERROR_COM_CRC, + MMC_ERROR_ILLEGAL_COMMAND, + MMC_ERROR_CARD_ECC_FAILED, + MMC_ERROR_CC, + MMC_ERROR_GENERAL, + MMC_ERROR_UNDERRUN, + MMC_ERROR_OVERRUN, + MMC_ERROR_CID_CSD_OVERWRITE, + MMC_ERROR_STATE_MISMATCH, + MMC_ERROR_HEADER_MISMATCH, + MMC_ERROR_TIMEOUT, + MMC_ERROR_CRC, + MMC_ERROR_DRIVER_FAILURE, +}; + +/* Standard MMC/SD clock speeds */ +#define MMC_CLOCK_SLOW 400000 /* 400 kHz for initial setup */ +#define MMC_CLOCK_FAST 20000000 /* 20 MHz for maximum for normal operation */ +#define SD_CLOCK_FAST 24000000 /* 24 MHz for SD Cards */ +#define SD_CLOCK_HIGH 48000000 /* 48 MHz for SD Cards */ + +/* Extra MMC commands for state control */ +/* Use negative numbers to disambiguate */ +#define MMC_CIM_RESET -1 + +/* Standard MMC commands (3.1) type argument response */ + /* class 1 */ +#define MMC_GO_IDLE_STATE 0 /* bc */ +#define MMC_SEND_OP_COND 1 /* bcr [31:0] OCR R3 */ +#define MMC_ALL_SEND_CID 2 /* bcr R2 */ +#define MMC_SET_RELATIVE_ADDR 3 /* ac [31:16] RCA R1 */ +#define MMC_SET_DSR 4 /* bc [31:16] RCA */ +#define MMC_SELECT_CARD 7 /* ac [31:16] RCA R1 */ +#define MMC_SEND_CSD 9 /* ac [31:16] RCA R2 */ +#define MMC_SEND_CID 10 /* ac [31:16] RCA R2 */ +#define MMC_READ_DAT_UNTIL_STOP 11 /* adtc [31:0] dadr R1 */ +#define MMC_STOP_TRANSMISSION 12 /* ac R1b */ +#define MMC_SEND_STATUS 13 /* ac [31:16] RCA R1 */ +#define MMC_GO_INACTIVE_STATE 15 /* ac [31:16] RCA */ + + /* class 2 */ +#define MMC_SET_BLOCKLEN 16 /* ac [31:0] block len R1 */ +#define MMC_READ_SINGLE_BLOCK 17 /* adtc [31:0] data addr R1 */ +#define MMC_READ_MULTIPLE_BLOCK 18 /* adtc [31:0] data addr R1 */ + + /* class 3 */ +#define MMC_WRITE_DAT_UNTIL_STOP 20 /* adtc [31:0] data addr R1 */ + + /* class 4 */ +#define MMC_SET_BLOCK_COUNT 23 /* adtc [31:0] data addr R1 */ +#define MMC_WRITE_BLOCK 24 /* adtc [31:0] data addr R1 */ +#define MMC_WRITE_MULTIPLE_BLOCK 25 /* adtc R1 */ +#define MMC_PROGRAM_CID 26 /* adtc R1 */ +#define MMC_PROGRAM_CSD 27 /* adtc R1 */ + + /* class 6 */ +#define MMC_SET_WRITE_PROT 28 /* ac [31:0] data addr R1b */ +#define MMC_CLR_WRITE_PROT 29 /* ac [31:0] data addr R1b */ +#define MMC_SEND_WRITE_PROT 30 /* adtc [31:0] wpdata addr R1 */ + + /* class 5 */ +#define MMC_ERASE_GROUP_START 35 /* ac [31:0] data addr R1 */ +#define MMC_ERASE_GROUP_END 36 /* ac [31:0] data addr R1 */ +#define MMC_ERASE 37 /* ac R1b */ + + /* class 9 */ +#define MMC_FAST_IO 39 /* ac R4 */ +#define MMC_GO_IRQ_STATE 40 /* bcr R5 */ + + /* class 7 */ +#define MMC_LOCK_UNLOCK 42 /* adtc R1b */ + + /* class 8 */ +#define MMC_APP_CMD 55 /* ac [31:16] RCA R1 */ +#define MMC_GEN_CMD 56 /* adtc [0] RD/WR R1b */ + + /* SD class */ +#define SD_SEND_OP_COND 41 /* bcr [31:0] OCR R3 */ +#define SET_BUS_WIDTH 6 /* ac [1:0] bus width R1 */ +#define SEND_SCR 51 /* adtc [31:0] staff R1 */ + +/* Don't change the order of these; they are used in dispatch tables */ +enum mmc_rsp_t +{ + RESPONSE_NONE = 0, + RESPONSE_R1 = 1, + RESPONSE_R1B = 2, + RESPONSE_R2_CID = 3, + RESPONSE_R2_CSD = 4, + RESPONSE_R3 = 5, + RESPONSE_R4 = 6, + RESPONSE_R5 = 7, + RESPONSE_R6 = 8, +}; + + +/* + MMC status in R1 + Type + e : error bit + s : status bit + r : detected and set for the actual command response + x : detected and set during command execution. the host must poll + the card by sending status command in order to read these bits. + Clear condition + a : according to the card state + b : always related to the previous command. Reception of + a valid command will clear it (with a delay of one command) + c : clear by read + */ + +#define R1_OUT_OF_RANGE (1 << 31) /* er, c */ +#define R1_ADDRESS_ERROR (1 << 30) /* erx, c */ +#define R1_BLOCK_LEN_ERROR (1 << 29) /* er, c */ +#define R1_ERASE_SEQ_ERROR (1 << 28) /* er, c */ +#define R1_ERASE_PARAM (1 << 27) /* ex, c */ +#define R1_WP_VIOLATION (1 << 26) /* erx, c */ +#define R1_CARD_IS_LOCKED (1 << 25) /* sx, a */ +#define R1_LOCK_UNLOCK_FAILED (1 << 24) /* erx, c */ +#define R1_COM_CRC_ERROR (1 << 23) /* er, b */ +#define R1_ILLEGAL_COMMAND (1 << 22) /* er, b */ +#define R1_CARD_ECC_FAILED (1 << 21) /* ex, c */ +#define R1_CC_ERROR (1 << 20) /* erx, c */ +#define R1_ERROR (1 << 19) /* erx, c */ +#define R1_UNDERRUN (1 << 18) /* ex, c */ +#define R1_OVERRUN (1 << 17) /* ex, c */ +#define R1_CID_CSD_OVERWRITE (1 << 16) /* erx, c, CID/CSD overwrite */ +#define R1_WP_ERASE_SKIP (1 << 15) /* sx, c */ +#define R1_CARD_ECC_DISABLED (1 << 14) /* sx, a */ +#define R1_ERASE_RESET (1 << 13) /* sr, c */ +#define R1_STATUS(x) (x & 0xFFFFE000) +#define R1_CURRENT_STATE(x) ((x & 0x00001E00) >> 9) /* sx, b (4 bits) */ +#define R1_READY_FOR_DATA (1 << 8) /* sx, a */ +#define R1_APP_CMD (1 << 7) /* sr, c */ + +enum card_state +{ + CARD_STATE_EMPTY = -1, + CARD_STATE_IDLE = 0, + CARD_STATE_READY = 1, + CARD_STATE_IDENT = 2, + CARD_STATE_STBY = 3, + CARD_STATE_TRAN = 4, + CARD_STATE_DATA = 5, + CARD_STATE_RCV = 6, + CARD_STATE_PRG = 7, + CARD_STATE_DIS = 8, +}; + +/* These are unpacked versions of the actual responses */ +struct mmc_response_r1 +{ + unsigned char cmd; + unsigned int status; +}; + +struct mmc_cid +{ + unsigned char mid; + unsigned short oid; + unsigned char pnm[7]; /* Product name (we null-terminate) */ + unsigned char prv; + unsigned int psn; + unsigned char mdt; +}; + +struct mmc_csd +{ + unsigned char csd_structure; + unsigned char spec_vers; + unsigned char taac; + unsigned char nsac; + unsigned char tran_speed; + unsigned short ccc; + unsigned char read_bl_len; + unsigned char read_bl_partial; + unsigned char write_blk_misalign; + unsigned char read_blk_misalign; + unsigned char dsr_imp; + unsigned short c_size; + unsigned char vdd_r_curr_min; + unsigned char vdd_r_curr_max; + unsigned char vdd_w_curr_min; + unsigned char vdd_w_curr_max; + unsigned char c_size_mult; + union + { + struct /* MMC system specification version 3.1 */ + { + unsigned char erase_grp_size; + unsigned char erase_grp_mult; + } v31; + struct /* MMC system specification version 2.2 */ + { + unsigned char sector_size; + unsigned char erase_grp_size; + } v22; + } erase; + unsigned char wp_grp_size; + unsigned char wp_grp_enable; + unsigned char default_ecc; + unsigned char r2w_factor; + unsigned char write_bl_len; + unsigned char write_bl_partial; + unsigned char file_format_grp; + unsigned char copy; + unsigned char perm_write_protect; + unsigned char tmp_write_protect; + unsigned char file_format; + unsigned char ecc; +}; + +struct mmc_response_r3 +{ + unsigned int ocr; +}; + +#define MMC_VDD_145_150 0x00000001 /* VDD voltage 1.45 - 1.50 */ +#define MMC_VDD_150_155 0x00000002 /* VDD voltage 1.50 - 1.55 */ +#define MMC_VDD_155_160 0x00000004 /* VDD voltage 1.55 - 1.60 */ +#define MMC_VDD_160_165 0x00000008 /* VDD voltage 1.60 - 1.65 */ +#define MMC_VDD_165_170 0x00000010 /* VDD voltage 1.65 - 1.70 */ +#define MMC_VDD_17_18 0x00000020 /* VDD voltage 1.7 - 1.8 */ +#define MMC_VDD_18_19 0x00000040 /* VDD voltage 1.8 - 1.9 */ +#define MMC_VDD_19_20 0x00000080 /* VDD voltage 1.9 - 2.0 */ +#define MMC_VDD_20_21 0x00000100 /* VDD voltage 2.0 ~ 2.1 */ +#define MMC_VDD_21_22 0x00000200 /* VDD voltage 2.1 ~ 2.2 */ +#define MMC_VDD_22_23 0x00000400 /* VDD voltage 2.2 ~ 2.3 */ +#define MMC_VDD_23_24 0x00000800 /* VDD voltage 2.3 ~ 2.4 */ +#define MMC_VDD_24_25 0x00001000 /* VDD voltage 2.4 ~ 2.5 */ +#define MMC_VDD_25_26 0x00002000 /* VDD voltage 2.5 ~ 2.6 */ +#define MMC_VDD_26_27 0x00004000 /* VDD voltage 2.6 ~ 2.7 */ +#define MMC_VDD_27_28 0x00008000 /* VDD voltage 2.7 ~ 2.8 */ +#define MMC_VDD_28_29 0x00010000 /* VDD voltage 2.8 ~ 2.9 */ +#define MMC_VDD_29_30 0x00020000 /* VDD voltage 2.9 ~ 3.0 */ +#define MMC_VDD_30_31 0x00040000 /* VDD voltage 3.0 ~ 3.1 */ +#define MMC_VDD_31_32 0x00080000 /* VDD voltage 3.1 ~ 3.2 */ +#define MMC_VDD_32_33 0x00100000 /* VDD voltage 3.2 ~ 3.3 */ +#define MMC_VDD_33_34 0x00200000 /* VDD voltage 3.3 ~ 3.4 */ +#define MMC_VDD_34_35 0x00400000 /* VDD voltage 3.4 ~ 3.5 */ +#define MMC_VDD_35_36 0x00800000 /* VDD voltage 3.5 ~ 3.6 */ +#define MMC_CARD_BUSY 0x80000000 /* Card Power up status bit */ + + +/* CSD field definitions */ +#define CSD_STRUCT_VER_1_0 0 /* Valid for system specification 1.0 - 1.2 */ +#define CSD_STRUCT_VER_1_1 1 /* Valid for system specification 1.4 - 2.2 */ +#define CSD_STRUCT_VER_1_2 2 /* Valid for system specification 3.1 */ + +#define CSD_SPEC_VER_0 0 /* Implements system specification 1.0 - 1.2 */ +#define CSD_SPEC_VER_1 1 /* Implements system specification 1.4 */ +#define CSD_SPEC_VER_2 2 /* Implements system specification 2.0 - 2.2 */ +#define CSD_SPEC_VER_3 3 /* Implements system specification 3.1 */ + +/* the information structure of MMC/SD Card */ +typedef struct MMC_INFO +{ + int id; /* Card index */ + int sd; /* MMC or SD card */ + int rca; /* RCA */ + unsigned int scr; /* SCR 63:32*/ + int flags; /* Ejected, inserted */ + enum card_state state; /* empty, ident, ready, whatever */ + + /* Card specific information */ + struct mmc_cid cid; + struct mmc_csd csd; + unsigned int block_num; + unsigned int block_len; + unsigned int erase_unit; +} mmc_info; + +static mmc_info mmcinfo; + +struct mmc_request +{ + int index; /* Slot index - used for CS lines */ + int cmd; /* Command to send */ + unsigned int arg; /* Argument to send */ + enum mmc_rsp_t rtype; /* Response type expected */ + + /* Data transfer (these may be modified at the low level) */ + unsigned short nob; /* Number of blocks to transfer*/ + unsigned short block_len; /* Block length */ + unsigned char *buffer; /* Data buffer */ + unsigned int cnt; /* Data length, for PIO */ + + /* Results */ + unsigned char response[18]; /* Buffer to store response - CRC is optional */ + enum mmc_result_t result; +}; + +#define MMC_OCR_ARG 0x00ff8000 /* Argument of OCR */ + +/*********************************************************************** + * MMC Events + */ +#define MMC_EVENT_NONE 0x00 /* No events */ +#define MMC_EVENT_RX_DATA_DONE 0x01 /* Rx data done */ +#define MMC_EVENT_TX_DATA_DONE 0x02 /* Tx data done */ +#define MMC_EVENT_PROG_DONE 0x04 /* Programming is done */ + +static int use_4bit; /* Use 4-bit data bus */ +static int num_6; +static int sd2_0; + +/* Stop the MMC clock and wait while it happens */ +static inline int jz_mmc_stop_clock(void) +{ + int timeout = 1000; + + DEBUG("stop MMC clock"); + REG_MSC_STRPCL = MSC_STRPCL_CLOCK_CONTROL_STOP; + + while (timeout && (REG_MSC_STAT & MSC_STAT_CLK_EN)) + { + timeout--; + if (timeout == 0) + { + DEBUG("Timeout on stop clock waiting"); + return MMC_ERROR_TIMEOUT; + } + udelay(1); + } + DEBUG("clock off time is %d microsec", timeout); + return MMC_NO_ERROR; +} + +/* Start the MMC clock and operation */ +static inline int jz_mmc_start_clock(void) +{ + REG_MSC_STRPCL = + MSC_STRPCL_CLOCK_CONTROL_START | MSC_STRPCL_START_OP; + return MMC_NO_ERROR; +} + +static inline unsigned int jz_mmc_calc_clkrt(int is_sd, unsigned int rate) +{ + unsigned int clkrt; + unsigned int clk_src = is_sd ? 24000000 : 20000000; + + clkrt = 0; + while (rate < clk_src) + { + clkrt++; + clk_src >>= 1; + } + return clkrt; +} + +static int jz_mmc_check_status(struct mmc_request *request) +{ + unsigned int status = REG_MSC_STAT; + + /* Checking for response or data timeout */ + if (status & (MSC_STAT_TIME_OUT_RES | MSC_STAT_TIME_OUT_READ)) + { + DEBUG("MMC/SD timeout, MMC_STAT 0x%x CMD %d", status, + request->cmd); + return MMC_ERROR_TIMEOUT; + } + + /* Checking for CRC error */ + if (status & + (MSC_STAT_CRC_READ_ERROR | MSC_STAT_CRC_WRITE_ERROR | + MSC_STAT_CRC_RES_ERR)) + { + DEBUG("MMC/CD CRC error, MMC_STAT 0x%x", status); + return MMC_ERROR_CRC; + } + + return MMC_NO_ERROR; +} + +/* Obtain response to the command and store it to response buffer */ +static void jz_mmc_get_response(struct mmc_request *request) +{ + int i; + unsigned char *buf; + unsigned int data; + + DEBUG("fetch response for request %d, cmd %d", request->rtype, + request->cmd); + buf = request->response; + request->result = MMC_NO_ERROR; + + switch (request->rtype) + { + case RESPONSE_R1: + case RESPONSE_R1B: + case RESPONSE_R6: + case RESPONSE_R3: + case RESPONSE_R4: + case RESPONSE_R5: + { + data = REG_MSC_RES; + buf[0] = (data >> 8) & 0xff; + buf[1] = data & 0xff; + data = REG_MSC_RES; + buf[2] = (data >> 8) & 0xff; + buf[3] = data & 0xff; + data = REG_MSC_RES; + buf[4] = data & 0xff; + + DEBUG("request %d, response [%02x %02x %02x %02x %02x]", + request->rtype, buf[0], buf[1], buf[2], + buf[3], buf[4]); + break; + } + case RESPONSE_R2_CID: + case RESPONSE_R2_CSD: + { + for (i = 0; i < 16; i += 2) + { + data = REG_MSC_RES; + buf[i] = (data >> 8) & 0xff; + buf[i + 1] = data & 0xff; + } + DEBUG("request %d, response [", request->rtype); + break; + } + case RESPONSE_NONE: + DEBUG("No response"); + break; + + default: + DEBUG("unhandled response type for request %d", + request->rtype); + break; + } +} + +#ifdef MMC_DMA_ENABLE +static int jz_mmc_receive_data_dma(struct mmc_request *req) +{ + int ch = RX_DMA_CHANNEL; + unsigned int size = req->block_len * req->nob; + unsigned char err = 0; + + /* flush dcache */ + dma_cache_wback_inv((unsigned long) req->buffer, size); + /* setup dma channel */ + REG_DMAC_DSAR(ch) = PHYSADDR(MSC_RXFIFO); /* DMA source addr */ + REG_DMAC_DTAR(ch) = PHYSADDR((unsigned long) req->buffer); /* DMA dest addr */ + REG_DMAC_DTCR(ch) = (size + 3) / 4; /* DMA transfer count */ + REG_DMAC_DRSR(ch) = DMAC_DRSR_RS_MSCIN; /* DMA request type */ + +#if MMC_DMA_INTERRUPT + REG_DMAC_DCMD(ch) = + DMAC_DCMD_DAI | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | + DMAC_DCMD_DS_32BIT | DMAC_DCMD_TIE; + REG_DMAC_DCCSR(ch) = DMAC_DCCSR_EN | DMAC_DCCSR_NDES; + OSSemPend(mmc_dma_rx_sem, 100, &err); +#else + REG_DMAC_DCMD(ch) = + DMAC_DCMD_DAI | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | + DMAC_DCMD_DS_32BIT; + REG_DMAC_DCCSR(ch) = DMAC_DCCSR_EN | DMAC_DCCSR_NDES; + while (REG_DMAC_DTCR(ch)); +#endif +/* clear status and disable channel */ + REG_DMAC_DCCSR(ch) = 0; +#if MMC_DMA_INTERRUPT + return (err == OS_NO_ERR); +#else + return 0; +#endif +} + +static int jz_mmc_transmit_data_dma(struct mmc_request *req) +{ + int ch = TX_DMA_CHANNEL; + unsigned int size = req->block_len * req->nob; + unsigned char err = 0; + + /* flush dcache */ + dma_cache_wback_inv((unsigned long) req->buffer, size); + /* setup dma channel */ + REG_DMAC_DSAR(ch) = PHYSADDR((unsigned long) req->buffer); /* DMA source addr */ + REG_DMAC_DTAR(ch) = PHYSADDR(MSC_TXFIFO); /* DMA dest addr */ + REG_DMAC_DTCR(ch) = (size + 3) / 4; /* DMA transfer count */ + REG_DMAC_DRSR(ch) = DMAC_DRSR_RS_MSCOUT; /* DMA request type */ + +#if MMC_DMA_INTERRUPT + REG_DMAC_DCMD(ch) = + DMAC_DCMD_SAI | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | + DMAC_DCMD_DS_32BIT | DMAC_DCMD_TIE; + REG_DMAC_DCCSR(ch) = DMAC_DCCSR_EN | DMAC_DCCSR_NDES; + OSSemPend(mmc_dma_tx_sem, 100, &err); +#else + REG_DMAC_DCMD(ch) = + DMAC_DCMD_SAI | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | + DMAC_DCMD_DS_32BIT; + REG_DMAC_DCCSR(ch) = DMAC_DCCSR_EN | DMAC_DCCSR_NDES; + /* wait for dma completion */ + while (REG_DMAC_DTCR(ch)); +#endif + /* clear status and disable channel */ + REG_DMAC_DCCSR(ch) = 0; +#if MMC_DMA_INTERRUPT + return (err == OS_NO_ERR); +#else + return 0; +#endif +} + +#endif /* MMC_DMA_ENABLE */ + +static int jz_mmc_receive_data(struct mmc_request *req) +{ + unsigned int nob = req->nob; + unsigned int wblocklen = (unsigned int) (req->block_len + 3) >> 2; /* length in word */ + unsigned char *buf = req->buffer; + unsigned int *wbuf = (unsigned int *) buf; + unsigned int waligned = (((unsigned int) buf & 0x3) == 0); /* word aligned ? */ + unsigned int stat, timeout, data, cnt; + + for (; nob >= 1; nob--) + { + timeout = 0x3FFFFFF; + + while (timeout) + { + timeout--; + stat = REG_MSC_STAT; + + if (stat & MSC_STAT_TIME_OUT_READ) + return MMC_ERROR_TIMEOUT; + else if (stat & MSC_STAT_CRC_READ_ERROR) + return MMC_ERROR_CRC; + else if (!(stat & MSC_STAT_DATA_FIFO_EMPTY) + || (stat & MSC_STAT_DATA_FIFO_AFULL)) { + /* Ready to read data */ + break; + } + + udelay(1); + } + + if (!timeout) + return MMC_ERROR_TIMEOUT; + + /* Read data from RXFIFO. It could be FULL or PARTIAL FULL */ + DEBUG("Receive Data = %d", wblocklen); + cnt = wblocklen; + while (cnt) + { + data = REG_MSC_RXFIFO; + if (waligned) + *wbuf++ = data; + else + { + *buf++ = (unsigned char) (data >> 0); + *buf++ = (unsigned char) (data >> 8); + *buf++ = (unsigned char) (data >> 16); + *buf++ = (unsigned char) (data >> 24); + } + cnt--; + while (cnt + && (REG_MSC_STAT & + MSC_STAT_DATA_FIFO_EMPTY)); + } + } + + return MMC_NO_ERROR; +} + +static int jz_mmc_transmit_data(struct mmc_request *req) +{ + unsigned int nob = req->nob; + unsigned int wblocklen = (unsigned int) (req->block_len + 3) >> 2; /* length in word */ + unsigned char *buf = req->buffer; + unsigned int *wbuf = (unsigned int *) buf; + unsigned int waligned = (((unsigned int) buf & 0x3) == 0); /* word aligned ? */ + unsigned int stat, timeout, data, cnt; + + for (; nob >= 1; nob--) + { + timeout = 0x3FFFFFF; + + while (timeout) + { + timeout--; + stat = REG_MSC_STAT; + + if (stat & + (MSC_STAT_CRC_WRITE_ERROR | + MSC_STAT_CRC_WRITE_ERROR_NOSTS)) + return MMC_ERROR_CRC; + else if (!(stat & MSC_STAT_DATA_FIFO_FULL)) + { + /* Ready to write data */ + break; + } + + udelay(1); + } + + if (!timeout) + return MMC_ERROR_TIMEOUT; + + /* Write data to TXFIFO */ + cnt = wblocklen; + while (cnt) + { + while (REG_MSC_STAT & MSC_STAT_DATA_FIFO_FULL); + + if (waligned) + REG_MSC_TXFIFO = *wbuf++; + else + { + data = *buf++; + data |= *buf++ << 8; + data |= *buf++ << 16; + data |= *buf++ << 24; + REG_MSC_TXFIFO = data; + } + + cnt--; + } + } + + return MMC_NO_ERROR; +} + +/* Set the MMC clock frequency */ +static void jz_mmc_set_clock(int sd, unsigned int rate) +{ + int clkrt = 0; + + sd = sd ? 1 : 0; + + jz_mmc_stop_clock(); + + if(sd2_0) + { + __cpm_select_msc_hs_clk(sd); /* select clock source from CPM */ + REG_CPM_CPCCR |= CPM_CPCCR_CE; + REG_MSC_CLKRT = 0; + } + else + { + __cpm_select_msc_clk(sd); /* select clock source from CPM */ + REG_CPM_CPCCR |= CPM_CPCCR_CE; + clkrt = jz_mmc_calc_clkrt(sd, rate); + REG_MSC_CLKRT = clkrt; + } + DEBUG("set clock to %u Hz is_sd=%d clkrt=%d", rate, sd, clkrt); +} + +/******************************************************************************************************************** +** Name: int jz_mmc_exec_cmd() +** Function: send command to the card, and get a response +** Input: struct mmc_request *req: MMC/SD request +** Output: 0: right >0: error code +********************************************************************************************************************/ +static int jz_mmc_exec_cmd(struct mmc_request *request) +{ + unsigned int cmdat = 0, events = 0; + int retval, timeout = 0x3fffff; + + /* Indicate we have no result yet */ + request->result = MMC_NO_RESPONSE; + if (request->cmd == MMC_CIM_RESET) + { + /* On reset, 1-bit bus width */ + use_4bit = 0; + + /* Reset MMC/SD controller */ + __msc_reset(); + + /* On reset, drop MMC clock down */ + jz_mmc_set_clock(0, MMC_CLOCK_SLOW); + + /* On reset, stop MMC clock */ + jz_mmc_stop_clock(); + } + if (request->cmd == MMC_SEND_OP_COND) + { + DEBUG("Have a MMC card"); + /* always use 1bit for MMC */ + use_4bit = 0; + } + if (request->cmd == SET_BUS_WIDTH) + { + if (request->arg == 0x2) + { + DEBUG("Use 4-bit bus width"); + use_4bit = 1; + } + else + { + DEBUG("Use 1-bit bus width"); + use_4bit = 0; + } + } + + /* stop clock */ + jz_mmc_stop_clock(); + + /* mask all interrupts */ + //REG_MSC_IMASK = 0xffff; + /* clear status */ + REG_MSC_IREG = 0xffff; + /*open interrupt */ + REG_MSC_IMASK = (~7); + /* use 4-bit bus width when possible */ + if (use_4bit) + cmdat |= MSC_CMDAT_BUS_WIDTH_4BIT; + + /* Set command type and events */ + switch (request->cmd) + { + /* MMC core extra command */ + case MMC_CIM_RESET: + cmdat |= MSC_CMDAT_INIT; /* Initialization sequence sent prior to command */ + break; + + /* bc - broadcast - no response */ + case MMC_GO_IDLE_STATE: + case MMC_SET_DSR: + break; + + /* bcr - broadcast with response */ + case MMC_SEND_OP_COND: + case MMC_ALL_SEND_CID: + + case MMC_GO_IRQ_STATE: + break; + + /* adtc - addressed with data transfer */ + case MMC_READ_DAT_UNTIL_STOP: + case MMC_READ_SINGLE_BLOCK: + case MMC_READ_MULTIPLE_BLOCK: + case SEND_SCR: +#if defined(MMC_DMA_ENABLE) + cmdat |= + MSC_CMDAT_DATA_EN | MSC_CMDAT_READ | MSC_CMDAT_DMA_EN; +#else + cmdat |= MSC_CMDAT_DATA_EN | MSC_CMDAT_READ; +#endif + events = MMC_EVENT_RX_DATA_DONE; + break; + + case 6: + if (num_6 < 2) + { + +#if defined(MMC_DMA_ENABLE) + cmdat |= + MSC_CMDAT_DATA_EN | MSC_CMDAT_READ | + MSC_CMDAT_DMA_EN; +#else + cmdat |= MSC_CMDAT_DATA_EN | MSC_CMDAT_READ; +#endif + events = MMC_EVENT_RX_DATA_DONE; + } + break; + + case MMC_WRITE_DAT_UNTIL_STOP: + case MMC_WRITE_BLOCK: + case MMC_WRITE_MULTIPLE_BLOCK: + case MMC_PROGRAM_CID: + case MMC_PROGRAM_CSD: + case MMC_SEND_WRITE_PROT: + case MMC_GEN_CMD: + case MMC_LOCK_UNLOCK: +#if defined(MMC_DMA_ENABLE) + cmdat |= + MSC_CMDAT_DATA_EN | MSC_CMDAT_WRITE | MSC_CMDAT_DMA_EN; +#else + cmdat |= MSC_CMDAT_DATA_EN | MSC_CMDAT_WRITE; +#endif + events = MMC_EVENT_TX_DATA_DONE | MMC_EVENT_PROG_DONE; + break; + + case MMC_STOP_TRANSMISSION: + events = MMC_EVENT_PROG_DONE; + break; + + /* ac - no data transfer */ + default: + break; + } + + /* Set response type */ + switch (request->rtype) + { + case RESPONSE_NONE: + break; + case RESPONSE_R1B: + cmdat |= MSC_CMDAT_BUSY; + /*FALLTHRU*/ + case RESPONSE_R1: + cmdat |= MSC_CMDAT_RESPONSE_R1; + break; + case RESPONSE_R2_CID: + case RESPONSE_R2_CSD: + cmdat |= MSC_CMDAT_RESPONSE_R2; + break; + case RESPONSE_R3: + cmdat |= MSC_CMDAT_RESPONSE_R3; + break; + case RESPONSE_R4: + cmdat |= MSC_CMDAT_RESPONSE_R4; + break; + case RESPONSE_R5: + cmdat |= MSC_CMDAT_RESPONSE_R5; + break; + case RESPONSE_R6: + cmdat |= MSC_CMDAT_RESPONSE_R6; + break; + default: + break; + } + + /* Set command index */ + if (request->cmd == MMC_CIM_RESET) + REG_MSC_CMD = MMC_GO_IDLE_STATE; + else + REG_MSC_CMD = request->cmd; + + /* Set argument */ + REG_MSC_ARG = request->arg; + + /* Set block length and nob */ + if (request->cmd == SEND_SCR) + { /* get SCR from DataFIFO */ + REG_MSC_BLKLEN = 8; + REG_MSC_NOB = 1; + } + else + { + REG_MSC_BLKLEN = request->block_len; + REG_MSC_NOB = request->nob; + } + + /* Set command */ + REG_MSC_CMDAT = cmdat; + + DEBUG("Send cmd %d cmdat: %x arg: %x resp %d", request->cmd, + cmdat, request->arg, request->rtype); + + /* Start MMC/SD clock and send command to card */ + jz_mmc_start_clock(); + + /* Wait for command completion */ + //__intc_unmask_irq(IRQ_MSC); + //wakeup_wait(&sd_wakeup, 100); + while (timeout-- && !(REG_MSC_STAT & MSC_STAT_END_CMD_RES)); + + + if (timeout == 0) + return MMC_ERROR_TIMEOUT; + + REG_MSC_IREG = MSC_IREG_END_CMD_RES; /* clear flag */ + + /* Check for status */ + retval = jz_mmc_check_status(request); + if (retval) + return retval; + + /* Complete command with no response */ + if (request->rtype == RESPONSE_NONE) + return MMC_NO_ERROR; + + /* Get response */ + jz_mmc_get_response(request); + + /* Start data operation */ + if (events & (MMC_EVENT_RX_DATA_DONE | MMC_EVENT_TX_DATA_DONE)) + { + if (events & MMC_EVENT_RX_DATA_DONE) + { + if (request->cmd == SEND_SCR) + { + /* SD card returns SCR register as data. + MMC core expect it in the response buffer, + after normal response. */ + request->buffer = + (unsigned char *) ((unsigned int) request->response + 5); + } +#ifdef MMC_DMA_ENABLE + jz_mmc_receive_data_dma(request); +#else + jz_mmc_receive_data(request); +#endif + } + + if (events & MMC_EVENT_TX_DATA_DONE) + { +#ifdef MMC_DMA_ENABLE + jz_mmc_transmit_data_dma(request); +#else + jz_mmc_transmit_data(request); +#endif + } + //__intc_unmask_irq(IRQ_MSC); + //wakeup_wait(&sd_wakeup, 100); + /* Wait for Data Done */ + while (!(REG_MSC_IREG & MSC_IREG_DATA_TRAN_DONE)); + REG_MSC_IREG = MSC_IREG_DATA_TRAN_DONE; /* clear status */ + + } + + /* Wait for Prog Done event */ + if (events & MMC_EVENT_PROG_DONE) + { + //__intc_unmask_irq(IRQ_MSC); + //wakeup_wait(&sd_wakeup, 100); + while (!(REG_MSC_IREG & MSC_IREG_PRG_DONE)); + REG_MSC_IREG = MSC_IREG_PRG_DONE; /* clear status */ + } + + /* Command completed */ + + return MMC_NO_ERROR; /* return successfully */ +} + +/******************************************************************************************************************* +** Name: int mmc_chkcard() +** Function: check whether card is insert entirely +** Input: NULL +** Output: 1: insert entirely 0: not insert entirely +********************************************************************************************************************/ +static int jz_mmc_chkcard(void) +{ + if (MMC_INSERT_STATUS() == 0) + return 1; /* insert entirely */ + else + return 0; /* not insert entirely */ +} + +#if MMC_DMA_INTERRUPT +static void jz_mmc_tx_handler(unsigned int arg) +{ + if (__dmac_channel_address_error_detected(arg)) + { + DEBUG("%s: DMAC address error.", __FUNCTION__); + __dmac_channel_clear_address_error(arg); + } + if (__dmac_channel_transmit_end_detected(arg)) + { + + __dmac_channel_clear_transmit_end(arg); + OSSemPost(mmc_dma_tx_sem); + } +} + +static void jz_mmc_rx_handler(unsigned int arg) +{ + if (__dmac_channel_address_error_detected(arg)) + { + DEBUG("%s: DMAC address error.", __FUNCTION__); + __dmac_channel_clear_address_error(arg); + } + if (__dmac_channel_transmit_end_detected(arg)) + { + __dmac_channel_clear_transmit_end(arg); + OSSemPost(mmc_dma_rx_sem); + } +} +#endif + +/* MSC interrupt handler */ +void MSC(void) +{ + //wakeup_signal(&sd_wakeup); +} + +/******************************************************************************************************************* +** Name: void mmc_hardware_init() +** Function: initialize the hardware condiction that access sd card +** Input: NULL +** Output: NULL +********************************************************************************************************************/ +static void jz_mmc_hardware_init(void) +{ + mmc_init_gpio(); /* init GPIO */ + MMC_POWER_ON(); /* turn on power of card */ + MMC_RESET(); /* reset mmc/sd controller */ + MMC_IRQ_MASK(); /* mask all IRQs */ + jz_mmc_stop_clock(); /* stop MMC/SD clock */ +#ifdef MMC_DMA_ENABLE + __cpm_start_dmac(); + __dmac_enable_module(); +// REG_DMAC_DMACR = DMAC_DMACR_DME; +#if MMC_DMA_INTERRUPT + mmc_dma_rx_sem = OSSemCreate(0); + mmc_dma_tx_sem = OSSemCreate(0); + request_irq(IRQ_DMA_0 + RX_DMA_CHANNEL, jz_mmc_rx_handler, + RX_DMA_CHANNEL); + request_irq(IRQ_DMA_0 + TX_DMA_CHANNEL, jz_mmc_tx_handler, + TX_DMA_CHANNEL); +#endif +#endif +} + +static void mmc_send_cmd(struct mmc_request *request, int cmd, unsigned int arg, + unsigned short nob, unsigned short block_len, + enum mmc_rsp_t rtype, unsigned char* buffer) +{ + request->cmd = cmd; + request->arg = arg; + request->rtype = rtype; + request->nob = nob; + request->block_len = block_len; + request->buffer = buffer; + request->cnt = nob * block_len; + printf("mmc_send_cmd: command = %d",cmd); + jz_mmc_exec_cmd(request); +} + +static bool inited = false; +int sd_init(void) +{ + if(!inited) + { + jz_mmc_hardware_init(); + wakeup_init(&sd_wakeup); + inited = true; + } + + struct mmc_request test; + //mmc_send_cmd(&test, MMC_CIM_RESET, 0, 0, 0, RESPONSE_NONE, NULL); + mmc_send_cmd(&test, MMC_GO_IDLE_STATE, 0, 0, 0, RESPONSE_NONE, NULL); + mmc_send_cmd(&test, SD_SEND_OP_COND, MMC_OCR_ARG, 0, 0, RESPONSE_R3, NULL); + + return 0; +} + +bool card_detect_target(void) +{ + return jz_mmc_chkcard() == 1; +} + +#ifdef HAVE_HOTSWAP +void card_enable_monitoring_target(bool on) +{ + if(on) + { + + } + else + { + + } +} +#endif + +/* TODO */ +tCardInfo* card_get_info_target(int card_no) +{ + static tCardInfo card; + + return &card; +} + +/* TODO */ +int sd_read_sectors(unsigned long start, int count, void* buf) +{ + (void)start; + (void)count; + (void)buf; + return -1; +} + +/* TODO */ +int sd_write_sectors(unsigned long start, int count, const void* buf) +{ + (void)start; + (void)count; + (void)buf; + return -1; +} diff --git a/firmware/target/mips/ingenic_jz47xx/ata-sd-target.h b/firmware/target/mips/ingenic_jz47xx/ata-sd-target.h new file mode 100644 index 0000000000..f788fd6a41 --- /dev/null +++ b/firmware/target/mips/ingenic_jz47xx/ata-sd-target.h @@ -0,0 +1,39 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2008 by Maurus Cuelenaere + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#ifndef ATA_SD_TARGET_H +#define ATA_SD_TARGET_H + +#include "inttypes.h" +#include "hotswap.h" + +tCardInfo *card_get_info_target(int card_no); +bool card_detect_target(void); + +#ifdef HAVE_HOTSWAP +void card_enable_monitoring_target(bool on); +void microsd_int(void); /* ??? */ +#endif + +int sd_read_sectors(unsigned long start, int count, void* buf); +int sd_write_sectors(unsigned long start, int count, const void* buf); +int sd_init(void); + +#endif diff --git a/firmware/target/mips/ingenic_jz47xx/codec-jz4740.c b/firmware/target/mips/ingenic_jz47xx/codec-jz4740.c new file mode 100644 index 0000000000..6c3ed8cf2a --- /dev/null +++ b/firmware/target/mips/ingenic_jz47xx/codec-jz4740.c @@ -0,0 +1,280 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2008 by Maurus Cuelenaere + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include "config.h" +#include "jz4740.h" + +static unsigned short codec_volume; +static unsigned short codec_base_gain; +static unsigned short codec_mic_gain; +static bool HP_on_off_flag; +static int HP_register_value; +static int IS_WRITE_PCM; + +static void i2s_codec_clear(void) +{ + REG_ICDC_CDCCR1 = (ICDC_CDCCR1_SW2ON | ICDC_CDCCR1_PDVR | ICDC_CDCCR1_PDVRA | ICDC_CDCCR1_VRCGL | + ICDC_CDCCR1_VRCGH | ICDC_CDCCR1_HPOV0 | ICDC_CDCCR1_PDHPM | ICDC_CDCCR1_PDHP | + ICDC_CDCCR1_SUSPD | ICDC_CDCCR1_RST); +} + +static void i2s_codec_init(void) +{ + __aic_select_i2s(); + __i2s_internal_codec(); + + __aic_enable(); + + __i2s_set_oss_sample_size(16); + + REG_ICDC_CDCCR1 = (ICDC_CDCCR1_SW2ON | ICDC_CDCCR1_PDVR | ICDC_CDCCR1_PDVRA | ICDC_CDCCR1_VRCGL | + ICDC_CDCCR1_VRCGH | ICDC_CDCCR1_HPOV0 | ICDC_CDCCR1_PDHPM | ICDC_CDCCR1_PDHP | + ICDC_CDCCR1_SUSPD | ICDC_CDCCR1_RST); /* reset */ + udelay(10); + REG_ICDC_CDCCR1 = (ICDC_CDCCR1_SW2ON | ICDC_CDCCR1_PDVR | ICDC_CDCCR1_PDVRA | ICDC_CDCCR1_VRCGL | + ICDC_CDCCR1_VRCGH | ICDC_CDCCR1_HPOV0 | ICDC_CDCCR1_PDHPM | ICDC_CDCCR1_PDHP | + ICDC_CDCCR1_SUSPD | ICDC_CDCCR1_RST); + //REG_ICDC_CDCCR2 = (ICDC_CDCCR2_AINVOL(ICDC_CDCCR2_AINVOL_DB(0)) | ICDC_CDCCR2_SMPR(ICDC_CDCCR2_SMPR_48) | + REG_ICDC_CDCCR2 = (ICDC_CDCCR2_AINVOL(23) | ICDC_CDCCR2_SMPR(ICDC_CDCCR2_SMPR_48) | + ICDC_CDCCR2_HPVOL(ICDC_CDCCR2_HPVOL_6)); + HP_on_off_flag = 0; /* HP is off */ +} + +static void i2s_codec_set_mic(unsigned short v) /* 0 <= v <= 100 */ +{ + v = v & 0xff; + if(v < 0) + v = 0; + if(v > 100) + v = 100; + codec_mic_gain = 31 * v/100; + + REG_ICDC_CDCCR2 = ((REG_ICDC_CDCCR2 & ~(0x1f << 16)) | (codec_mic_gain << 16)); +} + +static void i2s_codec_set_bass(unsigned short v) /* 0 <= v <= 100 */ +{ + v = v & 0xff; + if(v < 0) + v = 0; + if(v > 100) + v = 100; + + if(v < 25) + codec_base_gain = 0; + if(v >= 25 && v < 50) + codec_base_gain = 1; + if(v >= 50 && v < 75) + codec_base_gain = 2; + if(v >= 75 && v <= 100) + codec_base_gain = 3; + + REG_ICDC_CDCCR2 = ((REG_ICDC_CDCCR2 & ~(0x3 << 4)) | (codec_base_gain << 4)); +} + +static void i2s_codec_set_volume(unsigned short v) /* 0 <= v <= 100 */ +{ + v = v & 0xff; + if(v < 0) + v = 0; + if(v > 100) + v = 100; + + if(v < 25) + codec_volume = 0; + if(v >= 25 && v < 50) + codec_volume = 1; + if(v >= 50 && v < 75) + codec_volume = 2; + if(v >= 75 && v <= 100) + codec_volume = 3; + + REG_ICDC_CDCCR2 = ((REG_ICDC_CDCCR2 & ~(0x3)) | codec_volume); +} + +static unsigned short i2s_codec_get_bass(void) +{ + unsigned short val; + int ret; + if(codec_base_gain == 0) + val = 0; + if(codec_base_gain == 1) + val = 25; + if(codec_base_gain == 2) + val = 50; + if(codec_base_gain == 3) + val = 75; + + ret = val << 8; + val = val | ret; +} + +static unsigned short i2s_codec_get_mic(void) +{ + unsigned short val; + int ret; + val = 100 * codec_mic_gain / 31; + ret = val << 8; + val = val | ret; +} + +static unsigned short i2s_codec_get_volume(void) +{ + unsigned short val; + int ret; + + if(codec_volume == 0) + val = 0; + if(codec_volume == 1) + val = 25; + if(codec_volume == 2) + val = 50; + if(codec_volume == 3) + val = 75; + + ret = val << 8; + val = val | ret; + return val; +} + +static void i2s_codec_set_samplerate(unsigned short rate) +{ + unsigned short speed = 0; + unsigned short val = 0; + + switch (rate) + { + case 8000: + speed = 0; + break; + case 11025: + speed = 1; + break; + case 12000: + speed = 2; + break; + case 16000: + speed = 3; + break; + case 22050: + speed = 4; + break; + case 24000: + speed = 5; + break; + case 32000: + speed = 6; + break; + case 44100: + speed = 7; + break; + case 48000: + speed = 8; + break; + default: + break; + } + REG_ICDC_CDCCR2 |= 0x00000f00; + speed = speed << 8; + + speed |= 0xfffff0ff; + REG_ICDC_CDCCR2 &= speed; +} + +static void HP_turn_on(void) +{ + //see 1.3.4.1 + + REG_ICDC_CDCCR1 &= ~(ICDC_CDCCR1_SUSPD | ICDC_CDCCR1_RST); //set suspend 0 + + mdelay(15); + REG_ICDC_CDCCR1 &= ~(ICDC_CDCCR1_PDVR | ICDC_CDCCR1_VRCGL | ICDC_CDCCR1_VRCGH); + REG_ICDC_CDCCR1 |= (ICDC_CDCCR1_EDAC | ICDC_CDCCR1_HPCG); + + mdelay(600); + REG_ICDC_CDCCR1 &= ~(ICDC_CDCCR1_PDVRA | ICDC_CDCCR1_HPCG | ICDC_CDCCR1_PDHPM | ICDC_CDCCR1_PDHP); + + mdelay(2); + HP_register_value = REG_ICDC_CDCCR1; + + //see 1.3.4.2 + /*REG_ICDC_CDCCR1 &= 0xfffffffc; + mdelay(7); + REG_ICDC_CDCCR1 |= 0x00040400; + mdelay(15); + REG_ICDC_CDCCR1 &= 0xfffbfbff; + udelay(500); + REG_ICDC_CDCCR1 &= 0xffe5fcff; + REG_ICDC_CDCCR1 |= 0x01000000; + mdelay(400); + REG_ICDC_CDCCR1 &= 0xfffeffff; + mdelay(7); + HP_register_value = REG_ICDC_CDCCR1;*/ + + //see 1.3.4.3 + +} + + +static void HP_turn_off(void) +{ + //see 1.3.4.1 + mdelay(2); + REG_ICDC_CDCCR1 = HP_register_value; + REG_ICDC_CDCCR1 |= 0x001b0300; + REG_ICDC_CDCCR1 &= 0xfeffffff; + + mdelay(15); + REG_ICDC_CDCCR1 |= 0x00000002;//set suspend 1 + + //see 1.3.4.2 + /*mdelay(4); + REG_ICDC_CDCCR1 = HP_register_value; + REG_ICDC_CDCCR1 |= 0x001b0300; + REG_ICDC_CDCCR1 &= 0xfeffffff; + mdelay(4); + REG_ICDC_CDCCR1 |= 0x00000400; + mdelay(15); + REG_ICDC_CDCCR1 &= 0xfffffdff; + mdelay(7); + REG_ICDC_CDCCR1 |= 0x00000002;*/ + + //see 1.3.4.3 + +} + +void audiohw_mute(bool mute) +{ + if(mute) + REG_ICDC_CDCCR1 |= ICDC_CDCCR1_HPMUTE; + else + REG_ICDC_CDCCR1 &= ~ICDC_CDCCR1_HPMUTE; +} + +void audiohw_preinit(void) +{ + i2s_reset(); +} + +void audiohw_postinit(void) +{ + audiohw_mute(false); +} diff --git a/firmware/target/mips/ingenic_jz47xx/onda_vx747/sadc-onda_vx747.c b/firmware/target/mips/ingenic_jz47xx/onda_vx747/sadc-onda_vx747.c index 0f1cfca937..64ea86135f 100644 --- a/firmware/target/mips/ingenic_jz47xx/onda_vx747/sadc-onda_vx747.c +++ b/firmware/target/mips/ingenic_jz47xx/onda_vx747/sadc-onda_vx747.c @@ -24,6 +24,7 @@ #include "jz4740.h" #include "button.h" #include "button-target.h" +#include "powermgmt.h" #define BTN_OFF (1 << 29) #define BTN_VOL_DOWN (1 << 27) @@ -49,15 +50,61 @@ static short x_pos = -1, y_pos = -1, datacount = 0; static bool pen_down = false; static int cur_touch = 0; +static unsigned short bat_val = 0; static enum touchscreen_mode current_mode = TOUCHSCREEN_POINT; -static int touchscreen_buttons[3][3] = +static const int touchscreen_buttons[3][3] = { {BUTTON_TOPLEFT, BUTTON_TOPMIDDLE, BUTTON_TOPRIGHT}, {BUTTON_MIDLEFT, BUTTON_CENTER, BUTTON_MIDRIGHT}, {BUTTON_BOTTOMLEFT, BUTTON_BOTTOMMIDDLE, BUTTON_BOTTOMRIGHT} }; +const unsigned short battery_level_dangerous[BATTERY_TYPES_COUNT] = +{ + /* TODO */ + 3400 +}; + +const unsigned short battery_level_shutoff[BATTERY_TYPES_COUNT] = +{ + /* TODO */ + 3300 +}; + +/* voltages (millivolt) of 0%, 10%, ... 100% when charging disabled */ +const unsigned short percent_to_volt_discharge[BATTERY_TYPES_COUNT][11] = +{ + /* TODO */ + { 3300, 3680, 3740, 3760, 3780, 3810, 3870, 3930, 3970, 4070, 4160 }, +}; + +/* voltages (millivolt) of 0%, 10%, ... 100% when charging enabled */ +const unsigned short percent_to_volt_charge[11] = +{ + /* TODO */ + 3300, 3680, 3740, 3760, 3780, 3810, 3870, 3930, 3970, 4070, 4160 +}; + +/* VBAT = (BDATA/4096) * 7.5V */ +#define BATTERY_SCALE_FACTOR 7500 + +/* Returns battery voltage from ADC [millivolts] */ +unsigned int battery_adc_voltage(void) +{ + register unsigned short dummy; + dummy = REG_SADC_BATDAT; + dummy = REG_SADC_BATDAT; + + bat_val = 0; + REG_SADC_ENA |= SADC_ENA_PBATEN; + + while(bat_val == 0) + yield(); + + return (bat_val*BATTERY_SCALE_FACTOR)>>12; +} + void button_init_device(void) { REG_SADC_ENA = 0; @@ -72,8 +119,8 @@ void button_init_device(void) REG_SADC_SAMETIME = 350; REG_SADC_WAITTIME = 100; REG_SADC_STATE &= (~REG_SADC_STATE); - REG_SADC_CTRL &= (~(SADC_CTRL_PENDM | SADC_CTRL_PENUM | SADC_CTRL_TSRDYM)); - REG_SADC_ENA = SADC_ENA_TSEN; //| SADC_ENA_PBATEN | SADC_ENA_SADCINEN); + REG_SADC_CTRL = (~(SADC_CTRL_PENDM | SADC_CTRL_PENUM | SADC_CTRL_TSRDYM | SADC_CTRL_PBATRDYM)); + REG_SADC_ENA = (SADC_ENA_TSEN | SADC_ENA_PBATEN); __gpio_as_input(32*3 + 29); __gpio_as_input(32*3 + 27); @@ -231,6 +278,7 @@ void SADC(void) } if(state & SADC_CTRL_PBATRDYM) { + bat_val = REG_SADC_BATDAT; /* Battery AD IRQ */ } if(state & SADC_CTRL_SRDYM) diff --git a/firmware/target/mips/ingenic_jz47xx/pcm-jz4740.c b/firmware/target/mips/ingenic_jz47xx/pcm-jz4740.c new file mode 100644 index 0000000000..a5cc61b844 --- /dev/null +++ b/firmware/target/mips/ingenic_jz47xx/pcm-jz4740.c @@ -0,0 +1,164 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2008 by Maurus Cuelenaere + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include "system.h" +#include "kernel.h" +#include "logf.h" +#include "audio.h" +#include "sound.h" +#include "pcm.h" +#include "jz4740.h" + +/**************************************************************************** + ** Playback DMA transfer + **/ + +void pcm_postinit(void) +{ + audiohw_postinit(); /* implemented not for all codecs */ + pcm_apply_settings(); +} + +const void * pcm_play_dma_get_peak_buffer(int *count) +{ + /* TODO */ + *count = 0; + return NULL; +} + +void pcm_play_dma_init(void) +{ + /* TODO */ + + /* Initialize default register values. */ + audiohw_init(); + + /* Power on */ + audiohw_enable_output(true); + + /* Unmute the master channel (DAC should be at zero point now). */ + audiohw_mute(false); +} + +void pcm_apply_settings(void) +{ + /* TODO */ +} + +void pcm_set_frequency(unsigned int frequency) +{ + (void) frequency; + /* TODO */ +} + +static void play_start_pcm(void) +{ + pcm_apply_settings(); + + /* TODO */ +} + +static void play_stop_pcm(void) +{ + /* TODO */ +} + +void pcm_play_dma_start(const void *addr, size_t size) +{ + (void)addr; + (void)size; + /* TODO */ + + play_start_pcm(); +} + +void pcm_play_dma_stop(void) +{ + play_stop_pcm(); + + /* TODO */ +} + +void pcm_play_lock(void) +{ + /* TODO */ +} + +void pcm_play_unlock(void) +{ + /* TODO */ +} + +void pcm_play_dma_pause(bool pause) +{ + if(pause) + play_stop_pcm(); + else + play_start_pcm(); + +} + +size_t pcm_get_bytes_waiting(void) +{ + /* TODO */ + return 0; +} + +#ifdef HAVE_RECORDING +/* TODO */ +void pcm_rec_dma_init(void) +{ +} + +void pcm_rec_dma_close(void) +{ +} + +void pcm_rec_dma_start(void *addr, size_t size) +{ + (void) addr; + (void) size; +} + +void pcm_rec_dma_stop(void) +{ +} + +void pcm_rec_lock(void) +{ +} + +void pcm_rec_unlock(void) +{ +} + +const void * pcm_rec_dma_get_peak_buffer(int *count) +{ + *count = 0; + return NULL; +} + +void pcm_record_more(void *start, size_t size) +{ + (void) start; + (void) size; +} +#endif diff --git a/firmware/target/mips/ingenic_jz47xx/usb-jz4740.c b/firmware/target/mips/ingenic_jz47xx/usb-jz4740.c index 2121d3e4b0..7cefdadbe3 100644 --- a/firmware/target/mips/ingenic_jz47xx/usb-jz4740.c +++ b/firmware/target/mips/ingenic_jz47xx/usb-jz4740.c @@ -20,6 +20,7 @@ ****************************************************************************/ #include "config.h" +#include "string.h" #include "system.h" #include "usb_ch9.h" #include "usb_drv.h" @@ -27,7 +28,7 @@ #include "jz4740.h" #include "thread.h" -#if 0 +#if 1 #define EP1_INTR_BIT 2 #define EP_FIFO_NOEMPTY 2 @@ -38,14 +39,327 @@ #define IS_CACHE(x) (x < 0xa0000000) +#define USB_EP0_IDLE 0 +#define USB_EP0_RX 1 +#define USB_EP0_TX 2 + +enum ep_type +{ + ep_control, ep_bulk, ep_interrupt +}; + +struct usb_endpoint +{ + void *buf; + unsigned int length; + void *ptr; + + const enum ep_type type; + const bool use_dma; + const bool in; + + const void *fifo_addr; + unsigned short fifo_size; +}; + +static unsigned char ep0_rx_buf[64]; +static unsigned char ep0_tx_buf[64]; +static unsigned char ep0state = USB_EP0_IDLE; +static struct usb_endpoint endpoints[] = +{ + /* buf length ptr type use_dma in fifo_addr fifo_size */ + {&ep0_rx_buf, 0, &ep0_rx_buf, ep_control, false, true, (void*)USB_FIFO_EP0, 64 }, + {&ep0_tx_buf, 0, &ep0_tx_buf, ep_control, false, false, (void*)USB_FIFO_EP0, 64 }, + {NULL, 0, NULL, ep_bulk, true, true, (void*)USB_FIFO_EP1, 512}, + {NULL, 0, NULL, ep_bulk, true, false, (void*)USB_FIFO_EP1, 512}, + {NULL, 0, NULL, ep_interrupt, false, true, (void*)USB_FIFO_EP2, 64 } +}; + +static inline void select_endpoint(int ep) +{ + REG_USB_REG_INDEX = ep; +} + +static void readFIFO(struct usb_endpoint *ep, unsigned int size) +{ + unsigned int *d = (unsigned int *)ep->ptr; + unsigned int s; + s = (size + 3) >> 2; + while (s--) + *d++ = REG32(ep->fifo_addr); +} + +static void writeFIFO(struct usb_endpoint *ep, unsigned int size) +{ + unsigned int *d = (unsigned int *)ep->ptr; + unsigned char *c; + int s, q; + + if (size > 0) + { + s = size >> 2; + while (s--) + REG32(ep->fifo_addr) = *d++; + + q = size & 3; + if (q) + { + c = (unsigned char *)d; + while (q--) + REG8(ep->fifo_addr) = *c++; + } + } +} + +static void sendPKT(int ep_nr, const unsigned char* ptr, unsigned int size) +{ + struct usb_endpoint *ep = &endpoints[ep_nr]; + + if (ep_nr != 0) + { + ep->buf = (void*)ptr; + ep->ptr = (void*)ptr; + ep->length = size; + select_endpoint(ep_nr); + if (size <= ep->fifo_size) + { + writeFIFO(ep, size); + REG_USB_REG_INCSR |= USB_INCSR_INPKTRDY; + ep->ptr = ep->buf + size; + } + else + { + writeFIFO(ep, ep->fifo_size); + REG_USB_REG_INCSR |= USB_INCSR_INPKTRDY; + ep->ptr += ep->fifo_size; + } + } + else /* EP0 */ + { + ep->length = size; + ep->ptr = ep->buf; + memcpy(ep->buf, ptr, size); + ep0state = USB_EP0_TX; + } +} + +static void getPKT(int ep_nr, const unsigned char *ptr, unsigned int size) +{ + struct usb_endpoint *ep = &endpoints[ep_nr]; + + memcpy((void*)ptr, ep->ptr, size); + if (ep->length > size) + ep->length -= size; + else + { + size = ep->length; + ep->length = 0; + } + + ep->ptr += size; +} + +static void EP0_handler(void) +{ + unsigned char csr0; + + /* Read CSR0 */ + select_endpoint(0); + csr0 = REG_USB_REG_CSR0; + + /* Check for SentStall + if sentstall is set, clear the sentstall bit + */ + if (csr0 & USB_CSR0_SENTSTALL) + { + REG_USB_REG_CSR0 = csr0 & ~USB_CSR0_SENTSTALL; + ep0state = USB_EP0_IDLE; + return; + } + + /* Check for SetupEnd */ + if (csr0 & USB_CSR0_SETUPEND) + { + REG_USB_REG_CSR0 |= USB_CSR0_SVDSETUPEND; + ep0state = USB_EP0_IDLE; + return; + } + + /* Call relevant routines for endpoint 0 state */ + if (ep0state == USB_EP0_IDLE) + { + if (csr0 & USB_CSR0_OUTPKTRDY) /* There is data in the fifo */ + { + readFIFO(&endpoints[0], 8); + REG_USB_REG_CSR0 |= USB_CSR0_SVDOUTPKTRDY; /* clear OUTRD bit */ + usb_core_control_request((struct usb_ctrlrequest*)endpoints[0].buf); + } + endpoints[0].length = 0; + endpoints[0].ptr = endpoints[0].buf; + } + + if (ep0state == USB_EP0_TX) + { + if ((&endpoints[1].ptr - &endpoints[1].buf) <= endpoints[1].fifo_size) + { + writeFIFO(&endpoints[1], (&endpoints[1].ptr - &endpoints[1].buf)); + endpoints[1].ptr = &endpoints[1].buf + endpoints[1].length; + REG_USB_REG_CSR0 |= (USB_CSR0_INPKTRDY | USB_CSR0_DATAEND); /* Set data end! */ + ep0state = USB_EP0_IDLE; + } + else + { + writeFIFO(&endpoints[1], endpoints[1].fifo_size); + REG_USB_REG_CSR0 |= USB_CSR0_INPKTRDY; + endpoints[1].ptr += endpoints[1].fifo_size; + } + } +} + +static void setup_endpoint(struct usb_endpoint *ep) +{ + ep->ptr = ep->buf; + ep->length = 0; + + if(ep->in) + { + if(ep->type == ep_bulk) + { + register int size; + + if((REG_USB_REG_POWER & USB_POWER_HSMODE) == 0) + size = 64; + else + size = 512; + + REG_USB_REG_INMAXP = size; + ep->fifo_size = size; + } + else + REG_USB_REG_INMAXP = ep->fifo_size; + + REG_USB_REG_INCSR = 0x2048; + } + else + { + REG_USB_REG_OUTMAXP = ep->fifo_size; + REG_USB_REG_OUTCSR = 0x0090; + } +} + +static void udc_reset(void) +{ + register int i; + + /* data init */ + ep0state = USB_EP0_IDLE; + + /* Disable interrupts */ + REG_USB_REG_INTRINE = 0; + REG_USB_REG_INTROUTE = 0; + REG_USB_REG_INTRUSBE = 0; + + REG_USB_REG_FADDR = 0; + REG_USB_REG_POWER = 0x60; /* High speed */ + + select_endpoint(0); + REG_USB_REG_CSR0 = 0xC0; + + for(i=1; i<3; i++) + { + select_endpoint(i); + setup_endpoint(&endpoints[i]); + } + + /* enable intr */ + REG_USB_REG_INTRINE = 0x3; + REG_USB_REG_INTROUTE = 0x2; + REG_USB_REG_INTRUSBE = 0x4; +} + +/* Interrupt handler */ +void UDC(void) +{ + /* Read interrupt registers */ + unsigned char intrUSB = REG_USB_REG_INTRUSB & 0x07; /* Mask SOF */ + unsigned short intrIn = REG_USB_REG_INTRIN; + unsigned short intrOut = REG_USB_REG_INTROUT; + unsigned char intrDMA = REG_USB_REG_INTR; + + if(intrUSB == 0 && intrIn == 0 && intrOut == 0 && intrDMA == 0) + return; + + /* EPIN & EPOUT are all handled in DMA */ + if(intrIn & USB_INTR_EP0) + EP0_handler(); + if(intrUSB & USB_INTR_RESET) + udc_reset(); + if(intrUSB & USB_INTR_SUSPEND); + if(intrUSB & USB_INTR_RESUME); + if(intrDMA & USB_INTR_DMA_BULKIN) + { + usb_core_transfer_complete(((REG_USB_REG_CNTL1 >> 4) & 0xF) | USB_DIR_IN, USB_DIR_IN, 0, 0); + } + if(intrDMA & USB_INTR_DMA_BULKOUT) + { + usb_core_transfer_complete(((REG_USB_REG_CNTL2 >> 4) & 0xF) | USB_DIR_OUT, USB_DIR_OUT, 0, 0); + } +} + +bool usb_drv_stalled(int endpoint, bool in) +{ + select_endpoint(endpoint); + + if(endpoint == 0) + return (REG_USB_REG_CSR0 & USB_CSR0_SENDSTALL) != 0; + else + { + if(in) + return (REG_USB_REG_INCSR & USB_INCSR_SENDSTALL) != 0; + else + return (REG_USB_REG_OUTCSR & USB_OUTCSR_SENDSTALL) != 0; + } +} + +void usb_drv_stall(int endpoint, bool stall, bool in) +{ + select_endpoint(endpoint); + + if(endpoint == 0) + { + if(stall) + REG_USB_REG_CSR0 |= USB_CSR0_SENDSTALL; + else + REG_USB_REG_CSR0 &= ~USB_CSR0_SENDSTALL; + } + else + { + if(in) + { + if(stall) + REG_USB_REG_INCSR |= USB_INCSR_SENDSTALL; + else + REG_USB_REG_INCSR &= ~USB_INCSR_SENDSTALL; + } + else + { + if(stall) + REG_USB_REG_OUTCSR |= USB_OUTCSR_SENDSTALL; + else + REG_USB_REG_OUTCSR &= ~USB_OUTCSR_SENDSTALL; + } + } +} + + bool usb_drv_connected(void) { - return (__gpio_get_pin(GPIO_UDC_DETE)==1); + return __gpio_get_pin(GPIO_UDC_DETE) == 1; } int usb_detect(void) { - if(__gpio_get_pin(GPIO_UDC_DETE)==1) + if(__gpio_get_pin(GPIO_UDC_DETE) == 1) return USB_INSERTED; else return USB_EXTRACTED; @@ -68,49 +382,51 @@ void usb_enable(bool on) void usb_drv_init(void) { - /* Set this bit to allow the UDC entering low-power mode when - * there are no actions on the USB bus. - * UDC still works during this bit was set. - */ - //__cpm_stop_udc(); + /* Set this bit to allow the UDC entering low-power mode when + * there are no actions on the USB bus. + * UDC still works during this bit was set. + */ + //__cpm_stop_udc(); __cpm_start_udc(); - /* Enable the USB PHY */ - REG_CPM_SCR |= CPM_SCR_USBPHY_ENABLE; + /* Enable the USB PHY */ + REG_CPM_SCR |= CPM_SCR_USBPHY_ENABLE; - /* Disable interrupts */ - REG_USB_REG_INTRINE = 0; - REG_USB_REG_INTROUTE = 0; - REG_USB_REG_INTRUSBE = 0; + /* Disable interrupts */ + REG_USB_REG_INTRINE = 0; + REG_USB_REG_INTROUTE = 0; + REG_USB_REG_INTRUSBE = 0; - /* Enable interrupts */ - REG_USB_REG_INTRINE |= USB_INTR_EP0; - REG_USB_REG_INTRUSBE |= USB_INTR_RESET; + /* Enable interrupts */ + REG_USB_REG_INTRINE |= USB_INTR_EP0; + REG_USB_REG_INTRUSBE |= USB_INTR_RESET; - /* Enable SUSPEND */ - /* usb_setb(USB_REG_POWER, USB_POWER_SUSPENDM); */ + /* Enable SUSPEND */ + /* usb_setb(USB_REG_POWER, USB_POWER_SUSPENDM); */ - /* Enable HS Mode */ + /* Enable HS Mode */ REG_USB_REG_POWER |= USB_POWER_HSENAB; - /* Let host detect UDC: - * Software must write a 1 to the PMR:USB_POWER_SOFTCONN bit to turn this - * transistor on and pull the USBDP pin HIGH. - */ - REG_USB_REG_POWER |= USB_POWER_SOFTCONN; + /* Let host detect UDC: + * Software must write a 1 to the PMR:USB_POWER_SOFTCONN bit to turn this + * transistor on and pull the USBDP pin HIGH. + */ + REG_USB_REG_POWER |= USB_POWER_SOFTCONN; + + udc_reset(); } void usb_drv_exit(void) { - /* Disable interrupts */ - REG_USB_REG_INTRINE = 0; - REG_USB_REG_INTROUTE = 0; - REG_USB_REG_INTRUSBE = 0; + /* Disable interrupts */ + REG_USB_REG_INTRINE = 0; + REG_USB_REG_INTROUTE = 0; + REG_USB_REG_INTRUSBE = 0; - /* Disable DMA */ - REG_USB_REG_CNTL1 = 0; - REG_USB_REG_CNTL2 = 0; + /* Disable DMA */ + REG_USB_REG_CNTL1 = 0; + REG_USB_REG_CNTL2 = 0; /* Disconnect from usb */ REG_USB_REG_POWER &= ~USB_POWER_SOFTCONN; @@ -126,253 +442,248 @@ void usb_drv_set_address(int address) REG_USB_REG_FADDR = address; } -/* Interrupt handler */ -void UDC(void) -{ - -} #else //------------------------------------------ #ifndef u8 -#define u8 unsigned char +#define u8 unsigned char #endif #ifndef u16 -#define u16 unsigned short +#define u16 unsigned short #endif #ifndef u32 -#define u32 unsigned int +#define u32 unsigned int #endif #ifndef s8 -#define s8 char +#define s8 char #endif #ifndef s16 -#define s16 short +#define s16 short #endif #ifndef s32 -#define s32 int +#define s32 int #endif extern int usbdebug; enum USB_ENDPOINT_TYPE { - ENDPOINT_TYPE_CONTROL, - /* Typically used to configure a device when attached to the host. - * It may also be used for other device specific purposes, including - * control of other pipes on the device. - */ - ENDPOINT_TYPE_ISOCHRONOUS, - /* Typically used for applications which need guaranteed speed. - * Isochronous transfer is fast but with possible data loss. A typical - * use is audio data which requires a constant data rate. - */ - ENDPOINT_TYPE_BULK, - /* Typically used by devices that generate or consume data in relatively - * large and bursty quantities. Bulk transfer has wide dynamic latitude - * in transmission constraints. It can use all remaining available bandwidth, - * but with no guarantees on bandwidth or latency. Since the USB bus is - * normally not very busy, there is typically 90% or more of the bandwidth - * available for USB transfers. - */ - ENDPOINT_TYPE_INTERRUPT - /* Typically used by devices that need guaranteed quick responses - * (bounded latency). - */ + ENDPOINT_TYPE_CONTROL, + /* Typically used to configure a device when attached to the host. + * It may also be used for other device specific purposes, including + * control of other pipes on the device. + */ + ENDPOINT_TYPE_ISOCHRONOUS, + /* Typically used for applications which need guaranteed speed. + * Isochronous transfer is fast but with possible data loss. A typical + * use is audio data which requires a constant data rate. + */ + ENDPOINT_TYPE_BULK, + /* Typically used by devices that generate or consume data in relatively + * large and bursty quantities. Bulk transfer has wide dynamic latitude + * in transmission constraints. It can use all remaining available bandwidth, + * but with no guarantees on bandwidth or latency. Since the USB bus is + * normally not very busy, there is typically 90% or more of the bandwidth + * available for USB transfers. + */ + ENDPOINT_TYPE_INTERRUPT + /* Typically used by devices that need guaranteed quick responses + * (bounded latency). + */ }; enum USB_STANDARD_REQUEST_CODE { - GET_STATUS, - CLEAR_FEATURE, - SET_FEATURE = 3, - SET_ADDRESS = 5, - GET_DESCRIPTOR, - SET_DESCRIPTOR, - GET_CONFIGURATION, - SET_CONFIGURATION, - GET_INTERFACE, - SET_INTERFACE, - SYNCH_FRAME + GET_STATUS, + CLEAR_FEATURE, + SET_FEATURE = 3, + SET_ADDRESS = 5, + GET_DESCRIPTOR, + SET_DESCRIPTOR, + GET_CONFIGURATION, + SET_CONFIGURATION, + GET_INTERFACE, + SET_INTERFACE, + SYNCH_FRAME }; enum USB_DESCRIPTOR_TYPE { - DEVICE_DESCRIPTOR = 1, - CONFIGURATION_DESCRIPTOR, - STRING_DESCRIPTOR, - INTERFACE_DESCRIPTOR, - ENDPOINT_DESCRIPTOR, - DEVICE_QUALIFIER_DESCRIPTOR, - OTHER_SPEED_CONFIGURATION_DESCRIPTOR, - INTERFACE_POWER1_DESCRIPTOR + DEVICE_DESCRIPTOR = 1, + CONFIGURATION_DESCRIPTOR, + STRING_DESCRIPTOR, + INTERFACE_DESCRIPTOR, + ENDPOINT_DESCRIPTOR, + DEVICE_QUALIFIER_DESCRIPTOR, + OTHER_SPEED_CONFIGURATION_DESCRIPTOR, + INTERFACE_POWER1_DESCRIPTOR }; enum USB_FEATURE_SELECTOR { - ENDPOINT_HALT, - DEVICE_REMOTE_WAKEUP, - TEST_MODE + ENDPOINT_HALT, + DEVICE_REMOTE_WAKEUP, + TEST_MODE }; enum USB_CLASS_CODE { - CLASS_DEVICE, - CLASS_AUDIO, - CLASS_COMM_AND_CDC_CONTROL, - CLASS_HID, - CLASS_PHYSICAL = 0x05, - CLASS_STILL_IMAGING, - CLASS_PRINTER, - CLASS_MASS_STORAGE, - CLASS_HUB, - CLASS_CDC_DATA, - CLASS_SMART_CARD, - CLASS_CONTENT_SECURITY = 0x0d, - CLASS_VIDEO, - CLASS_DIAGNOSTIC_DEVICE = 0xdc, - CLASS_WIRELESS_CONTROLLER = 0xe0, - CLASS_MISCELLANEOUS = 0xef, - CLASS_APP_SPECIFIC = 0xfe, - CLASS_VENDOR_SPECIFIC = 0xff + CLASS_DEVICE, + CLASS_AUDIO, + CLASS_COMM_AND_CDC_CONTROL, + CLASS_HID, + CLASS_PHYSICAL = 0x05, + CLASS_STILL_IMAGING, + CLASS_PRINTER, + CLASS_MASS_STORAGE, + CLASS_HUB, + CLASS_CDC_DATA, + CLASS_SMART_CARD, + CLASS_CONTENT_SECURITY = 0x0d, + CLASS_VIDEO, + CLASS_DIAGNOSTIC_DEVICE = 0xdc, + CLASS_WIRELESS_CONTROLLER = 0xe0, + CLASS_MISCELLANEOUS = 0xef, + CLASS_APP_SPECIFIC = 0xfe, + CLASS_VENDOR_SPECIFIC = 0xff }; typedef struct { - u8 bmRequestType; - u8 bRequest; - u16 wValue; - u16 wIndex; - u16 wLength; + u8 bmRequestType; + u8 bRequest; + u16 wValue; + u16 wIndex; + u16 wLength; } __attribute__ ((packed)) USB_DeviceRequest; typedef struct { - u8 bLength; - u8 bDescriptorType; - u16 bcdUSB; - u8 bDeviceClass; - u8 bDeviceSubClass; - u8 bDeviceProtocol; - u8 bMaxPacketSize0; - u16 idVendor; - u16 idProduct; - u16 bcdDevice; - u8 iManufacturer; - u8 iProduct; - u8 iSerialNumber; - u8 bNumConfigurations; + u8 bLength; + u8 bDescriptorType; + u16 bcdUSB; + u8 bDeviceClass; + u8 bDeviceSubClass; + u8 bDeviceProtocol; + u8 bMaxPacketSize0; + u16 idVendor; + u16 idProduct; + u16 bcdDevice; + u8 iManufacturer; + u8 iProduct; + u8 iSerialNumber; + u8 bNumConfigurations; } __attribute__ ((packed)) USB_DeviceDescriptor; typedef struct { - u8 bLength; - u8 bDescriptorType; - u16 bcdUSB; - u8 bDeviceClass; - u8 bDeviceSubClass; - u8 bDeviceProtocol; - u8 bMaxPacketSize0; - u8 bNumConfigurations; - u8 bReserved; + u8 bLength; + u8 bDescriptorType; + u16 bcdUSB; + u8 bDeviceClass; + u8 bDeviceSubClass; + u8 bDeviceProtocol; + u8 bMaxPacketSize0; + u8 bNumConfigurations; + u8 bReserved; } __attribute__ ((packed)) USB_DeviceQualifierDescriptor; typedef struct { - u8 bLength; - u8 bDescriptorType; - u16 wTotalLength; - u8 bNumInterfaces; - u8 bConfigurationValue; - u8 iConfiguration; - u8 bmAttributes; - u8 MaxPower; + u8 bLength; + u8 bDescriptorType; + u16 wTotalLength; + u8 bNumInterfaces; + u8 bConfigurationValue; + u8 iConfiguration; + u8 bmAttributes; + u8 MaxPower; } __attribute__ ((packed)) USB_ConfigDescriptor; typedef struct { - u8 bLength; - u8 bDescriptorType; - u16 wTotalLength; - u8 bNumInterfaces; - u8 bConfigurationValue; - u8 iConfiguration; - u8 bmAttributes; - u8 bMaxPower; + u8 bLength; + u8 bDescriptorType; + u16 wTotalLength; + u8 bNumInterfaces; + u8 bConfigurationValue; + u8 iConfiguration; + u8 bmAttributes; + u8 bMaxPower; } __attribute__ ((packed)) USB_OtherSpeedConfigDescriptor; typedef struct { - u8 bLength; - u8 bDescriptorType; - u8 bInterfaceNumber; - u8 bAlternateSetting; - u8 bNumEndpoints; - u8 bInterfaceClass; - u8 bInterfaceSubClass; - u8 bInterfaceProtocol; - u8 iInterface; + u8 bLength; + u8 bDescriptorType; + u8 bInterfaceNumber; + u8 bAlternateSetting; + u8 bNumEndpoints; + u8 bInterfaceClass; + u8 bInterfaceSubClass; + u8 bInterfaceProtocol; + u8 iInterface; } __attribute__ ((packed)) USB_InterfaceDescriptor; typedef struct { - u8 bLegth; - u8 bDescriptorType; - u8 bEndpointAddress; - u8 bmAttributes; - u16 wMaxPacketSize; - u8 bInterval; + u8 bLegth; + u8 bDescriptorType; + u8 bEndpointAddress; + u8 bmAttributes; + u16 wMaxPacketSize; + u8 bInterval; } __attribute__ ((packed)) USB_EndPointDescriptor; typedef struct { - u8 bLength; - u8 bDescriptorType; - u16 SomeDesriptor[1]; + u8 bLength; + u8 bDescriptorType; + u16 SomeDesriptor[1]; } __attribute__ ((packed)) USB_StringDescriptor; //------------------------------------------ -#define MAX_EP0_SIZE 64 -#define MAX_EP1_SIZE 512 +#define MAX_EP0_SIZE 64 +#define MAX_EP1_SIZE 512 #define USB_HS 0 #define USB_FS 1 #define USB_LS 2 //definitions of EP0 -#define USB_EP0_IDLE 0 -#define USB_EP0_RX 1 -#define USB_EP0_TX 2 +#define USB_EP0_IDLE 0 +#define USB_EP0_RX 1 +#define USB_EP0_TX 2 /* Define maximum packet size for endpoint 0 */ -#define M_EP0_MAXP 64 +#define M_EP0_MAXP 64 /* Endpoint 0 status structure */ static __inline__ void usb_setb(u32 port, u8 val) { - volatile u8 *ioport = (volatile u8 *)(port); - *ioport = (*ioport) | val; + volatile u8 *ioport = (volatile u8 *)(port); + *ioport = (*ioport) | val; } static __inline__ void usb_clearb(u32 port, u8 val) { - volatile u8 *ioport = (volatile u8 *)(port); - *ioport = (*ioport) & ~val; + volatile u8 *ioport = (volatile u8 *)(port); + *ioport = (*ioport) & ~val; } static __inline__ void usb_setw(u32 port, u16 val) { - volatile u16 *ioport = (volatile u16 *)(port); - *ioport = (*ioport) | val; + volatile u16 *ioport = (volatile u16 *)(port); + *ioport = (*ioport) | val; } static __inline__ void usb_clearw(u32 port, u16 val) { - volatile u16 *ioport = (volatile u16 *)(port); - *ioport = (*ioport) & ~val; + volatile u16 *ioport = (volatile u16 *)(port); + *ioport = (*ioport) & ~val; } //--------------------------------- #define BULK_OUT_BUF_SIZE 0x20000 //buffer size : @@ -380,118 +691,118 @@ static __inline__ void usb_clearw(u32 port, u16 val) enum UDC_STATE { - IDLE, - BULK_IN, - BULK_OUT + IDLE, + BULK_IN, + BULK_OUT }; enum USB_JZ4740_REQUEST //add for USB_BOOT { - VR_GET_CUP_INFO = 0, - VR_SET_DATA_ADDERSS, - VR_SET_DATA_LENGTH, - VR_FLUSH_CACHES, - VR_PROGRAM_START1, - VR_PROGRAM_START2, - VR_NOR_OPS, - VR_NAND_OPS, - VR_SDRAM_OPS, - VR_CONFIGRATION + VR_GET_CUP_INFO = 0, + VR_SET_DATA_ADDERSS, + VR_SET_DATA_LENGTH, + VR_FLUSH_CACHES, + VR_PROGRAM_START1, + VR_PROGRAM_START2, + VR_NOR_OPS, + VR_NAND_OPS, + VR_SDRAM_OPS, + VR_CONFIGRATION }; enum NOR_OPS_TYPE { - NOR_INIT = 0, - NOR_QUERY, - NOR_WRITE, - NOR_ERASE_CHIP, - NOR_ERASE_SECTOR + NOR_INIT = 0, + NOR_QUERY, + NOR_WRITE, + NOR_ERASE_CHIP, + NOR_ERASE_SECTOR }; enum NOR_FLASH_TYPE { - NOR_AM29 = 0, - NOR_SST28, - NOR_SST39x16, - NOR_SST39x8 + NOR_AM29 = 0, + NOR_SST28, + NOR_SST39x16, + NOR_SST39x8 }; enum NAND_OPS_TYPE { - NAND_QUERY = 0, - NAND_INIT, - NAND_MARK_BAD, - NAND_READ_OOB, - NAND_READ_RAW, - NAND_ERASE, - NAND_READ, - NAND_PROGRAM, - NAND_READ_TO_RAM + NAND_QUERY = 0, + NAND_INIT, + NAND_MARK_BAD, + NAND_READ_OOB, + NAND_READ_RAW, + NAND_ERASE, + NAND_READ, + NAND_PROGRAM, + NAND_READ_TO_RAM }; enum SDRAM_OPS_TYPE { - SDRAM_LOAD, + SDRAM_LOAD, }; enum DATA_STRUCTURE_OB { - DS_flash_info , - DS_hand + DS_flash_info , + DS_hand }; /*typedef enum _USB_BOOT_STATUS { - USB_NO_ERR =0 , - GET_CPU_INFO_ERR, - SET_DATA_ADDRESS_ERR, - SET_DATA_LENGTH_ERR, - FLUSH_CAHCES_ERR, - PROGRAM_START1_ERR, - PROGRAM_START2_ERR, - NOR_OPS_ERR, - NAND_OPS_ERR, - NOR_FLASHTYPE_ERR, - OPS_NOTSUPPORT_ERR + USB_NO_ERR =0 , + GET_CPU_INFO_ERR, + SET_DATA_ADDRESS_ERR, + SET_DATA_LENGTH_ERR, + FLUSH_CAHCES_ERR, + PROGRAM_START1_ERR, + PROGRAM_START2_ERR, + NOR_OPS_ERR, + NAND_OPS_ERR, + NOR_FLASHTYPE_ERR, + OPS_NOTSUPPORT_ERR }USB_BOOT_STATUS;*/ enum OPTION { - OOB_ECC, - OOB_NO_ECC, - NO_OOB, + OOB_ECC, + OOB_NO_ECC, + NO_OOB, }; //------------------------- static inline void jz_writeb(u32 address, u8 value) { - *((volatile u8 *)address) = value; + *((volatile u8 *)address) = value; } static inline void jz_writew(u32 address, u16 value) { - *((volatile u16 *)address) = value; + *((volatile u16 *)address) = value; } static inline void jz_writel(u32 address, u32 value) { - *((volatile u32 *)address) = value; + *((volatile u32 *)address) = value; } static inline u8 jz_readb(u32 address) { - return *((volatile u8 *)address); + return *((volatile u8 *)address); } static inline u16 jz_readw(u32 address) { - return *((volatile u16 *)address); + return *((volatile u16 *)address); } static inline u32 jz_readl(u32 address) { - return *((volatile u32 *)address); + return *((volatile u32 *)address); } //--------------------------- @@ -510,530 +821,560 @@ static u8 ep0state,USB_Version; static u32 fifoaddr[] = { - TXFIFOEP0, TXFIFOEP0+4 ,TXFIFOEP0+8 + TXFIFOEP0, TXFIFOEP0+4 ,TXFIFOEP0+8 }; static u32 fifosize[] = { - MAX_EP0_SIZE, MAX_EP1_SIZE + MAX_EP0_SIZE, MAX_EP1_SIZE }; static void udcReadFifo(u8 *ptr, int size) { - u32 *d = (u32 *)ptr; - int s; - s = (size + 3) >> 2; - while (s--) - *d++ = REG32(fifo); + u32 *d = (u32 *)ptr; + int s; + s = (size + 3) >> 2; + while (s--) + *d++ = REG32(fifo); } static void udcWriteFifo(u8 *ptr, int size) { - u32 *d = (u32 *)ptr; - u8 *c; - int s, q; + u32 *d = (u32 *)ptr; + u8 *c; + int s, q; - if (size > 0) { - s = size >> 2; - while (s--) - REG32(fifo) = *d++; - q = size & 3; - if (q) { - c = (u8 *)d; - while (q--) - REG8(fifo) = *c++; - } - } + if (size > 0) { + s = size >> 2; + while (s--) + REG32(fifo) = *d++; + q = size & 3; + if (q) { + c = (u8 *)d; + while (q--) + REG8(fifo) = *c++; + } + } } void HW_SendPKT(int ep, const u8 *buf, int size) { - fifo = fifoaddr[ep]; + fifo = fifoaddr[ep]; - if (ep!=0) - { - Bulk_in_size = size; - Bulk_in_finish = 0; - jz_writeb(USB_REG_INDEX, ep); - if (Bulk_in_size - Bulk_in_finish <= fifosize[ep]) - { - udcWriteFifo((u8 *)((u32)buf+Bulk_in_finish), - Bulk_in_size - Bulk_in_finish); - usb_setb(USB_REG_INCSR, USB_INCSR_INPKTRDY); - Bulk_in_finish = Bulk_in_size; - } + if (ep!=0) + { + Bulk_in_size = size; + Bulk_in_finish = 0; + jz_writeb(USB_REG_INDEX, ep); + if (Bulk_in_size - Bulk_in_finish <= fifosize[ep]) + { + udcWriteFifo((u8 *)((u32)buf+Bulk_in_finish), + Bulk_in_size - Bulk_in_finish); + usb_setb(USB_REG_INCSR, USB_INCSR_INPKTRDY); + Bulk_in_finish = Bulk_in_size; + } else - { - udcWriteFifo((u8 *)((u32)buf+Bulk_in_finish), - fifosize[ep]); - usb_setb(USB_REG_INCSR, USB_INCSR_INPKTRDY); - Bulk_in_finish += fifosize[ep]; + { + udcWriteFifo((u8 *)((u32)buf+Bulk_in_finish), + fifosize[ep]); + usb_setb(USB_REG_INCSR, USB_INCSR_INPKTRDY); + Bulk_in_finish += fifosize[ep]; Bulk_in_buf = (u8*)buf; - } - } - else //EP0 - { - tx_size = size; - finished = 0; - memcpy((void *)tx_buf, buf, size); - ep0state = USB_EP0_TX; - } + } + } + else //EP0 + { + tx_size = size; + finished = 0; + memcpy((void *)tx_buf, buf, size); + ep0state = USB_EP0_TX; + } } -void HW_GetPKT(int ep, const u8 *buf, int size) +void HW_GetPKT(int ep, const u8 *buf, unsigned int size) { - memcpy((void *)buf, (u8 *)rx_buf, size); - fifo = fifoaddr[ep]; - if (rx_size > size) - rx_size -= size; - else { - size = rx_size; - rx_size = 0; - } - memcpy((u8 *)rx_buf, (u8 *)((u32)rx_buf+size), rx_size); + memcpy((void *)buf, (u8 *)rx_buf, size); + fifo = fifoaddr[ep]; + if (rx_size > size) + rx_size -= size; + else + { + size = rx_size; + rx_size = 0; + } + memcpy((u8 *)rx_buf, (u8 *)((u32)rx_buf+size), rx_size); +} + +void Enable_DMA(u8* buf, u32 length) +{ + dma_cache_wback_inv((u32)buf, length); + jz_writeb(USB_REG_INDEX, 1); + usb_setw(USB_REG_INCSR, 0x9400); + usb_clearw(USB_REG_INTRINE, 0x2); //disable OUT intr + jz_writel(USB_REG_ADDR1, (u32)buf); + jz_writel(USB_REG_COUNT1, length); + jz_writel(USB_REG_CNTL1, 0x001f); +} + +void Disable_DMA(void) +{ + jz_writeb(USB_REG_INDEX, 1); + usb_clearw(USB_REG_INCSR, 0x9400); + usb_setw(USB_REG_INTRINE, 0x2); //Enable OUT intr } static USB_DeviceDescriptor devDesc = { - sizeof(USB_DeviceDescriptor), - DEVICE_DESCRIPTOR, //1 - 0x0200, //Version 2.0 - 0xff, //Vendor spec class - 0xff, - 0xff, - 64, /* Ep0 FIFO size */ - 0x601a, //vendor ID - 0xDEAD, //Product ID - 0xffff, - 0x00, - 0x00, - 0x00, - 0x01 + sizeof(USB_DeviceDescriptor), + DEVICE_DESCRIPTOR, //1 + 0x0200, //Version 2.0 + 0xff, //Vendor spec class + 0xff, + 0xff, + 64, /* Ep0 FIFO size */ + 0x601a, //vendor ID + 0xDEAD, //Product ID + 0xffff, + 0x00, + 0x00, + 0x00, + 0x01 }; -#define CONFIG_DESCRIPTOR_LEN (sizeof(USB_ConfigDescriptor) + \ - sizeof(USB_InterfaceDescriptor) + \ - sizeof(USB_EndPointDescriptor) * 2) +#define CONFIG_DESCRIPTOR_LEN (sizeof(USB_ConfigDescriptor) + \ + sizeof(USB_InterfaceDescriptor) + \ + sizeof(USB_EndPointDescriptor) * 2) static struct { - USB_ConfigDescriptor configuration_descriptor; - USB_InterfaceDescriptor interface_descritor; - USB_EndPointDescriptor endpoint_descriptor[2]; + USB_ConfigDescriptor configuration_descriptor; + USB_InterfaceDescriptor interface_descritor; + USB_EndPointDescriptor endpoint_descriptor[2]; } __attribute__ ((packed)) confDesc = { - { - sizeof(USB_ConfigDescriptor), - CONFIGURATION_DESCRIPTOR, - CONFIG_DESCRIPTOR_LEN, - 0x01, - 0x01, - 0x00, - 0xc0, // Self Powered, no remote wakeup - 0x64 // Maximum power consumption 2000 mA - }, - { - sizeof(USB_InterfaceDescriptor), - INTERFACE_DESCRIPTOR, - 0x00, - 0x00, - 0x02, /* ep number */ - 0xff, - 0xff, - 0xff, - 0x00 - }, - { - { - sizeof(USB_EndPointDescriptor), - ENDPOINT_DESCRIPTOR, - (1 << 7) | 1,// endpoint 2 is IN endpoint - 2, /* bulk */ - 512, - 0 - }, - { - sizeof(USB_EndPointDescriptor), - ENDPOINT_DESCRIPTOR, - (0 << 7) | 1,// endpoint 5 is OUT endpoint - 2, /* bulk */ - 512, /* OUT EP FIFO size */ - 0 - } - } + { + sizeof(USB_ConfigDescriptor), + CONFIGURATION_DESCRIPTOR, + CONFIG_DESCRIPTOR_LEN, + 0x01, + 0x01, + 0x00, + 0xc0, // Self Powered, no remote wakeup + 0x64 // Maximum power consumption 2000 mA + }, + { + sizeof(USB_InterfaceDescriptor), + INTERFACE_DESCRIPTOR, + 0x00, + 0x00, + 0x02, /* ep number */ + 0xff, + 0xff, + 0xff, + 0x00 + }, + { + { + sizeof(USB_EndPointDescriptor), + ENDPOINT_DESCRIPTOR, + (1 << 7) | 1,// endpoint 2 is IN endpoint + 2, /* bulk */ + 512, + 0 + }, + { + sizeof(USB_EndPointDescriptor), + ENDPOINT_DESCRIPTOR, + (0 << 7) | 1,// endpoint 5 is OUT endpoint + 2, /* bulk */ + 512, /* OUT EP FIFO size */ + 0 + } + } }; void sendDevDescString(int size) { - u16 str_ret[13] = { - 0x031a,//0x1a=26 byte - 0x0041, - 0x0030, - 0x0030, - 0x0041, - 0x0030, - 0x0030, - 0x0041, - 0x0030, - 0x0030, - 0x0041, - 0x0030, - 0x0030 - }; - if(size >= 26) - size = 26; - str_ret[0] = (0x0300 | size); - HW_SendPKT(0, (u8 *)str_ret,size); + u16 str_ret[13] = { + 0x031a,//0x1a=26 byte + 0x0041, + 0x0030, + 0x0030, + 0x0041, + 0x0030, + 0x0030, + 0x0041, + 0x0030, + 0x0030, + 0x0041, + 0x0030, + 0x0030 + }; + if(size >= 26) + size = 26; + str_ret[0] = (0x0300 | size); + HW_SendPKT(0, (u8 *)str_ret,size); } void sendDevDesc(int size) { switch (size) { - case 18: - HW_SendPKT(0, (u8 *)&devDesc, sizeof(devDesc)); - break; - default: - HW_SendPKT(0, (u8 *)&devDesc, 8); - break; - } + case 18: + HW_SendPKT(0, (u8 *)&devDesc, sizeof(devDesc)); + break; + default: + HW_SendPKT(0, (u8 *)&devDesc, 8); + break; + } } void sendConfDesc(int size) { - switch (size) { - case 9: - HW_SendPKT(0, (u8 *)&confDesc, 9); - break; - case 8: - HW_SendPKT(0, (u8 *)&confDesc, 8); - break; - default: - HW_SendPKT(0, (u8 *)&confDesc, sizeof(confDesc)); - break; - } + switch (size) { + case 9: + HW_SendPKT(0, (u8 *)&confDesc, 9); + break; + case 8: + HW_SendPKT(0, (u8 *)&confDesc, 8); + break; + default: + HW_SendPKT(0, (u8 *)&confDesc, sizeof(confDesc)); + break; + } } void EP0_init(u32 out, u32 out_size, u32 in, u32 in_size) { - confDesc.endpoint_descriptor[0].bEndpointAddress = (1<<7) | in; - confDesc.endpoint_descriptor[0].wMaxPacketSize = in_size; - confDesc.endpoint_descriptor[1].bEndpointAddress = (0<<7) | out; - confDesc.endpoint_descriptor[1].wMaxPacketSize = out_size; + confDesc.endpoint_descriptor[0].bEndpointAddress = (1<<7) | in; + confDesc.endpoint_descriptor[0].wMaxPacketSize = in_size; + confDesc.endpoint_descriptor[1].bEndpointAddress = (0<<7) | out; + confDesc.endpoint_descriptor[1].wMaxPacketSize = out_size; } static void udc_reset(void) { - //data init - ep0state = USB_EP0_IDLE; - Bulk_in_size = 0; - Bulk_in_finish = 0; - Bulk_out_size = 0; - udc_state = IDLE; - tx_size = 0; - rx_size = 0; - finished = 0; - /* Enable the USB PHY */ -// REG_CPM_SCR |= CPM_SCR_USBPHY_ENABLE; - /* Disable interrupts */ - jz_writew(USB_REG_INTRINE, 0); - jz_writew(USB_REG_INTROUTE, 0); - jz_writeb(USB_REG_INTRUSBE, 0); - jz_writeb(USB_REG_FADDR,0); - jz_writeb(USB_REG_POWER,0x60); //High speed - jz_writeb(USB_REG_INDEX,0); - jz_writeb(USB_REG_CSR0,0xc0); - jz_writeb(USB_REG_INDEX,1); - jz_writew(USB_REG_INMAXP,512); - jz_writew(USB_REG_INCSR,0x2048); - jz_writeb(USB_REG_INDEX,1); - jz_writew(USB_REG_OUTMAXP,512); - jz_writew(USB_REG_OUTCSR,0x0090); - jz_writew(USB_REG_INTRINE,0x3); //enable intr - jz_writew(USB_REG_INTROUTE,0x2); - jz_writeb(USB_REG_INTRUSBE,0x4); + //data init + ep0state = USB_EP0_IDLE; + Bulk_in_size = 0; + Bulk_in_finish = 0; + Bulk_out_size = 0; + udc_state = IDLE; + tx_size = 0; + rx_size = 0; + finished = 0; + /* Enable the USB PHY */ +// REG_CPM_SCR |= CPM_SCR_USBPHY_ENABLE; + /* Disable interrupts */ + jz_writew(USB_REG_INTRINE, 0); + jz_writew(USB_REG_INTROUTE, 0); + jz_writeb(USB_REG_INTRUSBE, 0); + jz_writeb(USB_REG_FADDR,0); + jz_writeb(USB_REG_POWER,0x60); //High speed + jz_writeb(USB_REG_INDEX,0); + jz_writeb(USB_REG_CSR0,0xc0); + jz_writeb(USB_REG_INDEX,1); + jz_writew(USB_REG_INMAXP,512); + jz_writew(USB_REG_INCSR,0x2048); + jz_writeb(USB_REG_INDEX,1); + jz_writew(USB_REG_OUTMAXP,512); + jz_writew(USB_REG_OUTCSR,0x0090); + jz_writew(USB_REG_INTRINE,0x3); //enable intr + jz_writew(USB_REG_INTROUTE,0x2); + jz_writeb(USB_REG_INTRUSBE,0x4); - if ((jz_readb(USB_REG_POWER)&0x10)==0) - { - jz_writeb(USB_REG_INDEX,1); - jz_writew(USB_REG_INMAXP,64); - jz_writew(USB_REG_INCSR,0x2048); - jz_writeb(USB_REG_INDEX,1); - jz_writew(USB_REG_OUTMAXP,64); - jz_writew(USB_REG_OUTCSR,0x0090); - USB_Version=USB_FS; - fifosize[1]=64; - EP0_init(1,64,1,64); - } - else - { - jz_writeb(USB_REG_INDEX,1); - jz_writew(USB_REG_INMAXP,512); - jz_writew(USB_REG_INCSR,0x2048); - jz_writeb(USB_REG_INDEX,1); - jz_writew(USB_REG_OUTMAXP,512); - jz_writew(USB_REG_OUTCSR,0x0090); - USB_Version=USB_HS; - fifosize[1]=512; - EP0_init(1,512,1,512); - } + if ((jz_readb(USB_REG_POWER)&0x10)==0) + { + jz_writeb(USB_REG_INDEX,1); + jz_writew(USB_REG_INMAXP,64); + jz_writew(USB_REG_INCSR,0x2048); + jz_writeb(USB_REG_INDEX,1); + jz_writew(USB_REG_OUTMAXP,64); + jz_writew(USB_REG_OUTCSR,0x0090); + USB_Version=USB_FS; + fifosize[1]=64; + EP0_init(1,64,1,64); + } + else + { + jz_writeb(USB_REG_INDEX,1); + jz_writew(USB_REG_INMAXP,512); + jz_writew(USB_REG_INCSR,0x2048); + jz_writeb(USB_REG_INDEX,1); + jz_writew(USB_REG_OUTMAXP,512); + jz_writew(USB_REG_OUTCSR,0x0090); + USB_Version=USB_HS; + fifosize[1]=512; + EP0_init(1,512,1,512); + } } void usbHandleStandDevReq(u8 *buf) { - USB_DeviceRequest *dreq = (USB_DeviceRequest *)buf; - switch (dreq->bRequest) { - case GET_DESCRIPTOR: - if (dreq->bmRequestType == 0x80) /* Dev2Host */ - switch(dreq->wValue >> 8) - { - case DEVICE_DESCRIPTOR: - sendDevDesc(dreq->wLength); - break; - case CONFIGURATION_DESCRIPTOR: - sendConfDesc(dreq->wLength); - break; - case STRING_DESCRIPTOR: - if (dreq->wLength == 0x02) - HW_SendPKT(0, "\x04\x03", 2); - else - sendDevDescString(dreq->wLength); - //HW_SendPKT(0, "\x04\x03\x09\x04", 2); - break; - } - ep0state=USB_EP0_TX; - - break; - case SET_ADDRESS: - jz_writeb(USB_REG_FADDR,dreq->wValue); - break; - case GET_STATUS: - switch (dreq->bmRequestType) { - case 80: /* device */ - HW_SendPKT(0, "\x01\x00", 2); - break; - case 81: /* interface */ - case 82: /* ep */ - HW_SendPKT(0, "\x00\x00", 2); - break; - } - ep0state=USB_EP0_TX; - break; - case CLEAR_FEATURE: - case SET_CONFIGURATION: - case SET_INTERFACE: - case SET_FEATURE: - break; - } + USB_DeviceRequest *dreq = (USB_DeviceRequest *)buf; + switch (dreq->bRequest) { + case GET_DESCRIPTOR: + if (dreq->bmRequestType == 0x80) /* Dev2Host */ + switch(dreq->wValue >> 8) + { + case DEVICE_DESCRIPTOR: + sendDevDesc(dreq->wLength); + break; + case CONFIGURATION_DESCRIPTOR: + sendConfDesc(dreq->wLength); + break; + case STRING_DESCRIPTOR: + if (dreq->wLength == 0x02) + HW_SendPKT(0, "\x04\x03", 2); + else + sendDevDescString(dreq->wLength); + //HW_SendPKT(0, "\x04\x03\x09\x04", 2); + break; + } + ep0state=USB_EP0_TX; + + break; + case SET_ADDRESS: + jz_writeb(USB_REG_FADDR,dreq->wValue); + break; + case GET_STATUS: + switch (dreq->bmRequestType) { + case 80: /* device */ + HW_SendPKT(0, "\x01\x00", 2); + break; + case 81: /* interface */ + case 82: /* ep */ + HW_SendPKT(0, "\x00\x00", 2); + break; + } + ep0state=USB_EP0_TX; + break; + case CLEAR_FEATURE: + case SET_CONFIGURATION: + case SET_INTERFACE: + case SET_FEATURE: + break; + } } unsigned char nandbuffer[4096]; +extern void jz_nand_read(int block, int page, unsigned char *buf); void usbHandleVendorReq(u8 *buf) { - USB_DeviceRequest *dreq = (USB_DeviceRequest *)buf; - switch (dreq->bRequest) + USB_DeviceRequest *dreq = (USB_DeviceRequest *)buf; + switch (dreq->bRequest) { case 0xB0: memset(&nandbuffer, 0, 4096); - jz_nand_read(dreq->wValue, dreq->wIndex, &nandbuffer); + jz_nand_read(dreq->wValue, dreq->wIndex, nandbuffer); //printf("Read block %d page %d", dreq->wValue, dreq->wIndex); udc_state = IDLE; break; - case 0xAB: - HW_SendPKT(1, nandbuffer, 4096); + case 0xAB: + Enable_DMA(nandbuffer, 4096); + //HW_SendPKT(1, nandbuffer, 4096); //printf("Send data"); - //udc_state = BULK_OUT; - break; - case 0x12: - HW_SendPKT(0, "TEST", 4); - //printf("Send test"); - udc_state = IDLE; + //udc_state = BULK_OUT; break; - } + case 0x12: + HW_SendPKT(0, "TEST", 4); + //printf("Send test"); + udc_state = IDLE; + break; + } } void Handshake_PKT(void) { - if (udc_state!=IDLE) - { - HW_SendPKT(1,(u8 *)handshake_PKT,sizeof(handshake_PKT)); - udc_state = IDLE; - } + if (udc_state!=IDLE) + { + HW_SendPKT(1,(u8 *)handshake_PKT,sizeof(handshake_PKT)); + udc_state = IDLE; + } } void usbHandleDevReq(u8 *buf) { - switch ((buf[0] & (3 << 5)) >> 5) { - case 0: /* Standard request */ - usbHandleStandDevReq(buf); - break; - case 1: /* Class request */ - break; - case 2: /* Vendor request */ - usbHandleVendorReq(buf); - break; - } + switch ((buf[0] & (3 << 5)) >> 5) { + case 0: /* Standard request */ + usbHandleStandDevReq(buf); + break; + case 1: /* Class request */ + break; + case 2: /* Vendor request */ + usbHandleVendorReq(buf); + break; + } } void EP0_Handler (void) { - u8 byCSR0; + u8 byCSR0; /* Read CSR0 */ - jz_writeb(USB_REG_INDEX, 0); - byCSR0 = jz_readb(USB_REG_CSR0); + jz_writeb(USB_REG_INDEX, 0); + byCSR0 = jz_readb(USB_REG_CSR0); /* Check for SentStall if sendstall is set ,clear the sendstall bit*/ - if (byCSR0 & USB_CSR0_SENTSTALL) - { - jz_writeb(USB_REG_CSR0, (byCSR0 & ~USB_CSR0_SENDSTALL)); - ep0state = USB_EP0_IDLE; - return; - } + if (byCSR0 & USB_CSR0_SENTSTALL) + { + jz_writeb(USB_REG_CSR0, (byCSR0 & ~USB_CSR0_SENDSTALL)); + ep0state = USB_EP0_IDLE; + return; + } /* Check for SetupEnd */ - if (byCSR0 & USB_CSR0_SETUPEND) - { - jz_writeb(USB_REG_CSR0, (byCSR0 | USB_CSR0_SVDSETUPEND)); - ep0state = USB_EP0_IDLE; - return; - } + if (byCSR0 & USB_CSR0_SETUPEND) + { + jz_writeb(USB_REG_CSR0, (byCSR0 | USB_CSR0_SVDSETUPEND)); + ep0state = USB_EP0_IDLE; + return; + } /* Call relevant routines for endpoint 0 state */ - if (ep0state == USB_EP0_IDLE) - { - if (byCSR0 & USB_CSR0_OUTPKTRDY) //There are datas in fifo - { - USB_DeviceRequest *dreq; - fifo=fifoaddr[0]; - udcReadFifo((u8 *)rx_buf, sizeof(USB_DeviceRequest)); - usb_setb(USB_REG_CSR0, 0x48);//clear OUTRD bit - dreq = (USB_DeviceRequest *)rx_buf; - usbHandleDevReq((u8 *)rx_buf); - } - rx_size = 0; - } - - if (ep0state == USB_EP0_TX) - { - fifo=fifoaddr[0]; - if (tx_size - finished <= 64) - { - udcWriteFifo((u8 *)((u32)tx_buf+finished), - tx_size - finished); - finished = tx_size; - usb_setb(USB_REG_CSR0, USB_CSR0_INPKTRDY); - usb_setb(USB_REG_CSR0, USB_CSR0_DATAEND); //Set dataend! - ep0state=USB_EP0_IDLE; - } else - { - udcWriteFifo((u8 *)((u32)tx_buf+finished), 64); - usb_setb(USB_REG_CSR0, USB_CSR0_INPKTRDY); - finished += 64; - } - } - return; + if (ep0state == USB_EP0_IDLE) + { + if (byCSR0 & USB_CSR0_OUTPKTRDY) //There are datas in fifo + { + USB_DeviceRequest *dreq; + fifo=fifoaddr[0]; + udcReadFifo((u8 *)rx_buf, sizeof(USB_DeviceRequest)); + usb_setb(USB_REG_CSR0, 0x48);//clear OUTRD bit + dreq = (USB_DeviceRequest *)rx_buf; + usbHandleDevReq((u8 *)rx_buf); + } + rx_size = 0; + } + + if (ep0state == USB_EP0_TX) + { + fifo=fifoaddr[0]; + if (tx_size - finished <= 64) + { + udcWriteFifo((u8 *)((u32)tx_buf+finished), + tx_size - finished); + finished = tx_size; + usb_setb(USB_REG_CSR0, USB_CSR0_INPKTRDY); + usb_setb(USB_REG_CSR0, USB_CSR0_DATAEND); //Set dataend! + ep0state=USB_EP0_IDLE; + } else + { + udcWriteFifo((u8 *)((u32)tx_buf+finished), 64); + usb_setb(USB_REG_CSR0, USB_CSR0_INPKTRDY); + finished += 64; + } + } + return; } void EPIN_Handler(u8 EP) { - jz_writeb(USB_REG_INDEX, EP); - fifo = fifoaddr[EP]; + jz_writeb(USB_REG_INDEX, EP); + fifo = fifoaddr[EP]; - if (Bulk_in_size-Bulk_in_finish==0) - { - Handshake_PKT(); - return; - } + if (Bulk_in_size-Bulk_in_finish==0) + { + Handshake_PKT(); + return; + } - if (Bulk_in_size - Bulk_in_finish <= fifosize[EP]) - { - udcWriteFifo((u8 *)((u32)Bulk_in_buf+Bulk_in_finish), - Bulk_in_size - Bulk_in_finish); - usb_setw(USB_REG_INCSR, USB_INCSR_INPKTRDY); - Bulk_in_finish = Bulk_in_size; - } + if (Bulk_in_size - Bulk_in_finish <= fifosize[EP]) + { + udcWriteFifo((u8 *)((u32)Bulk_in_buf+Bulk_in_finish), + Bulk_in_size - Bulk_in_finish); + usb_setw(USB_REG_INCSR, USB_INCSR_INPKTRDY); + Bulk_in_finish = Bulk_in_size; + } else - { - udcWriteFifo((u8 *)((u32)Bulk_in_buf+Bulk_in_finish), - fifosize[EP]); - usb_setw(USB_REG_INCSR, USB_INCSR_INPKTRDY); - Bulk_in_finish += fifosize[EP]; - } + { + udcWriteFifo((u8 *)((u32)Bulk_in_buf+Bulk_in_finish), + fifosize[EP]); + usb_setw(USB_REG_INCSR, USB_INCSR_INPKTRDY); + Bulk_in_finish += fifosize[EP]; + } } void EPOUT_Handler(u8 EP) { - u32 size; - jz_writeb(USB_REG_INDEX, EP); - size = jz_readw(USB_REG_OUTCOUNT); - fifo = fifoaddr[EP]; - udcReadFifo((u8 *)((u32)Bulk_out_buf+Bulk_out_size), size); - usb_clearb(USB_REG_OUTCSR,USB_OUTCSR_OUTPKTRDY); - Bulk_out_size += size; + u32 size; + jz_writeb(USB_REG_INDEX, EP); + size = jz_readw(USB_REG_OUTCOUNT); + fifo = fifoaddr[EP]; + udcReadFifo((u8 *)((u32)Bulk_out_buf+Bulk_out_size), size); + usb_clearb(USB_REG_OUTCSR,USB_OUTCSR_OUTPKTRDY); + Bulk_out_size += size; } void UDC(void) { - u8 IntrUSB; - u16 IntrIn; - u16 IntrOut; + u8 IntrUSB; + u16 IntrIn; + u16 IntrOut; + u16 IntrDMA; /* Read interrupt registers */ - IntrUSB = jz_readb(USB_REG_INTRUSB); - IntrIn = jz_readw(USB_REG_INTRIN); - IntrOut = jz_readw(USB_REG_INTROUT); + IntrUSB = jz_readb(USB_REG_INTRUSB); + IntrIn = jz_readw(USB_REG_INTRIN); + IntrOut = jz_readw(USB_REG_INTROUT); + IntrDMA = jz_readb(USB_REG_INTR); - if ( IntrUSB == 0 && IntrIn == 0 && IntrOut == 0) - return; + if ( IntrUSB == 0 && IntrIn == 0 && IntrOut == 0) + return; - if (IntrIn & 2) - { - EPIN_Handler(1); - } - if (IntrOut & 2) - { - EPOUT_Handler(1); - } - if (IntrUSB & USB_INTR_RESET) - { - udc_reset(); - } + if (IntrIn & 2) + { + EPIN_Handler(1); + } + if (IntrOut & 2) + { + EPOUT_Handler(1); + } + if (IntrUSB & USB_INTR_RESET) + { + udc_reset(); + } /* Check for endpoint 0 interrupt */ - if (IntrIn & USB_INTR_EP0) - { - EP0_Handler(); - } + if (IntrIn & USB_INTR_EP0) + { + EP0_Handler(); + } - IntrIn = jz_readw(USB_REG_INTRIN); - return; + if (IntrDMA & 0x1) //channel 1 :OUT + { + if (tx_size > 0 && tx_size % fifosize[1] != 0) + { + jz_writeb(USB_REG_INDEX, 1); + usb_clearb(USB_REG_INCSR, USB_INCSR_INPKTRDY); + } + Disable_DMA(); + } } void __udc_start(void) { udc_reset(); - ep0state = USB_EP0_IDLE; - Bulk_in_size = 0; - Bulk_in_finish = 0; - Bulk_out_size = 0; - udc_state = IDLE; - tx_size = 0; - rx_size = 0; - finished = 0; + ep0state = USB_EP0_IDLE; + Bulk_in_size = 0; + Bulk_in_finish = 0; + Bulk_out_size = 0; + udc_state = IDLE; + tx_size = 0; + rx_size = 0; + finished = 0; - if ((jz_readb(USB_REG_POWER)&0x10)==0) - { - USB_Version=USB_FS; - fifosize[1]=64; - EP0_init(1,64,1,64); - } - else - { - USB_Version=USB_HS; - fifosize[1]=512; - EP0_init(1,512,1,512); - } + if ((jz_readb(USB_REG_POWER)&0x10)==0) + { + USB_Version=USB_FS; + fifosize[1]=64; + EP0_init(1,64,1,64); + } + else + { + USB_Version=USB_HS; + fifosize[1]=512; + EP0_init(1,512,1,512); + } - USB_Version=USB_HS; + USB_Version=USB_HS; system_enable_irq(IRQ_UDC); }