827 lines
17 KiB
C
827 lines
17 KiB
C
|
||
/*
|
||
* Copyright (c) 2007-2017 Allwinnertech Co., Ltd.
|
||
*
|
||
* This software is licensed under the terms of the GNU General Public
|
||
* License version 2, as published by the Free Software Foundation, and
|
||
* may be copied, distributed, and modified under those terms.
|
||
*
|
||
* This program is distributed in the hope that it will be useful,
|
||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
* GNU General Public License for more details.
|
||
*
|
||
*/
|
||
|
||
/**
|
||
* spi_hal.c
|
||
* date: 2012/2/12 22:34:41
|
||
* author: Aaron<leafy.myeh@allwinnertech.com>
|
||
* history: V0.1
|
||
*/
|
||
//#include "include.h"
|
||
#include "nand_type_spinand.h"
|
||
#include "spic.h"
|
||
#include "spinand_drv_cfg.h"
|
||
#include "spinand_interface_for_common.h"
|
||
|
||
#define MAX_SPI_NUM 2
|
||
#if 0
|
||
struct spic_info {
|
||
__u32 spi_no;
|
||
__s32 irq;
|
||
__u32 sclk;
|
||
__u32 master;
|
||
u8 *txbuf;
|
||
__u32 txptr;
|
||
__u32 txnum;
|
||
u8 *rxbuf;
|
||
__u32 rxptr;
|
||
__u32 rxnum;
|
||
__u32 usedma;
|
||
__s32 txdma_ch;
|
||
__s32 rxdma_ch;
|
||
__u32 error;
|
||
volatile __u32 done;
|
||
volatile __u32 txdma_done;
|
||
volatile __u32 rxdma_done;
|
||
} spicinfo[MAX_SPI_NUM];
|
||
#endif
|
||
// extern void *SPIC_IO_BASE;
|
||
|
||
#if 0
|
||
__u32 spi_cfg_mclk(__u32 spi_no, __u32 src, __u32 mclk)
|
||
{
|
||
struct spic_info *spic = &spicinfo[spi_no];
|
||
__u32 mclk_base = CCM_SPI_CLK_REG + 4 * spi_no;
|
||
__u32 source_clk;
|
||
__u32 rval;
|
||
__u32 m, n, div;
|
||
|
||
#ifdef FPGA_PLATFORM
|
||
spic->sclk = 24000000;
|
||
return spic->sclk;
|
||
#else
|
||
switch (src) {
|
||
case 0:
|
||
source_clk = 24000000;
|
||
break;
|
||
case 1:
|
||
source_clk = ccm_get_pll_periph0_clk();
|
||
break;
|
||
case 2:
|
||
source_clk = ccm_get_pll_periph1_clk();
|
||
break;
|
||
default:
|
||
printk("Wrong SPI clock source :%x\n", src);
|
||
break;
|
||
}
|
||
|
||
div = (source_clk + mclk - 1) / mclk;
|
||
div = div == 0 ? 1 : div;
|
||
if (div > 128) {
|
||
m = 1;
|
||
n = 0;
|
||
printk("Source clock is too high\n");
|
||
} else if (div > 64) {
|
||
n = 3;
|
||
m = div >> 3;
|
||
} else if (div > 32) {
|
||
n = 2;
|
||
m = div >> 2;
|
||
} else if (div > 16) {
|
||
n = 1;
|
||
m = div >> 1;
|
||
} else {
|
||
n = 0;
|
||
m = div;
|
||
}
|
||
|
||
rval = (1U << 31) | (src << 24) | (n << 16) | (m - 1);
|
||
writew(rval, mclk_base);
|
||
spic->sclk = source_clk / (1 << n) / (m - 1);
|
||
return spic->sclk;
|
||
#endif
|
||
}
|
||
|
||
/*
|
||
*__u32 spi_get_mlk(__u32 spi_no)
|
||
*{
|
||
* return spicinfo[spi_no].sclk;
|
||
*}
|
||
*/
|
||
void spi_onoff(__u32 spi_no, __u32 onoff)
|
||
{
|
||
__u32 clkid[] = {SPI_CKID};
|
||
|
||
switch (spi_no) {
|
||
case 0:
|
||
//pc0~3,pc2:cs,muliti3
|
||
gpio_set_cfg(GPIO_C(0), 4, 3);
|
||
gpio_set_pull(GPIO_C(2), 1, 1);
|
||
gpio_set_drv(GPIO_C(0), 4, 1);
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
|
||
ccm_module_reset(clkid[spi_no]);
|
||
if (onoff)
|
||
ccm_clock_enable(clkid[spi_no]);
|
||
else
|
||
ccm_clock_disable(clkid[spi_no]);
|
||
}
|
||
#endif
|
||
|
||
#if 0
|
||
void spi_irq_handler(__u32 spi_no)
|
||
{
|
||
struct spic_info *spic = &spicinfo[spi_no];
|
||
__u32 isr = readw(SPI_ISR);
|
||
|
||
/* check error */
|
||
if (isr & (SPI_TXUR_INT|SPI_TXOF_INT|SPI_RXUR_INT|SPI_RXOF_INT)) {
|
||
printk("spi %d FIFO run error, isr 0x%x\n", spi_no, isr);
|
||
spic->done = 1;
|
||
spic->error = isr & (SPI_TXUR_INT|SPI_TXOF_INT|SPI_RXUR_INT|
|
||
SPI_RXOF_INT);
|
||
goto out;
|
||
}
|
||
/* check transfer compelete */
|
||
if (isr & SPI_TC_INT) {
|
||
if (!spic->usedma && (isr & SPI_RXREQ_INT)) {
|
||
__u32 rcnt = readw(SPI_FSR) & 0xff;
|
||
// if (rcnt > spic->rxnum - spic->rxptr)
|
||
// rcnt = spic->rxnum - spic->rxptr;
|
||
while (rcnt) {
|
||
spic->rxbuf[spic->rxptr++] = readb(SPI_RXD);
|
||
rcnt--;
|
||
}
|
||
if (spic->rxptr != spic->rxnum)
|
||
printk("Rx number != total number\n");
|
||
}
|
||
writew(SPI_ERROR_INT, SPI_IER);
|
||
spic->done = 1;
|
||
goto out;
|
||
}
|
||
if (!spic->usedma) {
|
||
if (isr & SPI_RXREQ_INT) {
|
||
//__u32 rcnt = SPI_RX_WL;
|
||
__u32 rcnt = readw(SPI_FSR) & 0xff;
|
||
|
||
if (rcnt > spic->rxnum - spic->rxptr)
|
||
rcnt = spic->rxnum - spic->rxptr;
|
||
while (rcnt) {
|
||
spic->rxbuf[spic->rxptr++] = readb(SPI_RXD);
|
||
rcnt--;
|
||
}
|
||
}
|
||
if (isr & SPI_TXREQ_INT) {
|
||
__u32 tcnt = SPI_FIFO_SIZE - SPI_TX_WL;
|
||
|
||
if (tcnt > spic->txnum - spic->txptr)
|
||
tcnt = spic->txnum - spic->txptr;
|
||
while (tcnt) {
|
||
writeb(spic->txbuf[spic->txptr++], SPI_TXD);
|
||
tcnt--;
|
||
}
|
||
}
|
||
}
|
||
out:
|
||
writew(isr, SPI_ISR);
|
||
}
|
||
|
||
#define SPIx_IRQ_DEFINE(_n) \
|
||
static void spi##_n##_irq_hdle(void) \
|
||
{ \
|
||
spi_irq_handler(_n); \
|
||
}
|
||
SPIx_IRQ_DEFINE(0)
|
||
SPIx_IRQ_DEFINE(1)
|
||
|
||
static void (*spi_irq_hdle[])(void) = {
|
||
spi0_irq_hdle,
|
||
spi1_irq_hdle,
|
||
|
||
};
|
||
#endif
|
||
|
||
#if 0
|
||
#if 0
|
||
void spic_set_clk(__u32 spi_no, __u32 clk)
|
||
{
|
||
// __u32 mclk = spi_get_mlk(spi_no);
|
||
__u32 mclk = AHBCLK;
|
||
__u32 div;
|
||
__u32 cdr1 = 0;
|
||
__u32 cdr2 = 0;
|
||
__u32 cdr_sel = 0;
|
||
|
||
div = mclk/(clk<<1)-1;
|
||
|
||
if (mclk < (clk<<1))
|
||
div++;
|
||
|
||
if (mclk%(clk<<1))
|
||
div++;
|
||
|
||
if (div == 0) {
|
||
cdr1 = 0;
|
||
cdr2 = 0;
|
||
cdr_sel = 0;
|
||
} else if (div <= 0x100) {
|
||
cdr1 = 0;
|
||
cdr2 = div;
|
||
cdr_sel = 1;
|
||
} else {
|
||
div = 0;
|
||
while (mclk > clk) {
|
||
div++;
|
||
mclk >>= 1;
|
||
}
|
||
cdr1 = div;
|
||
cdr2 = 0;
|
||
cdr_sel = 0;
|
||
}
|
||
|
||
writel((cdr_sel<<12)|(cdr1<<8)|cdr2, SPI_CCR);
|
||
}
|
||
#else
|
||
void spic_set_clk(__u32 spi_no, __u32 clk)
|
||
{
|
||
// __u32 mclk = spi_get_mlk(spi_no);
|
||
__u32 mclk = AHBCLK;
|
||
__u32 div;
|
||
__u32 cdr1 = 0;
|
||
__u32 cdr2 = 0;
|
||
__u32 cdr_sel = 0;
|
||
|
||
if (mclk < clk) {
|
||
printk("spi %d set_clk failed,%d MHz < %d MHz\n",
|
||
spi_no, (mclk / 1000000), (clk / 1000000));
|
||
}
|
||
|
||
div = mclk/(clk<<1);
|
||
if ((mclk < (clk<<1)) && (mclk > clk))
|
||
div++;
|
||
|
||
if (div == 0) {
|
||
cdr1 = 0;
|
||
cdr2 = 0;
|
||
cdr_sel = 0;
|
||
} else if (div <= 0x100) {
|
||
cdr1 = 0;
|
||
cdr2 = div-1;
|
||
cdr_sel = 1;
|
||
} else {
|
||
div = 0;
|
||
while (mclk > clk) {
|
||
div++;
|
||
mclk >>= 1;
|
||
}
|
||
cdr1 = div;
|
||
cdr2 = 0;
|
||
cdr_sel = 0;
|
||
}
|
||
|
||
writew((cdr_sel<<12)|(cdr1<<8)|cdr2, SPI_CCR);
|
||
}
|
||
#endif
|
||
|
||
__u32 spic_get_clk(__u32 spi_no)
|
||
{
|
||
// __u32 mclk = spi_get_mlk(spi_no);
|
||
__u32 mclk = AHBCLK;
|
||
__u32 temp;
|
||
__u32 temp_clk;
|
||
|
||
mclk = mclk / 1000000;
|
||
temp = readw(SPI_CCR);
|
||
if (temp && (1<<12)) {
|
||
temp_clk = mclk / 2 / ((temp & 0xff) + 1);
|
||
} else {
|
||
temp_clk = mclk >> ((temp >> 8) & 0xf);
|
||
}
|
||
return temp_clk;
|
||
}
|
||
#endif
|
||
|
||
__s32 Wait_Tc_Complete(void)
|
||
{
|
||
__u32 timeout = 0xffffff;
|
||
|
||
while (!(readw(SPI_ISR) & (0x1 << 12))) {// wait transfer complete
|
||
timeout--;
|
||
if (!timeout)
|
||
break;
|
||
}
|
||
if (timeout == 0) {
|
||
PHY_ERR("TC Complete wait status timeout!\n");
|
||
return ERR_TIMEOUT;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
__s32 Spic_init(__u32 spi_no)
|
||
{
|
||
__u32 rval;
|
||
// __s32 irq;
|
||
|
||
// MEMSET(&spicinfo[spi_no], 0, sizeof(struct spic_info));
|
||
|
||
// init pin
|
||
if (0 != NAND_PIORequest(spi_no)) {
|
||
PHY_ERR("request spi gpio fail!\n");
|
||
return -1;
|
||
} else
|
||
PHY_DBG("request spi gpio ok!\n");
|
||
|
||
// SPIC_IO_BASE = NAND_GetIOBaseAddr();
|
||
|
||
// request general dma channel
|
||
if (0 != spinand_request_tx_dma()) {
|
||
PHY_ERR("request tx dma fail!\n");
|
||
return -1;
|
||
} else
|
||
PHY_DBG("request general tx dma channel ok!\n");
|
||
|
||
if (0 != spinand_request_rx_dma()) {
|
||
PHY_ERR("request rx dma fail!\n");
|
||
return -1;
|
||
} else
|
||
PHY_DBG("request general rx dma channel ok!\n");
|
||
|
||
// init clk
|
||
NAND_ClkRequest(spi_no);
|
||
NAND_SetClk(spi_no, 20, 20 * 2);
|
||
|
||
rval = SPI_SOFT_RST | SPI_TXPAUSE_EN | SPI_MASTER | SPI_ENABLE;
|
||
writew(rval, SPI_GCR);
|
||
|
||
rval = SPI_SET_SS_1 | SPI_DHB |
|
||
SPI_SS_ACTIVE0; // set ss to high,discard unused burst,SPI select
|
||
// signal polarity(low,1=idle)
|
||
writew(rval, SPI_TCR);
|
||
|
||
writew(0x1000,
|
||
SPI_CCR); // SPI data clk = source clk / 2, Duty Ratio <20><> 50%
|
||
#if 0
|
||
irq = irq_request(SPI_IRQNO(spi_no), spi_irq_hdle[spi_no]);
|
||
if (irq < 0) {
|
||
printk("Request spi %d irq failed\n", spi_no);
|
||
return -1;
|
||
}
|
||
irq_enable(irq);
|
||
spicinfo[spi_no].irq = irq;
|
||
#endif
|
||
// spicinfo[spi_no].master = 1;
|
||
writew(SPI_TXFIFO_RST | (SPI_TX_WL << 16) | (SPI_RX_WL), SPI_FCR);
|
||
writew(SPI_ERROR_INT, SPI_IER);
|
||
|
||
return 0;
|
||
}
|
||
|
||
__s32 Spic_exit(__u32 spi_no)
|
||
{
|
||
__u32 rval;
|
||
// __s32 irq;
|
||
|
||
rval = readw(SPI_GCR);
|
||
rval &= (~(SPI_SOFT_RST | SPI_MASTER | SPI_ENABLE));
|
||
writew(rval, SPI_GCR);
|
||
#if 0
|
||
irq = spicinfo[spi_no].irq;
|
||
irq_disable(irq);
|
||
irq_free(irq);
|
||
#endif
|
||
|
||
NAND_ClkRelease(spi_no);
|
||
|
||
spinand_releasetxdma();
|
||
spinand_releaserxdma();
|
||
|
||
// init pin
|
||
NAND_PIORelease(spi_no);
|
||
|
||
// MEMSET(&spicinfo[spi_no], 0, sizeof(struct spic_info));
|
||
|
||
rval = SPI_SET_SS_1 | SPI_DHB |
|
||
SPI_SS_ACTIVE0; // set ss to high,discard unused burst,SPI select
|
||
// signal polarity(low,1=idle)
|
||
writew(rval, SPI_TCR);
|
||
|
||
return 0;
|
||
}
|
||
|
||
void Spic_set_master_slave(__u32 spi_no, __u32 master)
|
||
{
|
||
__u32 rval = readw(SPI_GCR) & (~(1 << 1));
|
||
|
||
rval |= master << 1;
|
||
writew(rval, SPI_GCR);
|
||
// spicinfo[spi_no].master = master;
|
||
}
|
||
|
||
void Spic_sel_ss(__u32 spi_no, __u32 ssx)
|
||
{
|
||
__u32 rval = readw(SPI_TCR) & (~(3 << 4));
|
||
|
||
rval |= ssx << 4;
|
||
writew(rval, SPI_TCR);
|
||
}
|
||
// add for aw1650
|
||
void Spic_set_transmit_LSB(__u32 spi_no, __u32 tmod)
|
||
{
|
||
__u32 rval = readw(SPI_TCR) & (~(1 << 12));
|
||
|
||
rval |= tmod << 12;
|
||
writew(rval, SPI_TCR);
|
||
}
|
||
|
||
void Spic_set_ss_level(__u32 spi_no, __u32 level)
|
||
{
|
||
__u32 rval = readw(SPI_TCR) & (~(1 << 7));
|
||
|
||
rval |= level << 7;
|
||
writew(rval, SPI_TCR);
|
||
}
|
||
|
||
void Spic_set_rapids(__u32 spi_no, __u32 rapids)
|
||
{
|
||
__u32 rval = readw(SPI_TCR) & (~(1 << 10));
|
||
|
||
rval |= rapids << 10;
|
||
writew(rval, SPI_TCR);
|
||
}
|
||
|
||
void Spic_set_sample_mode(__u32 spi_no, __u32 smod)
|
||
{
|
||
__u32 rval = readw(SPI_TCR) & (~(1 << 13));
|
||
|
||
rval |= smod << 13;
|
||
writew(rval, SPI_TCR);
|
||
}
|
||
|
||
void Spic_set_sample(__u32 spi_no, __u32 sample)
|
||
{
|
||
__u32 rval = readw(SPI_TCR) & (~(1 << 11));
|
||
|
||
rval |= sample << 11;
|
||
writew(rval, SPI_TCR);
|
||
}
|
||
|
||
void Spic_set_trans_mode(__u32 spi_no, __u32 mode)
|
||
{
|
||
__u32 rval = readw(SPI_TCR) & (~(3 << 0));
|
||
|
||
rval |= mode << 0;
|
||
writew(rval, SPI_TCR);
|
||
}
|
||
|
||
void Spic_set_wait_clk(__u32 spi_no, __u32 swc, __u32 wcc)
|
||
{
|
||
writew((swc << 16) | (wcc), SPI_WCR);
|
||
}
|
||
#if 0
|
||
void spic_dma_onoff(__u32 spi_no, __u32 dma)
|
||
{
|
||
spicinfo[spi_no].usedma = dma;
|
||
}
|
||
|
||
void spic_dma_txcb(__u32 data)
|
||
{
|
||
struct spic_info *spic = (struct spic_info *)data;
|
||
|
||
spic->txdma_done = 1;
|
||
}
|
||
|
||
void spic_dma_rxcb(__u32 data)
|
||
{
|
||
struct spic_info *spic = (struct spic_info *)data;
|
||
|
||
spic->rxdma_done = 1;
|
||
}
|
||
|
||
__s32 spic_dma_config(__u32 spi_no, __u32 tx_mode, __u32 buff_addr, __u32 len)
|
||
{
|
||
struct spic_info *spic = &spicinfo[spi_no];
|
||
__s32 chan;
|
||
__u32 param = 0;
|
||
__u32 config;
|
||
__u32 dmatype[] = {DMA_TYPE_SPI0};
|
||
__u32 drqno_tx[] = {DMA_CFG_DST_DRQ_SPI0};
|
||
__u32 drqno_rx[] = {DMA_CFG_SRC_DRQ_SPI0};
|
||
|
||
if (tx_mode == 1) {
|
||
chan = dma_request(dmatype[spi_no], spic_dma_txcb,
|
||
DMA_QUEUE_END_IRQFLAG, (__u32)spic);
|
||
if (chan < 0) {
|
||
printk("Request spi %d dma channel failed\n", spi_no);
|
||
return -1;
|
||
}
|
||
spic->txdma_ch = chan;
|
||
param = 0x10;
|
||
config = DMA_CFG_SRC_BST1_WIDTH8 | DMA_CFG_SRC_LINEAR |
|
||
drqno_tx[spi_no] | DMA_CFG_DST_BST1_WIDTH8 |
|
||
DMA_CFG_DST_IO;
|
||
|
||
config |= DMA_CFG_SRC_DRQ_SDRAM;
|
||
|
||
dma_setup(chan, config, param);
|
||
dma_enqueue(chan, (__u32)buff_addr, SPI_TXD, len);
|
||
|
||
NAND_CleanFlushDCacheRegion(buff_addr, len);
|
||
nand_dma_config_start(tx_mode, buff_addr, len);
|
||
} else {
|
||
chan = dma_request(dmatype[spi_no], spic_dma_rxcb,
|
||
DMA_QUEUE_END_IRQFLAG, (__u32)spic);
|
||
if (chan < 0) {
|
||
printk("Request spi %d dma channel failed\n", spi_no);
|
||
return -1;
|
||
}
|
||
spic->rxdma_ch = chan;
|
||
param = 0x10;
|
||
config = DMA_CFG_DST_BST1_WIDTH8 | DMA_CFG_DST_LINEAR |
|
||
drqno_rx[spi_no] | DMA_CFG_SRC_BST1_WIDTH8 |
|
||
DMA_CFG_SRC_IO;
|
||
|
||
config |= DMA_CFG_DST_DRQ_SDRAM;
|
||
|
||
dma_setup(chan, config, param);
|
||
dma_enqueue(chan, SPI_RXD, (__u32)buff_addr, len);
|
||
}
|
||
dma_start(chan);
|
||
|
||
// NAND_CleanFlushDCacheRegion(buff_addr, len);
|
||
// nand_dma_config_start( rw, nand_dma_addr[NandIndex][0], len);
|
||
|
||
return 0;
|
||
}
|
||
#endif
|
||
void Spic_config_io_mode(__u32 spi_no, __u32 rxmode, __u32 dbc, __u32 stc)
|
||
{
|
||
if (rxmode == 0)
|
||
writew((dbc << 24) | (stc), SPI_BCC);
|
||
else if (rxmode == 1)
|
||
writew((1 << 28) | (dbc << 24) | (stc), SPI_BCC);
|
||
else if (rxmode == 2)
|
||
writew((1 << 29) | (dbc << 24) | (stc), SPI_BCC);
|
||
}
|
||
|
||
/*
|
||
* spi txrx
|
||
* _ _______ ______________
|
||
* |_______|/_/_/_/_/_/_/_|
|
||
*/
|
||
#if 0
|
||
__s32 spic_rw(__u32 spi_no, __u32 txlen, void *txbuff, __u32 rxlen,
|
||
void *rxbuff, __u32 dummy_cnt)
|
||
{
|
||
struct spic_info *spic = &spicinfo[spi_no];
|
||
__u32 ier;
|
||
//__u32 tmp;
|
||
spic->txdma_done = 0;
|
||
spic->rxdma_done = 0;
|
||
spic->done = 0;
|
||
|
||
/* config transmit counters */
|
||
ier = readl(SPI_IER)|SPI_TC_INT; //transmit complete enable
|
||
writel(ier, SPI_IER);
|
||
pattern_goto(20);
|
||
writel(txlen, SPI_MTC);
|
||
pattern_goto(21);
|
||
writel(txlen+rxlen+dummy_cnt, SPI_MBC);
|
||
pattern_goto(22);
|
||
/* start transmit */
|
||
writel(readl(SPI_TCR)|SPI_EXCHANGE, SPI_TCR);
|
||
pattern_goto(23);
|
||
/* config dma */
|
||
if (spic->usedma) {
|
||
__u32 fcr = readl(SPI_FCR);
|
||
|
||
if (rxlen) {
|
||
fcr |= SPI_RXDMAREQ_EN;
|
||
writel(fcr, SPI_FCR);
|
||
pattern_goto(24);
|
||
spic_dma_config(spi_no, 0, rxbuff, rxlen);
|
||
pattern_goto(25);
|
||
}
|
||
if (txlen) {
|
||
/* flush cache */
|
||
#ifdef SYS_ENABLE_DCACHE
|
||
FlushDcacheRegion((void *)txbuff, txlen);
|
||
#endif
|
||
fcr |= SPI_TXDMAREQ_EN;
|
||
writel(fcr, SPI_FCR);
|
||
pattern_goto(26);
|
||
spic_dma_config(spi_no, 1, txbuff, txlen);
|
||
pattern_goto(27);
|
||
}
|
||
|
||
/* wait dma done */
|
||
while (rxlen && !spic->rxdma_done) {
|
||
};
|
||
while (txlen && !spic->txdma_done) {
|
||
};
|
||
pattern_goto(28);
|
||
if (rxlen) {
|
||
/* flush cache */
|
||
#ifdef SYS_ENABLE_DCACHE
|
||
FlushDcacheRegion((void *)rxbuff, rxlen);
|
||
#endif
|
||
}
|
||
spic->rxdma_done = 0;
|
||
spic->txdma_done = 0;
|
||
fcr &= ~(SPI_TXDMAREQ_EN|SPI_RXDMAREQ_EN);
|
||
writel(fcr, SPI_FCR);
|
||
pattern_goto(29);
|
||
} else {
|
||
spic->txbuf = txbuff;
|
||
spic->txptr = 0;
|
||
spic->txnum = txlen;
|
||
spic->rxbuf = rxbuff;
|
||
spic->rxptr = 0;
|
||
spic->rxnum = rxlen;
|
||
if (rxlen)
|
||
ier |= SPI_RXREQ_INT;
|
||
pattern_goto(30);
|
||
if (txlen)
|
||
ier |= SPI_TXREQ_INT;
|
||
pattern_goto(31);
|
||
writel(ier, SPI_IER);
|
||
pattern_goto(32);
|
||
}
|
||
pattern_goto(33);
|
||
/* wait transfer compelete */
|
||
while (!spic->done) {
|
||
};
|
||
pattern_goto(34);
|
||
if (spic->error) {
|
||
printk("spi %d transfer failed\n", spi_no);
|
||
writel(readl(SPI_FCR)|SPI_TXFIFO_RST, SPI_FCR);
|
||
pattern_goto(35);
|
||
return -1;
|
||
}
|
||
pattern_goto(36);
|
||
writel(readl(SPI_IER)&(~(SPI_RXREQ_INT|SPI_TXREQ_INT|SPI_TC_INT)),
|
||
SPI_IER);
|
||
pattern_goto(39);
|
||
return 0;
|
||
}
|
||
#else
|
||
__s32 Spic_rw(__u32 spi_no, __u32 tcnt, __u8 *txbuf, __u32 rcnt, __u8 *rxbuf,
|
||
__u32 dummy_cnt)
|
||
{
|
||
__u32 i = 0, fcr;
|
||
__u32 tx_dma_flag = 0;
|
||
__u32 rx_dma_flag = 0;
|
||
__s32 timeout = 0xffff;
|
||
|
||
writew(0, SPI_IER);
|
||
writew(0xffffffff, SPI_ISR); // clear status register
|
||
|
||
writew(tcnt, SPI_MTC);
|
||
writew(tcnt + rcnt + dummy_cnt, SPI_MBC);
|
||
|
||
// read and write by cpu operation
|
||
if (tcnt) {
|
||
if (tcnt < 64) {
|
||
i = 0;
|
||
while (i < tcnt) {
|
||
// send data
|
||
// while ((readw(SPI_FSR)>>16)==SPI_FIFO_SIZE);
|
||
if (((readw(SPI_FSR) >> 16) & 0x7f) ==
|
||
SPI_FIFO_SIZE)
|
||
PHY_ERR("TX FIFO size error!\n");
|
||
writeb(*(txbuf + i), SPI_TXD);
|
||
i++;
|
||
}
|
||
} else {
|
||
tx_dma_flag = 1;
|
||
|
||
writew((readw(SPI_FCR) | SPI_TXDMAREQ_EN), SPI_FCR);
|
||
|
||
nand_dma_config_start(1, (__u32)txbuf, tcnt);
|
||
#if 0
|
||
timeout = 0xffffff;
|
||
while (readw(DMA_IRQ_PEND_REG)&0x7 != 7) {
|
||
timeout--;
|
||
if (!timeout)
|
||
break;
|
||
}
|
||
if (timeout == 0) {
|
||
PHY_ERR("TX DMA wait status timeout!\n");
|
||
return ERR_TIMEOUT;
|
||
}
|
||
#endif
|
||
}
|
||
}
|
||
/* start transmit */
|
||
writew(readw(SPI_TCR) | SPI_EXCHANGE, SPI_TCR);
|
||
if (rcnt) {
|
||
if (rcnt < 64) {
|
||
i = 0;
|
||
#if 1
|
||
timeout = 0xfffff;
|
||
while (1) {
|
||
if (((readw(SPI_FSR)) & 0x7f) == rcnt)
|
||
break;
|
||
if (timeout < 0) {
|
||
PHY_ERR(
|
||
"RX FIFO size error,timeout!\n");
|
||
break;
|
||
}
|
||
timeout--;
|
||
}
|
||
#endif
|
||
while (i < rcnt) {
|
||
// receive valid data
|
||
// while(((readw(SPI_FSR))&0x7f)==0);
|
||
// while((((readw(SPI_FSR))&0x7f)!=rcnt)||
|
||
// timeout < 0))
|
||
// PHY_ERR("RX FIFO size error!\n");
|
||
*(rxbuf + i) = readb(SPI_RXD);
|
||
i++;
|
||
}
|
||
} else {
|
||
rx_dma_flag = 1;
|
||
|
||
writew((readw(SPI_FCR) | SPI_RXDMAREQ_EN), SPI_FCR);
|
||
|
||
nand_dma_config_start(0, (__u32)rxbuf, rcnt);
|
||
#if 0
|
||
timeout = 0xffffff;
|
||
while (readw(DMA_IRQ_PEND_REG)&0x7 != 7) {
|
||
timeout--;
|
||
if (!timeout)
|
||
break;
|
||
}
|
||
if (timeout == 0) {
|
||
PHY_ERR("RX DMA wait status timeout!\n");
|
||
return ERR_TIMEOUT;
|
||
}
|
||
|
||
//while (readw(SPI_FSR)&0x7f);
|
||
if (readw(SPI_FSR)&0x7f) {
|
||
PHY_ERR("RX FIFO not empty after DMA finish!\n");
|
||
}
|
||
#endif
|
||
}
|
||
}
|
||
|
||
if (NAND_WaitDmaFinish(tx_dma_flag, rx_dma_flag)) {
|
||
PHY_ERR("DMA wait status timeout!\n");
|
||
return ERR_TIMEOUT;
|
||
}
|
||
|
||
if (Wait_Tc_Complete()) {
|
||
PHY_ERR("wait tc complete timeout!\n");
|
||
return ERR_TIMEOUT;
|
||
}
|
||
|
||
if (tx_dma_flag)
|
||
Nand_Dma_End(1, (__u32)txbuf, tcnt);
|
||
|
||
if (rx_dma_flag)
|
||
Nand_Dma_End(0, (__u32)rxbuf, rcnt);
|
||
|
||
fcr = readw(SPI_FCR);
|
||
fcr &= ~(SPI_TXDMAREQ_EN | SPI_RXDMAREQ_EN);
|
||
writew(fcr, SPI_FCR);
|
||
if (readw(SPI_ISR) &
|
||
(0xf << 8)) {/* (1U << 11) | (1U << 10) | (1U << 9) | (1U << 8)) */
|
||
PHY_ERR("FIFO status error: 0x%x!\n", readw(SPI_ISR));
|
||
return NAND_OP_FALSE;
|
||
}
|
||
|
||
if (readw(SPI_TCR) & SPI_EXCHANGE)
|
||
PHY_ERR("XCH Control Error!!\n");
|
||
|
||
writew(0xffffffff, SPI_ISR); /* clear flag */
|
||
|
||
return NAND_OP_TRUE;
|
||
}
|
||
#endif
|
||
|
||
__s32 spi_nand_rdid(__u32 spi_no, __u32 chip, __u32 id_addr, __u32 addr_cnt,
|
||
__u32 id_cnt, void *id)
|
||
{
|
||
__s32 ret = NAND_OP_TRUE;
|
||
__u8 sdata[2];
|
||
__u32 txnum;
|
||
__u32 rxnum;
|
||
|
||
txnum = 1 + addr_cnt;
|
||
rxnum = id_cnt; // mira nand:rxnum=5
|
||
|
||
sdata[0] = SPI_NAND_RDID;
|
||
sdata[1] = id_addr; // add 00H:Maunufation ID,01H:Device ID
|
||
|
||
Spic_sel_ss(spi_no, chip);
|
||
|
||
Spic_config_io_mode(spi_no, 0, 0, txnum);
|
||
ret = Spic_rw(spi_no, txnum, (void *)sdata, rxnum, (void *)id, 0);
|
||
return ret;
|
||
}
|