text: /*******************************************************************************
  Copyright (c) 2020, Vayavya Labs Pvt. Ltd.
  All rights reserved.
  
  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions are met:
      * Redistributions of source code must retain the above copyright
        notice, this list of conditions and the following disclaimer.
      * Redistributions in binary form must reproduce the above copyright
        notice, this list of conditions and the following disclaimer in the
        documentation and/or other materials provided with the distribution.
      * Neither the name of Vayavya Labs Pvt. Ltd. nor the
        names of its contributors may be used to endorse or promote products
        derived from this software without specific prior written permission.
  
  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  DISCLAIMED. IN NO EVENT SHALL VAYAVYA LABS PVT. LTD. BE LIABLE FOR ANY
  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  ******************************************************************************/
  
  /** @file ldd.h
    * 
    * @brief File captures required interface to access the UFS host controller
    *  driver along with well defined data types as per JESD220C UFS spec 2.1. 
  */
  
  #pragma once 
  
  #include "ufs_upiu.h"
  
  enum {
      UFS_TASK_REQ_UPIU_SIZE_DWORDS   = 8,
      UFS_TASK_RSP_UPIU_SIZE_DWORDS   = 8,
      UFS_ALIGNED_UPIU_SIZE           = 512,
      UFS_SG                          = 128,
      UFS_PRDT_BUFFER_SIZE            = 4096,
  };
  
  typedef struct ufs_struct {
      unsigned int    vendor_id;  /* Vendor ID from the bus */
      unsigned int    device_id;  /* Device ID from the bus */
      unsigned char   task_tag;   /*task tag value*/
  
      unsigned int    block_count;    /*logical block count*/
      unsigned int    block_size;     /*logical block size*/
      unsigned char*  scsi_cmd_id;    /* Unique id that holds scsi command */
      unsigned int    opcode;         /* operational code */
      struct ufs_dev_prv_data *prv_data;  /* ufs device private data structure */
  }ufs_struct;
  
  /**
   * struct prdt_table - UFS PRD Entry
   * @base_addr: Lower 32bit physical address DW-0
   * @upper_addr: Upper 32bit physical address DW-1
   * @reserved: Reserved for future use DW-2
   * @size: size of physical segment DW-3
   */
  typedef struct prdt_table {
      unsigned int    data_base_address;
      unsigned int    data_upper_address;
      unsigned int    reserved;
      unsigned int    data_byte_count;
  }prdt_table;
  
  /**
   * struct utp_transfer_cmd_desc - UFS Command Descriptor structure
   * @command_upiu: Command UPIU Frame address
   * @response_upiu: Response UPIU Frame address
   * @prd_table: Physical Region Descriptor
   */
  typedef struct utp_transfer_cmd_desc {
      unsigned char command_upiu[UFS_ALIGNED_UPIU_SIZE];
      unsigned char response_upiu[UFS_ALIGNED_UPIU_SIZE];
      struct prdt_table    prdt[UFS_SG];
  }utp_transfer_cmd_desc;
  
  /**
   * struct utp_task_req_desc - UTMRD structure
   * @task_req_upiu: Pointer to task request UPIU DW-4 to DW-11
   * @task_rsp_upiu: Pointer to task response UPIU DW12 to DW-19
   */
  typedef struct utp_task_mgmt_req_desc {
  
      unsigned int task_req_upiu[UFS_TASK_REQ_UPIU_SIZE_DWORDS];
  
      unsigned int task_rsp_upiu[UFS_TASK_RSP_UPIU_SIZE_DWORDS];
  }utp_task_mgmt_req_desc;
  //RPMB Data Frame Structure
  /* \struct rpmb_frame - rpmb frame as defined by specs
   *
   * @stuff        : stuff bytes
   * @key_mac      : The authentication key or the message authentication
   *                 code (MAC) depending on the request/response type.
   *                 The MAC will be delivered in the last (or the only)
   *                 block of data.
   * @data         : Data to be written or read by signed access.
   * @nonce        : Random number generated by the host for the requests
   *                 and copied to the response by the RPMB engine.
   * @write_counter: Counter value for the total amount of the successful
   *                 authenticated data write requests made by the host.
   * @addr         : Address of the data to be programmed to or read
   *                 from the RPMB. Address is the serial number of
   *                 the accessed block (half sector 256B).
   * @block_count  : Number of blocks (half sectors, 256B) requested to be
   *                 read/programmed.
   * @result       : Includes information about the status of the write counter
   *                 (valid, expired) and result of the access made to the RPMB.
   * @req_resp     : Defines the type of request and response to/from the memory.
   */
  struct rpmb_frame {
      unsigned char   stuff[196];
      unsigned char   key_mac[32];
      unsigned char   data[256];
      unsigned char   nonce[16];
      unsigned int    write_counter;
      unsigned short  addr;
      unsigned short  block_count;
      unsigned short  result;
      unsigned short  req_resp;
  };
  
  typedef enum{
      UFS_SUCCESS=0,
      UFS_FAILURE=1,
  }status_t;
  
  /**
   * \brief  Initialization of UFS host controller at logical layer
   *
   * \param  *ufshci   Pointer to ufs_struct
   *
   * \return           UFS_SUCCESS or FAILURE
   *
   */
  int ufs_preinit(struct ufs_struct *ufshci, unsigned int vendor_id, unsigned int device_id);
  int ufs_init(struct ufs_struct *ufshci);
  
  /**
   * \brief  de-initialization of UFS host controller at logical layer
   *      deallocates the memory of private data structure
   * \param  
   *
   * \return           void
   *
   */
  int ufs_deinit(struct ufs_struct *ufshci);
  
  
  
  /* UFS Protocol Information Units */
  
  /**
   * \brief  Creates NOP out UPIU that needs to be sent to device
   *
   * \param  *ufshci      Pointer to ufs_struct
   * \param  *cmd     Unique id that hold command information
   * \return              UFS_SUCCESS or FAILURE
   *
   */
  int ufs_upiu_create_nop_out(struct ufs_struct *ufshci, struct utp_transfer_cmd_desc *cmd);
  
  
  /**
   * \brief  Sent from Device as a response to NOP out
   *
   * \param  *ufshci      Pointer to ufs_struct
   * \param  *cmd         Unique id that hold command information
   * \return              UFS_SUCCESS or FAILURE
   *
   */
  int ufs_upiu_receive_nop_in(struct ufs_struct *ufshci, struct utp_transfer_cmd_desc *cmd);
  
  
  /**
   * \brief  Creates SCSI command UPIU that needs to be sent to device
   *
   * \param  *ufshci      Pointer to ufs_struct
   * \param  flag         Flag value that needs to be configure
                          in the 1st bit of the SCSI command
   * \param  lba          logical block addr
   * \param  size         size value
   * \param  pagecode     Specifies which mode page to return
   * \param  subpage_code Specifies which subpage mode page to return
   * \param  power_flush_loej_start_bit  value of power_flush, no_flush, loej and  *                       start bits`
   * \return              
   *
   */
  int ufs_create_scsi_cmd(struct ufs_struct *ufshci, unsigned int opcode, unsigned int flag, unsigned int lba,unsigned int size, unsigned char pagecode, unsigned char subpage_code, unsigned char power_flush_loej_start_bit);
  
  /**
   * \brief  Creates UPIU command to send to the device
   *
   * \param  *ufshci      Pointer to ufs_struct
   * \param  *cmd     Unique id that hold command information
   * \param  data_buff_id Unique_id that holds the data to be sent
   * \param  expected_data_len expected data length
   * \param  lun      logical Unit Number
   * \param  flag     flag value
   * \return    UFS_SUCCESS or FAILURE 
   *
   */
  int ufs_upiu_create_cmd(struct ufs_struct *ufshci, struct utp_transfer_cmd_desc *cmd, unsigned char *data_buff,unsigned char *scsi_cmd, unsigned int expected_data_len, unsigned char lun, unsigned char flag);
  
  
  /**
   * \brief  decodes the response received from device to host on UPIU command sent
   *
   * \param  *ufshci      Pointer to ufs_struct
   * \param  *cmd     Unique id that hold command information
   * \return              UFS_SUCCESS or FAILURE 
   *
   */
  int ufs_upiu_receive_response(struct ufs_struct *ufshci, struct utp_transfer_cmd_desc *cmd);
  
  /**
   * \brief  creates query request UPIU to be sent from host to device
   *
   * \param  *ufshci      Pointer to ufs_struct
   * \param  *cmd     Unique id that hold command information
   * \param  data_buff_id 
   * \param  flag     flag value
   * \param  data_buff_id data segment length
   * \param  query_op     Query op-code specifies query request
              operation read/write.
   * \param  query_fun    unique value to each query function
   * \param  idn_value    index value
   * \param  select_val   selector value
   * \param  length   query data length
   * \param  value_data   write attribute value
   * \param  min_um_area_size_id Unique id that holds Minimum Unified
              memory area size
   * \return              UFS_SUCCESS or FAILURE 
   *
   */
  int ufs_upiu_create_query_request(struct ufs_struct *ufshci, struct utp_transfer_cmd_desc *cmd,
          unsigned char *data_transfer_buff, unsigned char flag,
          unsigned int data_segment_len, ufs_query_type query_op,
          ufs_query_function query_fun, unsigned char idn_value,
          unsigned char index_val, unsigned char select_val,
          unsigned short length, unsigned int value_data, unsigned int *min_um_area_size_buf);
  
  /**
   * \brief  checks for the success of the response received from device
   *
   * \param  *ufshci      Pointer to ufs_struct
   * \param  *cmd     Unique id that hold command information
   * \param  data_read_buff_id Unique id that holds the read data
   * \param min_um_area_size_id Unique id that holds Minimum Unified
              memory area size 
   * \return              UFS_SUCCESS or FAILURE 
   *
   */
  int ufs_upiu_receive_query_response(struct ufs_struct *ufshci, struct utp_transfer_cmd_desc *cmd,unsigned char *data_read_buff, unsigned int *min_um_area_size_buf);
  
  /* TASK MANAGMENT */
  
  /**
   * \brief  creates task management request UPIU that needs to be sent to device
   *
   * \param  *ufshci      Pointer to ufs_struct
   * \param  *utmrd   unique value that holds UTMRD data
   * \param  flag     flag value
   * \param  lun      logical unit number
   * \param  tm_function  task management function value
   * \return              UFS_SUCCESS or FAILURE 
   *
   */
  int ufs_upiu_create_task_management_request(struct ufs_struct *ufshci, struct utp_task_mgmt_req_desc *utmrd,
          unsigned char flag, unsigned char lun, unsigned char tm_function);
  
  /**
   * \brief  decodes and check the response received from device
   *
   * \param  *ufshci      Pointer to ufs_struct
   * \param  *utmrd   Unique id that holds UTMRD related value
   * \return              UFS_SUCCESS or FAILURE 
   *
   */
  int ufs_upiu_receive_task_management_response(struct ufs_struct *ufshci, struct utp_task_mgmt_req_desc *utmrd);
  
  
  /**
   * \brief  releases the memory assigned to the input command buffer id
   *
   * \param  *cmd Unique id that hold command information
   * \return              
   *
   */
  int ufs_destroy_command(struct utp_transfer_cmd_desc *cmd);
  
  /**
   * \brief  created RPMB data frame
   *
   * \param  rpmb_buff_id Unique id that holds RPMB related info  
   * \param  data_buff_id Unique Id that holds the data that needs to be
              transferred
   * \param  counter  Write Counter value
   * \param  addr     Address location to read from or to write to
   * \param  block_count  Number of blocks to read or write
   * \param  req_code     RPMB message request
   *
   * \return              void
   *
   */
  void ufs_create_replay_protected_memory_block_frame (unsigned char *rpmb_buffer_id, 
          unsigned char *data_buffer_id, 
          unsigned int counter, 
          unsigned short addr,
          unsigned short block_count, 
          unsigned short req_code);
  
  
  
  /* LDD WRAPPER API */
  
  
  /**
   * \brief it handles the interrupts of UFSHCI. 
   *    It checks the interrupt status register and sets respective events. 
   *
   * \return              
   *
   */
  int ufshci_interrupt_routine(struct ufs_struct *ufshci);
  
  /**
   * \brief  Checks the bus master support capabilities 
   *
   * \param  *ufshci   Pointer to ufs_struct
   * \return              
   *
   */
  int ufshci_check_device_bus_master_support(struct ufs_struct *ufshci);
  
  /**
   * \brief  check whether endpoint reset is supported by device or not
   *
   * \param  *ufshci   Pointer to ufs_struct
   * \return              
   *
   */
  int ufshci_check_device_management_entity_endpoint_reset(struct ufs_struct *ufshci);
  
  /**
   * \brief  configures auto hibernation mode after idle state
   *
   * \param  *ufshci   Pointer to ufs_struct
   * \param  timer_scale  timer scale value
   * \param  timer_value  timer value
   * \param  hclk_div_value HCLK divider value
   * \return              
   *
   */
  int ufshci_config_auto_hibernation(struct ufs_struct *ufshci, unsigned char timer_scale, unsigned short timer_value,
          unsigned int hclk_div_value);
  
  /**
   * \brief  checks whether the UNIPRO stack has entered or exited successful in 
   *         hibernation mode and prints the status of hibernation request 
   *
   * \param  *ufshci   Pointer to ufs_struct
   * \return              
   *
   */
  int ufshci_verify_hibernation(struct ufs_struct *ufshci);
  
  /**
   * \brief  enables interrupt aggregation value and configures counter and timer values.
   *
   * \param  *ufshci   Pointer to ufs_struct
   * \param  count        counter value
   * \param  timer        timer value
   * \return              
   *
   */
  int ufshci_config_intr_aggregation(struct ufs_struct *ufshci, unsigned char count, unsigned char timer);
  
  /**
   * \brief  resets interrupr aggregation and resets counter/timer values. 
   *
   * \param  *ufshci   Pointer to ufs_struct
   * \return              
   *
   */
  int ufshci_reset_intr_aggregation(struct ufs_struct *ufshci);
  
  /**
   * \brief  configures buffer size 
   *
   * \param  buffer_size  Max Burst length value
   * \return              
   *
   */
  int ufshci_configure_buffer_size(struct ufs_struct *ufshci, unsigned char buffer_size);
  
  /**
   * \brief  configures the UME Base address and upper boundary of the Unified Memory area. 
   *
   * \param  *ufshci   Pointer to ufs_struct
   * \param  ume_base_addr UME base address
   * \param  umaomax      Upper boundary of the Unified Memory area
   * \return              
   *
   */
  int ufshci_configure_unified_memory_extention_mode(struct ufs_struct *ufshci, unsigned long long ume_base_addr, unsigned int umaomax);
  
  /**
   * \brief  enables unified memory extension feature
   *
   * \param  *ufshci   Pointer to ufs_struct
   * \return              
   *
   */
  int ufshci_enable_unifies_memory_extention(struct ufs_struct *ufshci);
  
  /**
   * \brief  reads bpurgestatus attribute. 
   *
   * \param  *ufshci   Pointer to ufs_struct
   * \return              
   *
   */
  int ufshci_read_purge_attribute(struct ufs_struct *ufshci,struct utp_transfer_cmd_desc *cmd);
  
  /**
   * \brief  reads the value present in simplified register offset. 
   *
   * \param  *ufshci   Pointer to ufs_struct
   * \param  buffer_id    buffer to store read register
   * \param  register_offset register offset
   * \return              
   *
   */
  int ufshci_register_read(struct ufs_struct *ufshci, unsigned int *buffer, unsigned int register_offset);
  
  /**
   * \brief  writes the value to specified register offset. 
   *
   * \param  *ufshci   Pointer to ufs_struct
   * \param  value        value that needs to be stored
   * \param  register_offset register offset
   * \return              
   *
   */
  int ufshci_register_write(struct ufs_struct *ufshci, unsigned int register_offset, unsigned int value);
  
  /**
   * \brief  configures UNIPRO DME primitives through UIC command registers
   *
   * \param  *ufshci   Pointer to ufs_struct
   * \param  dme_opcode   Op-code of a UIC Command to be
              dispatched to local UIC layer
   * \param  mib_attr     the ID of the attribute of the requested
   * \param  gen_select_idx targeted M-PHY data lane or CPort or Test Feature when relevant
   * \param  reset_level  reset type
   * \param  attr_set_type  indicates whether attribute value is normal or static
   * \param  mib_write_value indicates value of attribute to be set
   * \return              
   *
   */
  int ufshci_unipro_config_dme(struct ufs_struct *ufshci, unsigned char dme_opcode, unsigned short mib_attr,
          unsigned short gen_select_idx, unsigned char reset_level, unsigned char attr_set_type,
          unsigned int mib_write_val);
  
  /**
   * \brief  Checks the command completion status. 
   *
   * \param  *ufshci   Pointer to ufs_struct
   * \param  dme_opcode   OPCODE of UIC command
   * \return              
   *
   */
  int ufshci_unipro_check_cmd_completion(struct ufs_struct *ufshci, unsigned char dme_opcode);
  
  /**
   * \brief  indicates the host device that the command is configured in the slot
   *     by setting respective slot in doorbell register and 
   *     waits until command completion interrupts occurs. 
   *
   * \param  *ufshci   Pointer to ufs_struct
   * \return              
   *
   */
  int ufshci_utrd_doorbell_complete(struct ufs_struct *ufshci);
  
  /**
   * \brief  It checks the service response fields of task management response UPI. 
   *
   * \param  *ufshci   Pointer to ufs_struct
   * \param  *utmrd        
   * \return              
   *
   */
  int ufshci_utmrd_check_response(struct ufs_struct *ufshci, struct utp_task_mgmt_req_desc *utmrd);
  
  
  /**
   * \brief  fills up UTMRD descriptor 
   *
   * \param  *ufshci   Pointer to ufs_struct
   * \param  *utmrd     Unique id pointing to UTMRD related info
   * \return              
   *
   */
  int ufshci_utmrd_descriptor(struct ufs_struct *ufshci, struct utp_task_mgmt_req_desc *utmrd);
  
  /**
   * \brief  fills up the UTRD descriptor
   *
   * \param  *ufshci      Pointer to ufs_struct
   * \param  *cmd     Unique id that hold command information
   * \param  prdt_len     PRDT length
   * \param  dir          data direction
   * \param  intr_bit     interrupt bit
   * \return              
   *
   */
  int ufshci_utrd_descriptor(struct ufs_struct *ufshci,struct utp_transfer_cmd_desc *cmd, unsigned short prdt_len, unsigned char dir,
          unsigned char intr_bit);
  
  /**
   * \brief  It indicates that command is configured in the slot by setting respective slot
         in doorbell register and waits until command completion interrupts occurs, up which it checks OCS field.
   *
   * \param  *ufshci   Pointer to ufs_struct
   * \return              
   *
   */
  int ufshci_utmrd_doorbell_complete(struct ufs_struct *ufshci);
  
  /**
   * \brief  To handle this error, it performs re-initialization of the UFS host controller.
   *
   * \param  *ufshci   Pointer to ufs_struct
   * \return              
   *
   */
  int ufshci_handle_hibernate_error(struct ufs_struct *ufshci);
  
  /**
   * \brief  It waits for device fatal error interrupt to occur. 
   *     To handle this error it performs DME reset and re-initialization of the UFS host controller. 
   *
   * \param  *ufshci   Pointer to ufs_struct
   * \return              
   *
   */
  int ufshci_handle_device_fatal_error(struct ufs_struct *ufshci);
  
  
  /**
   * \brief  To handle this error, it performs re-initialization of the UFS host controller.
   *
   * \param  *ufshci   pointer to ufs_struct
   * \return              
   *
   */
  int ufshci_handle_host_controller_fatal_error(struct ufs_struct *ufshci);
  
  /**
   * \brief  This task handles a system bus error which occurs due to bad memory pointers, 
   *      bad operation and protection violation. It waits for system bus interrupt to occur. 
   *
   * \param  *ufshci   pointer to ufs_struct
   * \return              
   *
   */
  int ufshci_handle_system_bus_error(struct ufs_struct *ufshci);
  
  /**
   * \brief  waits for an UFS interconnect error interrupt to occur. 
   *     Upon interrupt it checks for UIC layer error registers to know which
   *     layer caused an error. To handle this error, 
   *     it performs re-initialization of the UFS host controller. 
   *
   * \param  *ufshci   pointer to ufs_struct
   * \return              
   *
   */
  int ufshci_handle_uic_error(struct ufs_struct *ufshci);
  
  /**
   * \brief  provides type descriptor with value 0x3 and sends
   *     the UNMAP command to the device to perform erase operation
   * \param  *ufshci   pointer to ufs_struct
   * \param  *cmd      pointer to transfer cmd
   * \param  *buf_id   buffer_id
   * \param  lun       logical unit number
   * \param  num_of_desc number of descriptors
   * \return              
   *
   */
  int ufshci_erase_test(struct ufs_struct *ufshci, struct utp_transfer_cmd_desc *cmd, unsigned char *buf,
          unsigned char lun, unsigned short num_of_desc);
  
  /**
   * \brief  free-up the acquired memory indicated by a unique id
   * \param  *buf_id   buffer_id
   * \return              
   *
   */
  int ufs_release_memory(char *buffer_id);
  
  
  // Helper API`s
  
  /**
   * allocAndClearMem() - Brief This function allocates the requested memory.
   * @num: number of elements.
   * @sz: size of each element.
   *
   * This function allocates the requested memory and sets the allocated memory to zero. 
   *
   * Return: Returns the pointer to the allocated memory.
   */
  void *AllocAndClearMem (size_t num, size_t sz);
  
  /**
   * relMem() - Brief This function releases the memory allocated for the
   * given pointer.
   * @ptr: pointer to the memory.
   *
   * Return: void.
   */
  void mem_free (void* ptr);
  
  