mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-12-09 13:15:18 -05:00
Add cleaned-up xDuoo X3 support
Cleaned up, rebased, and forward-ported from the xvortex fork. (original credit to vsoftster@gmail.com) Change-Id: Ibcc023a0271ea81e901450a88317708c2683236d Signed-off-by: Solomon Peachy <pizza@shaftnet.org>
This commit is contained in:
parent
b3e2bd619b
commit
0662793ca0
114 changed files with 17348 additions and 101 deletions
|
|
@ -5,8 +5,10 @@ OUTPUT_ARCH(MIPS)
|
|||
ENTRY(_start)
|
||||
STARTUP(target/mips/ingenic_jz47xx/crt0.o)
|
||||
|
||||
#define DRAMORIG 0x80004000
|
||||
#define DRAMSIZE (MEMORYSIZE * 0x100000)
|
||||
#define STUBOFFSET 0x4000
|
||||
|
||||
#define DRAMORIG (0x80000000 + STUBOFFSET)
|
||||
#define DRAMSIZE (MEMORYSIZE * 0x100000 - STUBOFFSET)
|
||||
#define IRAMORIG 0x80000000
|
||||
#define IRAMSIZE 16K
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
****************************************************************************/
|
||||
|
||||
#include "config.h"
|
||||
#include "jz4740.h"
|
||||
#include "cpu.h"
|
||||
#include "nand.h"
|
||||
#include "nand_id.h"
|
||||
#include "system.h"
|
||||
|
|
|
|||
692
firmware/target/mips/ingenic_jz47xx/ata-nand-jz4760.c
Normal file
692
firmware/target/mips/ingenic_jz47xx/ata-nand-jz4760.c
Normal file
|
|
@ -0,0 +1,692 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2016 by Roman Stolyarov
|
||||
*
|
||||
* 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 "cpu.h"
|
||||
#include "nand.h"
|
||||
#include "nand_id.h"
|
||||
#include "system.h"
|
||||
#include "panic.h"
|
||||
#include "kernel.h"
|
||||
#include "storage.h"
|
||||
#include "string.h"
|
||||
/*#define LOGF_ENABLE*/
|
||||
#include "logf.h"
|
||||
|
||||
//#define USE_DMA
|
||||
//#define USE_ECC
|
||||
|
||||
/*
|
||||
* Standard NAND flash commands
|
||||
*/
|
||||
#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_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_READID 0x90
|
||||
#define NAND_CMD_ERASE2 0xd0
|
||||
#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
|
||||
|
||||
/* Status bits */
|
||||
#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
|
||||
|
||||
/*
|
||||
* NAND parameter struct
|
||||
*/
|
||||
struct nand_param {
|
||||
unsigned int bus_width; /* data bus width: 8-bit/16-bit */
|
||||
unsigned int row_cycle; /* row address cycles: 2/3 */
|
||||
unsigned int page_size; /* page size in bytes: 512/2048/4096 */
|
||||
unsigned int oob_size; /* oob size in bytes: 16/64/128 */
|
||||
unsigned int page_per_block; /* pages per block: 32/64/128 */
|
||||
unsigned int bad_block_pos; /* bad block pos in oob: 0/5 */
|
||||
};
|
||||
|
||||
/*
|
||||
* jz4760_nand.c
|
||||
*
|
||||
* NAND read routine for JZ4760
|
||||
*
|
||||
* Copyright (c) 2005-2008 Ingenic Semiconductor Inc.
|
||||
*
|
||||
*/
|
||||
|
||||
#define CFG_NAND_BASE 0xBA000000
|
||||
#define NAND_ADDR_OFFSET 0x00800000
|
||||
#define NAND_CMD_OFFSET 0x00400000
|
||||
|
||||
#define CFG_NAND_SMCR1 0x0d444400
|
||||
|
||||
#define NAND_DATAPORT CFG_NAND_BASE
|
||||
#define NAND_ADDRPORT (CFG_NAND_BASE | NAND_ADDR_OFFSET)
|
||||
#define NAND_COMMPORT (CFG_NAND_BASE | NAND_CMD_OFFSET)
|
||||
|
||||
#define ECC_BLOCK 512
|
||||
#define ECC_POS 24
|
||||
#define PAR_SIZE 13
|
||||
|
||||
#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_select() (REG_NEMC_NFCSR |= NEMC_NFCSR_NFE1 | NEMC_NFCSR_NFCE1)
|
||||
#define __nand_deselect() (REG_NEMC_NFCSR &= ~(NEMC_NFCSR_NFE1 | NEMC_NFCSR_NFCE1))
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
|
||||
static struct nand_info* chip_info = NULL;
|
||||
static struct nand_info* bank;
|
||||
static unsigned long nand_size;
|
||||
static struct nand_param internal_param;
|
||||
static struct mutex nand_mtx;
|
||||
#ifdef USE_DMA
|
||||
static struct mutex nand_dma_mtx;
|
||||
static struct semaphore nand_dma_complete;
|
||||
#endif
|
||||
static unsigned char temp_page[2048]; /* Max page size */
|
||||
|
||||
static inline void jz_nand_wait_ready(void)
|
||||
{
|
||||
unsigned int timeout = 1000;
|
||||
while ((REG_GPIO_PXPIN(0) & 0x00100000) && timeout--);
|
||||
while (!(REG_GPIO_PXPIN(0) & 0x00100000));
|
||||
}
|
||||
|
||||
#ifndef USE_DMA
|
||||
static inline void jz_nand_read_buf16(void *buf, int count)
|
||||
{
|
||||
register int i;
|
||||
register unsigned short *p = (unsigned short *)buf;
|
||||
|
||||
for (i = 0; i < count; i += 2)
|
||||
*p++ = __nand_data16();
|
||||
}
|
||||
|
||||
static inline void jz_nand_read_buf8(void *buf, int count)
|
||||
{
|
||||
register int i;
|
||||
register unsigned char *p = (unsigned char *)buf;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
*p++ = __nand_data8();
|
||||
}
|
||||
#else
|
||||
static void jz_nand_write_dma(void *source, unsigned int len, int bw)
|
||||
{
|
||||
mutex_lock(&nand_dma_mtx);
|
||||
|
||||
if(((unsigned int)source < 0xa0000000) && len)
|
||||
dma_cache_wback_inv((unsigned long)source, len);
|
||||
|
||||
dma_enable();
|
||||
|
||||
REG_DMAC_DCCSR(DMA_NAND_CHANNEL) = DMAC_DCCSR_NDES;
|
||||
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; /* Enable DMA channel */
|
||||
#if 1
|
||||
while( REG_DMAC_DTCR(DMA_NAND_CHANNEL) )
|
||||
yield();
|
||||
#else
|
||||
REG_DMAC_DCMD(DMA_NAND_CHANNEL) |= DMAC_DCMD_TIE; /* Enable DMA interrupt */
|
||||
semaphore_wait(&nand_dma_complete, TIMEOUT_BLOCK);
|
||||
#endif
|
||||
|
||||
REG_DMAC_DCCSR(DMA_NAND_CHANNEL) &= ~DMAC_DCCSR_EN; /* Disable DMA channel */
|
||||
|
||||
dma_disable();
|
||||
|
||||
mutex_unlock(&nand_dma_mtx);
|
||||
}
|
||||
|
||||
static void jz_nand_read_dma(void *target, unsigned int len, int bw)
|
||||
{
|
||||
mutex_lock(&nand_dma_mtx);
|
||||
|
||||
if(((unsigned int)target < 0xa0000000) && len)
|
||||
dma_cache_wback_inv((unsigned long)target, len);
|
||||
|
||||
dma_enable();
|
||||
|
||||
REG_DMAC_DCCSR(DMA_NAND_CHANNEL) = DMAC_DCCSR_NDES ;
|
||||
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; /* Enable DMA channel */
|
||||
#if 1
|
||||
while( REG_DMAC_DTCR(DMA_NAND_CHANNEL) )
|
||||
yield();
|
||||
#else
|
||||
REG_DMAC_DCMD(DMA_NAND_CHANNEL) |= DMAC_DCMD_TIE; /* Enable DMA interrupt */
|
||||
semaphore_wait(&nand_dma_complete, TIMEOUT_BLOCK);
|
||||
#endif
|
||||
|
||||
//REG_DMAC_DCCSR(DMA_NAND_CHANNEL) &= ~DMAC_DCCSR_EN; /* Disable DMA channel */
|
||||
|
||||
dma_disable();
|
||||
|
||||
mutex_unlock(&nand_dma_mtx);
|
||||
}
|
||||
|
||||
void DMA_CALLBACK(DMA_NAND_CHANNEL)(void)
|
||||
{
|
||||
if (REG_DMAC_DCCSR(DMA_NAND_CHANNEL) & DMAC_DCCSR_HLT)
|
||||
REG_DMAC_DCCSR(DMA_NAND_CHANNEL) &= ~DMAC_DCCSR_HLT;
|
||||
|
||||
if (REG_DMAC_DCCSR(DMA_NAND_CHANNEL) & DMAC_DCCSR_AR)
|
||||
REG_DMAC_DCCSR(DMA_NAND_CHANNEL) &= ~DMAC_DCCSR_AR;
|
||||
|
||||
if (REG_DMAC_DCCSR(DMA_NAND_CHANNEL) & DMAC_DCCSR_CT)
|
||||
REG_DMAC_DCCSR(DMA_NAND_CHANNEL) &= ~DMAC_DCCSR_CT;
|
||||
|
||||
if (REG_DMAC_DCCSR(DMA_NAND_CHANNEL) & DMAC_DCCSR_TT)
|
||||
REG_DMAC_DCCSR(DMA_NAND_CHANNEL) &= ~DMAC_DCCSR_TT;
|
||||
|
||||
semaphore_release(&nand_dma_complete);
|
||||
}
|
||||
#endif /* USE_DMA */
|
||||
|
||||
static inline void jz_nand_read_buf(void *buf, int count, int bw)
|
||||
{
|
||||
#ifdef USE_DMA
|
||||
if (bw == 8)
|
||||
jz_nand_read_dma(buf, count, 8);
|
||||
else
|
||||
jz_nand_read_dma(buf, count, 16);
|
||||
#else
|
||||
if (bw == 8)
|
||||
jz_nand_read_buf8(buf, count);
|
||||
else
|
||||
jz_nand_read_buf16(buf, count);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef USE_ECC
|
||||
/*
|
||||
* Correct 1~9-bit errors in 512-bytes data
|
||||
*/
|
||||
static void jz_rs_correct(unsigned char *dat, int idx, int mask)
|
||||
{
|
||||
int i, j;
|
||||
unsigned short d, d1, dm;
|
||||
|
||||
i = (idx * 9) >> 3;
|
||||
j = (idx * 9) & 0x7;
|
||||
|
||||
i = (j == 0) ? (i - 1) : i;
|
||||
j = (j == 0) ? 7 : (j - 1);
|
||||
|
||||
if (i > 512)
|
||||
return;
|
||||
|
||||
if (i == 512)
|
||||
d = dat[i - 1];
|
||||
else
|
||||
d = (dat[i] << 8) | dat[i - 1];
|
||||
|
||||
d1 = (d >> j) & 0x1ff;
|
||||
d1 ^= mask;
|
||||
|
||||
dm = ~(0x1ff << j);
|
||||
d = (d & dm) | (d1 << j);
|
||||
|
||||
dat[i - 1] = d & 0xff;
|
||||
if (i < 512)
|
||||
dat[i] = (d >> 8) & 0xff;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Read oob
|
||||
*/
|
||||
static int jz_nand_read_oob(unsigned long page_addr, unsigned char *buf, int size)
|
||||
{
|
||||
struct nand_param *nandp = &internal_param;
|
||||
int page_size, row_cycle, bus_width;
|
||||
int col_addr;
|
||||
|
||||
page_size = nandp->page_size;
|
||||
row_cycle = nandp->row_cycle;
|
||||
bus_width = nandp->bus_width;
|
||||
|
||||
if (page_size >= 2048)
|
||||
col_addr = page_size;
|
||||
else
|
||||
col_addr = 0;
|
||||
|
||||
if (page_size >= 2048)
|
||||
/* Send READ0 command */
|
||||
__nand_cmd(NAND_CMD_READ0);
|
||||
else
|
||||
/* Send READOOB command */
|
||||
__nand_cmd(NAND_CMD_READOOB);
|
||||
|
||||
/* Send column address */
|
||||
__nand_addr(col_addr & 0xff);
|
||||
if (page_size >= 2048)
|
||||
__nand_addr((col_addr >> 8) & 0xff);
|
||||
|
||||
/* Send page address */
|
||||
__nand_addr(page_addr & 0xff);
|
||||
__nand_addr((page_addr >> 8) & 0xff);
|
||||
if (row_cycle == 3)
|
||||
__nand_addr((page_addr >> 16) & 0xff);
|
||||
|
||||
/* Send READSTART command for 2048 ps NAND */
|
||||
if (page_size >= 2048)
|
||||
__nand_cmd(NAND_CMD_READSTART);
|
||||
|
||||
/* Wait for device ready */
|
||||
jz_nand_wait_ready();
|
||||
|
||||
/* Read oob data */
|
||||
jz_nand_read_buf(buf, size, bus_width);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* nand_read_page()
|
||||
*
|
||||
* Input:
|
||||
*
|
||||
* block - block number: 0, 1, 2, ...
|
||||
* page - page number within a block: 0, 1, 2, ...
|
||||
* dst - pointer to target buffer
|
||||
*/
|
||||
static int jz_nand_read_page(unsigned long page_addr, unsigned char *dst)
|
||||
{
|
||||
struct nand_param *nandp = &internal_param;
|
||||
int page_size, oob_size, page_per_block;
|
||||
int row_cycle, bus_width, ecc_count;
|
||||
int i;
|
||||
#ifdef USE_ECC
|
||||
int j;
|
||||
#endif
|
||||
unsigned char *data_buf;
|
||||
unsigned char oob_buf[nandp->oob_size];
|
||||
|
||||
page_size = nandp->page_size;
|
||||
oob_size = nandp->oob_size;
|
||||
page_per_block = nandp->page_per_block;
|
||||
row_cycle = nandp->row_cycle;
|
||||
bus_width = nandp->bus_width;
|
||||
|
||||
/*
|
||||
* Read oob data
|
||||
*/
|
||||
jz_nand_read_oob(page_addr, oob_buf, oob_size);
|
||||
|
||||
/*
|
||||
* Read page data
|
||||
*/
|
||||
|
||||
/* Send READ0 command */
|
||||
__nand_cmd(NAND_CMD_READ0);
|
||||
|
||||
/* Send column address */
|
||||
__nand_addr(0);
|
||||
if (page_size >= 2048)
|
||||
__nand_addr(0);
|
||||
|
||||
/* Send page address */
|
||||
__nand_addr(page_addr & 0xff);
|
||||
__nand_addr((page_addr >> 8) & 0xff);
|
||||
if (row_cycle >= 3)
|
||||
__nand_addr((page_addr >> 16) & 0xff);
|
||||
|
||||
/* Send READSTART command for 2048 ps NAND */
|
||||
if (page_size >= 2048)
|
||||
__nand_cmd(NAND_CMD_READSTART);
|
||||
|
||||
/* Wait for device ready */
|
||||
jz_nand_wait_ready();
|
||||
|
||||
/* Read page data */
|
||||
data_buf = dst;
|
||||
|
||||
ecc_count = page_size / ECC_BLOCK;
|
||||
|
||||
for (i = 0; i < ecc_count; i++)
|
||||
{
|
||||
#ifdef USE_ECC
|
||||
volatile unsigned char *paraddr = (volatile unsigned char *)EMC_NFPAR0;
|
||||
unsigned int stat;
|
||||
|
||||
/* Enable RS decoding */
|
||||
REG_EMC_NFINTS = 0x0;
|
||||
__ecc_decoding_4bit();
|
||||
#endif
|
||||
|
||||
/* Read data */
|
||||
jz_nand_read_buf((void *)data_buf, ECC_BLOCK, bus_width);
|
||||
|
||||
#ifdef USE_ECC
|
||||
/* Set PAR values */
|
||||
for (j = 0; j < PAR_SIZE; j++)
|
||||
*paraddr++ = oob_buf[ECC_POS + i*PAR_SIZE + j];
|
||||
|
||||
/* Set PRDY */
|
||||
REG_EMC_NFECR |= EMC_NFECR_PRDY;
|
||||
|
||||
/* Wait for completion */
|
||||
__ecc_decode_sync();
|
||||
|
||||
/* Disable decoding */
|
||||
__ecc_disable();
|
||||
|
||||
/* Check result of decoding */
|
||||
stat = REG_EMC_NFINTS;
|
||||
if (stat & EMC_NFINTS_ERR)
|
||||
{
|
||||
/* Error occurred */
|
||||
if (stat & EMC_NFINTS_UNCOR)
|
||||
{
|
||||
/* Uncorrectable error occurred */
|
||||
logf("Uncorrectable ECC error at NAND page address 0x%lx", page_addr);
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned int errcnt, index, mask;
|
||||
|
||||
errcnt = (stat & EMC_NFINTS_ERRCNT_MASK) >> EMC_NFINTS_ERRCNT_BIT;
|
||||
switch (errcnt)
|
||||
{
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
jz_rs_correct(data_buf, index, mask);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
data_buf += ECC_BLOCK;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int jz_nand_init(void)
|
||||
{
|
||||
unsigned char cData[5];
|
||||
|
||||
__gpio_as_nand_16bit(1);
|
||||
|
||||
REG_NEMC_SMCR1 = CFG_NAND_SMCR1 | 0x40;
|
||||
|
||||
__nand_select();
|
||||
|
||||
__nand_cmd(NAND_CMD_READID);
|
||||
__nand_addr(NAND_CMD_READ0);
|
||||
cData[0] = __nand_data8();
|
||||
cData[1] = __nand_data8();
|
||||
cData[2] = __nand_data8();
|
||||
cData[3] = __nand_data8();
|
||||
cData[4] = __nand_data8();
|
||||
|
||||
__nand_deselect();
|
||||
|
||||
logf("NAND chip %d: 0x%x 0x%x 0x%x 0x%x 0x%x", i+1, cData[0], cData[1],
|
||||
cData[2], cData[3], cData[4]);
|
||||
|
||||
bank = nand_identify(cData);
|
||||
|
||||
if(bank == NULL)
|
||||
{
|
||||
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; /* panicf() doesn't return though */
|
||||
}
|
||||
|
||||
chip_info = bank;
|
||||
|
||||
internal_param.bus_width = 16;
|
||||
internal_param.row_cycle = chip_info->row_cycles;
|
||||
internal_param.page_size = chip_info->page_size;
|
||||
internal_param.oob_size = chip_info->spare_size;
|
||||
internal_param.page_per_block = chip_info->pages_per_block;
|
||||
internal_param.bad_block_pos = 0;
|
||||
|
||||
nand_size = ((chip_info->page_size * chip_info->blocks_per_bank * chip_info->pages_per_block) - 0x200000) / 512;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nand_init(void)
|
||||
{
|
||||
int res = 0;
|
||||
static bool inited = false;
|
||||
|
||||
if(!inited)
|
||||
{
|
||||
res = jz_nand_init();
|
||||
mutex_init(&nand_mtx);
|
||||
#ifdef USE_DMA
|
||||
mutex_init(&nand_dma_mtx);
|
||||
semaphore_init(&nand_dma_complete, 1, 0);
|
||||
system_enable_irq(DMA_IRQ(DMA_NAND_CHANNEL));
|
||||
#endif
|
||||
|
||||
inited = true;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline int read_sector(unsigned long start, unsigned int count,
|
||||
void* buf, unsigned int chip_size)
|
||||
{
|
||||
register int ret;
|
||||
|
||||
if(UNLIKELY(start % chip_size == 0 && count == chip_size))
|
||||
ret = jz_nand_read_page(start / chip_size, buf);
|
||||
else
|
||||
{
|
||||
ret = jz_nand_read_page(start / chip_size, temp_page);
|
||||
memcpy(buf, temp_page + (start % chip_size), count);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int write_sector(unsigned long start, unsigned int count,
|
||||
const void* buf, unsigned int chip_size)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
(void)start;
|
||||
(void)count;
|
||||
(void)buf;
|
||||
(void)chip_size;
|
||||
|
||||
/* TODO */
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int nand_read_sectors(IF_MV(int drive,) unsigned long start, int count, void* buf)
|
||||
{
|
||||
#ifdef HAVE_MULTIVOLUME
|
||||
(void)drive;
|
||||
#endif
|
||||
int ret = 0;
|
||||
unsigned int _count, chip_size = chip_info->page_size;
|
||||
unsigned long _start;
|
||||
|
||||
logf("start");
|
||||
mutex_lock(&nand_mtx);
|
||||
|
||||
_start = start << 9;
|
||||
_start += 0x200000; /* skip BL */
|
||||
_count = count << 9;
|
||||
|
||||
__nand_select();
|
||||
ret = read_sector(_start, _count, buf, chip_size);
|
||||
__nand_deselect();
|
||||
|
||||
mutex_unlock(&nand_mtx);
|
||||
|
||||
logf("nand_read_sectors(%ld, %d, 0x%x): %d", start, count, (int)buf, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int nand_write_sectors(IF_MV(int drive,) unsigned long start, int count, const void* buf)
|
||||
{
|
||||
#ifdef HAVE_MULTIVOLUME
|
||||
(void)drive;
|
||||
#endif
|
||||
int ret = 0;
|
||||
unsigned int _count, chip_size = chip_info->page_size;
|
||||
unsigned long _start;
|
||||
|
||||
logf("start");
|
||||
mutex_lock(&nand_mtx);
|
||||
|
||||
_start = start << 9;
|
||||
_start += chip_info->page_size * chip_info->pages_per_block; /* skip BL */
|
||||
_count = count << 9;
|
||||
|
||||
__nand_select();
|
||||
ret = write_sector(_start, _count, buf, chip_size);
|
||||
__nand_deselect();
|
||||
|
||||
mutex_unlock(&nand_mtx);
|
||||
|
||||
logf("nand_write_sectors(%ld, %d, 0x%x): %d", start, count, (int)buf, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef HAVE_STORAGE_FLUSH
|
||||
int nand_flush(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void nand_spindown(int seconds)
|
||||
{
|
||||
/* null */
|
||||
(void)seconds;
|
||||
}
|
||||
|
||||
void nand_sleep(void)
|
||||
{
|
||||
/* null */
|
||||
}
|
||||
|
||||
void nand_spin(void)
|
||||
{
|
||||
/* null */
|
||||
}
|
||||
|
||||
void nand_enable(bool on)
|
||||
{
|
||||
/* null - flash controller is enabled/disabled as needed. */
|
||||
(void)on;
|
||||
}
|
||||
|
||||
/* TODO */
|
||||
long nand_last_disk_activity(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nand_spinup_time(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nand_sleepnow(void)
|
||||
{
|
||||
}
|
||||
|
||||
#ifdef STORAGE_GET_INFO
|
||||
void nand_get_info(IF_MV(int drive,) struct storage_info *info)
|
||||
{
|
||||
#ifdef HAVE_MULTIVOLUME
|
||||
(void)drive;
|
||||
#endif
|
||||
|
||||
/* firmware version */
|
||||
info->revision="0.00";
|
||||
|
||||
info->vendor="Rockbox";
|
||||
info->product="NAND Storage";
|
||||
|
||||
/* blocks count */
|
||||
info->num_sectors = nand_size;
|
||||
info->sector_size = 512;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_STORAGE_MULTI
|
||||
int nand_num_drives(int first_drive)
|
||||
{
|
||||
/* We don't care which logical drive number(s) we have been assigned */
|
||||
(void)first_drive;
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
#include "config.h"
|
||||
#include "gcc_extensions.h"
|
||||
#include "jz4740.h"
|
||||
#include "cpu.h"
|
||||
#include "ata-sd-target.h"
|
||||
#include "led.h"
|
||||
#include "sdmmc.h"
|
||||
|
|
|
|||
1487
firmware/target/mips/ingenic_jz47xx/ata-sd-jz4760.c
Normal file
1487
firmware/target/mips/ingenic_jz47xx/ata-sd-jz4760.c
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -26,6 +26,8 @@
|
|||
bool backlight_hw_init(void);
|
||||
void backlight_hw_on(void);
|
||||
void backlight_hw_off(void);
|
||||
#ifdef HAVE_BACKLIGHT_BRIGHTNESS
|
||||
void backlight_hw_brightness(int brightness);
|
||||
#endif /* HAVE_BACKLIGHT_BRIGHTNESS */
|
||||
|
||||
#endif /* BACKLIGHT_TARGET_H */
|
||||
|
|
|
|||
293
firmware/target/mips/ingenic_jz47xx/codec-jz4760.c
Normal file
293
firmware/target/mips/ingenic_jz47xx/codec-jz4760.c
Normal file
|
|
@ -0,0 +1,293 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
*
|
||||
* Copyright (C) 2016 by Roman Stolyarov
|
||||
*
|
||||
* 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 "audio.h"
|
||||
#include "sound.h"
|
||||
#include "cpu.h"
|
||||
#include "system.h"
|
||||
#include "pcm_sw_volume.h"
|
||||
#include "cs4398.h"
|
||||
#include "kernel.h"
|
||||
|
||||
#define PIN_CS_RST (32*1+10)
|
||||
#define PIN_CODEC_PWRON (32*1+13)
|
||||
#define PIN_AP_MUTE (32*1+14)
|
||||
#define PIN_JD_CON (32*1+16)
|
||||
|
||||
static void pop_ctrl(const int val)
|
||||
{
|
||||
if(val)
|
||||
__gpio_clear_pin(PIN_JD_CON);
|
||||
else
|
||||
__gpio_set_pin(PIN_JD_CON);
|
||||
}
|
||||
|
||||
static void amp_enable(const int val)
|
||||
{
|
||||
if(val)
|
||||
__gpio_set_pin(PIN_CODEC_PWRON);
|
||||
else
|
||||
__gpio_clear_pin(PIN_CODEC_PWRON);
|
||||
}
|
||||
|
||||
static void dac_enable(const int val)
|
||||
{
|
||||
if(val)
|
||||
__gpio_set_pin(PIN_CS_RST);
|
||||
else
|
||||
__gpio_clear_pin(PIN_CS_RST);
|
||||
}
|
||||
|
||||
static void ap_mute(bool mute)
|
||||
{
|
||||
if(mute)
|
||||
__gpio_clear_pin(PIN_AP_MUTE);
|
||||
else
|
||||
__gpio_set_pin(PIN_AP_MUTE);
|
||||
}
|
||||
|
||||
static void audiohw_mute(bool mute)
|
||||
{
|
||||
if(mute)
|
||||
cs4398_write_reg(CS4398_REG_MUTE, cs4398_read_reg(CS4398_REG_MUTE) | CS4398_MUTE_A | CS4398_MUTE_B);
|
||||
else
|
||||
cs4398_write_reg(CS4398_REG_MUTE, cs4398_read_reg(CS4398_REG_MUTE) & ~(CS4398_MUTE_A | CS4398_MUTE_B));
|
||||
}
|
||||
|
||||
void audiohw_preinit(void)
|
||||
{
|
||||
cs4398_write_reg(CS4398_REG_MISC, CS4398_CPEN | CS4398_PDN);
|
||||
cs4398_write_reg(CS4398_REG_MODECTL, CS4398_FM_SINGLE | CS4398_DEM_NONE | CS4398_DIF_LJUST);
|
||||
cs4398_write_reg(CS4398_REG_VOLMIX, CS4398_ATAPI_A_L | CS4398_ATAPI_B_R);
|
||||
cs4398_write_reg(CS4398_REG_MUTE, CS4398_MUTEP_LOW);
|
||||
cs4398_write_reg(CS4398_REG_VOL_A, 0xff);
|
||||
cs4398_write_reg(CS4398_REG_VOL_B, 0xff);
|
||||
cs4398_write_reg(CS4398_REG_RAMPFILT, CS4398_ZERO_CROSS | CS4398_SOFT_RAMP);
|
||||
cs4398_write_reg(CS4398_REG_MISC, CS4398_CPEN);
|
||||
}
|
||||
|
||||
void audiohw_init(void)
|
||||
{
|
||||
__gpio_as_func1(3*32+12); // BCK
|
||||
__gpio_as_func0(3*32+13); // LRCK
|
||||
__gpio_as_func2(4*32+5); // MCLK
|
||||
__gpio_as_func0(4*32+7); // DO
|
||||
|
||||
pop_ctrl(0);
|
||||
ap_mute(true);
|
||||
amp_enable(0);
|
||||
dac_enable(0);
|
||||
|
||||
__gpio_as_output(PIN_JD_CON);
|
||||
__gpio_as_output(PIN_AP_MUTE);
|
||||
__gpio_as_output(PIN_CODEC_PWRON);
|
||||
__gpio_as_output(PIN_CS_RST);
|
||||
|
||||
mdelay(100);
|
||||
amp_enable(1);
|
||||
|
||||
/* set AIC clk PLL1 */
|
||||
__cpm_select_i2sclk_pll();
|
||||
__cpm_select_i2sclk_pll1();
|
||||
|
||||
__cpm_enable_pll_change();
|
||||
__cpm_set_i2sdiv(43-1);
|
||||
|
||||
__cpm_start_aic();
|
||||
|
||||
/* Init AIC */
|
||||
__i2s_enable_sclk();
|
||||
__i2s_external_codec();
|
||||
__i2s_select_msbjustified();
|
||||
__i2s_as_master();
|
||||
__i2s_enable_transmit_dma();
|
||||
__i2s_set_transmit_trigger(24);
|
||||
__i2s_set_oss_sample_size(16);
|
||||
__i2s_enable();
|
||||
|
||||
/* Init DAC */
|
||||
dac_enable(1);
|
||||
udelay(1);
|
||||
audiohw_preinit();
|
||||
}
|
||||
|
||||
static int vol_tenthdb2hw(const int tdb)
|
||||
{
|
||||
if (tdb < CS4398_VOLUME_MIN) {
|
||||
return 0xff;
|
||||
} else if (tdb > CS4398_VOLUME_MAX) {
|
||||
return 0x00;
|
||||
} else {
|
||||
return (-tdb/5);
|
||||
}
|
||||
}
|
||||
|
||||
void audiohw_set_volume(int vol_l, int vol_r)
|
||||
{
|
||||
cs4398_write_reg(CS4398_REG_VOL_A, vol_tenthdb2hw(vol_l));
|
||||
cs4398_write_reg(CS4398_REG_VOL_B, vol_tenthdb2hw(vol_r));
|
||||
}
|
||||
|
||||
void audiohw_set_lineout_volume(int vol_l, int vol_r)
|
||||
{
|
||||
#if 0 /* unused */
|
||||
cs4398_write_reg(CS4398_REG_VOL_A, vol_tenthdb2hw(vol_l));
|
||||
cs4398_write_reg(CS4398_REG_VOL_B, vol_tenthdb2hw(vol_r));
|
||||
#else
|
||||
(void)vol_l;
|
||||
(void)vol_r;
|
||||
#endif
|
||||
}
|
||||
|
||||
void audiohw_set_filter_roll_off(int value)
|
||||
{
|
||||
/* 0 = fast (sharp);
|
||||
1 = slow */
|
||||
if (value == 0) {
|
||||
cs4398_write_reg(CS4398_REG_RAMPFILT, cs4398_read_reg(CS4398_REG_RAMPFILT) & ~CS4398_FILT_SEL);
|
||||
} else {
|
||||
cs4398_write_reg(CS4398_REG_RAMPFILT, cs4398_read_reg(CS4398_REG_RAMPFILT) | CS4398_FILT_SEL);
|
||||
}
|
||||
}
|
||||
|
||||
void pll1_init(unsigned int freq);
|
||||
void audiohw_set_frequency(int fsel)
|
||||
{
|
||||
unsigned int pll1_speed;
|
||||
unsigned char mclk_div, bclk_div, func_mode;
|
||||
|
||||
switch(fsel)
|
||||
{
|
||||
case HW_FREQ_8:
|
||||
pll1_speed = 426000000;
|
||||
mclk_div = 52;
|
||||
bclk_div = 16;
|
||||
func_mode = 0;
|
||||
break;
|
||||
case HW_FREQ_11:
|
||||
pll1_speed = 508000000;
|
||||
mclk_div = 45;
|
||||
bclk_div = 16;
|
||||
func_mode = 0;
|
||||
break;
|
||||
case HW_FREQ_12:
|
||||
pll1_speed = 516000000;
|
||||
mclk_div = 42;
|
||||
bclk_div = 16;
|
||||
func_mode = 0;
|
||||
break;
|
||||
case HW_FREQ_16:
|
||||
pll1_speed = 426000000;
|
||||
mclk_div = 52;
|
||||
bclk_div = 8;
|
||||
func_mode = 0;
|
||||
break;
|
||||
case HW_FREQ_22:
|
||||
pll1_speed = 508000000;
|
||||
mclk_div = 45;
|
||||
bclk_div = 8;
|
||||
func_mode = 0;
|
||||
break;
|
||||
case HW_FREQ_24:
|
||||
pll1_speed = 516000000;
|
||||
mclk_div = 42;
|
||||
bclk_div = 8;
|
||||
func_mode = 0;
|
||||
break;
|
||||
case HW_FREQ_32:
|
||||
pll1_speed = 426000000;
|
||||
mclk_div = 52;
|
||||
bclk_div = 4;
|
||||
func_mode = 0;
|
||||
break;
|
||||
case HW_FREQ_44:
|
||||
pll1_speed = 508000000;
|
||||
mclk_div = 45;
|
||||
bclk_div = 4;
|
||||
func_mode = 0;
|
||||
break;
|
||||
case HW_FREQ_48:
|
||||
pll1_speed = 516000000;
|
||||
mclk_div = 42;
|
||||
bclk_div = 4;
|
||||
func_mode = 0;
|
||||
break;
|
||||
case HW_FREQ_64:
|
||||
pll1_speed = 426000000;
|
||||
mclk_div = 52;
|
||||
bclk_div = 2;
|
||||
func_mode = 1;
|
||||
break;
|
||||
case HW_FREQ_88:
|
||||
pll1_speed = 508000000;
|
||||
mclk_div = 45;
|
||||
bclk_div = 2;
|
||||
func_mode = 1;
|
||||
break;
|
||||
case HW_FREQ_96:
|
||||
pll1_speed = 516000000;
|
||||
mclk_div = 42;
|
||||
bclk_div = 2;
|
||||
func_mode = 1;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
__i2s_stop_bitclk();
|
||||
|
||||
/* 0 = Single-Speed Mode (<50KHz);
|
||||
1 = Double-Speed Mode (50-100KHz);
|
||||
2 = Quad-Speed Mode; (100-200KHz) */
|
||||
cs4398_write_reg(CS4398_REG_MODECTL, (cs4398_read_reg(CS4398_REG_MODECTL) & ~CS4398_FM_MASK) | func_mode);
|
||||
if (func_mode == 2)
|
||||
cs4398_write_reg(CS4398_REG_MISC, cs4398_read_reg(CS4398_REG_MISC) | CS4398_MCLKDIV2);
|
||||
else
|
||||
cs4398_write_reg(CS4398_REG_MISC, cs4398_read_reg(CS4398_REG_MISC) & ~CS4398_MCLKDIV2);
|
||||
|
||||
pll1_init(pll1_speed);
|
||||
__cpm_enable_pll_change();
|
||||
__cpm_set_i2sdiv(mclk_div-1);
|
||||
__i2s_set_i2sdiv(bclk_div-1);
|
||||
__i2s_start_bitclk();
|
||||
}
|
||||
|
||||
void audiohw_postinit(void)
|
||||
{
|
||||
sleep(HZ);
|
||||
audiohw_mute(false);
|
||||
ap_mute(false);
|
||||
pop_ctrl(1);
|
||||
}
|
||||
|
||||
void audiohw_close(void)
|
||||
{
|
||||
pop_ctrl(0);
|
||||
sleep(HZ/10);
|
||||
ap_mute(true);
|
||||
audiohw_mute(true);
|
||||
amp_enable(0);
|
||||
dac_enable(0);
|
||||
__i2s_disable();
|
||||
__cpm_stop_aic();
|
||||
sleep(HZ);
|
||||
pop_ctrl(1);
|
||||
}
|
||||
|
|
@ -50,6 +50,7 @@
|
|||
.set noat
|
||||
|
||||
#ifdef BOOTLOADER
|
||||
#ifndef XDUOO_X3
|
||||
/* These will get filled in by scramble */
|
||||
.word 0 /* Empty */
|
||||
.word 0 /* Filesize */
|
||||
|
|
@ -65,6 +66,7 @@ _relocate_loop:
|
|||
bne t1, t2, _relocate_loop
|
||||
sw t3, -4(t1)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
_start:
|
||||
la ra, _start
|
||||
|
|
|
|||
146
firmware/target/mips/ingenic_jz47xx/debug-jz4760.c
Normal file
146
firmware/target/mips/ingenic_jz47xx/debug-jz4760.c
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2016 by Roman Stolyarov
|
||||
*
|
||||
* 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 "system.h"
|
||||
#include "cpu.h"
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include "lcd.h"
|
||||
#include "kernel.h"
|
||||
#include "font.h"
|
||||
#include "button.h"
|
||||
#include "timefuncs.h"
|
||||
|
||||
#define CFG_UART_BASE UART1_BASE /* Base of the UART channel */
|
||||
|
||||
void serial_putc (const char c)
|
||||
{
|
||||
volatile u8 *uart_lsr = (volatile u8 *)(CFG_UART_BASE + OFF_LSR);
|
||||
volatile u8 *uart_tdr = (volatile u8 *)(CFG_UART_BASE + OFF_TDR);
|
||||
|
||||
if (c == '\n') serial_putc ('\r');
|
||||
|
||||
/* Wait for fifo to shift out some bytes */
|
||||
while ( !((*uart_lsr & (UARTLSR_TDRQ | UARTLSR_TEMT)) == 0x60) );
|
||||
|
||||
*uart_tdr = (u8)c;
|
||||
}
|
||||
|
||||
void serial_puts (const char *s)
|
||||
{
|
||||
while (*s) {
|
||||
serial_putc (*s++);
|
||||
}
|
||||
}
|
||||
|
||||
void serial_putsf(const char *format, ...)
|
||||
{
|
||||
static char printfbuf[256];
|
||||
int len;
|
||||
unsigned char *ptr;
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
|
||||
ptr = printfbuf;
|
||||
len = vsnprintf(ptr, sizeof(printfbuf), format, ap);
|
||||
va_end(ap);
|
||||
|
||||
serial_puts(ptr);
|
||||
serial_putc('\n');
|
||||
}
|
||||
|
||||
void serial_put_hex(unsigned int d)
|
||||
{
|
||||
char c[12];
|
||||
int i;
|
||||
for(i = 0; i < 8;i++)
|
||||
{
|
||||
c[i] = (d >> ((7 - i) * 4)) & 0xf;
|
||||
if(c[i] < 10)
|
||||
c[i] += 0x30;
|
||||
else
|
||||
c[i] += (0x41 - 10);
|
||||
}
|
||||
c[8] = '\n';
|
||||
c[9] = 0;
|
||||
serial_puts(c);
|
||||
|
||||
}
|
||||
|
||||
void serial_put_dec(unsigned int d)
|
||||
{
|
||||
char c[16];
|
||||
int i;
|
||||
int j = 0;
|
||||
int x = d;
|
||||
|
||||
while (x /= 10)
|
||||
j++;
|
||||
|
||||
for (i = j; i >= 0; i--) {
|
||||
c[i] = d % 10;
|
||||
c[i] += 0x30;
|
||||
d /= 10;
|
||||
}
|
||||
c[j + 1] = '\n';
|
||||
c[j + 2] = 0;
|
||||
serial_puts(c);
|
||||
}
|
||||
|
||||
void serial_dump_data(unsigned char* data, int len)
|
||||
{
|
||||
int i;
|
||||
for(i=0; i<len; i++)
|
||||
{
|
||||
unsigned char a = ((*data)>>4) & 0xf;
|
||||
if(a < 10)
|
||||
a += 0x30;
|
||||
else
|
||||
a += (0x41 - 10);
|
||||
serial_putc( a );
|
||||
|
||||
a = (*data) & 0xf;
|
||||
if(a < 10)
|
||||
a += 0x30;
|
||||
else
|
||||
a += (0x41 - 10);
|
||||
serial_putc( a );
|
||||
|
||||
serial_putc( ' ' );
|
||||
|
||||
data++;
|
||||
}
|
||||
|
||||
serial_putc( '\n' );
|
||||
}
|
||||
|
||||
bool dbg_ports(void)
|
||||
{
|
||||
serial_puts("dbg_ports\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool dbg_hw_info(void)
|
||||
{
|
||||
serial_puts("dbg_hw_info\n");
|
||||
return false;
|
||||
}
|
||||
31
firmware/target/mips/ingenic_jz47xx/dma-target.h
Normal file
31
firmware/target/mips/ingenic_jz47xx/dma-target.h
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2016 by Roman Stolyarov
|
||||
*
|
||||
* 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 __DMA_TARGET_H_
|
||||
#define __DMA_TARGET_H_
|
||||
|
||||
#include "system.h"
|
||||
#include <string.h>
|
||||
|
||||
void memset_dma(void *target, int c, size_t len, unsigned int bits);
|
||||
void memcpy_dma(void *target, const void *source, size_t len, unsigned int bits);
|
||||
|
||||
#endif /* __DMA_TARGET_H_ */
|
||||
102
firmware/target/mips/ingenic_jz47xx/dma_acc-jz4760.c
Normal file
102
firmware/target/mips/ingenic_jz47xx/dma_acc-jz4760.c
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2016 by Roman Stolyarov
|
||||
*
|
||||
* 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 "dma-target.h"
|
||||
|
||||
#define MDMA_CHANNEL 0
|
||||
|
||||
void memset_dma(void *target, int c, size_t len, unsigned int bits)
|
||||
{
|
||||
unsigned int d;
|
||||
unsigned char *dp;
|
||||
|
||||
if(((unsigned int)target < 0xa0000000) && len)
|
||||
dma_cache_wback_inv((unsigned long)target, len);
|
||||
|
||||
dp = (unsigned char *)((unsigned int)(&d) | 0xa0000000);
|
||||
*(dp + 0) = c;
|
||||
*(dp + 1) = c;
|
||||
*(dp + 2) = c;
|
||||
*(dp + 3) = c;
|
||||
|
||||
REG_MDMAC_DCCSR(MDMA_CHANNEL) = 0;
|
||||
REG_MDMAC_DSAR(MDMA_CHANNEL) = PHYSADDR((unsigned long)dp);
|
||||
REG_MDMAC_DTAR(MDMA_CHANNEL) = PHYSADDR((unsigned long)target);
|
||||
REG_MDMAC_DRSR(MDMA_CHANNEL) = DMAC_DRSR_RS_AUTO;
|
||||
switch (bits)
|
||||
{
|
||||
case 8:
|
||||
REG_MDMAC_DTCR(MDMA_CHANNEL) = len;
|
||||
REG_MDMAC_DCMD(MDMA_CHANNEL) = DMAC_DCMD_DAI | DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_8 | DMAC_DCMD_DS_8BIT;
|
||||
break;
|
||||
case 16:
|
||||
REG_MDMAC_DTCR(MDMA_CHANNEL) = len / 2;
|
||||
REG_MDMAC_DCMD(MDMA_CHANNEL) = DMAC_DCMD_DAI | DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_16 | DMAC_DCMD_DS_16BIT;
|
||||
break;
|
||||
case 32:
|
||||
REG_MDMAC_DTCR(MDMA_CHANNEL) = len / 4;
|
||||
REG_MDMAC_DCMD(MDMA_CHANNEL) = DMAC_DCMD_DAI | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BIT;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
REG_MDMAC_DCCSR(MDMA_CHANNEL) = DMAC_DCCSR_EN | DMAC_DCCSR_NDES;
|
||||
|
||||
while (REG_MDMAC_DTCR(MDMA_CHANNEL));
|
||||
|
||||
REG_MDMAC_DCCSR(MDMA_CHANNEL) = 0;
|
||||
}
|
||||
|
||||
void memcpy_dma(void *target, const void *source, size_t len, unsigned int bits)
|
||||
{
|
||||
if(((unsigned int)source < 0xa0000000) && len)
|
||||
dma_cache_wback_inv((unsigned long)source, len);
|
||||
|
||||
if(((unsigned int)target < 0xa0000000) && len)
|
||||
dma_cache_wback_inv((unsigned long)target, len);
|
||||
|
||||
REG_MDMAC_DCCSR(MDMA_CHANNEL) = 0;
|
||||
REG_MDMAC_DSAR(MDMA_CHANNEL) = PHYSADDR((unsigned long)source);
|
||||
REG_MDMAC_DTAR(MDMA_CHANNEL) = PHYSADDR((unsigned long)target);
|
||||
REG_MDMAC_DRSR(MDMA_CHANNEL) = DMAC_DRSR_RS_AUTO;
|
||||
switch (bits)
|
||||
{
|
||||
case 8:
|
||||
REG_MDMAC_DTCR(MDMA_CHANNEL) = len;
|
||||
REG_MDMAC_DCMD(MDMA_CHANNEL) = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_8 | DMAC_DCMD_DS_8BIT;
|
||||
break;
|
||||
case 16:
|
||||
REG_MDMAC_DTCR(MDMA_CHANNEL) = len / 2;
|
||||
REG_MDMAC_DCMD(MDMA_CHANNEL) = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_16 | DMAC_DCMD_DS_16BIT;
|
||||
break;
|
||||
case 32:
|
||||
REG_MDMAC_DTCR(MDMA_CHANNEL) = len / 4;
|
||||
REG_MDMAC_DCMD(MDMA_CHANNEL) = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BIT;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
REG_MDMAC_DCCSR(MDMA_CHANNEL) = DMAC_DCCSR_EN | DMAC_DCCSR_NDES;
|
||||
|
||||
while (REG_MDMAC_DTCR(MDMA_CHANNEL));
|
||||
|
||||
REG_MDMAC_DCCSR(MDMA_CHANNEL) = 0;
|
||||
}
|
||||
355
firmware/target/mips/ingenic_jz47xx/i2c-jz4760.c
Normal file
355
firmware/target/mips/ingenic_jz47xx/i2c-jz4760.c
Normal file
|
|
@ -0,0 +1,355 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2016 by Roman Stolyarov
|
||||
*
|
||||
* 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 "system.h"
|
||||
#include "cpu.h"
|
||||
#include "logf.h"
|
||||
#include "i2c.h"
|
||||
|
||||
#define I2C_CHN 1
|
||||
#define I2C_CLK 100000
|
||||
|
||||
#define I2C_READ 1
|
||||
#define I2C_WRITE 0
|
||||
|
||||
#define I2C_M_RD 1
|
||||
#define I2C_M_WR 2
|
||||
|
||||
#define TIMEOUT 100000
|
||||
|
||||
static char i2c_rwflags;
|
||||
static int i2c_ctrl_rest = 0;
|
||||
static unsigned char *msg_buf;
|
||||
static int cmd_cnt;
|
||||
static volatile int cmd_flag;
|
||||
static int r_cnt;
|
||||
static unsigned char i2c_subaddr = 0;
|
||||
|
||||
/*
|
||||
* I2C bus protocol basic routines
|
||||
*/
|
||||
|
||||
/* Interrupt handler */
|
||||
void I2C1(void)
|
||||
{
|
||||
int timeout = TIMEOUT;
|
||||
|
||||
if (__i2c_abrt_7b_addr_nack(I2C_CHN)) {
|
||||
int ret;
|
||||
cmd_flag = -1;
|
||||
__i2c_clear_interrupts(ret,I2C_CHN);
|
||||
REG_I2C_INTM(I2C_CHN) = 0x0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* first byte,when length > 1 */
|
||||
if (cmd_flag == 0 && cmd_cnt > 1) {
|
||||
cmd_flag = 1;
|
||||
if (i2c_rwflags == I2C_M_RD) {
|
||||
REG_I2C_DC(I2C_CHN) = I2C_READ << 8;
|
||||
} else {
|
||||
REG_I2C_DC(I2C_CHN) = (I2C_WRITE << 8) | *msg_buf++;
|
||||
}
|
||||
cmd_cnt--;
|
||||
}
|
||||
|
||||
if (i2c_rwflags == I2C_M_RD) {
|
||||
if (REG_I2C_STA(I2C_CHN) & I2C_STA_RFNE) {
|
||||
*msg_buf++ = REG_I2C_DC(I2C_CHN) & 0xff;
|
||||
r_cnt--;
|
||||
}
|
||||
|
||||
REG_I2C_DC(I2C_CHN) = I2C_READ << 8;
|
||||
} else {
|
||||
REG_I2C_DC(I2C_CHN) = (I2C_WRITE << 8) | *msg_buf++;
|
||||
}
|
||||
|
||||
cmd_cnt--;
|
||||
|
||||
if (!(cmd_cnt)) {
|
||||
REG_I2C_INTM(I2C_CHN) = 0x0;
|
||||
cmd_flag = 2;
|
||||
if (i2c_rwflags == I2C_M_RD){
|
||||
while (r_cnt > 2) {
|
||||
if ((REG_I2C_STA(I2C_CHN) & I2C_STA_RFNE) && timeout) {
|
||||
*msg_buf++ = REG_I2C_DC(I2C_CHN) & 0xff;
|
||||
r_cnt--;
|
||||
}
|
||||
if (!(timeout--)) {
|
||||
cmd_flag = -1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int i2c_set_clk(int i2c_clk)
|
||||
{
|
||||
int dev_clk = __cpm_get_pclk();
|
||||
int count = 0;
|
||||
|
||||
if (i2c_clk < 0 || i2c_clk > 400000)
|
||||
goto Set_clk_err;
|
||||
|
||||
count = dev_clk/i2c_clk - 23;
|
||||
if (count < 0)
|
||||
goto Set_clk_err;
|
||||
|
||||
if (i2c_clk <= 100000) {
|
||||
REG_I2C_CTRL(I2C_CHN) = 0x43 | i2c_ctrl_rest; /* standard speed mode*/
|
||||
if (count%2 == 0) {
|
||||
REG_I2C_SHCNT(I2C_CHN) = count/2 + 6 - 5;
|
||||
REG_I2C_SLCNT(I2C_CHN) = count/2 + 8 + 5;
|
||||
} else {
|
||||
REG_I2C_SHCNT(I2C_CHN) = count/2 + 6 -5;
|
||||
REG_I2C_SLCNT(I2C_CHN) = count/2 + 8 +5 + 1;
|
||||
}
|
||||
} else {
|
||||
REG_I2C_CTRL(I2C_CHN) = 0x45 | i2c_ctrl_rest; /* high speed mode*/
|
||||
if (count%2 == 0) {
|
||||
REG_I2C_FHCNT(I2C_CHN) = count/2 + 6;
|
||||
REG_I2C_FLCNT(I2C_CHN) = count/2 + 8;
|
||||
} else {
|
||||
REG_I2C_FHCNT(I2C_CHN) = count/2 + 6;
|
||||
REG_I2C_FLCNT(I2C_CHN) = count/2 + 8 + 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
Set_clk_err:
|
||||
|
||||
logf("i2c set sclk faild,i2c_clk=%d,dev_clk=%d.\n",i2c_clk,dev_clk);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int i2c_disable(void)
|
||||
{
|
||||
int timeout = TIMEOUT;
|
||||
|
||||
__i2c_disable(I2C_CHN);
|
||||
while(__i2c_is_enable(I2C_CHN) && (timeout > 0)) {
|
||||
udelay(1);
|
||||
timeout--;
|
||||
}
|
||||
if(timeout)
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int i2c_enable(void)
|
||||
{
|
||||
int timeout = TIMEOUT;
|
||||
|
||||
__i2c_enable(I2C_CHN);
|
||||
while(__i2c_is_disable(I2C_CHN) && (timeout > 0)) {
|
||||
udelay(1);
|
||||
timeout--;
|
||||
}
|
||||
if(timeout)
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void i2c_init_as_master(unsigned char address)
|
||||
{
|
||||
if(i2c_disable())
|
||||
logf("i2c not disable\n");
|
||||
|
||||
i2c_set_clk(I2C_CLK);
|
||||
|
||||
REG_I2C_TAR(I2C_CHN) = address; /* slave id needed write only once */
|
||||
REG_I2C_INTM(I2C_CHN) = 0x0; /* unmask all interrupts */
|
||||
REG_I2C_TXTL(I2C_CHN) = 0x1;
|
||||
|
||||
if(i2c_enable())
|
||||
logf("i2c not enable\n");
|
||||
}
|
||||
|
||||
int xfer_read_subaddr(unsigned char subaddr, unsigned char device, unsigned char *buf, int length)
|
||||
{
|
||||
int timeout,r_i = 0;
|
||||
|
||||
cmd_cnt = length;
|
||||
r_cnt = length;
|
||||
msg_buf = buf;
|
||||
i2c_rwflags = I2C_M_RD;
|
||||
i2c_ctrl_rest = I2C_CTRL_REST;
|
||||
i2c_init_as_master(device);
|
||||
|
||||
REG_I2C_DC(I2C_CHN) = (I2C_WRITE << 8) | subaddr;
|
||||
|
||||
cmd_flag = 0;
|
||||
REG_I2C_INTM(I2C_CHN) = 0x10;
|
||||
timeout = TIMEOUT;
|
||||
while (cmd_flag != 2 && --timeout) {
|
||||
if (cmd_flag == -1) {
|
||||
r_i = 1;
|
||||
goto R_dev_err;
|
||||
}
|
||||
udelay(10);
|
||||
}
|
||||
if (!timeout) {
|
||||
r_i = 4;
|
||||
goto R_timeout;
|
||||
}
|
||||
|
||||
while (r_cnt) {
|
||||
while (!(REG_I2C_STA(I2C_CHN) & I2C_STA_RFNE)) {
|
||||
if ((cmd_flag == -1) ||
|
||||
(REG_I2C_INTST(I2C_CHN) & I2C_INTST_TXABT) ||
|
||||
REG_I2C_TXABRT(I2C_CHN)) {
|
||||
int ret;
|
||||
r_i = 2;
|
||||
__i2c_clear_interrupts(ret,I2C_CHN);
|
||||
goto R_dev_err;
|
||||
}
|
||||
}
|
||||
*msg_buf++ = REG_I2C_DC(I2C_CHN) & 0xff;
|
||||
r_cnt--;
|
||||
}
|
||||
|
||||
timeout = TIMEOUT;
|
||||
while ((REG_I2C_STA(I2C_CHN) & I2C_STA_MSTACT) && --timeout)
|
||||
udelay(10);
|
||||
if (!timeout){
|
||||
r_i = 3;
|
||||
goto R_timeout;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
R_dev_err:
|
||||
R_timeout:
|
||||
|
||||
i2c_init_as_master(device);
|
||||
if (r_i == 1) {
|
||||
logf("Read i2c device 0x%2x failed in r_i = %d :device no ack.\n",device,r_i);
|
||||
} else if (r_i == 2) {
|
||||
logf("Read i2c device 0x%2x failed in r_i = %d :i2c abort.\n",device,r_i);
|
||||
} else if (r_i == 3) {
|
||||
logf("Read i2c device 0x%2x failed in r_i = %d :waite master inactive timeout.\n",device,r_i);
|
||||
} else if (r_i == 4) {
|
||||
logf("Read i2c device 0x%2x failed in r_i = %d.\n",device,r_i);
|
||||
} else {
|
||||
logf("Read i2c device 0x%2x failed in r_i = %d.\n",device,r_i);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int xfer_write_subaddr(unsigned char subaddr, unsigned char device, const unsigned char *buf, int length)
|
||||
{
|
||||
int timeout,w_i = 0;
|
||||
|
||||
cmd_cnt = length;
|
||||
r_cnt = length;
|
||||
msg_buf = (unsigned char *)buf;
|
||||
i2c_rwflags = I2C_M_WR;
|
||||
i2c_ctrl_rest = I2C_CTRL_REST;
|
||||
i2c_init_as_master(device);
|
||||
|
||||
REG_I2C_DC(I2C_CHN) = (I2C_WRITE << 8) | subaddr;
|
||||
|
||||
cmd_flag = 0;
|
||||
REG_I2C_INTM(I2C_CHN) = 0x10;
|
||||
|
||||
timeout = TIMEOUT;
|
||||
while ((cmd_flag != 2) && (--timeout))
|
||||
{
|
||||
if (cmd_flag == -1){
|
||||
w_i = 1;
|
||||
goto W_dev_err;
|
||||
}
|
||||
udelay(10);
|
||||
}
|
||||
|
||||
timeout = TIMEOUT;
|
||||
while((!(REG_I2C_STA(I2C_CHN) & I2C_STA_TFE)) && --timeout){
|
||||
udelay(10);
|
||||
}
|
||||
if (!timeout){
|
||||
w_i = 2;
|
||||
goto W_timeout;
|
||||
}
|
||||
|
||||
timeout = TIMEOUT;
|
||||
while (__i2c_master_active(I2C_CHN) && --timeout);
|
||||
if (!timeout){
|
||||
w_i = 3;
|
||||
goto W_timeout;
|
||||
}
|
||||
|
||||
if ((length == 1)&&
|
||||
((cmd_flag == -1) ||
|
||||
(REG_I2C_INTST(I2C_CHN) & I2C_INTST_TXABT) ||
|
||||
REG_I2C_TXABRT(I2C_CHN))) {
|
||||
int ret;
|
||||
w_i = 5;
|
||||
__i2c_clear_interrupts(ret,I2C_CHN);
|
||||
goto W_dev_err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
W_dev_err:
|
||||
W_timeout:
|
||||
|
||||
i2c_init_as_master(device);
|
||||
if (w_i == 1) {
|
||||
logf("Write i2c device 0x%2x failed in w_i=%d:device no ack. I2C_CHN:[%d]sxyzhang\n",device,w_i,I2C_CHN);
|
||||
} else if (w_i == 2) {
|
||||
logf("Write i2c device 0x%2x failed in w_i=%d:waite TF buff empty timeout.\n",device,w_i);
|
||||
} else if (w_i == 3) {
|
||||
logf("Write i2c device 0x%2x failed in w_i=%d:waite master inactive timeout.\n",device,w_i);
|
||||
} else if (w_i == 5) {
|
||||
logf("Write i2c device 0x%2x failed in w_i=%d:device no ack or abort.I2C_CHN:[%d]sxyzhang \n",device,w_i,I2C_CHN);
|
||||
} else {
|
||||
logf("Write i2c device 0x%2x failed in w_i=%d.\n",device,w_i);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int i2c_read(int device, unsigned char* buf, int count)
|
||||
{
|
||||
return xfer_read_subaddr(i2c_subaddr, device, &buf[0], count);
|
||||
}
|
||||
|
||||
int i2c_write(int device, const unsigned char* buf, int count)
|
||||
{
|
||||
if (count < 2)
|
||||
{
|
||||
i2c_subaddr = buf[0];
|
||||
return 0;
|
||||
}
|
||||
return xfer_write_subaddr(buf[0], device, &buf[1], count-1);
|
||||
}
|
||||
|
||||
void i2c_init(void)
|
||||
{
|
||||
__gpio_as_i2c(I2C_CHN);
|
||||
__cpm_start_i2c1();
|
||||
system_enable_irq(IRQ_I2C1);
|
||||
}
|
||||
53
firmware/target/mips/ingenic_jz47xx/kernel-jz4760.c
Normal file
53
firmware/target/mips/ingenic_jz47xx/kernel-jz4760.c
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2016 by Roman Stolyarov
|
||||
*
|
||||
* 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 "system.h"
|
||||
#include "kernel.h"
|
||||
#include "cpu.h"
|
||||
|
||||
void tick_start(unsigned int interval_in_ms)
|
||||
{
|
||||
unsigned int latch;
|
||||
|
||||
/* 12Mhz / 4 = 3Mhz */
|
||||
latch = interval_in_ms*1000 * 3;
|
||||
|
||||
REG_OST_OSTCSR = OSTCSR_PRESCALE4 | OSTCSR_EXT_EN;
|
||||
REG_OST_OSTDR = latch;
|
||||
REG_OST_OSTCNTL = 0;
|
||||
REG_OST_OSTCNTH = 0;
|
||||
|
||||
system_enable_irq(IRQ_TCU0);
|
||||
|
||||
REG_TCU_TMCR = TMCR_OSTMASK; /* unmask match irq */
|
||||
REG_TCU_TSCR = TSCR_OST; /* enable timer clock */
|
||||
REG_TCU_TESR = TESR_OST; /* start counting up */
|
||||
}
|
||||
|
||||
/* Interrupt handler */
|
||||
void TCU0(void)
|
||||
{
|
||||
REG_TCU_TFCR = TFCR_OSTFLAG; /* ACK timer */
|
||||
|
||||
/* Run through the list of tick tasks */
|
||||
call_tick_tasks();
|
||||
}
|
||||
28
firmware/target/mips/ingenic_jz47xx/lcd-jz4760.c
Normal file
28
firmware/target/mips/ingenic_jz47xx/lcd-jz4760.c
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2016 by Roman Stolyarov
|
||||
*
|
||||
* 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 <sys/types.h> /* off_t */
|
||||
|
||||
#include "config.h"
|
||||
#include "cpu.h"
|
||||
#include "lcd.h"
|
||||
#include "lcd-target.h"
|
||||
#include "system.h"
|
||||
#include "kernel.h"
|
||||
240
firmware/target/mips/ingenic_jz47xx/pcm-jz4760.c
Normal file
240
firmware/target/mips/ingenic_jz47xx/pcm-jz4760.c
Normal file
|
|
@ -0,0 +1,240 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2016 by Roman Stolyarov
|
||||
*
|
||||
* 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 "pcm-internal.h"
|
||||
#include "cpu.h"
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
** Playback DMA transfer
|
||||
**/
|
||||
|
||||
void pcm_play_dma_postinit(void)
|
||||
{
|
||||
audiohw_postinit();
|
||||
|
||||
/* Flush FIFO */
|
||||
__aic_flush_tfifo();
|
||||
}
|
||||
|
||||
void pcm_play_dma_init(void)
|
||||
{
|
||||
system_enable_irq(DMA_IRQ(DMA_AIC_TX_CHANNEL));
|
||||
|
||||
/* Initialize default register values. */
|
||||
audiohw_init();
|
||||
}
|
||||
|
||||
void pcm_dma_apply_settings(void)
|
||||
{
|
||||
audiohw_set_frequency(pcm_fsel);
|
||||
}
|
||||
|
||||
static const void* playback_address;
|
||||
static inline void set_dma(const void *addr, size_t size)
|
||||
{
|
||||
int burst_size;
|
||||
logf("%x %d %x", (unsigned int)addr, size, REG_AIC_SR);
|
||||
|
||||
dma_cache_wback_inv((unsigned long)addr, size);
|
||||
|
||||
if(size % 16)
|
||||
{
|
||||
if(size % 4)
|
||||
{
|
||||
size /= 2;
|
||||
burst_size = DMAC_DCMD_DS_16BIT;
|
||||
}
|
||||
else
|
||||
{
|
||||
size /= 4;
|
||||
burst_size = DMAC_DCMD_DS_32BIT;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
size /= 16;
|
||||
burst_size = DMAC_DCMD_DS_16BYTE;
|
||||
}
|
||||
|
||||
REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) = 0;
|
||||
REG_DMAC_DSAR(DMA_AIC_TX_CHANNEL) = PHYSADDR((unsigned long)addr);
|
||||
REG_DMAC_DTAR(DMA_AIC_TX_CHANNEL) = PHYSADDR((unsigned long)AIC_DR);
|
||||
REG_DMAC_DTCR(DMA_AIC_TX_CHANNEL) = size;
|
||||
REG_DMAC_DRSR(DMA_AIC_TX_CHANNEL) = DMAC_DRSR_RS_AICOUT;
|
||||
REG_DMAC_DCMD(DMA_AIC_TX_CHANNEL) = (DMAC_DCMD_SAI | DMAC_DCMD_SWDH_32 | burst_size | DMAC_DCMD_DWDH_16 | DMAC_DCMD_TIE);
|
||||
REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) = DMAC_DCCSR_NDES | DMAC_DCCSR_EN;
|
||||
|
||||
playback_address = addr;
|
||||
}
|
||||
|
||||
static inline void play_dma_callback(void)
|
||||
{
|
||||
const void *start;
|
||||
size_t size;
|
||||
|
||||
if (pcm_play_dma_complete_callback(PCM_DMAST_OK, &start, &size))
|
||||
{
|
||||
set_dma(start, size);
|
||||
REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) |= DMAC_DCCSR_EN;
|
||||
pcm_play_dma_status_callback(PCM_DMAST_STARTED);
|
||||
}
|
||||
}
|
||||
|
||||
void DMA_CALLBACK(DMA_AIC_TX_CHANNEL)(void) __attribute__ ((section(".icode")));
|
||||
void DMA_CALLBACK(DMA_AIC_TX_CHANNEL)(void)
|
||||
{
|
||||
if (REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) & DMAC_DCCSR_AR)
|
||||
{
|
||||
logf("PCM DMA address error");
|
||||
REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) &= ~DMAC_DCCSR_AR;
|
||||
}
|
||||
|
||||
if (REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) & DMAC_DCCSR_HLT)
|
||||
{
|
||||
logf("PCM DMA halt");
|
||||
REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) &= ~DMAC_DCCSR_HLT;
|
||||
}
|
||||
|
||||
if (REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) & DMAC_DCCSR_TT)
|
||||
{
|
||||
REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) &= ~DMAC_DCCSR_TT;
|
||||
play_dma_callback();
|
||||
}
|
||||
}
|
||||
|
||||
void pcm_play_dma_start(const void *addr, size_t size)
|
||||
{
|
||||
__dmac_channel_enable_clk(DMA_AIC_TX_CHANNEL);
|
||||
|
||||
set_dma(addr, size);
|
||||
|
||||
__aic_enable_replay();
|
||||
|
||||
__dmac_channel_enable_irq(DMA_AIC_TX_CHANNEL);
|
||||
}
|
||||
|
||||
void pcm_play_dma_stop(void)
|
||||
{
|
||||
int flags = disable_irq_save();
|
||||
|
||||
REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) = (REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) | DMAC_DCCSR_HLT) & ~DMAC_DCCSR_EN;
|
||||
|
||||
__dmac_channel_disable_clk(DMA_AIC_TX_CHANNEL);
|
||||
|
||||
__aic_disable_replay();
|
||||
|
||||
restore_irq(flags);
|
||||
}
|
||||
|
||||
static unsigned int play_lock = 0;
|
||||
void pcm_play_lock(void)
|
||||
{
|
||||
int flags = disable_irq_save();
|
||||
|
||||
if (++play_lock == 1)
|
||||
__dmac_channel_disable_irq(DMA_AIC_TX_CHANNEL);
|
||||
|
||||
restore_irq(flags);
|
||||
}
|
||||
|
||||
void pcm_play_unlock(void)
|
||||
{
|
||||
int flags = disable_irq_save();
|
||||
|
||||
if (--play_lock == 0)
|
||||
__dmac_channel_enable_irq(DMA_AIC_TX_CHANNEL);
|
||||
|
||||
restore_irq(flags);
|
||||
}
|
||||
|
||||
void pcm_play_dma_pause(bool pause)
|
||||
{
|
||||
int flags = disable_irq_save();
|
||||
|
||||
if(pause)
|
||||
REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) &= ~DMAC_DCCSR_EN;
|
||||
else
|
||||
REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) |= DMAC_DCCSR_EN;
|
||||
|
||||
restore_irq(flags);
|
||||
}
|
||||
|
||||
static int get_dma_count(void)
|
||||
{
|
||||
int count = REG_DMAC_DTCR(DMA_AIC_TX_CHANNEL);
|
||||
switch(REG_DMAC_DCMD(DMA_AIC_TX_CHANNEL) & DMAC_DCMD_DS_MASK)
|
||||
{
|
||||
case DMAC_DCMD_DS_16BIT:
|
||||
count *= 2;
|
||||
break;
|
||||
case DMAC_DCMD_DS_32BIT:
|
||||
count *= 4;
|
||||
break;
|
||||
case DMAC_DCMD_DS_16BYTE:
|
||||
count *= 16;
|
||||
break;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
size_t pcm_get_bytes_waiting(void)
|
||||
{
|
||||
int bytes, flags = disable_irq_save();
|
||||
|
||||
if(REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) & DMAC_DCCSR_EN)
|
||||
bytes = get_dma_count() & ~3;
|
||||
else
|
||||
bytes = 0;
|
||||
|
||||
restore_irq(flags);
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
const void * pcm_play_dma_get_peak_buffer(int *count)
|
||||
{
|
||||
int flags = disable_irq_save();
|
||||
|
||||
const void* addr;
|
||||
if(REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) & DMAC_DCCSR_EN)
|
||||
{
|
||||
int bytes = get_dma_count();
|
||||
*count = bytes >> 2;
|
||||
addr = (const void*)((int)(playback_address + bytes + 2) & ~3);
|
||||
}
|
||||
else
|
||||
{
|
||||
*count = 0;
|
||||
addr = NULL;
|
||||
}
|
||||
|
||||
restore_irq(flags);
|
||||
|
||||
return addr;
|
||||
}
|
||||
710
firmware/target/mips/ingenic_jz47xx/system-jz4760.c
Normal file
710
firmware/target/mips/ingenic_jz47xx/system-jz4760.c
Normal file
|
|
@ -0,0 +1,710 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2016 by Roman Stolyarov
|
||||
*
|
||||
* 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 "cpu.h"
|
||||
#include "mips.h"
|
||||
#include "mmu-mips.h"
|
||||
#include "panic.h"
|
||||
#include "system.h"
|
||||
#include "kernel.h"
|
||||
#include "power.h"
|
||||
|
||||
static int irq;
|
||||
static void UIRQ(void)
|
||||
{
|
||||
panicf("Unhandled interrupt occurred: %d", irq);
|
||||
}
|
||||
|
||||
#define intr(name) extern __attribute__((weak,alias("UIRQ"))) void name (void)
|
||||
|
||||
intr(I2C1);intr(I2C0);intr(UART3);intr(UART2);intr(UART1);intr(UART0);intr(GPU);
|
||||
intr(SSI1);intr(SSI0);intr(TSSI);intr(KBC);intr(SADC);intr(ETH);intr(UHC);
|
||||
intr(OTG);intr(TCU2);intr(TCU1);intr(TCU0);intr(GPS);intr(IPU);intr(CIM);
|
||||
intr(LCD);intr(RTC);intr(OWI);intr(AIC);intr(MSC2);intr(MSC1);intr(MSC0);
|
||||
intr(SCC);intr(BCH);intr(PCM);intr(HARB0);intr(HARB2);intr(AOSD);intr(CPM);
|
||||
|
||||
intr(DMA0);intr(DMA1);intr(DMA2);intr(DMA3);intr(DMA4);intr(DMA5);
|
||||
intr(DMA6);intr(DMA7);intr(DMA8);intr(DMA9);intr(DMA10);intr(DMA11);
|
||||
intr(MDMA0);intr(MDMA1);intr(MDMA2);
|
||||
intr(BDMA0);intr(BDMA1);intr(BDMA2);
|
||||
|
||||
intr(GPIO0);intr(GPIO1);intr(GPIO2);intr(GPIO3);intr(GPIO4);intr(GPIO5);
|
||||
intr(GPIO6);intr(GPIO7);intr(GPIO8);intr(GPIO9);intr(GPIO10);intr(GPIO11);
|
||||
intr(GPIO12);intr(GPIO13);intr(GPIO14);intr(GPIO15);intr(GPIO16);intr(GPIO17);
|
||||
intr(GPIO18);intr(GPIO19);intr(GPIO20);intr(GPIO21);intr(GPIO22);intr(GPIO23);
|
||||
intr(GPIO24);intr(GPIO25);intr(GPIO26);intr(GPIO27);intr(GPIO28);intr(GPIO29);
|
||||
intr(GPIO30);intr(GPIO31);intr(GPIO32);intr(GPIO33);intr(GPIO34);intr(GPIO35);
|
||||
intr(GPIO36);intr(GPIO37);intr(GPIO38);intr(GPIO39);intr(GPIO40);intr(GPIO41);
|
||||
intr(GPIO42);intr(GPIO43);intr(GPIO44);intr(GPIO45);intr(GPIO46);intr(GPIO47);
|
||||
intr(GPIO48);intr(GPIO49);intr(GPIO50);intr(GPIO51);intr(GPIO52);intr(GPIO53);
|
||||
intr(GPIO54);intr(GPIO55);intr(GPIO56);intr(GPIO57);intr(GPIO58);intr(GPIO59);
|
||||
intr(GPIO60);intr(GPIO61);intr(GPIO62);intr(GPIO63);intr(GPIO64);intr(GPIO65);
|
||||
intr(GPIO66);intr(GPIO67);intr(GPIO68);intr(GPIO69);intr(GPIO70);intr(GPIO71);
|
||||
intr(GPIO72);intr(GPIO73);intr(GPIO74);intr(GPIO75);intr(GPIO76);intr(GPIO77);
|
||||
intr(GPIO78);intr(GPIO79);intr(GPIO80);intr(GPIO81);intr(GPIO82);intr(GPIO83);
|
||||
intr(GPIO84);intr(GPIO85);intr(GPIO86);intr(GPIO87);intr(GPIO88);intr(GPIO89);
|
||||
intr(GPIO90);intr(GPIO91);intr(GPIO92);intr(GPIO93);intr(GPIO94);intr(GPIO95);
|
||||
intr(GPIO96);intr(GPIO97);intr(GPIO98);intr(GPIO99);intr(GPIO100);intr(GPIO101);
|
||||
intr(GPIO102);intr(GPIO103);intr(GPIO104);intr(GPIO105);intr(GPIO106);
|
||||
intr(GPIO107);intr(GPIO108);intr(GPIO109);intr(GPIO110);intr(GPIO111);
|
||||
intr(GPIO112);intr(GPIO113);intr(GPIO114);intr(GPIO115);intr(GPIO116);
|
||||
intr(GPIO117);intr(GPIO118);intr(GPIO119);intr(GPIO120);intr(GPIO121);
|
||||
intr(GPIO122);intr(GPIO123);intr(GPIO124);intr(GPIO125);intr(GPIO126);
|
||||
intr(GPIO127);intr(GPIO128);intr(GPIO129);intr(GPIO130);intr(GPIO131);
|
||||
intr(GPIO132);intr(GPIO133);intr(GPIO134);intr(GPIO135);intr(GPIO136);
|
||||
intr(GPIO137);intr(GPIO138);intr(GPIO139);intr(GPIO140);intr(GPIO141);
|
||||
intr(GPIO142);intr(GPIO143);intr(GPIO144);intr(GPIO145);intr(GPIO146);
|
||||
intr(GPIO147);intr(GPIO148);intr(GPIO149);intr(GPIO150);intr(GPIO151);
|
||||
intr(GPIO152);intr(GPIO153);intr(GPIO154);intr(GPIO155);intr(GPIO156);
|
||||
intr(GPIO157);intr(GPIO158);intr(GPIO159);intr(GPIO160);intr(GPIO161);
|
||||
intr(GPIO162);intr(GPIO163);intr(GPIO164);intr(GPIO165);intr(GPIO166);
|
||||
intr(GPIO167);intr(GPIO168);intr(GPIO169);intr(GPIO170);intr(GPIO171);
|
||||
intr(GPIO172);intr(GPIO173);intr(GPIO174);intr(GPIO175);intr(GPIO176);
|
||||
intr(GPIO177);intr(GPIO178);intr(GPIO179);intr(GPIO180);intr(GPIO181);
|
||||
intr(GPIO182);intr(GPIO183);intr(GPIO184);intr(GPIO185);intr(GPIO186);
|
||||
intr(GPIO187);intr(GPIO188);intr(GPIO189);intr(GPIO190);intr(GPIO191);
|
||||
|
||||
static void (* const irqvector[])(void) =
|
||||
{
|
||||
I2C1,I2C0,UART3,UART2,UART1,UART0,GPU,SSI1,
|
||||
SSI0,TSSI,UIRQ,KBC,UIRQ,UIRQ,UIRQ,UIRQ,
|
||||
UIRQ,UIRQ,SADC,ETH,UHC,OTG,UIRQ,UIRQ,
|
||||
UIRQ,TCU2,TCU1,TCU0,GPS,IPU,CIM,LCD,
|
||||
|
||||
RTC,OWI,AIC,MSC2,MSC1,MSC0,SCC,BCH, // 32
|
||||
PCM,HARB0,HARB2,AOSD,CPM,UIRQ,
|
||||
|
||||
DMA0,DMA1,DMA2,DMA3,DMA4,DMA5,DMA6,DMA7, // 46
|
||||
DMA8,DMA9,DMA10,DMA11,MDMA0,MDMA1,MDMA2,BDMA0,
|
||||
BDMA1,BDMA2,
|
||||
|
||||
GPIO0,GPIO1,GPIO2,GPIO3,GPIO4,GPIO5,GPIO6,GPIO7, // 64
|
||||
GPIO8,GPIO9,GPIO10,GPIO11,GPIO12,GPIO13,GPIO14,GPIO15,
|
||||
GPIO16,GPIO17,GPIO18,GPIO19,GPIO20,GPIO21,GPIO22,GPIO23,
|
||||
GPIO24,GPIO25,GPIO26,GPIO27,GPIO28,GPIO29,GPIO30,GPIO31,
|
||||
GPIO32,GPIO33,GPIO34,GPIO35,GPIO36,GPIO37,GPIO38,GPIO39,
|
||||
GPIO40,GPIO41,GPIO42,GPIO43,GPIO44,GPIO45,GPIO46,GPIO47,
|
||||
GPIO48,GPIO49,GPIO50,GPIO51,GPIO52,GPIO53,GPIO54,GPIO55,
|
||||
GPIO56,GPIO57,GPIO58,GPIO59,GPIO60,GPIO61,GPIO62,GPIO63,
|
||||
GPIO64,GPIO65,GPIO66,GPIO67,GPIO68,GPIO69,GPIO70,GPIO71,
|
||||
GPIO72,GPIO73,GPIO74,GPIO75,GPIO76,GPIO77,GPIO78,GPIO79,
|
||||
GPIO80,GPIO81,GPIO82,GPIO83,GPIO84,GPIO85,GPIO86,GPIO87,
|
||||
GPIO88,GPIO89,GPIO90,GPIO91,GPIO92,GPIO93,GPIO94,GPIO95,
|
||||
GPIO96,GPIO97,GPIO98,GPIO99,GPIO100,GPIO101,GPIO102,GPIO103,
|
||||
GPIO104,GPIO105,GPIO106,GPIO107,GPIO108,GPIO109,GPIO110,GPIO111,
|
||||
GPIO112,GPIO113,GPIO114,GPIO115,GPIO116,GPIO117,GPIO118,GPIO119,
|
||||
GPIO120,GPIO121,GPIO122,GPIO123,GPIO124,GPIO125,GPIO126,GPIO127,
|
||||
GPIO128,GPIO129,GPIO130,GPIO131,GPIO132,GPIO133,GPIO134,GPIO135,
|
||||
GPIO136,GPIO137,GPIO138,GPIO139,GPIO140,GPIO141,GPIO142,GPIO143,
|
||||
GPIO144,GPIO145,GPIO146,GPIO147,GPIO148,GPIO149,GPIO150,GPIO151,
|
||||
GPIO152,GPIO153,GPIO154,GPIO155,GPIO156,GPIO157,GPIO158,GPIO159,
|
||||
GPIO160,GPIO161,GPIO162,GPIO163,GPIO164,GPIO165,GPIO166,GPIO167,
|
||||
GPIO168,GPIO169,GPIO170,GPIO171,GPIO172,GPIO173,GPIO174,GPIO175,
|
||||
GPIO176,GPIO177,GPIO178,GPIO179,GPIO180,GPIO181,GPIO182,GPIO183,
|
||||
GPIO184,GPIO185,GPIO186,GPIO187,GPIO188,GPIO189,GPIO190,GPIO191
|
||||
};
|
||||
|
||||
static unsigned int dma_irq_mask = 0;
|
||||
static unsigned char mdma_irq_mask = 0;
|
||||
static unsigned char bdma_irq_mask = 0;
|
||||
static unsigned int gpio_irq_mask[6] = {0};
|
||||
|
||||
void system_enable_irq(unsigned int irq)
|
||||
{
|
||||
register unsigned int t;
|
||||
if ((irq >= IRQ_GPIO_0) && (irq <= IRQ_GPIO_0 + NUM_GPIO))
|
||||
{
|
||||
__gpio_unmask_irq(irq - IRQ_GPIO_0);
|
||||
t = (irq - IRQ_GPIO_0) >> 5;
|
||||
gpio_irq_mask[t] |= (1 << ((irq - IRQ_GPIO_0) & 0x1f));
|
||||
__intc_unmask_irq(IRQ_GPIO0 - t);
|
||||
}
|
||||
else if ((irq >= IRQ_DMA_0) && (irq <= IRQ_DMA_0 + NUM_DMA))
|
||||
{
|
||||
__dmac_channel_enable_irq(irq - IRQ_DMA_0);
|
||||
t = (irq - IRQ_DMA_0) / HALF_DMA_NUM;
|
||||
dma_irq_mask |= (1 << (irq - IRQ_DMA_0));
|
||||
__intc_unmask_irq(IRQ_DMAC0 - t);
|
||||
}
|
||||
else if ((irq >= IRQ_MDMA_0) && (irq <= IRQ_MDMA_0 + NUM_MDMA))
|
||||
{
|
||||
__mdmac_channel_enable_irq(irq - IRQ_MDMA_0);
|
||||
mdma_irq_mask |= (1 << (irq - IRQ_MDMA_0));
|
||||
__intc_unmask_irq(IRQ_MDMA);
|
||||
}
|
||||
else if ((irq >= IRQ_BDMA_0) && (irq <= IRQ_BDMA_0 + NUM_BDMA))
|
||||
{
|
||||
__bdmac_channel_enable_irq(irq - IRQ_BDMA_0);
|
||||
bdma_irq_mask |= (1 << (irq - IRQ_BDMA_0));
|
||||
__intc_unmask_irq(IRQ_BDMA);
|
||||
}
|
||||
else if (irq < IRQ_INTC_MAX)
|
||||
__intc_unmask_irq(irq);
|
||||
}
|
||||
|
||||
static void dis_irq(unsigned int irq)
|
||||
{
|
||||
register unsigned int t;
|
||||
if ((irq >= IRQ_GPIO_0) && (irq <= IRQ_GPIO_0 + NUM_GPIO))
|
||||
{
|
||||
__gpio_mask_irq(irq - IRQ_GPIO_0);
|
||||
t = (irq - IRQ_GPIO_0) >> 5;
|
||||
gpio_irq_mask[t] &= ~(1 << ((irq - IRQ_GPIO_0) & 0x1f));
|
||||
if (!gpio_irq_mask[t])
|
||||
__intc_mask_irq(IRQ_GPIO0 - t);
|
||||
}
|
||||
else if ((irq >= IRQ_DMA_0) && (irq < IRQ_DMA_0 + NUM_DMA))
|
||||
{
|
||||
__dmac_channel_disable_irq(irq - IRQ_DMA_0);
|
||||
dma_irq_mask &= ~(1 << (irq - IRQ_DMA_0));
|
||||
if (!(dma_irq_mask & 0x003F))
|
||||
__intc_mask_irq(IRQ_DMAC0);
|
||||
if (!(dma_irq_mask & 0x0FC0))
|
||||
__intc_mask_irq(IRQ_DMAC1);
|
||||
}
|
||||
else if ((irq >= IRQ_MDMA_0) && (irq < IRQ_MDMA_0 + NUM_MDMA))
|
||||
{
|
||||
__mdmac_channel_disable_irq(irq - IRQ_MDMA_0);
|
||||
mdma_irq_mask &= ~(1 << (irq - IRQ_MDMA_0));
|
||||
if (!mdma_irq_mask)
|
||||
__intc_mask_irq(IRQ_MDMA);
|
||||
}
|
||||
else if ((irq >= IRQ_BDMA_0) && (irq < IRQ_BDMA_0 + NUM_BDMA))
|
||||
{
|
||||
__bdmac_channel_disable_irq(irq - IRQ_BDMA_0);
|
||||
bdma_irq_mask &= ~(1 << (irq - IRQ_BDMA_0));
|
||||
if (!bdma_irq_mask)
|
||||
__intc_mask_irq(IRQ_BDMA);
|
||||
}
|
||||
else if (irq < IRQ_INTC_MAX)
|
||||
__intc_mask_irq(irq);
|
||||
}
|
||||
|
||||
static void ack_irq(unsigned int irq)
|
||||
{
|
||||
if ((irq >= IRQ_GPIO_0) && (irq <= IRQ_GPIO_0 + NUM_GPIO))
|
||||
{
|
||||
__gpio_ack_irq(irq - IRQ_GPIO_0);
|
||||
}
|
||||
}
|
||||
|
||||
static int get_irq_number(void)
|
||||
{
|
||||
static unsigned long ipl0, ipl1;
|
||||
register int irq0, irq1;
|
||||
|
||||
ipl0 |= REG_INTC_ICPR(0);
|
||||
ipl1 |= REG_INTC_ICPR(1);
|
||||
|
||||
if (!(ipl0 || ipl1))
|
||||
return -1;
|
||||
|
||||
__asm__ __volatile__("negu $8, %0 \n"
|
||||
"and $8, %0, $8 \n"
|
||||
"clz %0, %1 \n"
|
||||
"li $8, 31 \n"
|
||||
"subu %0, $8, %0 \n"
|
||||
: "=r" (irq0)
|
||||
: "r" (ipl0)
|
||||
: "t0"
|
||||
);
|
||||
|
||||
__asm__ __volatile__("negu $8, %0 \n"
|
||||
"and $8, %0, $8 \n"
|
||||
"clz %0, %1 \n"
|
||||
"li $8, 31 \n"
|
||||
"subu %0, $8, %0 \n"
|
||||
: "=r" (irq1)
|
||||
: "r" (ipl1)
|
||||
: "t0"
|
||||
);
|
||||
|
||||
if (UNLIKELY(irq0 < 0) && UNLIKELY(irq1 < 0))
|
||||
return -1;
|
||||
|
||||
if (!(ipl0 & 3)) {
|
||||
if (ipl0) {
|
||||
irq = irq0;
|
||||
ipl0 &= ~(1<<irq0);
|
||||
} else {
|
||||
irq = irq1 + 32;
|
||||
ipl1 &= ~(1<<irq1);
|
||||
}
|
||||
} else {
|
||||
if (ipl0 & 2) {
|
||||
irq = 1;
|
||||
ipl0 &= ~(1<<irq);
|
||||
} else {
|
||||
irq = 0;
|
||||
ipl0 &= ~(1<<irq);
|
||||
}
|
||||
}
|
||||
|
||||
switch (irq)
|
||||
{
|
||||
case IRQ_GPIO0:
|
||||
case IRQ_GPIO1:
|
||||
case IRQ_GPIO2:
|
||||
case IRQ_GPIO3:
|
||||
case IRQ_GPIO4:
|
||||
case IRQ_GPIO5:
|
||||
irq = __gpio_get_irq() + IRQ_GPIO_0;
|
||||
break;
|
||||
case IRQ_DMAC0:
|
||||
case IRQ_DMAC1:
|
||||
irq = __dmac_get_irq() + IRQ_DMA_0;
|
||||
break;
|
||||
case IRQ_MDMA:
|
||||
irq = __mdmac_get_irq() + IRQ_MDMA_0;
|
||||
break;
|
||||
case IRQ_BDMA:
|
||||
irq = __bdmac_get_irq() + IRQ_BDMA_0;
|
||||
break;
|
||||
}
|
||||
|
||||
return irq;
|
||||
}
|
||||
|
||||
void intr_handler(void)
|
||||
{
|
||||
register int irq = get_irq_number();
|
||||
if(UNLIKELY(irq < 0))
|
||||
return;
|
||||
|
||||
ack_irq(irq);
|
||||
if(LIKELY(irq >= 0))
|
||||
irqvector[irq]();
|
||||
}
|
||||
|
||||
#define EXC(x,y) case (x): return (y);
|
||||
static char* parse_exception(unsigned int cause)
|
||||
{
|
||||
switch(cause & M_CauseExcCode)
|
||||
{
|
||||
EXC(EXC_INT, "Interrupt");
|
||||
EXC(EXC_MOD, "TLB Modified");
|
||||
EXC(EXC_TLBL, "TLB Exception (Load or Ifetch)");
|
||||
EXC(EXC_ADEL, "Address Error (Load or Ifetch)");
|
||||
EXC(EXC_ADES, "Address Error (Store)");
|
||||
EXC(EXC_TLBS, "TLB Exception (Store)");
|
||||
EXC(EXC_IBE, "Instruction Bus Error");
|
||||
EXC(EXC_DBE, "Data Bus Error");
|
||||
EXC(EXC_SYS, "Syscall");
|
||||
EXC(EXC_BP, "Breakpoint");
|
||||
EXC(EXC_RI, "Reserved Instruction");
|
||||
EXC(EXC_CPU, "Coprocessor Unusable");
|
||||
EXC(EXC_OV, "Overflow");
|
||||
EXC(EXC_TR, "Trap Instruction");
|
||||
EXC(EXC_FPE, "Floating Point Exception");
|
||||
EXC(EXC_C2E, "COP2 Exception");
|
||||
EXC(EXC_MDMX, "MDMX Exception");
|
||||
EXC(EXC_WATCH, "Watch Exception");
|
||||
EXC(EXC_MCHECK, "Machine Check Exception");
|
||||
EXC(EXC_CacheErr, "Cache error caused re-entry to Debug Mode");
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void exception_handler(void* stack_ptr, unsigned int cause, unsigned int epc)
|
||||
{
|
||||
panicf("Exception occurred: %s [0x%08x] at 0x%08x (stack at 0x%08x)", parse_exception(cause), read_c0_badvaddr(), epc, (unsigned int)stack_ptr);
|
||||
}
|
||||
|
||||
void tlb_refill_handler(void)
|
||||
{
|
||||
panicf("TLB refill handler at 0x%08lx! [0x%x]", read_c0_epc(), read_c0_badvaddr());
|
||||
}
|
||||
|
||||
void udelay(unsigned int usec)
|
||||
{
|
||||
unsigned int i = usec * (__cpm_get_cclk() / 2000000);
|
||||
__asm__ __volatile__ (
|
||||
".set noreorder \n"
|
||||
"1: \n"
|
||||
"bne %0, $0, 1b \n"
|
||||
"addi %0, %0, -1 \n"
|
||||
".set reorder \n"
|
||||
: "=r" (i)
|
||||
: "0" (i)
|
||||
);
|
||||
}
|
||||
|
||||
void mdelay(unsigned int msec)
|
||||
{
|
||||
unsigned int i;
|
||||
for(i=0; i<msec; i++)
|
||||
udelay(1000);
|
||||
}
|
||||
|
||||
#define MHZ (1000 * 1000)
|
||||
static inline unsigned int pll_calc_m_n_od(unsigned int speed, unsigned int xtal)
|
||||
{
|
||||
const int pll_m_max = 0x7f, pll_m_min = 4;
|
||||
const int pll_n_max = 0x0f, pll_n_min = 2;
|
||||
|
||||
int od[] = {1, 2, 4, 8};
|
||||
|
||||
unsigned int plcr_m_n_od = 0;
|
||||
unsigned int distance;
|
||||
unsigned int tmp, raw;
|
||||
|
||||
int i, j, k;
|
||||
int m, n;
|
||||
|
||||
distance = 0xFFFFFFFF;
|
||||
|
||||
for (i = 0; i < (int)sizeof (od) / (int)sizeof(int); i++) {
|
||||
/* Limit: 500MHZ <= CLK_OUT * OD <= 1500MHZ */
|
||||
if ((speed * od[i]) < 500 * MHZ || (speed * od[i]) > 1500 * MHZ)
|
||||
continue;
|
||||
for (k = pll_n_min; k <= pll_n_max; k++) {
|
||||
n = k;
|
||||
|
||||
/* Limit: 1MHZ <= XIN/N <= 50MHZ */
|
||||
if ((xtal / n) < (1 * MHZ))
|
||||
break;
|
||||
if ((xtal / n) > (15 * MHZ))
|
||||
continue;
|
||||
|
||||
for (j = pll_m_min; j <= pll_m_max; j++) {
|
||||
m = j*2;
|
||||
|
||||
raw = xtal * m / n;
|
||||
tmp = raw / od[i];
|
||||
|
||||
tmp = (tmp > speed) ? (tmp - speed) : (speed - tmp);
|
||||
|
||||
if (tmp < distance) {
|
||||
distance = tmp;
|
||||
|
||||
plcr_m_n_od = (j << CPPCR0_PLLM_LSB)
|
||||
| (k << CPPCR0_PLLN_LSB)
|
||||
| (i << CPPCR0_PLLOD_LSB);
|
||||
|
||||
if (!distance) { /* Match. */
|
||||
return plcr_m_n_od;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return plcr_m_n_od;
|
||||
}
|
||||
|
||||
/* PLL output clock = EXTAL * NF / (NR * NO)
|
||||
*
|
||||
* NF = FD + 2, NR = RD + 2
|
||||
* NO = 1 (if OD = 0), NO = 2 (if OD = 1 or 2), NO = 4 (if OD = 3)
|
||||
*/
|
||||
static void pll0_init(unsigned int freq)
|
||||
{
|
||||
register unsigned int cfcr, plcr1;
|
||||
int n2FR[9] = {
|
||||
0, 0, 1, 2, 3, 0, 4, 0, 5
|
||||
};
|
||||
|
||||
/** divisors,
|
||||
* for jz4760b,I:H:H2:P:M:S.
|
||||
* DIV should be one of [1, 2, 3, 4, 6, 8]
|
||||
*/
|
||||
int div[6] = {1, 4, 4, 4, 4, 4};
|
||||
int usbdiv;
|
||||
|
||||
/* set ahb **/
|
||||
REG32(HARB0_BASE) = 0x00300000;
|
||||
REG32(0xb3070048) = 0x00000000;
|
||||
REG32(HARB2_BASE) = 0x00FFFFFF;
|
||||
|
||||
cfcr = CPCCR_PCS |
|
||||
(n2FR[div[0]] << CPCCR_CDIV_LSB) |
|
||||
(n2FR[div[1]] << CPCCR_HDIV_LSB) |
|
||||
(n2FR[div[2]] << CPCCR_H2DIV_LSB) |
|
||||
(n2FR[div[3]] << CPCCR_PDIV_LSB) |
|
||||
(n2FR[div[4]] << CPCCR_MDIV_LSB) |
|
||||
(n2FR[div[5]] << CPCCR_SDIV_LSB);
|
||||
|
||||
// write REG_DDRC_CTRL 8 times to clear ddr fifo
|
||||
REG_DDRC_CTRL = 0;
|
||||
REG_DDRC_CTRL = 0;
|
||||
REG_DDRC_CTRL = 0;
|
||||
REG_DDRC_CTRL = 0;
|
||||
REG_DDRC_CTRL = 0;
|
||||
REG_DDRC_CTRL = 0;
|
||||
REG_DDRC_CTRL = 0;
|
||||
REG_DDRC_CTRL = 0;
|
||||
|
||||
if (CFG_EXTAL > 16000000)
|
||||
cfcr |= CPCCR_ECS;
|
||||
else
|
||||
cfcr &= ~CPCCR_ECS;
|
||||
|
||||
cfcr &= ~CPCCR_MEM; /* mddr */
|
||||
cfcr |= CPCCR_CE;
|
||||
|
||||
plcr1 = pll_calc_m_n_od(freq, CFG_EXTAL);
|
||||
plcr1 |= (0x20 << CPPCR0_PLLST_LSB) /* PLL stable time */
|
||||
| CPPCR0_PLLEN; /* enable PLL */
|
||||
|
||||
/*
|
||||
* Init USB Host clock, pllout2 must be n*48MHz
|
||||
* For JZ4760b UHC - River.
|
||||
*/
|
||||
usbdiv = (cfcr & CPCCR_PCS) ? CPU_FREQ : (CPU_FREQ / 2);
|
||||
REG_CPM_UHCCDR = usbdiv / 48000000 - 1;
|
||||
|
||||
/* init PLL */
|
||||
REG_CPM_CPCCR = cfcr;
|
||||
REG_CPM_CPPCR0 = plcr1;
|
||||
|
||||
__cpm_enable_pll_change();
|
||||
|
||||
/*wait for pll output stable ...*/
|
||||
while (!(REG_CPM_CPPCR0 & CPPCR0_PLLS));
|
||||
|
||||
REG_CPM_CPPCR0 &= ~CPPCR0_LOCK;
|
||||
}
|
||||
|
||||
void pll1_init(unsigned int freq)
|
||||
{
|
||||
register unsigned int plcr2;
|
||||
|
||||
/* set CPM_CPCCR_MEM only for ddr1 or ddr2 */
|
||||
plcr2 = pll_calc_m_n_od(freq, CFG_EXTAL)
|
||||
| CPPCR1_PLL1EN; /* enable PLL1 */
|
||||
|
||||
/* init PLL_1 , source clock is extal clock */
|
||||
REG_CPM_CPPCR1 = plcr2;
|
||||
|
||||
__cpm_enable_pll_change();
|
||||
|
||||
/*wait for pll_1 output stable ...*/
|
||||
while (!(REG_CPM_CPPCR1 & CPPCR1_PLL1S));
|
||||
|
||||
REG_CPM_CPPCR1 &= ~CPPCR1_LOCK;
|
||||
}
|
||||
|
||||
static void serial_setbrg(void)
|
||||
{
|
||||
volatile u8 *uart_lcr = (volatile u8 *)(CFG_UART_BASE + OFF_LCR);
|
||||
volatile u8 *uart_dlhr = (volatile u8 *)(CFG_UART_BASE + OFF_DLHR);
|
||||
volatile u8 *uart_dllr = (volatile u8 *)(CFG_UART_BASE + OFF_DLLR);
|
||||
volatile u8 *uart_umr = (volatile u8 *)(CFG_UART_BASE + OFF_UMR);
|
||||
volatile u8 *uart_uacr = (volatile u8 *)(CFG_UART_BASE + OFF_UACR);
|
||||
u16 baud_div, tmp;
|
||||
|
||||
*uart_umr = 16;
|
||||
*uart_uacr = 0;
|
||||
baud_div = 13; /* 57600 */
|
||||
|
||||
tmp = *uart_lcr;
|
||||
tmp |= UARTLCR_DLAB;
|
||||
*uart_lcr = tmp;
|
||||
|
||||
*uart_dlhr = (baud_div >> 8) & 0xff;
|
||||
*uart_dllr = baud_div & 0xff;
|
||||
|
||||
tmp &= ~UARTLCR_DLAB;
|
||||
*uart_lcr = tmp;
|
||||
}
|
||||
|
||||
int serial_preinit(void)
|
||||
{
|
||||
volatile u8 *uart_fcr = (volatile u8 *)(CFG_UART_BASE + OFF_FCR);
|
||||
volatile u8 *uart_lcr = (volatile u8 *)(CFG_UART_BASE + OFF_LCR);
|
||||
volatile u8 *uart_ier = (volatile u8 *)(CFG_UART_BASE + OFF_IER);
|
||||
volatile u8 *uart_sircr = (volatile u8 *)(CFG_UART_BASE + OFF_SIRCR);
|
||||
|
||||
__gpio_as_uart1();
|
||||
__cpm_start_uart1();
|
||||
|
||||
/* Disable port interrupts while changing hardware */
|
||||
*uart_ier = 0;
|
||||
|
||||
/* Disable UART unit function */
|
||||
*uart_fcr = ~UARTFCR_UUE;
|
||||
|
||||
/* Set both receiver and transmitter in UART mode (not SIR) */
|
||||
*uart_sircr = ~(SIRCR_RSIRE | SIRCR_TSIRE);
|
||||
|
||||
/* Set databits, stopbits and parity. (8-bit data, 1 stopbit, no parity) */
|
||||
*uart_lcr = UARTLCR_WLEN_8 | UARTLCR_STOP1;
|
||||
|
||||
/* Set baud rate */
|
||||
serial_setbrg();
|
||||
|
||||
/* Enable UART unit, enable and clear FIFO */
|
||||
*uart_fcr = UARTFCR_UUE | UARTFCR_FE | UARTFCR_TFLS | UARTFCR_RFLS;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void usb_preinit(void)
|
||||
{
|
||||
/* Clear ECS bit of CPCCR, 0:clock source is EXCLK, 1:clock source is EXCLK/2 */
|
||||
REG_CPM_CPCCR &= ~CPCCR_ECS;
|
||||
|
||||
/* Clear all bits of USBCDR, 0:OTG clock source is pin EXCLK, PLL0 output, divider = 1:12MHZ */
|
||||
REG_CPM_USBCDR = 0;
|
||||
|
||||
/* Set CE bit of CPCCR, it means frequence is changed immediately */
|
||||
REG_CPM_CPCCR |= CPCCR_CE;
|
||||
|
||||
udelay(3);
|
||||
|
||||
/* Clear OTG bit of CLKGR0, 0:device can be accessed */
|
||||
REG_CPM_CLKGR0 &= ~CLKGR0_OTG;
|
||||
|
||||
/* fil */
|
||||
REG_CPM_USBVBFIL = 0x80;
|
||||
|
||||
/* rdt */
|
||||
REG_CPM_USBRDT = (600 * (CPU_FREQ / 1000000)) / 1000;
|
||||
|
||||
/* rdt - filload_en */
|
||||
REG_CPM_USBRDT |= (1 << 25);
|
||||
|
||||
/* TXRISETUNE & TXVREFTUNE. */
|
||||
REG_CPM_USBPCR &= ~0x3f;
|
||||
REG_CPM_USBPCR |= 0x35;
|
||||
|
||||
/* enable tx pre-emphasis */
|
||||
REG_CPM_USBPCR |= 0x40;
|
||||
|
||||
/* most DC leave of tx */
|
||||
REG_CPM_USBPCR |= 0xf;
|
||||
|
||||
/* Device Mode. */
|
||||
REG_CPM_USBPCR &= ~(1 << 31);
|
||||
REG_CPM_USBPCR |= USBPCR_VBUSVLDEXT;
|
||||
|
||||
/* phy reset */
|
||||
REG_CPM_USBPCR |= USBPCR_POR;
|
||||
udelay(30);
|
||||
REG_CPM_USBPCR &= ~USBPCR_POR;
|
||||
udelay(300);
|
||||
|
||||
/* Enable the USB PHY */
|
||||
REG_CPM_OPCR |= OPCR_OTGPHY_ENABLE;
|
||||
|
||||
/* Wait PHY Clock Stable. */
|
||||
udelay(300);
|
||||
}
|
||||
|
||||
void dma_preinit(void)
|
||||
{
|
||||
__cpm_start_mdma();
|
||||
__cpm_start_dmac();
|
||||
|
||||
REG_MDMAC_DMACKES = 0x1;
|
||||
|
||||
REG_DMAC_DMACR(DMA_AIC_TX_CHANNEL) = DMAC_DMACR_DMAE | DMAC_DMACR_FAIC;
|
||||
REG_DMAC_DMACR(DMA_SD_RX_CHANNEL) = DMAC_DMACR_DMAE | DMAC_DMACR_FMSC;
|
||||
REG_DMAC_DMACR(DMA_SD_TX_CHANNEL) = DMAC_DMACR_DMAE | DMAC_DMACR_FMSC;
|
||||
}
|
||||
|
||||
/* Gets called *before* main */
|
||||
void ICODE_ATTR system_main(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
__dcache_writeback_all();
|
||||
__icache_invalidate_all();
|
||||
|
||||
write_c0_status(1 << 28 | 1 << 10 ); /* Enable CP | Mask interrupt 2 */
|
||||
|
||||
/* Disable all interrupts */
|
||||
for(i=0; i<IRQ_INTC_MAX; i++)
|
||||
dis_irq(i);
|
||||
|
||||
mmu_init();
|
||||
|
||||
pll0_init(CPU_FREQ);
|
||||
pll1_init(CPU_FREQ);
|
||||
|
||||
serial_preinit();
|
||||
usb_preinit();
|
||||
dma_preinit();
|
||||
|
||||
/* Enable interrupts at core level */
|
||||
enable_interrupt();
|
||||
}
|
||||
|
||||
void system_reboot(void)
|
||||
{
|
||||
REG_WDT_WCSR = WCSR_PRESCALE4 | WCSR_CLKIN_EXT;
|
||||
REG_WDT_WCNT = 0;
|
||||
REG_WDT_WDR = JZ_EXTAL/1000; /* reset after 4ms */
|
||||
REG_TCU_TSCR = TSCR_WDT; /* enable wdt clock */
|
||||
REG_WDT_WCER = WCER_TCEN; /* wdt start */
|
||||
while (1);
|
||||
}
|
||||
|
||||
void system_exception_wait(void)
|
||||
{
|
||||
/* check for power button without including any .h file */
|
||||
while(1)
|
||||
{
|
||||
if( (~REG_GPIO_PXPIN(0)) & (1 << 30) )
|
||||
return;
|
||||
asm volatile("nop");
|
||||
}
|
||||
}
|
||||
|
||||
void power_off(void)
|
||||
{
|
||||
REG_CPM_RSR = 0x0;
|
||||
|
||||
/* Set minimum wakeup_n pin low-level assertion time for wakeup: 100ms */
|
||||
rtc_write_reg(RTC_HWFCR, HWFCR_WAIT_TIME(1000));
|
||||
|
||||
/* Set reset pin low-level assertion time after wakeup: must > 60ms */
|
||||
rtc_write_reg(RTC_HRCR, HRCR_WAIT_TIME(60));
|
||||
|
||||
/* clear wakeup status register */
|
||||
rtc_write_reg(RTC_HWRSR, 0x0);
|
||||
|
||||
/* set wake up valid level as low */
|
||||
rtc_write_reg(RTC_HWCR,0x8);
|
||||
|
||||
/* Put CPU to hibernate mode */
|
||||
rtc_write_reg(RTC_HCR, HCR_PD);
|
||||
|
||||
while (1);
|
||||
}
|
||||
|
||||
void system_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
int system_memory_guard(int newmode)
|
||||
{
|
||||
(void)newmode;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef HAVE_ADJUSTABLE_CPU_FREQ
|
||||
void set_cpu_frequency(long frequency)
|
||||
{
|
||||
serial_putsf("set_cpu_frequency: %d\n", frequency);
|
||||
}
|
||||
#endif
|
||||
|
|
@ -25,7 +25,7 @@
|
|||
#include <inttypes.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "jz4740.h"
|
||||
#include "cpu.h"
|
||||
#include "mipsregs.h"
|
||||
|
||||
#define CACHE_SIZE 16*1024
|
||||
|
|
@ -35,6 +35,8 @@
|
|||
/* no optimized byteswap functions implemented for mips, yet */
|
||||
#define NEED_GENERIC_BYTESWAPS
|
||||
|
||||
#define STORAGE_WANTS_ALIGN
|
||||
|
||||
/* This one returns the old status */
|
||||
static inline int set_interrupt_status(int status, int mask)
|
||||
{
|
||||
|
|
@ -86,10 +88,18 @@ void mdelay(unsigned int msec);
|
|||
void dma_enable(void);
|
||||
void dma_disable(void);
|
||||
|
||||
#if CONFIG_CPU == JZ4732
|
||||
#define DMA_AIC_TX_CHANNEL 0
|
||||
#define DMA_NAND_CHANNEL 1
|
||||
#define DMA_USB_CHANNEL 2
|
||||
#define DMA_LCD_CHANNEL 3
|
||||
#elif CONFIG_CPU == JZ4760B
|
||||
#define DMA_AIC_TX_CHANNEL 0
|
||||
#define DMA_NAND_CHANNEL 1
|
||||
#define DMA_USB_CHANNEL 2
|
||||
#define DMA_SD_RX_CHANNEL 3
|
||||
#define DMA_SD_TX_CHANNEL 4
|
||||
#endif
|
||||
|
||||
#define XDMA_CALLBACK(n) DMA ## n
|
||||
#define DMA_CALLBACK(n) XDMA_CALLBACK(n)
|
||||
|
|
@ -103,7 +113,7 @@ void dma_disable(void);
|
|||
*/
|
||||
static inline void core_sleep(void)
|
||||
{
|
||||
#if CONFIG_CPU == JZ4732
|
||||
#if CONFIG_CPU == JZ4732 || CONFIG_CPU == JZ4760B
|
||||
__cpm_idle_mode();
|
||||
#endif
|
||||
asm volatile(".set mips32r2 \n"
|
||||
|
|
|
|||
101
firmware/target/mips/ingenic_jz47xx/timer-jz4760.c
Normal file
101
firmware/target/mips/ingenic_jz47xx/timer-jz4760.c
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2016 by Roman Stolyarov
|
||||
*
|
||||
* 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 "cpu.h"
|
||||
#include "system.h"
|
||||
#include "timer.h"
|
||||
|
||||
/* Interrupt handler */
|
||||
void TCU1(void)
|
||||
{
|
||||
__tcu_clear_full_match_flag(5);
|
||||
|
||||
if (pfn_timer != NULL)
|
||||
pfn_timer();
|
||||
}
|
||||
|
||||
bool timer_set(long cycles, bool start)
|
||||
{
|
||||
unsigned int divider = cycles, prescaler_bit = 0, prescaler = 1, old_irq;
|
||||
|
||||
if(cycles < 1)
|
||||
return false;
|
||||
|
||||
if(start && pfn_unregister != NULL)
|
||||
{
|
||||
pfn_unregister();
|
||||
pfn_unregister = NULL;
|
||||
}
|
||||
|
||||
/* Increase prescale values starting from 0 to make the cycle count fit */
|
||||
while(divider > 65535 && prescaler <= 1024)
|
||||
{
|
||||
prescaler <<= 2; /* 1, 4, 16, 64, 256, 1024 */
|
||||
prescaler_bit++;
|
||||
divider = cycles / prescaler;
|
||||
}
|
||||
|
||||
old_irq = disable_irq_save();
|
||||
|
||||
__tcu_stop_counter(5);
|
||||
if(start)
|
||||
{
|
||||
__tcu_disable_pwm_output(5);
|
||||
|
||||
__tcu_mask_half_match_irq(5);
|
||||
__tcu_unmask_full_match_irq(5);
|
||||
|
||||
/* EXTAL clock = CFG_EXTAL (12Mhz in most targets) */
|
||||
__tcu_select_extalclk(5);
|
||||
}
|
||||
|
||||
REG_TCU_TCSR(5) = (REG_TCU_TCSR(5) & ~TCSR_PRESCALE_MASK) | (prescaler_bit << TCSR_PRESCALE_LSB);
|
||||
REG_TCU_TCNT(5) = 0;
|
||||
REG_TCU_TDHR(5) = 0;
|
||||
REG_TCU_TDFR(5) = divider;
|
||||
|
||||
__tcu_clear_full_match_flag(5);
|
||||
|
||||
if(start)
|
||||
{
|
||||
system_enable_irq(IRQ_TCU1);
|
||||
__tcu_start_counter(5);
|
||||
}
|
||||
|
||||
restore_irq(old_irq);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool timer_start(void)
|
||||
{
|
||||
__tcu_start_counter(5);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void timer_stop(void)
|
||||
{
|
||||
unsigned int old_irq = disable_irq_save();
|
||||
__tcu_stop_counter(5);
|
||||
restore_irq(old_irq);
|
||||
}
|
||||
870
firmware/target/mips/ingenic_jz47xx/usb-jz4760.c
Normal file
870
firmware/target/mips/ingenic_jz47xx/usb-jz4760.c
Normal file
|
|
@ -0,0 +1,870 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2016 by Roman Stolyarov
|
||||
*
|
||||
* 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"
|
||||
/*#define LOGF_ENABLE*/
|
||||
#include "logf.h"
|
||||
#include "system.h"
|
||||
#include "usb_ch9.h"
|
||||
#include "usb_drv.h"
|
||||
#include "usb_core.h"
|
||||
#include "cpu.h"
|
||||
#include "thread.h"
|
||||
|
||||
#define PIN_USB_DET (32*4+19)
|
||||
#define IRQ_USB_DET GPIO_IRQ(PIN_USB_DET)
|
||||
#define GPIO_USB_DET GPIO147
|
||||
|
||||
#define PIN_USB_DRVVBUS (32*4+10)
|
||||
#define PIN_USB_OTG_ID (32*3+7)
|
||||
|
||||
#define EP_BUF_LEFT(ep) ((ep)->length - (ep)->sent)
|
||||
#define EP_PTR(ep) ((void*)((unsigned int)(ep)->buf + (ep)->sent))
|
||||
#define EP_NUMBER(ep) (((int)(ep) - (int)&endpoints[0])/sizeof(struct usb_endpoint))
|
||||
#define EP_NUMBER2(ep) (EP_NUMBER((ep))/2)
|
||||
#define TOTAL_EP() (sizeof(endpoints)/sizeof(struct usb_endpoint))
|
||||
#define EP_IS_IN(ep) (EP_NUMBER((ep))%2)
|
||||
|
||||
enum ep_type
|
||||
{
|
||||
ep_control,
|
||||
ep_bulk,
|
||||
ep_interrupt,
|
||||
ep_isochronous
|
||||
};
|
||||
|
||||
struct usb_endpoint
|
||||
{
|
||||
void *buf;
|
||||
size_t length;
|
||||
union
|
||||
{
|
||||
size_t sent;
|
||||
size_t received;
|
||||
};
|
||||
bool busy;
|
||||
|
||||
const enum ep_type type;
|
||||
const bool use_dma;
|
||||
|
||||
const long fifo_addr;
|
||||
unsigned short fifo_size;
|
||||
|
||||
bool wait;
|
||||
struct semaphore complete;
|
||||
};
|
||||
|
||||
#define EP_INIT(_type, _fifo_addr, _fifo_size, _buf, _use_dma) \
|
||||
{ .type = (_type), .fifo_addr = (_fifo_addr), .fifo_size = (_fifo_size), \
|
||||
.buf = (_buf), .use_dma = (_use_dma), .length = 0, .busy = false, .wait = false }
|
||||
|
||||
static unsigned char ep0_rx_buf[64];
|
||||
static struct usb_endpoint endpoints[] =
|
||||
{
|
||||
EP_INIT(ep_control, USB_FIFO_EP(0), 64, NULL, false),
|
||||
EP_INIT(ep_control, USB_FIFO_EP(0), 64, &ep0_rx_buf, false),
|
||||
EP_INIT(ep_bulk, USB_FIFO_EP(1), 512, NULL, false),
|
||||
EP_INIT(ep_bulk, USB_FIFO_EP(1), 512, NULL, false),
|
||||
EP_INIT(ep_interrupt, USB_FIFO_EP(2), 64, NULL, false),
|
||||
EP_INIT(ep_interrupt, USB_FIFO_EP(2), 64, NULL, false),
|
||||
};
|
||||
|
||||
static inline void select_endpoint(int ep)
|
||||
{
|
||||
REG_USB_INDEX = ep;
|
||||
}
|
||||
|
||||
static void readFIFO(struct usb_endpoint *ep, unsigned int size)
|
||||
{
|
||||
logf("%s(EP%d, %d)", __func__, EP_NUMBER2(ep), size);
|
||||
|
||||
register unsigned char *ptr = (unsigned char*)EP_PTR(ep);
|
||||
register unsigned int *ptr32 = (unsigned int*)ptr;
|
||||
register unsigned int s = size >> 2;
|
||||
register unsigned int x;
|
||||
|
||||
if(size > 0)
|
||||
{
|
||||
if( ((unsigned int)ptr & 3) == 0 )
|
||||
{
|
||||
while(s--)
|
||||
*ptr32++ = REG32(ep->fifo_addr);
|
||||
|
||||
ptr = (unsigned char*)ptr32;
|
||||
}
|
||||
else
|
||||
{
|
||||
while(s--)
|
||||
{
|
||||
x = REG32(ep->fifo_addr);
|
||||
*ptr++ = x & 0xFF; x >>= 8;
|
||||
*ptr++ = x & 0xFF; x >>= 8;
|
||||
*ptr++ = x & 0xFF; x >>= 8;
|
||||
*ptr++ = x;
|
||||
}
|
||||
}
|
||||
|
||||
s = size & 3;
|
||||
while(s--)
|
||||
*ptr++ = REG8(ep->fifo_addr);
|
||||
}
|
||||
}
|
||||
|
||||
static void writeFIFO(struct usb_endpoint *ep, size_t size)
|
||||
{
|
||||
logf("%s(EP%d, %d)", __func__, EP_NUMBER2(ep), size);
|
||||
|
||||
register unsigned int *d32 = (unsigned int *)EP_PTR(ep);
|
||||
register size_t s = size >> 2;
|
||||
|
||||
if(size > 0)
|
||||
{
|
||||
while (s--)
|
||||
REG32(ep->fifo_addr) = *d32++;
|
||||
|
||||
if( (s = size & 3) )
|
||||
{
|
||||
register unsigned char *d8 = (unsigned char *)d32;
|
||||
while (s--)
|
||||
REG8(ep->fifo_addr) = *d8++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void flushFIFO(struct usb_endpoint *ep)
|
||||
{
|
||||
logf("%s(%d)", __func__, EP_NUMBER(ep));
|
||||
|
||||
switch (ep->type)
|
||||
{
|
||||
case ep_control:
|
||||
break;
|
||||
|
||||
case ep_bulk:
|
||||
case ep_interrupt:
|
||||
case ep_isochronous:
|
||||
if(EP_IS_IN(ep))
|
||||
REG_USB_INCSR |= (USB_INCSR_FF | USB_INCSR_CDT);
|
||||
else
|
||||
REG_USB_OUTCSR |= (USB_OUTCSR_FF | USB_OUTCSR_CDT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void ep_transfer_completed(struct usb_endpoint* ep)
|
||||
{
|
||||
ep->sent = 0;
|
||||
ep->length = 0;
|
||||
ep->buf = NULL;
|
||||
ep->busy = false;
|
||||
if(ep->wait)
|
||||
semaphore_release(&ep->complete);
|
||||
}
|
||||
|
||||
static void EP0_send(void)
|
||||
{
|
||||
struct usb_endpoint* ep = &endpoints[0];
|
||||
unsigned int length;
|
||||
unsigned char csr0;
|
||||
|
||||
select_endpoint(0);
|
||||
csr0 = REG_USB_CSR0;
|
||||
|
||||
if(ep->sent == 0)
|
||||
length = MIN(ep->length, ep->fifo_size);
|
||||
else
|
||||
length = MIN(EP_BUF_LEFT(ep), ep->fifo_size);
|
||||
|
||||
writeFIFO(ep, length);
|
||||
ep->sent += length;
|
||||
|
||||
if(ep->sent >= ep->length)
|
||||
{
|
||||
REG_USB_CSR0 = (csr0 | USB_CSR0_INPKTRDY | USB_CSR0_DATAEND); /* Set data end! */
|
||||
usb_core_transfer_complete(0, USB_DIR_IN, 0, ep->sent);
|
||||
ep_transfer_completed(ep);
|
||||
}
|
||||
else
|
||||
REG_USB_CSR0 = (csr0 | USB_CSR0_INPKTRDY);
|
||||
}
|
||||
|
||||
static void EP0_handler(void)
|
||||
{
|
||||
logf("%s()", __func__);
|
||||
|
||||
unsigned char csr0;
|
||||
struct usb_endpoint *ep_send = &endpoints[0];
|
||||
struct usb_endpoint *ep_recv = &endpoints[1];
|
||||
|
||||
/* Read CSR0 */
|
||||
select_endpoint(0);
|
||||
csr0 = REG_USB_CSR0;
|
||||
|
||||
/* Check for SentStall:
|
||||
This bit is set when a STALL handshake is transmitted. The CPU should clear this bit.
|
||||
*/
|
||||
if(csr0 & USB_CSR0_SENTSTALL)
|
||||
{
|
||||
REG_USB_CSR0 = csr0 & ~USB_CSR0_SENTSTALL;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check for SetupEnd:
|
||||
This bit will be set when a control transaction ends before the DataEnd bit has been set.
|
||||
An interrupt will be generated and the FIFO flushed at this time.
|
||||
The bit is cleared by the CPU writing a 1 to the ServicedSetupEnd bit.
|
||||
*/
|
||||
if(csr0 & USB_CSR0_SETUPEND)
|
||||
{
|
||||
REG_USB_CSR0 = csr0 | USB_CSR0_SVDSETUPEND;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Call relevant routines for endpoint 0 state */
|
||||
if(ep_send->busy)
|
||||
EP0_send();
|
||||
else if(csr0 & USB_CSR0_OUTPKTRDY) /* There is a packet in the fifo */
|
||||
{
|
||||
readFIFO(ep_recv, REG_USB_COUNT0);
|
||||
REG_USB_CSR0 = csr0 | USB_CSR0_SVDOUTPKTRDY; /* clear OUTPKTRDY bit */
|
||||
usb_core_control_request((struct usb_ctrlrequest*)ep_recv->buf);
|
||||
}
|
||||
}
|
||||
|
||||
static void EPIN_handler(unsigned int endpoint)
|
||||
{
|
||||
struct usb_endpoint* ep = &endpoints[endpoint*2];
|
||||
unsigned int length, csr;
|
||||
|
||||
select_endpoint(endpoint);
|
||||
csr = REG_USB_INCSR;
|
||||
logf("%s(%d): 0x%x", __func__, endpoint, csr);
|
||||
|
||||
if(!ep->busy)
|
||||
{
|
||||
logf("Entered EPIN handler without work!");
|
||||
return;
|
||||
}
|
||||
|
||||
if(csr & USB_INCSR_SENTSTALL)
|
||||
{
|
||||
REG_USB_INCSR = csr & ~USB_INCSR_SENTSTALL;
|
||||
return;
|
||||
}
|
||||
|
||||
if(ep->use_dma)
|
||||
return;
|
||||
|
||||
if(csr & USB_INCSR_FFNOTEMPT)
|
||||
{
|
||||
logf("FIFO is not empty! 0x%x", csr);
|
||||
return;
|
||||
}
|
||||
|
||||
logf("EP%d: %d -> %d", endpoint, ep->sent, ep->length);
|
||||
|
||||
if(ep->sent == 0)
|
||||
length = MIN(ep->length, ep->fifo_size);
|
||||
else
|
||||
length = MIN(EP_BUF_LEFT(ep), ep->fifo_size);
|
||||
|
||||
writeFIFO(ep, length);
|
||||
REG_USB_INCSR = csr | USB_INCSR_INPKTRDY;
|
||||
ep->sent += length;
|
||||
|
||||
if(ep->sent >= ep->length)
|
||||
{
|
||||
usb_core_transfer_complete(endpoint, USB_DIR_IN, 0, ep->sent);
|
||||
ep_transfer_completed(ep);
|
||||
logf("sent complete");
|
||||
}
|
||||
}
|
||||
|
||||
static void EPOUT_handler(unsigned int endpoint)
|
||||
{
|
||||
struct usb_endpoint* ep = &endpoints[endpoint*2+1];
|
||||
unsigned int size, csr;
|
||||
|
||||
if(!ep->busy)
|
||||
{
|
||||
logf("Entered EPOUT handler without work!");
|
||||
return;
|
||||
}
|
||||
|
||||
select_endpoint(endpoint);
|
||||
while((csr = REG_USB_OUTCSR) & (USB_OUTCSR_SENTSTALL|USB_OUTCSR_OUTPKTRDY))
|
||||
{
|
||||
logf("%s(%d): 0x%x", __func__, endpoint, csr);
|
||||
if(csr & USB_OUTCSR_SENTSTALL)
|
||||
{
|
||||
logf("stall sent, flushing fifo..");
|
||||
flushFIFO(ep);
|
||||
REG_USB_OUTCSR = csr & ~USB_OUTCSR_SENTSTALL;
|
||||
return;
|
||||
}
|
||||
|
||||
if(ep->use_dma)
|
||||
return;
|
||||
|
||||
if(csr & USB_OUTCSR_OUTPKTRDY) /* There is a packet in the fifo */
|
||||
{
|
||||
size = REG_USB_OUTCOUNT;
|
||||
|
||||
readFIFO(ep, size);
|
||||
ep->received += size;
|
||||
|
||||
/*if(csr & USB_OUTCSR_FFFULL)
|
||||
csr &= ~USB_OUTCSR_FFFULL;*/
|
||||
|
||||
REG_USB_OUTCSR = csr & ~USB_OUTCSR_OUTPKTRDY;
|
||||
|
||||
logf("received: %d max length: %d", ep->received, ep->length);
|
||||
|
||||
if(size < ep->fifo_size || ep->received >= ep->length)
|
||||
{
|
||||
usb_core_transfer_complete(endpoint, USB_DIR_OUT, 0, ep->received);
|
||||
ep_transfer_completed(ep);
|
||||
logf("receive transfer_complete");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void EPDMA_handler(int number)
|
||||
{
|
||||
int endpoint = -1;
|
||||
unsigned int size = 0;
|
||||
|
||||
if(number == USB_INTR_DMA_BULKIN)
|
||||
endpoint = (REG_USB_CNTL(0) >> 4) & 0xF;
|
||||
else if(number == USB_INTR_DMA_BULKOUT)
|
||||
endpoint = (REG_USB_CNTL(1) >> 4) & 0xF;
|
||||
|
||||
struct usb_endpoint* ep = &endpoints[endpoint];
|
||||
logf("DMA_BULK%d %d", number, endpoint);
|
||||
|
||||
if(number == USB_INTR_DMA_BULKIN)
|
||||
size = (unsigned int)ep->buf - REG_USB_ADDR(0);
|
||||
else if(number == USB_INTR_DMA_BULKOUT)
|
||||
size = (unsigned int)ep->buf - REG_USB_ADDR(1);
|
||||
|
||||
if(number == USB_INTR_DMA_BULKOUT)
|
||||
{
|
||||
/* Disable DMA */
|
||||
REG_USB_CNTL(1) = 0;
|
||||
|
||||
__dcache_invalidate_all();
|
||||
|
||||
select_endpoint(endpoint);
|
||||
/* Read out last packet manually */
|
||||
unsigned int lpack_size = REG_USB_OUTCOUNT;
|
||||
if(lpack_size > 0)
|
||||
{
|
||||
ep->buf += ep->length - lpack_size;
|
||||
readFIFO(ep, lpack_size);
|
||||
REG_USB_OUTCSR &= ~USB_OUTCSR_OUTPKTRDY;
|
||||
}
|
||||
}
|
||||
else if(number == USB_INTR_DMA_BULKIN && size % ep->fifo_size)
|
||||
{
|
||||
/* If the last packet is less than MAXP, set INPKTRDY manually */
|
||||
REG_USB_INCSR |= USB_INCSR_INPKTRDY;
|
||||
}
|
||||
|
||||
usb_core_transfer_complete(endpoint, EP_IS_IN(ep) ? USB_DIR_IN : USB_DIR_OUT,
|
||||
0, ep->length);
|
||||
ep_transfer_completed(ep);
|
||||
}
|
||||
|
||||
static void setup_endpoint(struct usb_endpoint *ep)
|
||||
{
|
||||
int csr, csrh;
|
||||
|
||||
select_endpoint(EP_NUMBER2(ep));
|
||||
|
||||
ep->busy = false;
|
||||
ep->wait = false;
|
||||
ep->sent = 0;
|
||||
ep->length = 0;
|
||||
|
||||
if(ep->type == ep_bulk)
|
||||
{
|
||||
if(REG_USB_POWER & USB_POWER_HSMODE)
|
||||
ep->fifo_size = 512;
|
||||
else
|
||||
ep->fifo_size = 64;
|
||||
}
|
||||
|
||||
if(EP_IS_IN(ep))
|
||||
{
|
||||
csr = (USB_INCSR_FF | USB_INCSR_CDT);
|
||||
csrh = USB_INCSRH_MODE;
|
||||
|
||||
if(ep->use_dma)
|
||||
csrh |= (USB_INCSRH_DMAREQENAB | USB_INCSRH_AUTOSET | USB_INCSRH_DMAREQMODE);
|
||||
|
||||
if(ep->type == ep_interrupt)
|
||||
csrh |= USB_INCSRH_FRCDATATOG;
|
||||
|
||||
REG_USB_INMAXP = ep->fifo_size;
|
||||
REG_USB_INCSR = csr;
|
||||
REG_USB_INCSRH = csrh;
|
||||
REG_USB_INTRINE |= USB_INTR_EP(EP_NUMBER2(ep));
|
||||
}
|
||||
else
|
||||
{
|
||||
csr = (USB_OUTCSR_FF | USB_OUTCSR_CDT);
|
||||
csrh = 0;
|
||||
|
||||
if(ep->type == ep_interrupt)
|
||||
csrh |= USB_OUTCSRH_DNYT;
|
||||
|
||||
if(ep->use_dma)
|
||||
csrh |= (USB_OUTCSRH_DMAREQENAB | USB_OUTCSRH_AUTOCLR | USB_OUTCSRH_DMAREQMODE);
|
||||
|
||||
REG_USB_OUTMAXP = ep->fifo_size;
|
||||
REG_USB_OUTCSR = csr;
|
||||
REG_USB_OUTCSRH = csrh;
|
||||
REG_USB_INTROUTE |= USB_INTR_EP(EP_NUMBER2(ep));
|
||||
}
|
||||
}
|
||||
|
||||
static void udc_reset(void)
|
||||
{
|
||||
/* From the datasheet:
|
||||
|
||||
When a reset condition is detected on the USB, the controller performs the following actions:
|
||||
* Sets FAddr to 0.
|
||||
* Sets Index to 0.
|
||||
* Flushes all endpoint FIFOs.
|
||||
* Clears all control/status registers.
|
||||
* Enables all endpoint interrupts.
|
||||
* Generates a Reset interrupt.
|
||||
*/
|
||||
|
||||
logf("%s()", __func__);
|
||||
|
||||
unsigned int i;
|
||||
|
||||
REG_USB_FADDR = 0;
|
||||
REG_USB_INDEX = 0;
|
||||
|
||||
/* Disable interrupts */
|
||||
REG_USB_INTRINE = 0;
|
||||
REG_USB_INTROUTE = 0;
|
||||
REG_USB_INTRUSBE = 0;
|
||||
|
||||
/* Disable DMA */
|
||||
REG_USB_CNTL(0) = 0;
|
||||
REG_USB_CNTL(1) = 0;
|
||||
|
||||
/* High speed, softconnect */
|
||||
REG_USB_POWER = (USB_POWER_SOFTCONN | USB_POWER_HSENAB);
|
||||
|
||||
/* Reset EP0 */
|
||||
select_endpoint(0);
|
||||
REG_USB_CSR0 = (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_SVDSETUPEND | USB_CSR0_FLUSHFIFO);
|
||||
|
||||
/* Reset other endpoints */
|
||||
for(i=2; i<TOTAL_EP(); i++)
|
||||
setup_endpoint(&endpoints[i]);
|
||||
|
||||
/* Enable interrupts */
|
||||
REG_USB_INTRINE |= USB_INTR_EP(0);
|
||||
REG_USB_INTRUSBE |= USB_INTR_RESET;
|
||||
|
||||
usb_core_bus_reset();
|
||||
}
|
||||
|
||||
/* Interrupt handler */
|
||||
void OTG(void)
|
||||
{
|
||||
/* Read interrupt registers */
|
||||
unsigned char intrUSB = REG_USB_INTRUSB & 0x07; /* Mask SOF */
|
||||
unsigned short intrIn = REG_USB_INTRIN;
|
||||
unsigned short intrOut = REG_USB_INTROUT;
|
||||
unsigned char intrDMA = REG_USB_INTR;
|
||||
|
||||
logf("%x %x %x %x", intrUSB, intrIn, intrOut, intrDMA);
|
||||
|
||||
/* EPIN & EPOUT are all handled in DMA */
|
||||
if(intrIn & USB_INTR_EP(0))
|
||||
EP0_handler();
|
||||
if(intrIn & USB_INTR_EP(1))
|
||||
EPIN_handler(1);
|
||||
if(intrIn & USB_INTR_EP(2))
|
||||
EPIN_handler(2);
|
||||
if(intrOut & USB_INTR_EP(1))
|
||||
EPOUT_handler(1);
|
||||
if(intrOut & USB_INTR_EP(2))
|
||||
EPOUT_handler(2);
|
||||
if(intrUSB & USB_INTR_RESET)
|
||||
udc_reset();
|
||||
if(intrUSB & USB_INTR_SUSPEND)
|
||||
logf("USB suspend");
|
||||
if(intrUSB & USB_INTR_RESUME)
|
||||
logf("USB resume");
|
||||
if(intrDMA & USB_INTR_DMA_BULKIN)
|
||||
EPDMA_handler(USB_INTR_DMA_BULKIN);
|
||||
if(intrDMA & USB_INTR_DMA_BULKOUT)
|
||||
EPDMA_handler(USB_INTR_DMA_BULKOUT);
|
||||
}
|
||||
|
||||
bool usb_drv_stalled(int endpoint, bool in)
|
||||
{
|
||||
endpoint &= 0x7F;
|
||||
|
||||
logf("%s(%d, %s)", __func__, endpoint, in?"IN":"OUT");
|
||||
|
||||
select_endpoint(endpoint);
|
||||
|
||||
if(endpoint == EP_CONTROL)
|
||||
return (REG_USB_CSR0 & USB_CSR0_SENDSTALL) != 0;
|
||||
else
|
||||
{
|
||||
if(in)
|
||||
return (REG_USB_INCSR & USB_INCSR_SENDSTALL) != 0;
|
||||
else
|
||||
return (REG_USB_OUTCSR & USB_OUTCSR_SENDSTALL) != 0;
|
||||
}
|
||||
}
|
||||
|
||||
void usb_drv_stall(int endpoint, bool stall, bool in)
|
||||
{
|
||||
endpoint &= 0x7F;
|
||||
|
||||
logf("%s(%d,%s,%s)", __func__, endpoint, stall?"Y":"N", in?"IN":"OUT");
|
||||
|
||||
select_endpoint(endpoint);
|
||||
|
||||
if(endpoint == EP_CONTROL)
|
||||
{
|
||||
if(stall)
|
||||
REG_USB_CSR0 |= USB_CSR0_SENDSTALL;
|
||||
else
|
||||
REG_USB_CSR0 &= ~USB_CSR0_SENDSTALL;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(in)
|
||||
{
|
||||
if(stall)
|
||||
REG_USB_INCSR |= USB_INCSR_SENDSTALL;
|
||||
else
|
||||
REG_USB_INCSR = (REG_USB_INCSR & ~USB_INCSR_SENDSTALL) | USB_INCSR_CDT;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(stall)
|
||||
REG_USB_OUTCSR |= USB_OUTCSR_SENDSTALL;
|
||||
else
|
||||
REG_USB_OUTCSR = (REG_USB_OUTCSR & ~USB_OUTCSR_SENDSTALL) | USB_OUTCSR_CDT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int usb_detect(void)
|
||||
{
|
||||
return (__gpio_get_pin(PIN_USB_DET) == 1)
|
||||
? USB_INSERTED : USB_EXTRACTED;
|
||||
}
|
||||
|
||||
void usb_init_device(void)
|
||||
{
|
||||
__gpio_clear_pin(PIN_USB_DRVVBUS);
|
||||
__gpio_as_output(PIN_USB_DRVVBUS);
|
||||
|
||||
__gpio_as_input(PIN_USB_OTG_ID);
|
||||
__gpio_as_input(PIN_USB_DET);
|
||||
|
||||
__gpio_disable_pull(PIN_USB_OTG_ID);
|
||||
__gpio_disable_pull(PIN_USB_DET);
|
||||
|
||||
#ifdef USB_STATUS_BY_EVENT
|
||||
__gpio_as_irq_rise_edge(PIN_USB_DET);
|
||||
system_enable_irq(IRQ_USB_DET);
|
||||
#endif
|
||||
|
||||
system_enable_irq(IRQ_OTG);
|
||||
|
||||
for(unsigned i=0; i<TOTAL_EP(); i++)
|
||||
semaphore_init(&endpoints[i].complete, 1, 0);
|
||||
}
|
||||
|
||||
#ifdef USB_STATUS_BY_EVENT
|
||||
static int usb_oneshot_callback(struct timeout *tmo)
|
||||
{
|
||||
(void)tmo;
|
||||
int state = usb_detect();
|
||||
|
||||
/* This is called only if the state was stable for HZ/16 - check state
|
||||
* and post appropriate event. */
|
||||
usb_status_event(state);
|
||||
|
||||
if(state == USB_EXTRACTED)
|
||||
__gpio_as_irq_rise_edge(PIN_USB_DET);
|
||||
else
|
||||
__gpio_as_irq_fall_edge(PIN_USB_DET);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void GPIO_USB_DET(void)
|
||||
{
|
||||
static struct timeout usb_oneshot;
|
||||
timeout_register(&usb_oneshot, usb_oneshot_callback, (HZ/16), 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
void usb_enable(bool on)
|
||||
{
|
||||
if(on)
|
||||
usb_core_init();
|
||||
else
|
||||
usb_core_exit();
|
||||
}
|
||||
|
||||
void usb_attach(void)
|
||||
{
|
||||
usb_enable(true);
|
||||
}
|
||||
|
||||
void usb_drv_init(void)
|
||||
{
|
||||
logf("%s()", __func__);
|
||||
|
||||
/* Dis- and reconnect from USB */
|
||||
REG_USB_POWER &= ~USB_POWER_SOFTCONN;
|
||||
mdelay(20);
|
||||
REG_USB_POWER |= USB_POWER_SOFTCONN;
|
||||
mdelay(20);
|
||||
|
||||
udc_reset();
|
||||
}
|
||||
|
||||
void usb_drv_exit(void)
|
||||
{
|
||||
logf("%s()", __func__);
|
||||
|
||||
REG_USB_FADDR = 0;
|
||||
REG_USB_INDEX = 0;
|
||||
|
||||
/* Disable interrupts */
|
||||
REG_USB_INTRINE = 0;
|
||||
REG_USB_INTROUTE = 0;
|
||||
REG_USB_INTRUSBE = 0;
|
||||
|
||||
/* Disable DMA */
|
||||
REG_USB_CNTL(0) = 0;
|
||||
REG_USB_CNTL(1) = 0;
|
||||
|
||||
/* Disconnect from USB */
|
||||
REG_USB_POWER &= ~USB_POWER_SOFTCONN;
|
||||
}
|
||||
|
||||
void usb_drv_set_address(int address)
|
||||
{
|
||||
logf("%s(%d)", __func__, address);
|
||||
|
||||
REG_USB_FADDR = address;
|
||||
}
|
||||
|
||||
static void usb_drv_send_internal(struct usb_endpoint* ep, void* ptr, int length, bool blocking)
|
||||
{
|
||||
if(ep->type == ep_control && ptr == NULL && length == 0)
|
||||
return; /* ACK request, handled in the ISR */
|
||||
|
||||
int flags = disable_irq_save();
|
||||
|
||||
ep->buf = ptr;
|
||||
ep->sent = 0;
|
||||
ep->length = length;
|
||||
ep->busy = true;
|
||||
if(blocking)
|
||||
ep->wait = true;
|
||||
|
||||
if(ep->type == ep_control)
|
||||
{
|
||||
EP0_send();
|
||||
}
|
||||
else
|
||||
{
|
||||
if(ep->use_dma)
|
||||
{
|
||||
//dma_cache_wback_inv((unsigned long)ptr, length);
|
||||
__dcache_writeback_all();
|
||||
REG_USB_ADDR(0) = PHYSADDR((unsigned long)ptr);
|
||||
REG_USB_COUNT(0) = length;
|
||||
REG_USB_CNTL(0) = (USB_CNTL_INTR_EN | USB_CNTL_MODE_1 |
|
||||
USB_CNTL_DIR_IN | USB_CNTL_ENA |
|
||||
USB_CNTL_EP(EP_NUMBER2(ep)) | USB_CNTL_BURST_16);
|
||||
}
|
||||
else
|
||||
EPIN_handler(EP_NUMBER2(ep));
|
||||
}
|
||||
|
||||
restore_irq(flags);
|
||||
|
||||
if(blocking)
|
||||
{
|
||||
semaphore_wait(&ep->complete, TIMEOUT_BLOCK);
|
||||
ep->wait = false;
|
||||
}
|
||||
}
|
||||
|
||||
int usb_drv_send_nonblocking(int endpoint, void* ptr, int length)
|
||||
{
|
||||
logf("%s(%d, 0x%x, %d)", __func__, endpoint, (int)ptr, length);
|
||||
|
||||
usb_drv_send_internal(&endpoints[(endpoint & 0x7F)*2], ptr, length, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usb_drv_send(int endpoint, void* ptr, int length)
|
||||
{
|
||||
logf("%s(%d, 0x%x, %d)", __func__, endpoint, (int)ptr, length);
|
||||
|
||||
usb_drv_send_internal(&endpoints[(endpoint & 0x7F)*2], ptr, length, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usb_drv_recv(int endpoint, void* ptr, int length)
|
||||
{
|
||||
int flags;
|
||||
struct usb_endpoint *ep;
|
||||
endpoint &= 0x7F;
|
||||
|
||||
logf("%s(%d, 0x%x, %d)", __func__, endpoint, (int)ptr, length);
|
||||
|
||||
if(endpoint == EP_CONTROL)
|
||||
return 0; /* all EP0 OUT transactions are handled within the ISR */
|
||||
else
|
||||
{
|
||||
flags = disable_irq_save();
|
||||
ep = &endpoints[endpoint*2+1];
|
||||
|
||||
ep->buf = ptr;
|
||||
ep->received = 0;
|
||||
ep->length = length;
|
||||
ep->busy = true;
|
||||
if(ep->use_dma)
|
||||
{
|
||||
//dma_cache_wback_inv((unsigned long)ptr, length);
|
||||
__dcache_writeback_all();
|
||||
REG_USB_ADDR(1) = PHYSADDR((unsigned long)ptr);
|
||||
REG_USB_COUNT(1) = length;
|
||||
REG_USB_CNTL(1) = (USB_CNTL_INTR_EN | USB_CNTL_MODE_1 |
|
||||
USB_CNTL_ENA | USB_CNTL_EP(endpoint) |
|
||||
USB_CNTL_BURST_16);
|
||||
}
|
||||
else
|
||||
EPOUT_handler(endpoint);
|
||||
|
||||
restore_irq(flags);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void usb_drv_set_test_mode(int mode)
|
||||
{
|
||||
logf("%s(%d)", __func__, mode);
|
||||
|
||||
switch(mode)
|
||||
{
|
||||
case 0:
|
||||
REG_USB_TESTMODE &= ~USB_TEST_ALL;
|
||||
break;
|
||||
case 1:
|
||||
REG_USB_TESTMODE |= USB_TEST_J;
|
||||
break;
|
||||
case 2:
|
||||
REG_USB_TESTMODE |= USB_TEST_K;
|
||||
break;
|
||||
case 3:
|
||||
REG_USB_TESTMODE |= USB_TEST_SE0NAK;
|
||||
break;
|
||||
case 4:
|
||||
REG_USB_TESTMODE |= USB_TEST_PACKET;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int usb_drv_port_speed(void)
|
||||
{
|
||||
return (REG_USB_POWER & USB_POWER_HSMODE) ? 1 : 0;
|
||||
}
|
||||
|
||||
void usb_drv_cancel_all_transfers(void)
|
||||
{
|
||||
logf("%s()", __func__);
|
||||
|
||||
unsigned int i, flags;
|
||||
flags = disable_irq_save();
|
||||
|
||||
for(i=0; i<TOTAL_EP(); i++)
|
||||
{
|
||||
if(i != 1) /* ep0 out needs special handling */
|
||||
endpoints[i].buf = NULL;
|
||||
|
||||
endpoints[i].sent = 0;
|
||||
endpoints[i].length = 0;
|
||||
|
||||
select_endpoint(i/2);
|
||||
flushFIFO(&endpoints[i]);
|
||||
}
|
||||
restore_irq(flags);
|
||||
}
|
||||
|
||||
|
||||
void usb_drv_release_endpoint(int ep)
|
||||
{
|
||||
(void)ep;
|
||||
logf("%s(%d, %s)", __func__, (ep & 0x7F), (ep >> 7) ? "IN" : "OUT");
|
||||
}
|
||||
|
||||
int usb_drv_request_endpoint(int type, int dir)
|
||||
{
|
||||
logf("%s(%d, %s)", __func__, type, (dir == USB_DIR_IN) ? "IN" : "OUT");
|
||||
|
||||
dir &= USB_ENDPOINT_DIR_MASK;
|
||||
type &= USB_ENDPOINT_XFERTYPE_MASK;
|
||||
|
||||
/* There are only 3+2 endpoints, so hardcode this ... */
|
||||
switch(type)
|
||||
{
|
||||
case USB_ENDPOINT_XFER_BULK:
|
||||
if(dir == USB_DIR_IN)
|
||||
return (1 | USB_DIR_IN);
|
||||
else
|
||||
return (1 | USB_DIR_OUT);
|
||||
|
||||
case USB_ENDPOINT_XFER_INT:
|
||||
if(dir == USB_DIR_IN)
|
||||
return (2 | USB_DIR_IN);
|
||||
else
|
||||
return (2 | USB_DIR_OUT);
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
31
firmware/target/mips/ingenic_jz47xx/xdebug.h
Normal file
31
firmware/target/mips/ingenic_jz47xx/xdebug.h
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2016 by Roman Stolyarov
|
||||
*
|
||||
* 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 __XDEBUG_H_
|
||||
#define __XDEBUG_H_
|
||||
|
||||
void serial_puts(const char *s);
|
||||
void serial_putsf(const char *format, ...);
|
||||
void serial_put_hex(unsigned int d);
|
||||
void serial_put_dec(unsigned int d);
|
||||
void serial_dump_data(unsigned char* data, int len);
|
||||
|
||||
#endif /* __XDEBUG_H_ */
|
||||
28
firmware/target/mips/ingenic_jz47xx/xduoo_x3/adc-target.h
Normal file
28
firmware/target/mips/ingenic_jz47xx/xduoo_x3/adc-target.h
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2016 by Roman Stolyarov
|
||||
*
|
||||
* 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 _ADC_TARGET_H_
|
||||
#define _ADC_TARGET_H_
|
||||
|
||||
#define NUM_ADC_CHANNELS 4
|
||||
|
||||
#define ADC_BUTTONS 0
|
||||
|
||||
#endif /* _ADC_TARGET_H_ */
|
||||
48
firmware/target/mips/ingenic_jz47xx/xduoo_x3/ata-sd-target.h
Normal file
48
firmware/target/mips/ingenic_jz47xx/xduoo_x3/ata-sd-target.h
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2016 by Roman Stolyarov
|
||||
*
|
||||
* 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 "cpu.h"
|
||||
#include "system.h"
|
||||
|
||||
#define PIN_SD1_CD (32*0+29) /* Pin to check card insertion */
|
||||
#define IRQ_SD1_CD GPIO_IRQ(PIN_SD1_CD)
|
||||
#define GPIO_SD1_CD GPIO29
|
||||
|
||||
#define PIN_SD2_CD (32*0+28) /* Pin to check card insertion */
|
||||
#define IRQ_SD2_CD GPIO_IRQ(PIN_SD2_CD)
|
||||
#define GPIO_SD2_CD GPIO28
|
||||
|
||||
static inline void sd_init_gpio(void)
|
||||
{
|
||||
__gpio_as_msc1_pd_4bit();
|
||||
__gpio_as_msc2_pb_4bit();
|
||||
|
||||
__gpio_as_input(PIN_SD1_CD);
|
||||
__gpio_as_input(PIN_SD2_CD);
|
||||
|
||||
__gpio_disable_pull(PIN_SD1_CD);
|
||||
__gpio_disable_pull(PIN_SD2_CD);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2016 by Roman Stolyarov
|
||||
*
|
||||
* 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 "cpu.h"
|
||||
#include "backlight-target.h"
|
||||
#include "lcd.h"
|
||||
|
||||
bool backlight_hw_init(void)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void backlight_hw_on(void)
|
||||
{
|
||||
lcd_enable(true);
|
||||
}
|
||||
|
||||
void backlight_hw_off(void)
|
||||
{
|
||||
lcd_enable(false);
|
||||
}
|
||||
|
||||
void backlight_hw_brightness(int brightness)
|
||||
{
|
||||
lcd_set_contrast(brightness*16-1);
|
||||
}
|
||||
|
||||
void lcd_sleep(void)
|
||||
{
|
||||
backlight_hw_off();
|
||||
}
|
||||
46
firmware/target/mips/ingenic_jz47xx/xduoo_x3/button-target.h
Normal file
46
firmware/target/mips/ingenic_jz47xx/xduoo_x3/button-target.h
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2016 by Roman Stolyarov
|
||||
*
|
||||
* 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 BUTTON_TARGET_H
|
||||
#define BUTTON_TARGET_H
|
||||
|
||||
#define HAS_BUTTON_HOLD
|
||||
|
||||
/* Main unit's buttons */
|
||||
#define BUTTON_POWER 0x00000001
|
||||
#define BUTTON_HOME 0x00000002
|
||||
#define BUTTON_OPTION 0x00000004
|
||||
#define BUTTON_PREV 0x00000008
|
||||
#define BUTTON_NEXT 0x00000010
|
||||
#define BUTTON_PLAY 0x00000020
|
||||
#define BUTTON_VOL_UP 0x00000040
|
||||
#define BUTTON_VOL_DOWN 0x00000080
|
||||
|
||||
#define BUTTON_LEFT 0
|
||||
#define BUTTON_RIGHT 0
|
||||
|
||||
#define BUTTON_MAIN (BUTTON_POWER | BUTTON_HOME | BUTTON_OPTION | BUTTON_PREV | \
|
||||
BUTTON_NEXT | BUTTON_PLAY | BUTTON_VOL_UP | BUTTON_VOL_DOWN)
|
||||
|
||||
/* Software power-off */
|
||||
#define POWEROFF_BUTTON BUTTON_POWER
|
||||
#define POWEROFF_COUNT 10
|
||||
|
||||
#endif /* BUTTON_TARGET_H */
|
||||
420
firmware/target/mips/ingenic_jz47xx/xduoo_x3/lcd-xduoo_x3.c
Normal file
420
firmware/target/mips/ingenic_jz47xx/xduoo_x3/lcd-xduoo_x3.c
Normal file
|
|
@ -0,0 +1,420 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2016 by Roman Stolyarov
|
||||
*
|
||||
* 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 "lcd.h"
|
||||
#include "system.h"
|
||||
#include "cpu.h"
|
||||
#include "string.h"
|
||||
|
||||
/* LCD pins */
|
||||
#define PIN_BL_EN (32*4+0)
|
||||
|
||||
#define PIN_LCD_D0 (32*2+2)
|
||||
#define PIN_LCD_D1 (32*2+3)
|
||||
#define PIN_LCD_D2 (32*2+4)
|
||||
#define PIN_LCD_D3 (32*2+5)
|
||||
#define PIN_LCD_D4 (32*2+6)
|
||||
#define PIN_LCD_D5 (32*2+7)
|
||||
#define PIN_LCD_D6 (32*2+12)
|
||||
#define PIN_LCD_D7 (32*2+13)
|
||||
|
||||
#define PIN_LCD_RD (32*2+8)
|
||||
#define PIN_LCD_DC (32*2+9)
|
||||
#define PIN_LCD_CS (32*2+14)
|
||||
#define PIN_LCD_RES (32*2+18)
|
||||
#define PIN_LCD_WR (32*2+19)
|
||||
|
||||
/* LCD setup codes */
|
||||
#define LCD_SET_LOWER_COLUMN_ADDRESS ((char)0x00)
|
||||
#define LCD_SET_HIGHER_COLUMN_ADDRESS ((char)0x10)
|
||||
#define LCD_SET_DISPLAY_START_LINE ((char)0x40)
|
||||
#define LCD_SET_CONTRAST_CONTROL_REGISTER ((char)0x81)
|
||||
#define LCD_SET_CHARGE_PUMP ((char)0x8D)
|
||||
#define LCD_SET_SEGMENT_REMAP ((char)0xA0)
|
||||
#define LCD_SET_SEGMENT_REMAP_INV ((char)0xA1)
|
||||
#define LCD_SET_ENTIRE_DISPLAY_OFF ((char)0xA4)
|
||||
#define LCD_SET_ENTIRE_DISPLAY_ON ((char)0xA5)
|
||||
#define LCD_SET_NORMAL_DISPLAY ((char)0xA6)
|
||||
#define LCD_SET_REVERSE_DISPLAY ((char)0xA7)
|
||||
#define LCD_SET_MULTIPLEX_RATIO ((char)0xA8)
|
||||
#define LCD_SET_DC_DC ((char)0xAD)
|
||||
#define LCD_SET_DISPLAY_OFF ((char)0xAE)
|
||||
#define LCD_SET_DISPLAY_ON ((char)0xAF)
|
||||
#define LCD_SET_PAGE_ADDRESS ((char)0xB0)
|
||||
#define LCD_SET_COM_OUTPUT_SCAN_DIRECTION ((char)0xC0)
|
||||
#define LCD_SET_COM_OUTPUT_SCAN_DIRECTION_INV ((char)0xC8)
|
||||
#define LCD_SET_DISPLAY_OFFSET ((char)0xD3)
|
||||
#define LCD_SET_DISPLAY_CLOCK_AND_OSC_FREQ ((char)0xD5)
|
||||
#define LCD_SET_VCOM_HW_CONFIGURATION ((char)0xDA)
|
||||
#define LCD_SET_VCOM_DESELECT_LEVEL ((char)0xDB)
|
||||
#define LCD_SET_PRECHARGE_PERIOD ((char)0xD9)
|
||||
#define LCD_NOP ((char)0xE3)
|
||||
|
||||
/* LCD command codes */
|
||||
#define LCD_CNTL_CONTRAST 0x81 /* Contrast */
|
||||
#define LCD_CNTL_OUTSCAN 0xc8 /* Output scan direction */
|
||||
#define LCD_CNTL_SEGREMAP 0xa1 /* Segment remap */
|
||||
#define LCD_CNTL_DISPON 0xaf /* Display on */
|
||||
|
||||
#define LCD_CNTL_PAGE 0xb0 /* Page address */
|
||||
#define LCD_CNTL_HIGHCOL 0x10 /* Upper column address */
|
||||
#define LCD_CNTL_LOWCOL 0x00 /* Lower column address */
|
||||
|
||||
#define LCD_COL_OFFSET 2 /* column offset */
|
||||
|
||||
static inline void bitdelay(void)
|
||||
{
|
||||
unsigned int i = 15;
|
||||
__asm__ __volatile__ (
|
||||
".set noreorder \n"
|
||||
"1: \n"
|
||||
"bne %0, $0, 1b \n"
|
||||
"addi %0, %0, -1 \n"
|
||||
".set reorder \n"
|
||||
: "=r" (i)
|
||||
: "0" (i)
|
||||
);
|
||||
}
|
||||
|
||||
void lcd_hw_init(void)
|
||||
{
|
||||
REG_GPIO_PXFUNC(2) = 0x000C73FC; /* D0-D7 RD DC CS RES WR */
|
||||
REG_GPIO_PXSELC(2) = 0x000C73FC;
|
||||
REG_GPIO_PXDIRS(2) = 0x000C73FC;
|
||||
REG_GPIO_PXDATS(2) = 0x000C73FC;
|
||||
__gpio_clear_pin(PIN_BL_EN);
|
||||
__gpio_as_output(PIN_BL_EN);
|
||||
__gpio_clear_pin(PIN_LCD_RES);
|
||||
udelay(1);
|
||||
__gpio_set_pin(PIN_LCD_RES);
|
||||
__gpio_clear_pin(PIN_LCD_CS);
|
||||
}
|
||||
|
||||
void lcd_write_command(int byte)
|
||||
{
|
||||
__gpio_clear_pin(PIN_LCD_DC);
|
||||
REG_GPIO_PXDATC(2) = 0x000030FC;
|
||||
REG_GPIO_PXDATS(2) = ((byte & 0xC0) << 6) | ((byte & 0x3F) << 2);
|
||||
__gpio_clear_pin(PIN_LCD_WR);
|
||||
bitdelay();
|
||||
__gpio_set_pin(PIN_LCD_WR);
|
||||
bitdelay();
|
||||
}
|
||||
|
||||
void lcd_write_data(const fb_data* p_bytes, int count)
|
||||
{
|
||||
__gpio_set_pin(PIN_LCD_DC);
|
||||
while (count--)
|
||||
{
|
||||
REG_GPIO_PXDATC(2) = 0x000030FC;
|
||||
REG_GPIO_PXDATS(2) = ((*p_bytes & 0xC0) << 6) | ((*p_bytes & 0x3F) << 2);
|
||||
p_bytes++;
|
||||
__gpio_clear_pin(PIN_LCD_WR);
|
||||
bitdelay();
|
||||
__gpio_set_pin(PIN_LCD_WR);
|
||||
bitdelay();
|
||||
}
|
||||
}
|
||||
|
||||
void lcd_enable_power(bool onoff)
|
||||
{
|
||||
if (onoff)
|
||||
__gpio_set_pin(PIN_BL_EN);
|
||||
else
|
||||
__gpio_clear_pin(PIN_BL_EN);
|
||||
}
|
||||
|
||||
/** globals **/
|
||||
|
||||
static bool display_on = false; /* used by lcd_enable */
|
||||
|
||||
/*** hardware configuration ***/
|
||||
|
||||
void lcd_set_contrast(int val)
|
||||
{
|
||||
lcd_write_command(LCD_CNTL_CONTRAST);
|
||||
lcd_write_command(val);
|
||||
}
|
||||
|
||||
void lcd_set_invert_display(bool yesno)
|
||||
{
|
||||
if (yesno)
|
||||
lcd_write_command(LCD_SET_REVERSE_DISPLAY);
|
||||
else
|
||||
lcd_write_command(LCD_SET_NORMAL_DISPLAY);
|
||||
}
|
||||
|
||||
/* turn the display upside down (call lcd_update() afterwards) */
|
||||
void lcd_set_flip(bool yesno)
|
||||
{
|
||||
if (yesno)
|
||||
{
|
||||
lcd_write_command(LCD_SET_SEGMENT_REMAP);
|
||||
lcd_write_command(LCD_SET_COM_OUTPUT_SCAN_DIRECTION);
|
||||
}
|
||||
else
|
||||
{
|
||||
lcd_write_command(LCD_SET_SEGMENT_REMAP_INV);
|
||||
lcd_write_command(LCD_SET_COM_OUTPUT_SCAN_DIRECTION_INV);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_LCD_ENABLE
|
||||
void lcd_enable(bool enable)
|
||||
{
|
||||
if(display_on == enable)
|
||||
return;
|
||||
|
||||
if( (display_on = enable) ) /* simple '=' is not a typo ! */
|
||||
{
|
||||
lcd_enable_power(enable);
|
||||
lcd_write_command(LCD_SET_DISPLAY_ON);
|
||||
send_event(LCD_EVENT_ACTIVATION, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
lcd_write_command(LCD_SET_DISPLAY_OFF);
|
||||
lcd_enable_power(enable);
|
||||
}
|
||||
}
|
||||
|
||||
bool lcd_active(void)
|
||||
{
|
||||
return display_on;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* LCD init, largely based on what OF does */
|
||||
void lcd_init_device(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
lcd_hw_init();
|
||||
|
||||
/* Set display off */
|
||||
lcd_write_command(LCD_SET_DISPLAY_OFF);
|
||||
|
||||
/* Set display clock and oscillator frequency */
|
||||
lcd_write_command(LCD_SET_DISPLAY_CLOCK_AND_OSC_FREQ);
|
||||
lcd_write_command(0x80);
|
||||
|
||||
/* Set multiplex ratio*/
|
||||
lcd_write_command(LCD_SET_MULTIPLEX_RATIO);
|
||||
lcd_write_command(0x3F);
|
||||
|
||||
/* Set display offset */
|
||||
lcd_write_command(LCD_SET_DISPLAY_OFFSET);
|
||||
lcd_write_command(0x00);
|
||||
|
||||
/* Set starting line as 0 */
|
||||
lcd_write_command(LCD_SET_DISPLAY_START_LINE);
|
||||
|
||||
/* Set charge pump */
|
||||
lcd_write_command(LCD_SET_CHARGE_PUMP);
|
||||
lcd_write_command(0x14); /* VCC Generated by Internal DC/DC Circuit */
|
||||
|
||||
/* Column 131 is remapped to SEG0 */
|
||||
lcd_write_command(LCD_SET_SEGMENT_REMAP_INV);
|
||||
|
||||
/* Invert COM scan direction (N-1 to 0) */
|
||||
lcd_write_command(LCD_SET_COM_OUTPUT_SCAN_DIRECTION_INV);
|
||||
|
||||
/* Set COM hardware configuration */
|
||||
lcd_write_command(LCD_SET_VCOM_HW_CONFIGURATION);
|
||||
lcd_write_command(0x12);
|
||||
|
||||
/* Set contrast control */
|
||||
lcd_write_command(LCD_SET_CONTRAST_CONTROL_REGISTER);
|
||||
lcd_write_command(0xCF); /* VCC Generated by Internal DC/DC Circuit */
|
||||
|
||||
/* Set pre-charge period */
|
||||
lcd_write_command(LCD_SET_PRECHARGE_PERIOD);
|
||||
lcd_write_command(0xF1); /* VCC Generated by Internal DC/DC Circuit */
|
||||
|
||||
/* Set VCOM deselect level */
|
||||
lcd_write_command(LCD_SET_VCOM_DESELECT_LEVEL);
|
||||
lcd_write_command(0x40);
|
||||
|
||||
/* Set normal display mode (not every pixel ON) */
|
||||
lcd_write_command(LCD_SET_ENTIRE_DISPLAY_OFF);
|
||||
|
||||
/* Set normal display mode (not inverted) */
|
||||
lcd_write_command(LCD_SET_NORMAL_DISPLAY);
|
||||
|
||||
fb_data p_bytes[LCD_WIDTH + 2 * LCD_COL_OFFSET];
|
||||
memset(p_bytes, 0, sizeof(p_bytes)); /* fills with 0 : pixel off */
|
||||
for(i = 0; i < 8; i++)
|
||||
{
|
||||
lcd_write_command (LCD_SET_PAGE_ADDRESS | (i /*& 0xf*/));
|
||||
lcd_write_data(p_bytes, LCD_WIDTH + 2 * LCD_COL_OFFSET);
|
||||
}
|
||||
|
||||
lcd_enable(true);
|
||||
|
||||
lcd_update();
|
||||
}
|
||||
|
||||
/*** Update functions ***/
|
||||
|
||||
/* Performance function that works with an external buffer
|
||||
note that by and bheight are in 8-pixel units! */
|
||||
void lcd_blit_mono(const unsigned char *data, int x, int by, int width,
|
||||
int bheight, int stride)
|
||||
{
|
||||
if(!display_on)
|
||||
return;
|
||||
|
||||
/* Copy display bitmap to hardware */
|
||||
while (bheight--)
|
||||
{
|
||||
lcd_write_command (LCD_CNTL_PAGE | (by++ & 0xf));
|
||||
lcd_write_command (LCD_CNTL_HIGHCOL | (((x+LCD_COL_OFFSET)>>4) & 0xf));
|
||||
lcd_write_command (LCD_CNTL_LOWCOL | ((x+LCD_COL_OFFSET) & 0xf));
|
||||
|
||||
lcd_write_data(data, width);
|
||||
data += stride;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifndef BOOTLOADER
|
||||
/* Helper function for lcd_grey_phase_blit(). */
|
||||
void lcd_grey_data(unsigned char *values, unsigned char *phases, int count) ICODE_ATTR;
|
||||
void lcd_grey_data(unsigned char *values, unsigned char *phases, int count)
|
||||
{
|
||||
unsigned char a, b, c, d;
|
||||
|
||||
__gpio_set_pin(PIN_LCD_DC);
|
||||
while(count--)
|
||||
{
|
||||
c = 0;
|
||||
d = 8;
|
||||
while(d--)
|
||||
{
|
||||
a = *phases;
|
||||
b = *values++;
|
||||
b += a & ~0x80;
|
||||
*phases++ = b;
|
||||
c <<= 1;
|
||||
c |= a >> 7;
|
||||
}
|
||||
REG_GPIO_PXDATC(2) = 0x000030FC;
|
||||
REG_GPIO_PXDATS(2) = ((c & 0xC0) << 6) | ((c & 0x3F) << 2);
|
||||
__gpio_clear_pin(PIN_LCD_WR);
|
||||
bitdelay();
|
||||
__gpio_set_pin(PIN_LCD_WR);
|
||||
bitdelay();
|
||||
}
|
||||
}
|
||||
|
||||
/* Performance function that works with an external buffer
|
||||
note that by and bheight are in 8-pixel units! */
|
||||
void lcd_blit_grey_phase(unsigned char *values, unsigned char *phases,
|
||||
int x, int by, int width, int bheight, int stride)
|
||||
{
|
||||
if(!display_on)
|
||||
return;
|
||||
|
||||
stride <<= 3; /* 8 pixels per block */
|
||||
/* Copy display bitmap to hardware */
|
||||
while (bheight--)
|
||||
{
|
||||
lcd_write_command (LCD_CNTL_PAGE | (by++ & 0xf));
|
||||
lcd_write_command (LCD_CNTL_HIGHCOL | (((x+LCD_COL_OFFSET)>>4) & 0xf));
|
||||
lcd_write_command (LCD_CNTL_LOWCOL | ((x+LCD_COL_OFFSET) & 0xf));
|
||||
|
||||
lcd_grey_data(values, phases, width);
|
||||
|
||||
values += stride;
|
||||
phases += stride;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Update the display.
|
||||
This must be called after all other LCD functions that change the display. */
|
||||
void lcd_update(void) ICODE_ATTR;
|
||||
void lcd_update(void)
|
||||
{
|
||||
int y;
|
||||
|
||||
if(!display_on)
|
||||
return;
|
||||
|
||||
/* Copy display bitmap to hardware */
|
||||
for (y = 0; y < LCD_FBHEIGHT; y++)
|
||||
{
|
||||
lcd_write_command (LCD_CNTL_PAGE | (y & 0xf));
|
||||
lcd_write_command (LCD_CNTL_HIGHCOL | ((LCD_COL_OFFSET >> 4) & 0xf));
|
||||
lcd_write_command (LCD_CNTL_LOWCOL | (LCD_COL_OFFSET & 0xf));
|
||||
|
||||
lcd_write_data (FBADDR(0, y), LCD_WIDTH);
|
||||
}
|
||||
}
|
||||
|
||||
/* Update a fraction of the display. */
|
||||
void lcd_update_rect(int, int, int, int) ICODE_ATTR;
|
||||
void lcd_update_rect(int x, int y, int width, int height)
|
||||
{
|
||||
int ymax;
|
||||
|
||||
if(!display_on)
|
||||
return;
|
||||
|
||||
/* The Y coordinates have to work on even 8 pixel rows */
|
||||
if (x < 0)
|
||||
{
|
||||
width += x;
|
||||
x = 0;
|
||||
}
|
||||
|
||||
if (x + width > LCD_WIDTH)
|
||||
width = LCD_WIDTH - x;
|
||||
|
||||
if (width <= 0)
|
||||
return; /* nothing left to do, 0 is harmful to lcd_write_data() */
|
||||
|
||||
if (y < 0)
|
||||
{
|
||||
height += y;
|
||||
y = 0;
|
||||
}
|
||||
|
||||
if (y + height > LCD_HEIGHT)
|
||||
height = LCD_HEIGHT - y;
|
||||
|
||||
if (height <= 0)
|
||||
return; /* nothing left to do */
|
||||
|
||||
ymax = (y + height-1) >> 3;
|
||||
y >>= 3;
|
||||
|
||||
/* Copy specified rectange bitmap to hardware */
|
||||
for (; y <= ymax; y++)
|
||||
{
|
||||
lcd_write_command (LCD_CNTL_PAGE | (y & 0xf));
|
||||
lcd_write_command (LCD_CNTL_HIGHCOL | (((x+LCD_COL_OFFSET) >> 4) & 0xf));
|
||||
lcd_write_command (LCD_CNTL_LOWCOL | ((x+LCD_COL_OFFSET) & 0xf));
|
||||
|
||||
lcd_write_data (FBADDR(x,y), width);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2016 by Roman Stolyarov
|
||||
*
|
||||
* 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 "power.h"
|
||||
#include "cpu.h"
|
||||
|
||||
#define CHARGE_STAT_GPIO (32*1+6) /* STAT port */
|
||||
|
||||
/* Detect which power sources are present. */
|
||||
unsigned int power_input_status(void)
|
||||
{
|
||||
if(!__gpio_get_pin(CHARGE_STAT_GPIO))
|
||||
return POWER_INPUT_USB_CHARGER;
|
||||
|
||||
return POWER_INPUT_NONE;
|
||||
}
|
||||
|
||||
void power_init(void)
|
||||
{
|
||||
__gpio_as_input(CHARGE_STAT_GPIO);
|
||||
__gpio_disable_pull(CHARGE_STAT_GPIO);
|
||||
}
|
||||
|
||||
bool charging_state(void)
|
||||
{
|
||||
return (power_input_status() == POWER_INPUT_USB_CHARGER);
|
||||
}
|
||||
214
firmware/target/mips/ingenic_jz47xx/xduoo_x3/sadc-xduoo_x3.c
Normal file
214
firmware/target/mips/ingenic_jz47xx/xduoo_x3/sadc-xduoo_x3.c
Normal file
|
|
@ -0,0 +1,214 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2016 by Roman Stolyarov
|
||||
*
|
||||
* 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 "system.h"
|
||||
#include "cpu.h"
|
||||
#include "button.h"
|
||||
#include "button-target.h"
|
||||
#include "powermgmt.h"
|
||||
#include "kernel.h"
|
||||
#include "backlight.h"
|
||||
#include "logf.h"
|
||||
#include "adc.h"
|
||||
|
||||
#define PIN_BTN_POWER (32*0+30)
|
||||
#define PIN_BTN_HOLD (32*1+15)
|
||||
|
||||
#define PIN_KEY_INT (32*4+13)
|
||||
#define KEY_INT_IRQ GPIO141
|
||||
|
||||
#define PIN_CHARGE_CON (32*1+7)
|
||||
|
||||
#define PIN_PH_DECT (32*1+11)
|
||||
#define IRQ_PH_DECT GPIO_IRQ(PIN_PH_DECT)
|
||||
#define GPIO_PH_DECT GPIO43
|
||||
|
||||
#define PIN_LO_DECT (32*1+12)
|
||||
#define IRQ_LO_DECT GPIO_IRQ(PIN_LO_DECT)
|
||||
#define GPIO_LO_DECT GPIO44
|
||||
|
||||
static volatile unsigned short bat_val,key_val;
|
||||
|
||||
bool headphones_inserted(void)
|
||||
{
|
||||
return (__gpio_get_pin(PIN_PH_DECT) != 0);
|
||||
}
|
||||
|
||||
void button_init_device(void)
|
||||
{
|
||||
key_val = 0xfff;
|
||||
|
||||
__gpio_as_input(PIN_BTN_POWER);
|
||||
__gpio_as_input(PIN_BTN_HOLD);
|
||||
|
||||
__gpio_disable_pull(PIN_BTN_POWER);
|
||||
__gpio_disable_pull(PIN_BTN_HOLD);
|
||||
|
||||
__gpio_as_irq_fall_edge(PIN_KEY_INT);
|
||||
system_enable_irq(GPIO_IRQ(PIN_KEY_INT));
|
||||
|
||||
__gpio_set_pin(PIN_CHARGE_CON); /* 0.7 A */
|
||||
__gpio_as_output(PIN_CHARGE_CON);
|
||||
|
||||
__gpio_as_input(PIN_LO_DECT);
|
||||
__gpio_as_input(PIN_PH_DECT);
|
||||
|
||||
__gpio_disable_pull(PIN_LO_DECT);
|
||||
__gpio_disable_pull(PIN_PH_DECT);
|
||||
}
|
||||
|
||||
bool button_hold(void)
|
||||
{
|
||||
return (__gpio_get_pin(PIN_BTN_HOLD) ? true : false);
|
||||
}
|
||||
|
||||
int button_read_device(void)
|
||||
{
|
||||
static bool hold_button = false;
|
||||
bool hold_button_old;
|
||||
|
||||
hold_button_old = hold_button;
|
||||
hold_button = (__gpio_get_pin(PIN_BTN_HOLD) ? true : false);
|
||||
|
||||
int btn = BUTTON_NONE;
|
||||
bool gpio_btn = (__gpio_get_pin(PIN_BTN_POWER) ? false : true);
|
||||
|
||||
REG_SADC_ADCFG = ADCFG_VBAT_SEL + ADCFG_CMD_AUX(1);
|
||||
REG_SADC_ADENA = ADENA_VBATEN + ADENA_AUXEN;
|
||||
|
||||
#ifndef BOOTLOADER
|
||||
if (hold_button != hold_button_old) {
|
||||
backlight_hold_changed(hold_button);
|
||||
}
|
||||
if (hold_button) {
|
||||
return BUTTON_NONE;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (gpio_btn)
|
||||
btn |= BUTTON_POWER;
|
||||
|
||||
if (key_val < 261)
|
||||
btn |= BUTTON_VOL_UP;
|
||||
else
|
||||
if (key_val < 653)
|
||||
btn |= BUTTON_VOL_DOWN;
|
||||
else
|
||||
if (key_val < 1101)
|
||||
btn |= BUTTON_PREV;
|
||||
else
|
||||
if (key_val < 1498)
|
||||
btn |= BUTTON_NEXT;
|
||||
else
|
||||
if (key_val < 1839)
|
||||
btn |= BUTTON_PLAY;
|
||||
else
|
||||
if (key_val < 2213)
|
||||
btn |= BUTTON_OPTION;
|
||||
else
|
||||
if (key_val < 2600)
|
||||
btn |= BUTTON_HOME;
|
||||
|
||||
return btn;
|
||||
}
|
||||
|
||||
/* called on button press interrupt */
|
||||
void KEY_INT_IRQ(void)
|
||||
{
|
||||
}
|
||||
|
||||
const unsigned short battery_level_dangerous[BATTERY_TYPES_COUNT] =
|
||||
{
|
||||
/* 5% */
|
||||
3634
|
||||
};
|
||||
|
||||
const unsigned short battery_level_shutoff[BATTERY_TYPES_COUNT] =
|
||||
{
|
||||
/* 0% */
|
||||
3300
|
||||
};
|
||||
|
||||
|
||||
/* voltages (millivolt) of 0%, 10%, ... 100% when charging disabled */
|
||||
const unsigned short percent_to_volt_discharge[BATTERY_TYPES_COUNT][11] =
|
||||
{
|
||||
{ 3300, 3652, 3704, 3730, 3753, 3786, 3836, 3906, 3973, 4061, 4160 }
|
||||
};
|
||||
|
||||
#if CONFIG_CHARGING
|
||||
/* voltages (millivolt) of 0%, 10%, ... 100% when charging enabled */
|
||||
const unsigned short percent_to_volt_charge[11] =
|
||||
{ 3300, 3652, 3704, 3730, 3753, 3786, 3836, 3906, 3973, 4061, 4160 };
|
||||
#endif /* CONFIG_CHARGING */
|
||||
|
||||
/* VBAT = (BDATA/1024) * 2.5V */
|
||||
#define BATTERY_SCALE_FACTOR 2460
|
||||
|
||||
/* Returns battery voltage from ADC [millivolts] */
|
||||
int _battery_voltage(void)
|
||||
{
|
||||
return (bat_val*BATTERY_SCALE_FACTOR)>>10;
|
||||
}
|
||||
|
||||
void adc_init(void)
|
||||
{
|
||||
bat_val = 0xfff;
|
||||
|
||||
__cpm_start_sadc();
|
||||
mdelay(10);
|
||||
REG_SADC_ADENA = 0; /* Power Up */
|
||||
mdelay(70);
|
||||
REG_SADC_ADSTATE = 0;
|
||||
REG_SADC_ADCTRL = ADCTRL_MASK_ALL - ADCTRL_ARDYM - ADCTRL_VRDYM;
|
||||
REG_SADC_ADCFG = ADCFG_VBAT_SEL + ADCFG_CMD_AUX(1);
|
||||
REG_SADC_ADCLK = (4 << 16) | (1 << 8) | 59; /* 200KHz */
|
||||
system_enable_irq(IRQ_SADC);
|
||||
}
|
||||
|
||||
void adc_close(void)
|
||||
{
|
||||
REG_SADC_ADENA = ADENA_POWER; /* Power Down */
|
||||
__intc_mask_irq(IRQ_SADC);
|
||||
mdelay(20);
|
||||
__cpm_stop_sadc();
|
||||
}
|
||||
|
||||
/* Interrupt handler */
|
||||
void SADC(void)
|
||||
{
|
||||
unsigned char state;
|
||||
unsigned char sadcstate;
|
||||
|
||||
sadcstate = REG_SADC_ADSTATE;
|
||||
state = REG_SADC_ADSTATE & (~REG_SADC_ADCTRL);
|
||||
REG_SADC_ADSTATE &= sadcstate;
|
||||
|
||||
if(state & ADCTRL_ARDYM)
|
||||
{
|
||||
key_val = REG_SADC_ADADAT;
|
||||
}
|
||||
if(state & ADCTRL_VRDYM)
|
||||
{
|
||||
bat_val = REG_SADC_ADVDAT;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue