/*******************************************************************//**
 *  @file   mmc_reg.h
 *
 *  Commands, registers, states, and constants as defined by MMC
 *  standard v4.2.
 **********************************************************************/

#ifndef _MMC_REG_H
#define _MMC_REG_H

/** Bitfield marking MMC cmd followed by read activity on data line(s).
 *  These are CMD8, 11, 14, 17, 18.     */
#define MMC_CMD_FOLLOWED_BY_RD  0x0000000000060900ull
/** Bitfield marking MMC cmd followed by write activity on data line(s).
 *  These are CMD19, 20, 24, 25, 27.    */
#define MMC_CMD_FOLLOWED_BY_WR  0x000000000B180000ull
/** Bitfield marking MMC cmd followed by other activity on data line(s).
 *  These are CMD 30, 26, 42, 56.       */
#define MMC_CMD_FOLLOWED_BY_DAT 0x0100040044000000ull

/*  globals */
extern const float tran_speed_freqs[8];     /**< values as defined in standard v4.2 section 8.3 */
extern const float tran_speed_mults[16];    /**< values as defined in standard v4.2 section 8.3 */

/**
 *  The relevant error bits in card status differ depending on command
 *  which was send last. This table masks the relevant error bits for
 *  each possible command according to table 26 in standard v4.2
 *  (jesd84b42.pdf).
 */
extern const unsigned long card_status_error_masks[64];

/**
 *  MMC register OCR (operation conditions register). See JESD84-B42.pdf
 *  section 8.1.
 */
union t_mmc_reg_ocr {
    struct {
        unsigned char   reserved1   : 7;
        unsigned char   vlow        : 1;    /**< low voltage 1.7V to 1.95V                      */

        unsigned char   v20_21      : 1;
        unsigned char   v21_22      : 1;
        unsigned char   v22_23      : 1;
        unsigned char   v23_24      : 1;
        unsigned char   v24_25      : 1;
        unsigned char   v25_26      : 1;
        unsigned char   v26_27      : 1;
        unsigned char   v27_28      : 1;

        unsigned char   v28_29      : 1;
        unsigned char   v29_30      : 1;
        unsigned char   v30_31      : 1;
        unsigned char   v31_32      : 1;
        unsigned char   v32_33      : 1;
        unsigned char   v33_34      : 1;
        unsigned char   v34_35      : 1;
        unsigned char   v35_36      : 1;

        unsigned char   reserved2   : 5;
        unsigned char   accessmode  : 2;    /**< 00b byte mode, 10b sector mode                 */
        unsigned char   busy        : 1;    /**< card power up status bit                       */
    } bit;                                  /**< bit wise access to register                    */
    unsigned long reg;                      /**< complete register as unsigned 4 byte integer   */
};

/**
 *  MMC card status as send by card as response argument of response
 *  type R1. You get R1 as answer to CMD3, CMD13 and several other
 *  commands. It contains error bits, status bits and current state the
 *  MMC is in. (See constant definitions MMC_STATE_* if you want to
 *  decode this state value.)
 */
union t_mmc_card_status {
    struct {
        unsigned char   reserved0_1             : 2;    /**< for manufacturer test mode                                     */
        unsigned char   reserved2_3             : 2;    /**< for app specific commands                                      */
        unsigned char   reserved4               : 1;
        unsigned char   app_cmd                 : 1;    /**< card will expect ACMD or command has been interpreted as ACMD  */
        unsigned char   reserved6               : 1;
        unsigned char   switch_error            : 1;    /**< card didn't switch to expected mode as requested by SWITCH cmd */

        unsigned char   ready_for_data          : 1;    /**< corresponds to buffer empty signalling on the bus              */
        unsigned char   current_state           : 4;    /**< card state when receiving command, see constants MMC_STATE_*   */
        unsigned char   erase_reset             : 1;    /**< see MMC standard for explanation                               */
        unsigned char   reserved14              : 1;    /**< reserved, must be set to 0                                     */
        unsigned char   wp_erase_skip           : 1;    /**< see MMC standard for explanation                               */

        unsigned char   cid_csd_overwrite       : 1;    /**< see MMC standard for explanation                               */
        unsigned char   overrun                 : 1;    /**< card could not sustain data programming in stream write mode   */
        unsigned char   underrun                : 1;    /**< card could not sustain data transfer in stream read mode       */
        unsigned char   error                   : 1;    /**< generic card error                                             */
        unsigned char   cc_error                : 1;    /**< card error not related to host command                         */
        unsigned char   card_ecc_failed         : 1;    /**< card internal ECC was applied but failed to correct the data   */
        unsigned char   illegal_command         : 1;    /**< command not legal for the card state                           */
        unsigned char   com_crc_error           : 1;    /**< crc check of previous command failed                           */

        unsigned char   lock_unlock_failed      : 1;    /**< sequence or passwd error detected in lock/unlock card command  */
        unsigned char   card_is_locked          : 1;    /**< card locked by host                                            */
        unsigned char   wp_violation            : 1;    /**< Attempt to program a write protected block.                    */
        unsigned char   erase_param             : 1;    /**< An invalid selection of erase groups for erase occurred        */
        unsigned char   erase_seq_error         : 1;    /**< An error in the sequence of erase commands occurred            */
        unsigned char   block_len_error         : 1;    /**< see MMC standard for explanation                               */
        unsigned char   address_misalign        : 1;    /**< see MMC standard for explanation                               */
        unsigned char   address_out_of_range    : 1;    /**< see MMC standard for explanation                               */
    } bit;                                              /**< struct for bit wise access to reg content                      */
    unsigned long reg;                                  /**< complete "register" as unsigned 4 byte integer                 */
};

/**
 *  Struct representing the content of the CID register without CRC.
 *
 *  @see    fill_cid_struct
 */
struct t_mmc_cid {
    unsigned char   mdt;    /**< manufacturing date     */
    unsigned long   psn;    /**< product serial number  */
    unsigned char   prv;    /**< product revision       */
    char            pnm[7]; /**< product name           */
    unsigned short  oid;    /**< oem/application ID     */
    unsigned char   mid;    /**< manufacturer ID        */
};

/**
 *  Struct representing the content of the CSD register without CRC.
 *
 *  @see    fill_csd_struct
 */
struct t_mmc_csd {
    unsigned char   ecc                 : 2;    /**< R/W/E  ECC code                                            */
    unsigned char   file_format         : 2;    /**< R/W    File format                                         */
    unsigned char   tmp_write_protect   : 1;    /**< R/W/E  Temporary write protection                          */
    unsigned char   perm_write_protect  : 1;    /**< R/W    Permanent write protection                          */
    unsigned char   copy                : 1;    /**< R/W    Copy flag (OTP)                                     */
    unsigned char   file_format_grp     : 1;    /**< R/W    File format group                                   */
    unsigned char   content_prot_app    : 1;    /**< R      Content protection application                      */
    unsigned char   write_bl_partial    : 1;    /**< R      Partial blocks for write allowed                    */
    unsigned char   write_bl_len        : 4;    /**< R      Max. write data block length                        */
    unsigned char   r2w_factor          : 3;    /**< R      Write speed factor                                  */
    unsigned char   default_ecc         : 2;    /**< R      Manufacturer default ECC                            */
    unsigned char   wp_grp_enable       : 1;    /**< R      Write protect group enable                          */
    unsigned char   wp_grp_size         : 5;    /**< R      Write protect group size                            */
    unsigned char   erase_grp_mult      : 5;    /**< R      Erase group multiplier                              */
    unsigned char   erase_grp_size      : 5;    /**< R      Erase group size                                    */
    unsigned char   c_size_mult         : 3;    /**< R      Device size multiplier                              */
    unsigned char   vdd_w_curr_max      : 3;    /**< R      Max. write current @ VDD max                        */
    unsigned char   vdd_w_curr_min      : 3;    /**< R      Max. write current @ VDD min                        */
    unsigned char   vdd_r_curr_max      : 3;    /**< R      Max. read current @ VDD max                         */
    unsigned char   vdd_r_curr_min      : 3;    /**< R      Max. read current @ VDD min                         */
    unsigned short  c_size              : 12;   /**< R      Device size                                         */
    unsigned char   dsr_imp             : 1;    /**< R      DSR implemented                                     */
    unsigned char   read_blk_misalign   : 1;    /**< R      Read block misalignement                            */
    unsigned char   write_blk_misalign  : 1;    /**< R      Write block misalignement                           */
    unsigned char   read_bl_partial     : 1;    /**< R      Partial blocks for read allowed                     */
    unsigned char   read_bl_len         : 4;    /**< R      Max. read data block length                         */
    unsigned short  ccc                 : 12;   /**< R      Card command classes                                */
    unsigned char   tran_speed          : 8;    /**< R      Max. bus clock frequency                            */
    unsigned char   nsac                : 8;    /**< R      Data read access-time 2 in CLK cycles (NSAC*100)    */
    unsigned char   taac                : 8;    /**< R      Data read access-time 1                             */
    unsigned char   spec_vers           : 4;    /**< R      System specification version                        */
    unsigned char   csd_structure       : 2;    /**< R      CSD structure                                       */
};

/**
 *  Struct representing the content of the EXT_CSD register.
 *
 *  @see    fill_ext_csd_struct
 */
struct t_mmc_ext_csd {
    /*  modes segment   */
    unsigned char   erased_mem_cont;        /**< RO     [181]   Erased Memory Content                                   */
    unsigned char   bus_width_mode;         /**< WO     [183]   Bus Width Mode                                          */
    unsigned char   hs_timing;              /**< R/W    [185]   High Speed Interface Timing                             */
    unsigned char   power_class;            /**< R/W    [187]   Power Class                                             */
    unsigned char   cmd_set_rev;            /**< RO     [189]   Command Set Revision                                    */
    unsigned char   cmd_set;                /**< R/W    [191]   Command Set                                             */

    /*  properties segment  */
    unsigned char   ext_csd_rev;            /**< R      [192]   Extended CSD Revision                                   */
    unsigned char   csd_structure;          /**< R      [194]   CSD Structure Version                                   */
    unsigned char   card_type;              /**< R      [196]   Card Type                                               */
    unsigned char   pwr_cl_52_195;          /**< R      [200]   Power Class for 52MHz @ 1.95V                           */
    unsigned char   pwr_cl_26_195;          /**< R      [201]   Power Class for 26MHz @ 1.95V                           */
    unsigned char   pwr_cl_52_360;          /**< R      [202]   Power Class for 52MHz @ 3.6V                            */
    unsigned char   pwr_cl_26_360;          /**< R      [203]   Power Class for 26MHz @ 3.6V                            */
    unsigned char   min_perf_r_4_26;        /**< R      [205]   Minimum Read Performance for 4bit @26MHz                */
    unsigned char   min_perf_w_4_26;        /**< R      [206]   Minimum Write Performance for 4bit @26MHz               */
    unsigned char   min_perf_r_8_26_4_52;   /**< R      [207]   Minimum Read Performance for 8bit @26MHz / 4bit @52MHz  */
    unsigned char   min_perf_w_8_26_4_52;   /**< R      [208]   Minimum Write Performance for 8bit @26MHz / 4bit @52MHz */
    unsigned char   min_perf_r_8_52;        /**< R      [209]   Minimum Read Performance for 8bit @52MHz                */
    unsigned char   min_perf_w_8_52;        /**< R      [210]   Minimum Write Performance for 8bit @52MHz               */
    unsigned long   sec_count;              /**< R  [215:212]   Sector Count                                            */
    unsigned char   s_cmd_set;              /**< R      [504]   Supported Command Sets                                  */
};

/*  MMC states according to JESD84-B42.pdf aka standard v4.2 table 25 */
#define MMC_STATE_IDLE  0
#define MMC_STATE_READY 1
#define MMC_STATE_IDENT 2
#define MMC_STATE_STBY  3
#define MMC_STATE_TRAN  4
#define MMC_STATE_DATA  5
#define MMC_STATE_RCV   6
#define MMC_STATE_PRG   7
#define MMC_STATE_DIS   8
#define MMC_STATE_BTST  9

/*  MMC commands    */

/** @name   command class 0 (basic)
 *  (mandatory for all card classes)
 *  @{
 */
#define MMC_GO_IDLE_STATE       0
#define MMC_SEND_OP_COND        1
#define MMC_ALL_SEND_CID        2
#define MMC_SET_RELATIVE_ADDR   3
#define MMC_SWITCH              6
#define MMC_SELECT_CARD         7
#define MMC_DESELECT_CARD       7
#define MMC_SEND_EXT_CSD        8
#define MMC_SEND_CSD            9
#define MMC_SEND_STATUS         13
#define MMC_GO_INACTIVE_STATE   15
/** @}  */

/** @name   command class 2 (block read)
 *  @{
 */
#define MMC_SET_BLOCKLEN        16
#define MMC_READ_SINGLE_BLOCK   17
/** @}  */

/** @name   command class 4 (block write)
 *  @{
 */
#define MMC_WRITE_BLOCK         24
/** @}  */

/** @name   command class 5 (erase)
 *  @{
 */
#define MMC_ERASE_GROUP_START   35
#define MMC_ERASE_GROUP_END     36
/** @}  */

/** @name   command class 8 (application specific)
 *  @{
 */
#define MMC_APP_CMD             55
/** @} */

/** @def    MMC_GO_IDLE_STATE
 *  @brief  CMD0: Resets the card to idle state.
 *  @param  [31:0]  stuff bits
 */

/** @def    MMC_SEND_OP_COND
 *  @brief  CMD1: Asks the card, in idle state, to send its Operating
 *          Conditions Register contents in the response on the CMD
 *          line.
 *  @param  [31:0]  OCR without busy
 *  @return R3
 */

/** @def    MMC_ALL_SEND_CID
 *  @brief  CMD2: Asks the card to send its CID number on the CMD line.
 *  @param  [31:0]  stuff bits
 *  @return R2
 */

/** @def    MMC_SET_RELATIVE_ADDR
 *  @brief  CMD3: Assigns relative address to the card.
 *  @param  [31:16] RCA
 *  @param  [15:0]  stuff bits
 *  @return R1
 */

/** @def    MMC_SWITCH
 *  @brief  CMD6: Switches the mode of operation of the selected card or
 *          modifies the EXT_CSD registers.
 *  @param  [31:26] Set to 0
 *  @param  [25:24] Access
 *  @param  [23:16] Index
 *  @param  [15:8]  Value
 *  @param  [7:3]   Set to 0
 *  @param  [2:0]   Cmd Set
 *  @return R1b
 */

/** @def    MMC_SELECT_CARD
 *  @brief  CMD7: Command toggles a card between the stand-by and
 *          transfer states or between the programming and disconnect
 *          states. In both cases the card is selected by its own
 *          relative address and gets deselected by any other address;
 *          address 0 deselects the card.
 *  @param  [31:16] RCA
 *  @param  [15:0]  stuff bits
 *  @return R1, R1b
 */

/** @def    MMC_DESELECT_CARD
 *  @see    MMC_SELECT_CARD
 */

/** @def    MMC_SEND_EXT_CSD
 *  @brief  CMD8: The card sends its EXT_CSD register as a block of
 *          data.
 *  @param  [31:0]  stuff bits
 *  @return R1
 */

/** @def    MMC_SEND_CSD
 *  @brief  CMD9: Addressed card sends its card-specific data (CSD) on
 *          the CMD line.
 *  @param  [31:16] RCA
 *  @param  [15:0]  stuff bits
 *  @return R2
 */

/** @def    MMC_SEND_STATUS
 *  @brief  CMD13: Addressed card sends its status register.
 *  @param  [31:16] RCA
 *  @param  [15:0]  stuff bits
 *  @return R1
 */

/** @def    MMC_GO_INACTIVE_STATE
 *  @brief  CMD15: Sets the card to inactive state.
 *  @param  [31:16] RCA
 *  @param  [15:0]  stuff bits
 */

/** @def    MMC_SET_BLOCKLEN
 *  @brief  CMD16: Sets the block length (in bytes) for all following
 *          block commands (read and write). Default block length is
 *          specified in the CSD.
 *  @param  [31:0] block length
 *  @return R1
 */

/** @def    MMC_READ_SINGLE_BLOCK
 *  @brief  CMD17: Reads a block of the size selected by the
 *          SET_BLOCKLEN command. The transferred data must not cross a
 *          physical block boundary, unless READ_BLK_MISALIGN is set in
 *          the CSD register.
 *  @param  [31:0] data address
 *  @return R1
 */

/** @def    MMC_WRITE_BLOCK
 *  @brief  CMD24: Writes a block of the size selected by the
 *          SET_BLOCKLEN command. The transferred data must not cross a
 *          physical block boundary unless WRITE_BLK_MISALIGN is set in
 *          the CSD.
 *  @param  [31:0] data address
 *  @return R1
 */

/** @def    MMC_ERASE_GROUP_START
 *  @brief  CMD35: Sets the address of the first erase group within a
 *          range to be selected for erase.
 *  @param  [31:0]  data address
 *  @return R1
 */

/** @def    MMC_ERASE_GROUP_END
 *  @brief  CMD36: Sets the address of the last erase group within a
 *          continuous range to be selected for erase.
 *  @param  [31:0]  data address
 *  @return R1
 */

/** @def    MMC_APP_CMD
 *  @brief  CMD55: Indicates to the card that the next command is an
 *          application specific command rather than a standard command.
 *  @param  [31:16] RCA
 *  @param  [15:0]  stuff bits
 *  @return R1
 */

#endif /* _MMC_REG_H */
