mirror of
https://gitlab.rtems.org/rtems/rtos/rtems.git
synced 2025-12-17 13:24:59 +08:00
683 lines
22 KiB
C
683 lines
22 KiB
C
/*===============================================================*\
|
|
| Project: RTEMS generic MPC5200 BSP |
|
|
+-----------------------------------------------------------------+
|
|
| Partially based on the code references which are named below. |
|
|
| Adaptions, modifications, enhancements and any recent parts of |
|
|
| the code are: |
|
|
| Copyright (c) 2005 |
|
|
| embedded brains GmbH |
|
|
| Obere Lagerstr. 30 |
|
|
| 82178 Puchheim |
|
|
| Germany |
|
|
| rtems@embedded-brains.de |
|
|
+-----------------------------------------------------------------+
|
|
| The license and distribution terms for this file may be |
|
|
| found in the file LICENSE in this distribution or at |
|
|
| |
|
|
| http://www.rtems.org/license/LICENSE. |
|
|
| |
|
|
+-----------------------------------------------------------------+
|
|
| this file contains the PCMCIA IDE access functions |
|
|
\*===============================================================*/
|
|
/***********************************************************************/
|
|
/* */
|
|
/* Module: pcmcia_ide.c */
|
|
/* Date: 07/17/2003 */
|
|
/* Purpose: RTEMS MPC5x00 PCMCIA IDE harddisk driver */
|
|
/* */
|
|
/*---------------------------------------------------------------------*/
|
|
/* */
|
|
/* Description: */
|
|
/* */
|
|
/*---------------------------------------------------------------------*/
|
|
/* */
|
|
/* Code */
|
|
/* References: RTEMS MBX8xx PCMCIA IDE harddisc driver */
|
|
/* Module: pcmcia_ide.c */
|
|
/* Project: RTEMS 4.6.0pre1 / Mbx8xx BSP */
|
|
/* Version */
|
|
/* Date: 01/14/2003 */
|
|
/* */
|
|
/* Author(s) / Copyright(s): */
|
|
/* */
|
|
/* Copyright (c) 2003 IMD */
|
|
/* Ingenieurbuero fuer Microcomputertechnik Th. Doerfler */
|
|
/* <Thomas.Doerfler@imd-systems.de> */
|
|
/* all rights reserved */
|
|
/* */
|
|
/* this file contains the BSP layer for PCMCIA IDE access below the */
|
|
/* libchip IDE harddisc driver based on a board specific driver from */
|
|
/* Eugeny S. Mints, Oktet */
|
|
/* */
|
|
/* The license and distribution terms for this file may be */
|
|
/* found in the file LICENSE in this distribution or at */
|
|
/* http://www.rtems.org/license/LICENSE. */
|
|
/* */
|
|
/*---------------------------------------------------------------------*/
|
|
/* */
|
|
/* Partially based on the code references which are named above. */
|
|
/* Adaptions, modifications, enhancements and any recent parts of */
|
|
/* the code are under the right of */
|
|
/* */
|
|
/* IPR Engineering, Dachauer Straße 38, D-80335 München */
|
|
/* Copyright(C) 2003 */
|
|
/* */
|
|
/*---------------------------------------------------------------------*/
|
|
/* */
|
|
/* IPR Engineering makes no representation or warranties with */
|
|
/* respect to the performance of this computer program, and */
|
|
/* specifically disclaims any responsibility for any damages, */
|
|
/* special or consequential, connected with the use of this program. */
|
|
/* */
|
|
/*---------------------------------------------------------------------*/
|
|
/* */
|
|
/* Version history: 1.0 */
|
|
/* */
|
|
/***********************************************************************/
|
|
|
|
#include <sys/param.h>
|
|
#include <rtems.h>
|
|
#include <rtems/error.h>
|
|
#include <rtems/score/sysstate.h>
|
|
#include <bsp.h>
|
|
#include <bsp/irq.h>
|
|
#include <bsp/mpc5200.h>
|
|
#include "./pcmcia_ide.h"
|
|
|
|
#include <libchip/ide_ctrl.h>
|
|
#include <libchip/ide_ctrl_cfg.h>
|
|
#include <libchip/ide_ctrl_io.h>
|
|
#include <string.h>
|
|
|
|
#define IDE_DMA_TEST FALSE
|
|
|
|
/* DMA supported PIO mode is broken */
|
|
#define IDE_USE_INT TRUE
|
|
#define IDE_READ_USE_DMA FALSE
|
|
#define IDE_USE_READ_PIO_OPT FALSE
|
|
#define IDE_WRITE_USE_DMA FALSE
|
|
#define IDE_USE_WRITE_PIO_OPT FALSE
|
|
#define IDE_USE_DMA (IDE_READ_USE_DMA || IDE_WRITE_USE_DMA)
|
|
|
|
#define IDE_USE_STATISTICS TRUE
|
|
|
|
#if IDE_USE_DMA
|
|
#define PCMCIA_IDE_DMA_WR_BD_CNT 2
|
|
#define PCMCIA_IDE_DMA_RD_BD_CNT 2
|
|
#define PCMCIA_IDE_INTERRUPT_EVENT RTEMS_EVENT_2
|
|
/* Task number assignment */
|
|
#include "../bestcomm/bestcomm_glue.h"
|
|
#include "../bestcomm/bestcomm_api.h"
|
|
#include "../bestcomm/task_api/bestcomm_cntrl.h"
|
|
#include "../bestcomm/task_api/tasksetup_bdtable.h"
|
|
|
|
#define IDE_RX_TASK_NO TASK_GEN_DP_BD_0
|
|
#define IDE_TX_TASK_NO TASK_GEN_DP_BD_1
|
|
static TaskId pcmcia_ide_rxTaskId; /* SDMA RX task ID */
|
|
static TaskId pcmcia_ide_txTaskId; /* SDMA TX task ID */
|
|
#define PCMCIA_IDE_RD_SECTOR_SIZE 512 /* FIXME: make this better... */
|
|
#define PCMCIA_IDE_WR_SECTOR_SIZE 512 /* FIXME: make this better... */
|
|
|
|
bool mpc5200_dma_task_started[2] = {false,false};
|
|
#endif /* IDE_USE_DMA */
|
|
|
|
#if IDE_USE_STATISTICS
|
|
uint32_t mpc5200_pcmciaide_write_block_call_cnt = 0;
|
|
uint32_t mpc5200_pcmciaide_write_block_block_cnt = 0;
|
|
uint32_t mpc5200_pcmciaide_read_block_call_cnt = 0;
|
|
uint32_t mpc5200_pcmciaide_read_block_block_cnt = 0;
|
|
#endif
|
|
|
|
extern volatile uint32_t * mpc5200_ata_drive_regs[];
|
|
extern uint32_t ata_pio_timings[2][6];
|
|
|
|
void mpc5200_pcmciaide_dma_blockop(
|
|
bool, int, uint16_t, rtems_blkdev_sg_buffer *, uint32_t *, uint32_t *);
|
|
/*
|
|
* support functions for PCMCIA IDE IF
|
|
*/
|
|
static bool mpc5200_pcmciaide_probe(int minor)
|
|
{
|
|
bool ide_card_plugged = false; /* assume: we don't have a card plugged in */
|
|
struct mpc5200_gpt *gpt = (struct mpc5200_gpt *)(&mpc5200.gpt[GPT2]);
|
|
|
|
#ifdef MPC5200_BOARD_DP2
|
|
/* Deactivate RESET signal */
|
|
rtems_interrupt_level level;
|
|
rtems_interrupt_disable(level);
|
|
mpc5200.gpiowe |= GPIO_W_PIN_PSC1_4;
|
|
mpc5200.gpiowod &= ~GPIO_W_PIN_PSC1_4;
|
|
mpc5200.gpiowdd |= GPIO_W_PIN_PSC1_4;
|
|
mpc5200.gpiowdo |= GPIO_W_PIN_PSC1_4;
|
|
rtems_interrupt_enable(level);
|
|
/* FIXME */
|
|
volatile int i = 0;
|
|
while (++i < 20000000);
|
|
#endif
|
|
|
|
/* enable card detection on GPT2 */
|
|
gpt->emsel = (GPT_EMSEL_GPIO_IN | GPT_EMSEL_TIMER_MS_GPIO);
|
|
|
|
#if defined (MPC5200_BOARD_BRS5L)
|
|
/* Check for card detection (-CD0) */
|
|
if((gpt->status) & GPT_STATUS_PIN)
|
|
ide_card_plugged = false;
|
|
else
|
|
#endif
|
|
ide_card_plugged = true;
|
|
|
|
return ide_card_plugged;
|
|
|
|
}
|
|
|
|
#define DMA1_T0(val) BSP_BFLD32(COUNT_VAL(val), 0, 7)
|
|
#define DMA1_TD(val) BSP_BFLD32(COUNT_VAL(val), 8, 15)
|
|
#define DMA1_TK(val) BSP_BFLD32(COUNT_VAL(val), 16, 23)
|
|
#define DMA1_TM(val) BSP_BFLD32(COUNT_VAL(val), 24, 31)
|
|
|
|
#define DMA2_TH(val) BSP_BFLD32(COUNT_VAL(val), 0, 7)
|
|
#define DMA2_TJ(val) BSP_BFLD32(COUNT_VAL(val), 8, 15)
|
|
#define DMA2_TN(val) BSP_BFLD32(COUNT_VAL(val), 16, 23)
|
|
|
|
static rtems_status_code mpc5200_pcmciaide_config_io_speed(int minor, uint16_t modes_avail)
|
|
{
|
|
uint8_t pio_t0, pio_t2_8, pio_t2_16, pio_t4, pio_t1, pio_ta;
|
|
|
|
if((modes_avail & ATA_MODES_PIO4) != 0)
|
|
{
|
|
|
|
pio_t0 = ata_pio_timings[PIO_4][T0];
|
|
pio_t2_8 = ata_pio_timings[PIO_4][T2_8];
|
|
pio_t2_16 = ata_pio_timings[PIO_4][T2_16];
|
|
pio_t4 = ata_pio_timings[PIO_4][T4];
|
|
pio_t1 = ata_pio_timings[PIO_4][T1];
|
|
pio_ta = ata_pio_timings[PIO_4][TA];
|
|
|
|
}
|
|
else
|
|
{
|
|
|
|
pio_t0 = ata_pio_timings[PIO_3][T0];
|
|
pio_t2_8 = ata_pio_timings[PIO_3][T2_8];
|
|
pio_t2_16 = ata_pio_timings[PIO_3][T2_16];
|
|
pio_t4 = ata_pio_timings[PIO_3][T4];
|
|
pio_t1 = ata_pio_timings[PIO_3][T1];
|
|
pio_ta = ata_pio_timings[PIO_3][TA];
|
|
|
|
}
|
|
|
|
/* set timings according according to selected ATA mode */
|
|
mpc5200.ata_pio1 = ATA_PIO_TIMING_1(pio_t0, pio_t2_8, pio_t2_16);
|
|
mpc5200.ata_pio2 = ATA_PIO_TIMING_2(pio_t4, pio_t1, pio_ta);
|
|
|
|
mpc5200.ata_dma1 = DMA1_T0(120) | DMA1_TD(70) | DMA1_TK(25) | DMA1_TM(25);
|
|
mpc5200.ata_dma2 = DMA2_TH(10) | DMA2_TJ(5) | DMA2_TN(10);
|
|
|
|
return RTEMS_SUCCESSFUL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void mpc5200_pcmciaide_read_reg(int minor, int reg, uint16_t *value)
|
|
{
|
|
volatile uint32_t *ata_reg = mpc5200_ata_drive_regs[reg];
|
|
|
|
if(reg == IDE_REGISTER_DATA_WORD)
|
|
*value = *(volatile uint16_t *)(ata_reg);
|
|
else
|
|
*value = *(volatile uint8_t *)(ata_reg);
|
|
}
|
|
|
|
|
|
static void mpc5200_pcmciaide_write_reg(int minor, int reg, uint16_t value)
|
|
{
|
|
volatile uint32_t *ata_reg = mpc5200_ata_drive_regs[reg];
|
|
|
|
if(reg == IDE_REGISTER_DATA_WORD)
|
|
*(volatile uint16_t *)(ata_reg) = value;
|
|
else
|
|
*(volatile uint8_t *)(ata_reg) = value;
|
|
}
|
|
|
|
#if IDE_USE_DMA
|
|
|
|
|
|
uint32_t pcmcia_ide_rxInterrupts;
|
|
uint32_t pcmcia_ide_txInterrupts;
|
|
volatile rtems_id pcmcia_ide_hdl_task = 0;
|
|
/*
|
|
* MPC5200 BestComm interrupt handlers
|
|
*/
|
|
static void pcmcia_ide_recv_dmairq_hdl(rtems_irq_hdl_param unused)
|
|
{
|
|
SDMA_CLEAR_IEVENT(&mpc5200.sdma.IntPend,IDE_RX_TASK_NO);
|
|
|
|
/*Disable receive ints*/
|
|
bestcomm_glue_irq_disable(IDE_RX_TASK_NO);
|
|
|
|
pcmcia_ide_rxInterrupts++; /* Rx int has occurred */
|
|
|
|
if (pcmcia_ide_hdl_task != 0) {
|
|
rtems_event_send(pcmcia_ide_hdl_task,PCMCIA_IDE_INTERRUPT_EVENT);
|
|
}
|
|
}
|
|
|
|
static void pcmcia_ide_xmit_dmairq_hdl(rtems_irq_hdl_param unused)
|
|
{
|
|
|
|
SDMA_CLEAR_IEVENT(&mpc5200.sdma.IntPend,IDE_TX_TASK_NO);
|
|
|
|
/*Disable transmit ints*/
|
|
bestcomm_glue_irq_disable(IDE_TX_TASK_NO);
|
|
|
|
pcmcia_ide_txInterrupts++; /* Tx int has occurred */
|
|
|
|
if (pcmcia_ide_hdl_task != 0) {
|
|
rtems_event_send(pcmcia_ide_hdl_task,PCMCIA_IDE_INTERRUPT_EVENT);
|
|
}
|
|
}
|
|
|
|
|
|
void mpc5200_pcmciaide_dma_init(int minor)
|
|
{
|
|
TaskSetupParamSet_t rxParam; /* RX task setup parameters */
|
|
TaskSetupParamSet_t txParam; /* TX task setup parameters */
|
|
/*
|
|
* Init Bestcomm system
|
|
*/
|
|
bestcomm_glue_init();
|
|
/*
|
|
* Setup the SDMA RX task.
|
|
*/
|
|
rxParam.NumBD = PCMCIA_IDE_DMA_RD_BD_CNT;
|
|
rxParam.Size.MaxBuf = PCMCIA_IDE_RD_SECTOR_SIZE;
|
|
rxParam.Initiator = INITIATOR_ALWAYS;
|
|
rxParam.StartAddrSrc =
|
|
(uint32)mpc5200_ata_drive_regs[IDE_REGISTER_DATA_WORD];
|
|
rxParam.IncrSrc = 0;
|
|
rxParam.SzSrc = sizeof(uint16_t);
|
|
rxParam.StartAddrDst = (uint32)NULL;
|
|
rxParam.IncrDst = sizeof(uint16_t);
|
|
rxParam.SzDst = sizeof(uint16_t); /* XXX: set this to 32 bit? */
|
|
|
|
pcmcia_ide_rxTaskId = TaskSetup(IDE_RX_TASK_NO,&rxParam );
|
|
|
|
/*
|
|
* Setup the TX task.
|
|
*/
|
|
txParam.NumBD = PCMCIA_IDE_DMA_WR_BD_CNT;
|
|
txParam.Size.MaxBuf = PCMCIA_IDE_WR_SECTOR_SIZE;
|
|
txParam.Initiator = INITIATOR_ALWAYS;
|
|
txParam.StartAddrSrc = (uint32)NULL;
|
|
txParam.IncrSrc = sizeof(uint16_t);
|
|
txParam.SzSrc = sizeof(uint16_t); /* do not set this to 32 bit! */
|
|
txParam.StartAddrDst =
|
|
(uint32)mpc5200_ata_drive_regs[IDE_REGISTER_DATA_WORD];
|
|
txParam.IncrDst = 0;
|
|
txParam.SzDst = sizeof(uint16_t);
|
|
|
|
pcmcia_ide_txTaskId = TaskSetup( IDE_TX_TASK_NO, &txParam );
|
|
/*
|
|
* FIXME: Init BD rings
|
|
*/
|
|
/*
|
|
* Enable the SmartDMA transmit/receive task.
|
|
* do not enable interrupts to CPU
|
|
*/
|
|
/*
|
|
* connect interrupt handlers
|
|
*/
|
|
bestcomm_glue_irq_install(IDE_TX_TASK_NO,pcmcia_ide_xmit_dmairq_hdl,NULL);
|
|
bestcomm_glue_irq_install(IDE_RX_TASK_NO,pcmcia_ide_recv_dmairq_hdl,NULL);
|
|
}
|
|
#endif /* IDE_USE_DMA */
|
|
|
|
void mpc5200_pcmciaide_dma_blockop(bool is_write,
|
|
int minor,
|
|
uint16_t block_size,
|
|
rtems_blkdev_sg_buffer *bufs,
|
|
uint32_t *cbuf,
|
|
uint32_t *pos)
|
|
|
|
{
|
|
#if IDE_USE_DMA
|
|
/*
|
|
* Nameing:
|
|
* - a block is one unit of data on disk (multiple sectors)
|
|
* - a buffer is a contignuous chunk of data in memory
|
|
* a block on disk may be filled with data from several buffers
|
|
*/
|
|
uint32_t buf_idx,bufs_from_dma, bufs_to_dma,bufs_total;
|
|
uint32_t bds_free;
|
|
uint32_t llength;
|
|
rtems_status_code rc = RTEMS_SUCCESSFUL;
|
|
rtems_event_set events;
|
|
BDIdx nxt_bd_idx;
|
|
bool use_irq = (_System_state_Current == SYSTEM_STATE_UP);
|
|
/*
|
|
* determine number of blocks
|
|
*/
|
|
llength = 0;
|
|
buf_idx = 0;
|
|
bufs += *cbuf; /* *cbuf is the index of the next buffer to send in this transaction */
|
|
while (llength < block_size) {
|
|
llength += bufs[buf_idx++].length;
|
|
}
|
|
bufs_from_dma = 0;
|
|
bufs_to_dma = 0;
|
|
bufs_total = buf_idx;
|
|
/*
|
|
* here all BDs should be unused
|
|
*/
|
|
bds_free = is_write ? PCMCIA_IDE_DMA_WR_BD_CNT : PCMCIA_IDE_DMA_RD_BD_CNT;
|
|
/*
|
|
* repeat, until all bufs are transferred
|
|
*/
|
|
while ((rc == RTEMS_SUCCESSFUL) &&
|
|
(bufs_from_dma < bufs_total)) {
|
|
|
|
while ((rc == RTEMS_SUCCESSFUL) &&
|
|
(bufs_to_dma < bufs_total) &&
|
|
(bds_free > 0)) {
|
|
/*
|
|
* fill in BD, set interrupt if needed
|
|
*/
|
|
SDMA_CLEAR_IEVENT(&mpc5200.sdma.IntPend,(is_write
|
|
? IDE_TX_TASK_NO
|
|
: IDE_RX_TASK_NO));
|
|
if (is_write) {
|
|
TaskBDAssign(pcmcia_ide_txTaskId ,
|
|
(void *)bufs[bufs_to_dma].buffer,
|
|
(void *)mpc5200_ata_drive_regs[IDE_REGISTER_DATA_WORD],
|
|
bufs[bufs_to_dma].length,
|
|
0/* flags */);
|
|
#if IDE_USE_STATISTICS
|
|
mpc5200_pcmciaide_write_block_block_cnt++;
|
|
#endif
|
|
}
|
|
else {
|
|
TaskBDAssign(pcmcia_ide_rxTaskId ,
|
|
(void *)mpc5200_ata_drive_regs[IDE_REGISTER_DATA_WORD],
|
|
(void *)bufs[bufs_to_dma].buffer,
|
|
bufs[bufs_to_dma].length,
|
|
0/* flags */);
|
|
#if IDE_USE_STATISTICS
|
|
mpc5200_pcmciaide_read_block_block_cnt++;
|
|
#endif
|
|
}
|
|
bufs_to_dma ++;
|
|
bds_free --;
|
|
}
|
|
if (is_write) {
|
|
TaskStart( pcmcia_ide_txTaskId, TASK_AUTOSTART_DISABLE,
|
|
pcmcia_ide_txTaskId, TASK_INTERRUPT_DISABLE );
|
|
}
|
|
else {
|
|
TaskStart( pcmcia_ide_rxTaskId, TASK_AUTOSTART_DISABLE,
|
|
pcmcia_ide_rxTaskId, TASK_INTERRUPT_DISABLE );
|
|
}
|
|
if (use_irq) {
|
|
|
|
/*
|
|
* enable interrupts, wait for interrupt event
|
|
*/
|
|
pcmcia_ide_hdl_task = rtems_task_self();
|
|
bestcomm_glue_irq_enable((is_write
|
|
? IDE_TX_TASK_NO
|
|
: IDE_RX_TASK_NO));
|
|
|
|
rtems_event_receive(PCMCIA_IDE_INTERRUPT_EVENT,
|
|
RTEMS_WAIT | RTEMS_EVENT_ANY,
|
|
RTEMS_NO_TIMEOUT, &events);
|
|
|
|
pcmcia_ide_hdl_task = 0;
|
|
}
|
|
else {
|
|
/*
|
|
* HACK: just wait some time...
|
|
*/
|
|
/*
|
|
* FIXME: poll, until SDMA is finished
|
|
*/
|
|
volatile int32_t i;
|
|
for (i = 0;i < 10000;i++) {};
|
|
}
|
|
|
|
do {
|
|
nxt_bd_idx = TaskBDRelease(is_write
|
|
? pcmcia_ide_txTaskId
|
|
: pcmcia_ide_rxTaskId);
|
|
if ((nxt_bd_idx != TASK_ERR_BD_RING_EMPTY) &&
|
|
(nxt_bd_idx != TASK_ERR_BD_BUSY)) {
|
|
(*cbuf)++;
|
|
(*pos) += bufs[bufs_from_dma].length;
|
|
bufs_from_dma++;
|
|
bds_free++;
|
|
}
|
|
} while ((nxt_bd_idx != TASK_ERR_BD_RING_EMPTY) &&
|
|
(nxt_bd_idx != TASK_ERR_BD_BUSY) &&
|
|
(bufs_from_dma < bufs_to_dma));
|
|
}
|
|
#endif /* IDE_USE_DMA */
|
|
}
|
|
|
|
|
|
static void mpc5200_pcmciaide_read_block(int minor, uint32_t block_size,
|
|
rtems_blkdev_sg_buffer *bufs, uint32_t *cbuf, uint32_t *pos)
|
|
{
|
|
|
|
volatile uint32_t *ata_reg=mpc5200_ata_drive_regs[IDE_REGISTER_DATA_WORD];
|
|
uint16_t cnt = 0;
|
|
uint16_t *lbuf = (uint16_t*)((uint8_t*)(bufs[(*cbuf)].buffer)+(*pos));
|
|
uint32_t llength = bufs[(*cbuf)].length;
|
|
bool use_dma;
|
|
|
|
#if IDE_USE_STATISTICS
|
|
mpc5200_pcmciaide_read_block_call_cnt++;
|
|
#endif
|
|
#if IDE_READ_USE_DMA
|
|
/*
|
|
* FIXME: walk through buffer list. If any buffer has other size than default,
|
|
* then do not use DMA
|
|
* Is this needed?
|
|
*/
|
|
use_dma = true;
|
|
/* use_dma = false; */
|
|
#else
|
|
use_dma = false;
|
|
#endif
|
|
if (use_dma) {
|
|
/*
|
|
* FIXME: wait for DRQ ready
|
|
* check, that once DRQ is ready, we really can send ALL data for this
|
|
* type of transfer mode
|
|
*/
|
|
while ((GET_UP_BYTE_OF_MPC5200_ATA_DRIVE_REG((volatile uint32_t)
|
|
(mpc5200.ata_dctr_dasr)) &
|
|
IDE_REGISTER_STATUS_DRQ) == 0);
|
|
/*
|
|
* translate (part of) buffer list into DMA BDs
|
|
* only last (available) DMA BD sends interrupt
|
|
* DMA BDs may get ready as soon as possible
|
|
*/
|
|
mpc5200_pcmciaide_dma_blockop(FALSE, /* read operation */
|
|
minor,
|
|
block_size,bufs,cbuf,pos);
|
|
}
|
|
else {
|
|
#if IDE_USE_READ_PIO_OPT
|
|
while(cnt < block_size) {
|
|
|
|
*lbuf++ = GET_UP_WORD_OF_MPC5200_ATA_DRIVE_REG(*(volatile uint32_t *)(ata_reg)); /* only 16 bit data port */
|
|
cnt += 2;
|
|
(*pos) += 2;
|
|
|
|
if((*pos) == llength) {
|
|
|
|
(*pos) = 0;
|
|
(*cbuf)++;
|
|
lbuf = bufs[(*cbuf)].buffer;
|
|
llength = bufs[(*cbuf)].length;
|
|
|
|
}
|
|
}
|
|
#else
|
|
|
|
while((GET_UP_BYTE_OF_MPC5200_ATA_DRIVE_REG((volatile uint32_t)(mpc5200.ata_dctr_dasr)) & IDE_REGISTER_STATUS_DRQ) && (cnt < block_size)) {
|
|
|
|
*lbuf++ = *(volatile uint16_t *)(ata_reg); /* only 16 bit data port */
|
|
cnt += 2;
|
|
(*pos) += 2;
|
|
|
|
if((*pos) == llength) {
|
|
(*pos) = 0;
|
|
(*cbuf)++;
|
|
lbuf = bufs[(*cbuf)].buffer;
|
|
llength = bufs[(*cbuf)].length;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
static void mpc5200_pcmciaide_write_block(int minor, uint32_t block_size,
|
|
rtems_blkdev_sg_buffer *bufs, uint32_t *cbuf, uint32_t *pos)
|
|
{
|
|
|
|
|
|
volatile uint32_t *ata_reg = mpc5200_ata_drive_regs[IDE_REGISTER_DATA_WORD];
|
|
uint16_t cnt = 0;
|
|
uint16_t *lbuf = (uint16_t *)((uint8_t *)(bufs[(*cbuf)].buffer) + (*pos));
|
|
uint32_t llength = bufs[(*cbuf)].length;
|
|
bool use_dma;
|
|
|
|
#if IDE_USE_STATISTICS
|
|
mpc5200_pcmciaide_write_block_call_cnt++;
|
|
#endif
|
|
#if IDE_WRITE_USE_DMA
|
|
/*
|
|
* FIXME: walk through buffer list. If any buffer has other size than default,
|
|
* then do not use DMA
|
|
* Is this needed?
|
|
*/
|
|
use_dma = true;
|
|
#else
|
|
use_dma = false;
|
|
#endif
|
|
|
|
if (use_dma) {
|
|
/*
|
|
* wait for DRQ ready
|
|
* FIXME: check, that once DRQ is ready, we really can send ALL data for this
|
|
* type of transfer mode
|
|
*/
|
|
while ((GET_UP_BYTE_OF_MPC5200_ATA_DRIVE_REG((volatile uint32_t)
|
|
(mpc5200.ata_dctr_dasr)) &
|
|
IDE_REGISTER_STATUS_DRQ) == 0);
|
|
/*
|
|
* translate (part of) buffer list into DMA BDs
|
|
* only last (available) DMA BD sends interrupt
|
|
* DMA BDs may get ready as soon as possible
|
|
*/
|
|
mpc5200_pcmciaide_dma_blockop(true, /* write opeartion */
|
|
minor,
|
|
block_size,bufs,cbuf,pos);
|
|
}
|
|
else {
|
|
#if IDE_USE_WRITE_PIO_OPT
|
|
while(cnt < block_size) {
|
|
int32_t loop_cnt,loop_max;
|
|
|
|
#if IDE_USE_STATISTICS
|
|
mpc5200_pcmciaide_write_block_block_cnt++;
|
|
#endif
|
|
|
|
loop_max = llength - (*pos) ;
|
|
if (loop_max > (block_size - cnt)) {
|
|
loop_max = (block_size - cnt);
|
|
}
|
|
for (loop_cnt = loop_max/2;loop_cnt > 0;loop_cnt--) {
|
|
*(volatile uint32_t *)(ata_reg) =
|
|
SET_UP_WORD_OF_MPC5200_ATA_DRIVE_REG(*lbuf++); /* only 16 bit data port */
|
|
}
|
|
cnt += loop_max;
|
|
(*pos) += loop_max;
|
|
|
|
if((*pos) == llength) {
|
|
|
|
(*pos) = 0;
|
|
(*cbuf)++;
|
|
lbuf = bufs[(*cbuf)].buffer;
|
|
llength = bufs[(*cbuf)].length;
|
|
}
|
|
}
|
|
#else
|
|
while((GET_UP_BYTE_OF_MPC5200_ATA_DRIVE_REG((volatile uint32_t)(mpc5200.ata_dctr_dasr))
|
|
& IDE_REGISTER_STATUS_DRQ)
|
|
&& (cnt < block_size)) {
|
|
*(volatile uint16_t *)(ata_reg) = *lbuf++; /* only 16 bit data port */
|
|
cnt += 2;
|
|
(*pos) += 2;
|
|
|
|
if((*pos) == llength) {
|
|
(*pos) = 0;
|
|
(*cbuf)++;
|
|
lbuf = bufs[(*cbuf)].buffer;
|
|
llength = bufs[(*cbuf)].length;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
static int mpc5200_pcmciaide_control(int minor, uint32_t cmd, void * arg)
|
|
{
|
|
return RTEMS_SUCCESSFUL;
|
|
}
|
|
|
|
static void mpc5200_pcmciaide_initialize(int minor)
|
|
{
|
|
#if defined (MPC5200_BOARD_BRS5L)
|
|
struct mpc5200_gpt *gpt = (struct mpc5200_gpt *)(&mpc5200.gpt[GPT7]);
|
|
|
|
/* invert ATA reset on GPT7 */
|
|
gpt->emsel = (GPT_EMSEL_GPIO_OUT_HIGH | GPT_EMSEL_TIMER_MS_GPIO);
|
|
#endif
|
|
/* reset ata host contr. and FIFO */
|
|
mpc5200.ata_hcfg |= (ATA_HCFG_SMR | ATA_HCFG_FR);
|
|
mpc5200.ata_hcfg &= ~(ATA_HCFG_SMR | ATA_HCFG_FR);
|
|
|
|
/* for the first access set lowest performance transfer mode to PIO3 */
|
|
mpc5200_pcmciaide_config_io_speed(minor, ATA_MODES_PIO3);
|
|
|
|
/* enable PIO operations (PIO 3/4) */
|
|
mpc5200.ata_hcfg |= ATA_HCFG_IORDY;
|
|
|
|
#ifdef IDE_USE_INT
|
|
mpc5200.ata_hcfg |= ATA_HCFG_IE ;
|
|
#endif
|
|
|
|
#if IDE_USE_DMA
|
|
mpc5200_pcmciaide_dma_init(minor);
|
|
#endif
|
|
}
|
|
|
|
|
|
/*
|
|
* The following table configures the functions used for IDE drivers
|
|
* in this BSP.
|
|
*/
|
|
ide_ctrl_fns_t mpc5200_pcmciaide_ctrl_fns =
|
|
{
|
|
mpc5200_pcmciaide_probe,
|
|
mpc5200_pcmciaide_initialize,
|
|
mpc5200_pcmciaide_control,
|
|
mpc5200_pcmciaide_read_reg,
|
|
mpc5200_pcmciaide_write_reg,
|
|
mpc5200_pcmciaide_read_block,
|
|
mpc5200_pcmciaide_write_block,
|
|
mpc5200_pcmciaide_config_io_speed
|
|
};
|
|
|