summaryrefslogblamecommitdiffstats
path: root/c/src/lib/libbsp/powerpc/gen5200/ide/pcmcia_ide.c
blob: 173c7a02ef078f92ab5f38dd99c74250271cd9b8 (plain) (tree)
1
2
3


                                                                   
















                                                                   
































                                                                         
                                                                    






                                                                         
                                                                           
















                                                                         
                                 
                
                    











                                     
 
                                      




                                     
                                                           
 











                                                   

                                       




                                                                        
                                                 











                                                     
                                   
                                                                         


                                      
                                       
   
                                                                              

                                                                       
                          












                                          


                                                             
                                 

                                       
                             

      
                            




                          







                                                       































                                                                                    


                                                                            





































                                                                    
                                                          

                        
                                            

                                                                 
 







                                                                     
                                                          

                           
                                            

                                                                 
 



















                                                                          
                        






                                                                          
                                                             













                                                                           
 
                                                               








                                               
     

                                                                            
 
                        
 
                                                 

                                                       
                                                                
                                                  


                                                 
               
    
             









                                                                 
                                                            




















                                                                                        


                                        



                                            


                                                             























                                                                            
                                                             










                                                               
                                              
                                        

                                                   
 

                                                       















                                                     

                                                                          


                                                                            

                                             
                        
                   




                                                      
                        
 

 
                                                                                               






                                                                            
                    
 








                                                                                

                        
     
                  







                                                                          
                                                                           
















                                                                                                                  
 
                             
 



                                         
 








                                                                                                                                               
 



                                    
                                       


       


   
                                                                  
                                                                                








                                                                              
               









                                                                                
                 
     
                  








                                                                                 
                                                                           





                                                   
                                                             
















                                                            
                                         



                                                                                    
 
                             
 


                                    
                                       


       

                                                                                           



                                                                            
 

















                                                                   
                                 




















                                                                         
      


















                                                                    
/*===============================================================*\
| 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                           |
|                    D-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.com/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.com/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 <rtems.h>
#include <rtems/error.h>
#include <rtems/score/sysstate.h>
#include <bsp.h>
#include <bsp/irq.h>
#include "../include/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>

#ifndef MIN
#define MIN(a,b) (((a)<(b))?(a):(b))
#endif
#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
 */
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)

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;

  }



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);
  }


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 */
}


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
  }
}

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
  }
}

int mpc5200_pcmciaide_control(int  minor, uint32_t cmd, void * arg)
  {
  return RTEMS_SUCCESSFUL;
  }

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
  };