///////////////////////////////////////////////////////////////////////////////////
// File     : boot_hba_driver.h
// Date     : 01/11/2013
// Authors  : Alain Greiner / Vu Son
// Copyright (c) UPMC-LIP6
///////////////////////////////////////////////////////////////////////////////////
// This file defines a simplified driver for SocLib vci_multi_ahci, 
// a multi-channel, block-oriented, external mass storage peripheral
// respecting the AHCI standard. The driver is used by the ALMOS-MKH
// boot-loader when the USE_IOC_HBA flag is set in the hard_config.h file.
// Each channel can access a different physical disk, modeled by a file 
// belonging to the operating system, and containing a complete disk image.
// However, this driver implementation only supports one channel, since the 
// ALMOS-MKH boot-loader only uses one physical hard drive.
// The driver uses a software FIFO to register a command defined by a 
// Command Descriptor. A 32-entry Command Descriptor array forms the
// Command List. Each Command Descriptor is associated with a Command Table
// describing one given command.
// All accesses to the device registers are performed via 2 low-level
// functions boot_hba_get_register() and boot_hba_set_register().
// Since the driver is used by the boot-loader, it implements synchronous
// accesses to block device by polling the HBA_PXCI register to detect the
// transfer completion, as interrupts are not activated.
///////////////////////////////////////////////////////////////////////////////////

#ifndef BOOT_HBA_DRIVER_H
#define BOOT_HBA_DRIVER_H

#include <hal_types.h>

/****************************************************************************
 *                            Driver register map.                          *
 ****************************************************************************/

enum HBA_registers
{
    HBA_PXCLB       = 0,        /* 32 LSB of the Command List address       */ 
    HBA_PXCLBU      = 1,        /* 32 MSB of the Command List address       */
    HBA_PXIS        = 2,        /* Channel status, for error reporting      */
    HBA_PXIE        = 3,        /* Enabling / disabling the IRQ line        */
    HBA_PXCMD       = 4,        /* Activate Command List polling            */
    HBA_PXCI        = 5,        /* Command status bit-vector.               */

    HBA_SPAN        = 0x400,    /* HBA channel segment size (32 bits words) */
};

/****************************************************************************
 * This structure defines the Command Descriptor.                           *
 ****************************************************************************/

typedef struct hba_cmd_desc_s
{
    unsigned char flag[2];      /* WRITE when bit 6 of flag[0] is set.      */
    unsigned char prdtl[2];     /* Number of buffers.                       */
    uint32_t      prdbc;        /* Number of bytes transfered.              */
    uint32_t      ctba;         /* 32 LSB of Command Table address.         */
    uint32_t      ctbau;        /* 32 MSB of Command Table address.         */

}
hba_cmd_desc_t;

/****************************************************************************
 * These structures define the Command Table associated with each Command   *
 * Descriptor.                                                              *
 *                                                                          *
 * For a given command, there is only one LBA coded in 48 bits to identify  *
 * the block(s) on the device to be transfered. Yet the memory buffer can   *
 * be splitted in a variable number of contiguous buffers. The Command      *
 * Table thus contains 2 data structures:                                   *
 *  - 'hba_cmd_header_t' structure: fixed-size header (16 bytes) defining   *
 *    the LBA.                                                              *
 *  - 'hba_cmd_buffer_t' structure: variable-sized array of fixed-size (16  *
 *    bytes) buffer descriptors.                                            *
 ****************************************************************************/
typedef struct hba_cmd_header_s
{
    /* Word 1. */
    uint32_t  res0;             /* Reserved.                                */

    /* Word 2. */
    unsigned char lba0;         /* LBA 7:0.                                 */
    unsigned char lba1;         /* LBA 15:8.                                */
    unsigned char lba2;         /* LBA 23:16.                               */
    unsigned char res1;         /* Reserved.                                */

    /* Word 3. */
    unsigned char lba3;         /* LBA 31:24.                               */
    unsigned char lba4;         /* LBA 39:32.                               */
    unsigned char lba5;         /* LBA 47:40.                               */
    unsigned char res2;         /* Reserved.                                */

    /* Word 4. */
    uint32_t  res3;             /* Reserved.                                */
}
hba_cmd_header_t;

typedef struct hba_cmd_buffer_s
{
    uint32_t dba;               /* 32 LSB buffer base address.              */
    uint32_t dbau;              /* 32 MSB buffer base address.              */
    uint32_t res;               /* Reserved.                                */
    uint32_t dbc;               /* Buffer bytes count.                      */
}
hba_cmd_buffer_t;

typedef struct hba_cmd_table_s
{
    hba_cmd_header_t header;
    hba_cmd_buffer_t buffer;
}
hba_cmd_table_t;

/****************************************************************************
 *                           Driver API functions.                          *
 ****************************************************************************/

/****************************************************************************
 * This function initializes the HBA hardware registers and  Command List.  *
 * @ returns 0 on success, -1 on error.                                     *
 ****************************************************************************/
int boot_hba_init();

/****************************************************************************
 * This function registers a command in the Command List and Command Table. *
 * @ lba        : LBA of the first block on the block device.               *
 * @ buff_addr  : memory buffer physical address.                           *
 * @ count      : number of blocks to be transfered.                        *
 * @ returns 0 on success, -1 on error.                                     *
 ****************************************************************************/
int boot_hba_access( uint32_t  lba,
                     uint64_t  buf_paddr,
                     uint32_t  count );

#endif // BOOT_HBA_DRIVER_H
