📄 mmc_pxa.c
字号:
MMC_CMDAT = MMC_CMDAT_R1|MMC_CMDAT_WRITE|MMC_CMDAT_BLOCK|MMC_CMDAT_DATA_EN;#ifndef PIO MMC_CMDAT |= MMC_CMDAT_MMC_DMA_EN; #endif MMC_NOB = 1; MMC_BLKLEN = transfer->blksz; MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD24(0x%04x%04x)\n", argh, argl ); if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, FALSE )) ) goto error; /* transfer the data to the caller supplied buffer */ if ( (ret = pxa_mmc_copy_to_buffer( ctrlr, transfer->type, transfer->buf, transfer->cnt )) < 0 ) goto error; if ( (ret = pxa_mmc_write_buffer( ctrlr, ret )) < 0 ) goto error; transfer->buf += ret; transfer->cnt -= ret; transfer->nob -= 1; pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_END_IO ); if ( (ret = pxa_mmc_complete_io( ctrlr, transfer->cmd, transfer->mode )) ) goto error; ret = 0; error: return ret;}/* This procedure sequentally writes data blocks to a card at a given address */static ssize_t pxa_mmc_write_mblock( mmc_controller_t ctrlr, mmc_data_transfer_req_t transfer ){ int ret = -EIO; u16 argh = 0UL, argl = 0UL; // printk(KERN_EMERG"%s::%s\n\n", __FILE__, __FUNCTION__); /* send CMD16 (SET_BLOCK_LEN) when requested block size is not the default * for the current card */ if ( transfer->blksz != ctrlr->stack.selected->info.write_bl_len ) { argh = transfer->blksz >> 16; argl = transfer->blksz; if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) ) goto error; MMC_CMD = CMD(16); /* SET_BLOCK_LEN */ MMC_ARGH = argh; MMC_ARGL = argl; MMC_CMDAT = MMC_CMDAT_R1; MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD16(0x%04x%04x)\n", argh, argl ); if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, FALSE )) ) goto error; } argh = transfer->addr >> 16; argl = transfer->addr;/* 1. stop bus clock */ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) ) goto error;/* 2. setup controller registers to start multiple block transfer */ MMC_CMD = CMD(25); /* WRITE_MULTIPLE_BLOCK */ MMC_ARGH = argh; MMC_ARGL = argl; MMC_NOB = transfer->nob; MMC_BLKLEN = transfer->blksz; MMC_CMDAT = MMC_CMDAT_R1|MMC_CMDAT_WRITE|MMC_CMDAT_BLOCK|MMC_CMDAT_DATA_EN;#ifndef PIO MMC_CMDAT |= MMC_CMDAT_MMC_DMA_EN; #endif/* 3. start clock */ if ( (ret = pxa_mmc_start_bus_clock( ctrlr )) ) goto error; /* 4. wait for cmd to complete */ MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD25(0x%04x%04x)\n", argh, argl ); if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, TRUE )) ) goto error;/* 6. transfer the data to the caller supplied buffer */ while ( transfer->cnt > 0 ) { if ( (ret = pxa_mmc_copy_to_buffer( ctrlr, transfer->type, transfer->buf, transfer->cnt )) < 0 ) goto error; if ( (ret = pxa_mmc_write_buffer( ctrlr, ret )) < 0 ) goto error; transfer->buf += ret; transfer->cnt -= ret; } pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_END_IO ); if ( (ret = pxa_mmc_complete_io( ctrlr, transfer->cmd, transfer->mode )) ) goto error; ret = 0; error: return ret;}static void pxa_mmc_irq( int irq, void *dev_id, struct pt_regs *regs ){ mmc_controller_t ctrlr = (mmc_controller_t)dev_id; pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data; static int irq_n=1;#ifdef PIO register int i, cnt, j; register char *buf; unsigned long * posi; char remain=0; unsigned long value;#endif hostdata->mmc_i_reg = MMC_I_REG; hostdata->mmc_stat = MMC_STAT; hostdata->mmc_cmdat = MMC_CMDAT; hostdata->mmc_cmd = MMC_CMD; // printk(KERN_EMERG"NO. %d MMC INTERRUPT OCCOUR \n", irq_n); /* printk(KERN_EMERG"%s::%s::MMC_I_MASK=0x%08x\n", __FILE__,__FUNCTION__, MMC_I_MASK); printk(KERN_EMERG"%s::%s::MMC_I_REG=0x%08x\n", __FILE__,__FUNCTION__, MMC_I_REG ); printk(KERN_EMERG"%s::%s::MMC_STAT=0x%08x\n", __FILE__, __FUNCTION__, MMC_STAT); printk(KERN_EMERG"%s::%s::MMC_CMDAT=0x%08x\n", __FILE__, __FUNCTION__, MMC_CMDAT); printk(KERN_EMERG"%s::%s::MMC_CMD=0x%08x\n", __FILE__, __FUNCTION__, MMC_CMD); */ // printk(KERN_EMERG"%s::%s::hostdata->state is 0x%08x\n", __FILE__, __FUNCTION__, hostdata->state); irq_n++;#if CONFIG_MMC_DEBUG_IRQ if ( --hostdata->irqcnt <= 0 ) { //printk( KERN_INFO __FUNCTION__"(): irqcnt exceeded\n" ); goto complete; }#endif switch ( hostdata->state ) { case PXA_MMC_FSM_IDLE: case PXA_MMC_FSM_CLK_OFF: case PXA_MMC_FSM_END_IO: case PXA_MMC_FSM_END_BUFFER: case PXA_MMC_FSM_END_CMD: goto complete;#ifdef PIO case PXA_MMC_FSM_BUFFER_IN_TRANSIT: // printk(KERN_EMERG"PXA_MMC_FSM_BUFFER_IN_TRANSIT\n"); if ( hostdata->mmc_stat & MMC_STAT_ERRORS ) goto complete; buf = hostdata->iobuf.buf.pos; cnt = (hostdata->iobuf.buf.cnt < 32) ? hostdata->iobuf.buf.cnt : 32; if ( hostdata->mmc_cmdat & MMC_CMDAT_WRITE ) { //printk(KERN_EMERG"EXECUTE THE WRITE OPERATION \n"); /*if ( !(hostdata->mmc_stat & MMC_STAT_XMIT_FIFO_EMPTY) ) break; */ posi = (unsigned long *) buf; remain = cnt % 4; cnt = cnt / 4; if (remain) cnt++; for ( i = 0; i < cnt; i++ ) { value = *posi++; MMC_TXFIFO = value; //MMC_TXFIFO = *buf++; } if ( remain ) MMC_PRTBUF = MMC_PRTBUF_BUF_PART_FULL; } else { /* i.e. MMC_CMDAT_READ */ /*if( !(hostdata->mmc_stat & MMC_STAT_RECV_FIFO_FULL) ) break;*/ // unsigned long value; posi = (unsigned long *) buf; remain = cnt % 4; cnt = cnt / 4; for( i = 0; i < cnt; i++ ) { value = MMC_RXFIFO; *posi++ = value; //*buf = MMC_RXFIFO ; // printk("MMC_STAT is 0x%08x, MMC_I_REG is 0x%08x, buf[%d] is 0x%08x\n",MMC_STAT ,MMC_I_REG, i , value); //buf++; } if (remain) { value = MMC_RXFIFO; buf = (char *)posi; for(j=0; j<remain; j++ ) { *buf++ = (value & 0xff); value = value >>8; } } } hostdata->iobuf.buf.pos = (char *)posi; hostdata->iobuf.buf.cnt -= (i*4 + remain); // printk("hostdata->iobuf.buf.cnt is %d\n", hostdata->iobuf.buf.cnt); if ( hostdata->iobuf.buf.cnt <= 0 ) { pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_END_BUFFER ); MMC_DEBUG( MMC_DEBUG_LEVEL3, "buffer transferred\n"); goto complete; } break; #endif /* PIO */ default: MMC_DEBUG( MMC_DEBUG_LEVEL3, "unexpected state %d\n", hostdata->state ); goto complete; } return; complete: MMC_I_MASK = MMC_I_MASK_ALL; complete( &hostdata->completion ); return;}#ifndef PIOstatic void pxa_mmc_dma_irq( int irq, void *dev_id, struct pt_regs *regs ){ mmc_controller_t ctrlr = (mmc_controller_t)dev_id; pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data; u32 dcsr; u32 ddadr; int chan = hostdata->iobuf.buf.chan; ddadr = DDADR( chan ); dcsr = DCSR( chan ); DCSR( chan ) = dcsr & ~DCSR_STOPIRQEN; MMC_DEBUG( MMC_DEBUG_LEVEL3, "MMC DMA interrupt: chan=%d ddadr=0x%08x " "dcmd=0x%08x dcsr=0x%08x\n", chan, ddadr, DCMD( chan ), dcsr );/* bus error */ if ( dcsr & DCSR_BUSERR ) { MMC_DEBUG( MMC_DEBUG_LEVEL3, "bus error on DMA channel %d\n", chan ); pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_ERROR ); goto complete; }/* data transfer completed */ if ( dcsr & DCSR_ENDINTR ) { MMC_DEBUG( MMC_DEBUG_LEVEL3, "buffer transferred\n" ); pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_END_BUFFER ); goto complete; } return;complete: complete( &hostdata->completion ); return;}#endifstatic int pxa_mmc_init( mmc_controller_t ctrlr ){ int ret = -ENODEV; pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data;#ifndef PIO register int i; register pxa_dma_desc *desc;#endif/* hardware initialization *//* I. prepare to transfer data *//* 1. allocate buffer */#ifndef PIO hostdata->iobuf.buf.read_desc = consistent_alloc( GFP_KERNEL, (PXA_MMC_IODATA_SIZE>>5) * sizeof( pxa_dma_desc ), &hostdata->iobuf.buf.read_desc_phys_addr, 0 ); if ( !hostdata->iobuf.buf.read_desc ) { ret = -ENOMEM; goto error; } hostdata->iobuf.buf.write_desc = consistent_alloc( GFP_KERNEL, (PXA_MMC_IODATA_SIZE>>5) * sizeof( pxa_dma_desc ), &hostdata->iobuf.buf.write_desc_phys_addr, 0 ); if ( !hostdata->iobuf.buf.write_desc ) { ret = -ENOMEM; goto error; } hostdata->iobuf.iodata = consistent_alloc( GFP_ATOMIC, PXA_MMC_IODATA_SIZE, &hostdata->iobuf.buf.phys_addr, 0 );#else hostdata->iobuf.iodata = kmalloc( PXA_MMC_IODATA_SIZE, GFP_ATOMIC );#endif if ( !hostdata->iobuf.iodata ) { ret = -ENOMEM; goto error; }/* 2. initialize iobuf */ hostdata->iobuf.blksz = PXA_MMC_BLKSZ_MAX; hostdata->iobuf.bufsz = PXA_MMC_IODATA_SIZE; hostdata->iobuf.nob = PXA_MMC_BLOCKS_PER_BUFFER;#ifndef PIO /* request DMA channel */ if ( (hostdata->iobuf.buf.chan = pxa_request_dma( "MMC", DMA_PRIO_LOW, pxa_mmc_dma_irq, ctrlr )) < 0 ) { MMC_ERROR( "failed to request DMA channel\n" ); goto error; } DRCMRRXMMC = hostdata->iobuf.buf.chan | DRCMR_MAPVLD; DRCMRTXMMC = hostdata->iobuf.buf.chan | DRCMR_MAPVLD; for ( i = 0; i < ((PXA_MMC_IODATA_SIZE>>5) - 1); i++ ) { desc = &hostdata->iobuf.buf.read_desc[i]; desc->ddadr = hostdata->iobuf.buf.read_desc_phys_addr + ((i + 1) * sizeof( pxa_dma_desc )); desc->dsadr = MMC_RXFIFO_PHYS_ADDR; desc->dtadr = hostdata->iobuf.buf.phys_addr + (i<<5); desc->dcmd = DCMD_FLOWSRC|DCMD_INCTRGADDR |DCMD_WIDTH1|DCMD_BURST32|(1<<5); desc = &hostdata->iobuf.buf.write_desc[i]; desc->ddadr = hostdata->iobuf.buf.write_desc_phys_addr + ((i + 1) * sizeof( pxa_dma_desc )); desc->dsadr = hostdata->iobuf.buf.phys_addr + (i<<5); desc->dtadr = MMC_TXFIFO_PHYS_ADDR; desc->dcmd = DCMD_FLOWTRG|DCMD_INCSRCADDR |DCMD_WIDTH1|DCMD_BURST32|(1<<5); } desc = &hostdata->iobuf.buf.read_desc[i]; desc->ddadr = (hostdata->iobuf.buf.read_desc_phys_addr + (i + 1) * sizeof( pxa_dma_desc))|DDADR_STOP; desc->dsadr = MMC_RXFIFO_PHYS_ADDR; desc->dtadr = hostdata->iobuf.buf.phys_addr + (i<<5); desc->dcmd = DCMD_FLOWSRC|DCMD_INCTRGADDR |DCMD_WIDTH1|DCMD_BURST32|(1<<5); desc = &hostdata->iobuf.buf.write_desc[i]; desc->ddadr = (hostdata->iobuf.buf.write_desc_phys_addr + (i + 1) * sizeof( pxa_dma_desc))|DDADR_STOP; desc->dsadr = hostdata->iobuf.buf.phys_addr + (i<<5); desc->dtadr = MMC_TXFIFO_PHYS_ADDR; desc->dcmd = DCMD_FLOWTRG|DCMD_INCSRCADDR |DCMD_WIDTH1|DCMD_BURST32|(1<<5);#endif/* II. MMC *//* 1) request irq */ if ( request_irq( IRQ_MMC, pxa_mmc_irq, 0, "MMC", ctrlr ) ) { MMC_ERROR( "failed to request IRQ_MMC\n" ); goto error; } /* 2) initialize h/w and ctrlr */ //set_GPIO_mode( GPIO6_MMCCLK_MD ); init_gpio( ); CKEN |= CKEN12_MMC; /* enable MMC unit clock */ ret = 0; goto out;error:#ifndef PIO/* free DMA resources */ if ( hostdata->iobuf.buf.chan >= 0 ) { DRCMRRXMMC = 0; DRCMRTXMMC = 0; pxa_free_dma( hostdata->iobuf.buf.chan ); } if ( hostdata->iobuf.iodata ) consistent_free( hostdata->iobuf.iodata, PXA_MMC_IODATA_SIZE, hostdata->iobuf.buf.phys_addr ); if ( hostdata->iobuf.buf.read_desc ) consistent_free( hostdata->iobuf.buf.read_desc, (PXA_MMC_IODATA_SIZE>>5) * sizeof( pxa_dma_desc ), hostdata->iobuf.buf.read_desc_phys_addr ); if ( hostdata->iobuf.buf.write_desc ) consistent_free( hostdata->iobuf.buf.write_desc, (PXA_MMC_IODATA_SIZE>>5) * sizeof( pxa_dma_desc ), hostdata->iobuf.buf.write_desc_phys_addr );#else kfree( hostdata->iobuf.iodata );#endifout: return ret; }static void pxa_mmc_remove( mmc_controller_t ctrlr ){ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data; /* 1) free buffer(s) */#ifndef PIO consistent_free( hostdata->iobuf.iodata, PXA_MMC_IODATA_SIZE, hostdata->iobuf.buf.phys_addr ); consistent_free( hostdata->iobuf.buf.read_desc, (PXA_MMC_IODATA_SIZE>>5) * sizeof( pxa_dma_desc ), hostdata->iobuf.buf.read_desc_phys_addr ); consistent_free( hostdata->iobuf.buf.write_desc, (PXA_MMC_IODATA_SIZE>>5) * sizeof( pxa_dma_desc ), hostdata->iobuf.buf.write_desc_phys_addr );/* 2) release DMA channel */ if ( hostdata->iobuf.buf.chan >= 0 ) { DRCMRRXMMC = 0; DRCMRTXMMC = 0; pxa_free_dma( hostdata->iobuf.buf.chan ); }#else kfree( hostdata->iobuf.iodata );#endif/* II. MMC *//* 1) release irq */ free_irq( IRQ_MMC, ctrlr ); CKEN &= ~CKEN12_MMC; /* disable MMC unit clock */}static int pxa_mmc_probe( mmc_controller_t ctrlr ){ return 1;}#ifdef CONFIG_PMstatic int pxa_mmc_suspend( mmc_controller_t ctrlr ){ int ret = -EBUSY; pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data; MMC_DEBUG( MMC_DEBUG_LEVEL2, "state=%s\n", PXA_MMC_STATE_LABEL( hostdata->state ) ); if ( hostdata->state == PXA_MMC_FSM_IDLE ) { /* save registers */ SAVED_MMC_CLKRT = MMC_CLKRT; SAVED_MMC_RESTO = MMC_RESTO; SAVED_MMC_SPI = MMC_SPI; SAVED_DRCMRRXMMC = DRCMRRXMMC; SAVED_DRCMRTXMMC = DRCMRTXMMC;#if 0 /* FIXME */ /* send CMD0 */ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) ) goto error; MMC_CMD = CMD(0); /* CMD0 with zero argument */ MMC_ARGH = 0UL; MMC_ARGL = 0UL; MMC_
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -