mirror of
https://gitlab.rtems.org/rtems/rtos/rtems.git
synced 2026-09-21 04:07:33 +08:00
bsps: Move libchip to bsps
This patch is a part of the BSP source reorganization. Update #3285.
This commit is contained in:
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
* Copyright (c) 2010 embedded brains GmbH.
|
||||
*
|
||||
* Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
|
||||
* Authors: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <libchip/ide_ctrl_io.h>
|
||||
#include <libchip/ide_ctrl_cfg.h>
|
||||
#include <libchip/ata_internal.h>
|
||||
|
||||
/* ata_process_request_on_init_phase --
|
||||
* Process the ATA request during system initialization. Request
|
||||
* processing is syncronous and doesn't use multiprocessing enviroment.
|
||||
*
|
||||
* PARAMETERS:
|
||||
* ctrl_minor - controller identifier
|
||||
* areq - ATA request
|
||||
*
|
||||
* RETURNS:
|
||||
* NONE
|
||||
*/
|
||||
void
|
||||
ata_process_request_on_init_phase(rtems_device_minor_number ctrl_minor,
|
||||
ata_req_t *areq)
|
||||
{
|
||||
uint16_t byte;/* emphasize that only 8 low bits is meaningful */
|
||||
uint8_t i;
|
||||
#if 0
|
||||
uint8_t dev;
|
||||
#endif
|
||||
uint16_t val, val1;
|
||||
volatile unsigned retries;
|
||||
|
||||
assert(areq);
|
||||
|
||||
#if 0
|
||||
dev = areq->regs.regs[IDE_REGISTER_DEVICE_HEAD] &
|
||||
IDE_REGISTER_DEVICE_HEAD_DEV;
|
||||
#endif
|
||||
|
||||
ide_controller_write_register(ctrl_minor, IDE_REGISTER_DEVICE_HEAD,
|
||||
areq->regs.regs[IDE_REGISTER_DEVICE_HEAD]);
|
||||
|
||||
retries = 0;
|
||||
do {
|
||||
ide_controller_read_register(ctrl_minor, IDE_REGISTER_STATUS, &byte);
|
||||
/* If device (on INIT, i.e. it should be idle) is neither
|
||||
* busy nor ready something's fishy, i.e., there is probably
|
||||
* no device present.
|
||||
* I'd like to do a proper timeout but don't know of a portable
|
||||
* timeout routine (w/o using multitasking / rtems_task_wake_after())
|
||||
*/
|
||||
if ( ! (byte & (IDE_REGISTER_STATUS_BSY | IDE_REGISTER_STATUS_DRDY))) {
|
||||
retries++;
|
||||
if ( 10000 == retries ) {
|
||||
/* probably no drive connected */
|
||||
areq->breq->status = RTEMS_UNSATISFIED;
|
||||
return;
|
||||
}
|
||||
}
|
||||
} while ((byte & IDE_REGISTER_STATUS_BSY) ||
|
||||
(!(byte & IDE_REGISTER_STATUS_DRDY)));
|
||||
|
||||
for (i=0; i< ATA_MAX_CMD_REG_OFFSET; i++)
|
||||
{
|
||||
uint32_t reg = (1 << i);
|
||||
if (areq->regs.to_write & reg)
|
||||
ide_controller_write_register(ctrl_minor, i,
|
||||
areq->regs.regs[i]);
|
||||
}
|
||||
|
||||
do {
|
||||
ide_controller_read_register(ctrl_minor, IDE_REGISTER_STATUS, &byte);
|
||||
} while (byte & IDE_REGISTER_STATUS_BSY);
|
||||
|
||||
ide_controller_read_register(ctrl_minor, IDE_REGISTER_STATUS, &val);
|
||||
ide_controller_read_register(ctrl_minor, IDE_REGISTER_ERROR, &val1);
|
||||
|
||||
if (val & IDE_REGISTER_STATUS_ERR)
|
||||
{
|
||||
areq->breq->status = RTEMS_IO_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
switch(areq->type)
|
||||
{
|
||||
case ATA_COMMAND_TYPE_PIO_IN:
|
||||
if (areq->cnt)
|
||||
{
|
||||
int ccbuf = areq->cbuf;
|
||||
ide_controller_read_data_block(ctrl_minor,
|
||||
areq->breq->bufs[0].length * areq->cnt,
|
||||
areq->breq->bufs, &areq->cbuf,
|
||||
&areq->pos);
|
||||
ccbuf = areq->cbuf - ccbuf;
|
||||
areq->cnt -= ccbuf;
|
||||
}
|
||||
if (areq->cnt == 0)
|
||||
{
|
||||
areq->breq->status = RTEMS_SUCCESSFUL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* this shouldn't happend on the initialization
|
||||
* phase!
|
||||
*/
|
||||
rtems_fatal_error_occurred(RTEMS_INTERNAL_ERROR);
|
||||
}
|
||||
break;
|
||||
|
||||
case ATA_COMMAND_TYPE_NON_DATA:
|
||||
areq->breq->status = RTEMS_SUCCESSFUL;
|
||||
areq->info = val1;
|
||||
break;
|
||||
|
||||
default:
|
||||
areq->breq->status = RTEMS_IO_ERROR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ata_breq_init(blkdev_request1 *breq, uint16_t *sector_buffer)
|
||||
{
|
||||
memset(breq, 0, sizeof(*breq));
|
||||
|
||||
breq->req.done_arg = breq;
|
||||
breq->req.bufnum = 1;
|
||||
breq->req.bufs [0].length = ATA_SECTOR_SIZE;
|
||||
breq->req.bufs [0].buffer = sector_buffer;
|
||||
}
|
||||
|
||||
rtems_status_code ata_identify_device(
|
||||
rtems_device_minor_number ctrl_minor,
|
||||
int dev,
|
||||
uint16_t *sector_buffer,
|
||||
ata_dev_t *device_entry
|
||||
)
|
||||
{
|
||||
ata_req_t areq;
|
||||
blkdev_request1 breq;
|
||||
|
||||
ata_breq_init(&breq, sector_buffer);
|
||||
|
||||
/*
|
||||
* Issue DEVICE IDENTIFY ATA command and get device
|
||||
* configuration
|
||||
*/
|
||||
memset(&areq, 0, sizeof(ata_req_t));
|
||||
areq.type = ATA_COMMAND_TYPE_PIO_IN;
|
||||
areq.regs.to_write = ATA_REGISTERS_VALUE(IDE_REGISTER_COMMAND);
|
||||
areq.regs.regs [IDE_REGISTER_COMMAND] = ATA_COMMAND_IDENTIFY_DEVICE;
|
||||
areq.regs.to_read = ATA_REGISTERS_VALUE(IDE_REGISTER_STATUS);
|
||||
areq.breq = (rtems_blkdev_request *)&breq;
|
||||
areq.cnt = breq.req.bufnum;
|
||||
areq.regs.regs [IDE_REGISTER_DEVICE_HEAD] |=
|
||||
dev << IDE_REGISTER_DEVICE_HEAD_DEV_POS;
|
||||
|
||||
/*
|
||||
* Process the request. Special processing of requests on
|
||||
* initialization phase is needed because at this moment there
|
||||
* is no multitasking enviroment
|
||||
*/
|
||||
ata_process_request_on_init_phase(ctrl_minor, &areq);
|
||||
|
||||
/* check status of I/O operation */
|
||||
if (breq.req.status != RTEMS_SUCCESSFUL) {
|
||||
return RTEMS_IO_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse returned device configuration and fill in ATA internal
|
||||
* device info structure
|
||||
*/
|
||||
device_entry->cylinders =
|
||||
CF_LE_W(sector_buffer[ATA_IDENT_WORD_NUM_OF_CURR_LOG_CLNDS]);
|
||||
device_entry->heads =
|
||||
CF_LE_W(sector_buffer[ATA_IDENT_WORD_NUM_OF_CURR_LOG_HEADS]);
|
||||
device_entry->sectors =
|
||||
CF_LE_W(sector_buffer[ATA_IDENT_WORD_NUM_OF_CURR_LOG_SECS]);
|
||||
device_entry->lba_sectors =
|
||||
CF_LE_W(sector_buffer[ATA_IDENT_WORD_NUM_OF_USR_SECS1]);
|
||||
device_entry->lba_sectors <<= 16;
|
||||
device_entry->lba_sectors += CF_LE_W(sector_buffer[ATA_IDENT_WORD_NUM_OF_USR_SECS0]);
|
||||
device_entry->lba_avaible =
|
||||
(CF_LE_W(sector_buffer[ATA_IDENT_WORD_CAPABILITIES]) >> 9) & 0x1;
|
||||
|
||||
if ((CF_LE_W(sector_buffer[ATA_IDENT_WORD_FIELD_VALIDITY]) &
|
||||
ATA_IDENT_BIT_VALID) == 0) {
|
||||
/* no "supported modes" info -> use default */
|
||||
device_entry->mode_active = ATA_MODES_PIO3;
|
||||
} else {
|
||||
device_entry->modes_available =
|
||||
((CF_LE_W(sector_buffer[64]) & 0x1) ? ATA_MODES_PIO3 : 0) |
|
||||
((CF_LE_W(sector_buffer[64]) & 0x2) ? ATA_MODES_PIO4 : 0) |
|
||||
((CF_LE_W(sector_buffer[63]) & 0x1) ? ATA_MODES_DMA0 : 0) |
|
||||
((CF_LE_W(sector_buffer[63]) & 0x2) ?
|
||||
ATA_MODES_DMA0 | ATA_MODES_DMA1 : 0) |
|
||||
((CF_LE_W(sector_buffer[63]) & 0x4) ?
|
||||
ATA_MODES_DMA0 | ATA_MODES_DMA1 | ATA_MODES_DMA2 : 0);
|
||||
if (device_entry->modes_available == 0) {
|
||||
return RTEMS_IO_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return RTEMS_SUCCESSFUL;
|
||||
}
|
||||
Reference in New Issue
Block a user