2013-02-25 20:14:33 +04:00
/*
* Universal Flash Storage Host controller driver
*
* This code is based on drivers / scsi / ufs / ufshcd . h
* Copyright ( C ) 2011 - 2013 Samsung India Software Operations
*
* Authors :
* Santosh Yaraganavi < santosh . sy @ samsung . com >
* Vinayak Holikatti < h . vinayak @ samsung . com >
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version 2
* of the License , or ( at your option ) any later version .
* See the COPYING file in the top - level directory or visit
* < http : //www.gnu.org/licenses/gpl-2.0.html>
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* This program is provided " AS IS " and " WITH ALL FAULTS " and
* without warranty of any kind . You are solely responsible for
* determining the appropriateness of using and distributing
* the program and assume all risks associated with your exercise
* of rights with respect to the program , including but not limited
* to infringement of third party rights , the risks and costs of
* program errors , damage to or loss of data , programs or equipment ,
* and unavailability or interruption of operations . Under no
* circumstances will the contributor of this Program be liable for
* any damages of any kind arising from your use or distribution of
* this program .
*/
# ifndef _UFSHCD_H
# define _UFSHCD_H
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/init.h>
# include <linux/interrupt.h>
# include <linux/io.h>
# include <linux/delay.h>
# include <linux/slab.h>
# include <linux/spinlock.h>
# include <linux/workqueue.h>
# include <linux/errno.h>
# include <linux/types.h>
# include <linux/wait.h>
# include <linux/bitops.h>
# include <linux/pm_runtime.h>
# include <linux/clk.h>
2013-06-26 21:09:29 +04:00
# include <linux/completion.h>
2013-02-25 20:14:33 +04:00
# include <asm/irq.h>
# include <asm/byteorder.h>
# include <scsi/scsi.h>
# include <scsi/scsi_cmnd.h>
# include <scsi/scsi_host.h>
# include <scsi/scsi_tcq.h>
# include <scsi/scsi_dbg.h>
# include <scsi/scsi_eh.h>
# include "ufs.h"
# include "ufshci.h"
# define UFSHCD "ufshcd"
# define UFSHCD_DRIVER_VERSION "0.2"
2013-07-29 23:05:57 +04:00
enum dev_cmd_type {
DEV_CMD_TYPE_NOP = 0x0 ,
2013-07-29 23:05:58 +04:00
DEV_CMD_TYPE_QUERY = 0x1 ,
2013-07-29 23:05:57 +04:00
} ;
2013-02-25 20:14:33 +04:00
/**
* struct uic_command - UIC command structure
* @ command : UIC command
* @ argument1 : UIC command argument 1
* @ argument2 : UIC command argument 2
* @ argument3 : UIC command argument 3
* @ cmd_active : Indicate if UIC command is outstanding
* @ result : UIC command result
2013-06-26 21:09:29 +04:00
* @ done : UIC command completion
2013-02-25 20:14:33 +04:00
*/
struct uic_command {
u32 command ;
u32 argument1 ;
u32 argument2 ;
u32 argument3 ;
int cmd_active ;
int result ;
2013-06-26 21:09:29 +04:00
struct completion done ;
2013-02-25 20:14:33 +04:00
} ;
/**
* struct ufshcd_lrb - local reference block
* @ utr_descriptor_ptr : UTRD address of the command
2013-07-29 23:05:57 +04:00
* @ ucd_req_ptr : UCD address of the command
2013-02-25 20:14:33 +04:00
* @ ucd_rsp_ptr : Response UPIU address for this command
* @ ucd_prdt_ptr : PRDT address of the command
* @ cmd : pointer to SCSI command
* @ sense_buffer : pointer to sense buffer address of the SCSI command
* @ sense_bufflen : Length of the sense buffer
* @ scsi_status : SCSI status of the command
* @ command_type : SCSI , UFS , Query .
* @ task_tag : Task tag of the command
* @ lun : LUN of the command
2013-07-29 23:05:57 +04:00
* @ intr_cmd : Interrupt command ( doesn ' t participate in interrupt aggregation )
2013-02-25 20:14:33 +04:00
*/
struct ufshcd_lrb {
struct utp_transfer_req_desc * utr_descriptor_ptr ;
2013-07-29 23:05:57 +04:00
struct utp_upiu_req * ucd_req_ptr ;
2013-02-25 20:14:33 +04:00
struct utp_upiu_rsp * ucd_rsp_ptr ;
struct ufshcd_sg_entry * ucd_prdt_ptr ;
struct scsi_cmnd * cmd ;
u8 * sense_buffer ;
unsigned int sense_bufflen ;
int scsi_status ;
int command_type ;
int task_tag ;
unsigned int lun ;
2013-07-29 23:05:57 +04:00
bool intr_cmd ;
2013-02-25 20:14:33 +04:00
} ;
2013-07-29 23:05:58 +04:00
/**
* struct ufs_query - holds relevent data structures for query request
* @ request : request upiu and function
* @ descriptor : buffer for sending / receiving descriptor
* @ response : response upiu and response
*/
struct ufs_query {
struct ufs_query_req request ;
u8 * descriptor ;
struct ufs_query_res response ;
} ;
2013-07-29 23:05:57 +04:00
/**
* struct ufs_dev_cmd - all assosiated fields with device management commands
* @ type : device management command type - Query , NOP OUT
* @ lock : lock to allow one command at a time
* @ complete : internal commands completion
* @ tag_wq : wait queue until free command slot is available
*/
struct ufs_dev_cmd {
enum dev_cmd_type type ;
struct mutex lock ;
struct completion * complete ;
wait_queue_head_t tag_wq ;
2013-07-29 23:05:58 +04:00
struct ufs_query query ;
2013-07-29 23:05:57 +04:00
} ;
2013-02-25 20:14:33 +04:00
/**
* struct ufs_hba - per adapter private structure
* @ mmio_base : UFSHCI base register address
* @ ucdl_base_addr : UFS Command Descriptor base address
* @ utrdl_base_addr : UTP Transfer Request Descriptor base address
* @ utmrdl_base_addr : UTP Task Management Descriptor base address
* @ ucdl_dma_addr : UFS Command Descriptor DMA address
* @ utrdl_dma_addr : UTRDL DMA address
* @ utmrdl_dma_addr : UTMRDL DMA address
* @ host : Scsi_Host instance of the driver
* @ dev : device handle
* @ lrb : local reference block
2013-07-29 23:05:57 +04:00
* @ lrb_in_use : lrb in use
2013-02-25 20:14:33 +04:00
* @ outstanding_tasks : Bits representing outstanding task requests
* @ outstanding_reqs : Bits representing outstanding transfer requests
* @ capabilities : UFS Controller Capabilities
* @ nutrs : Transfer Request Queue depth supported by controller
* @ nutmrs : Task Management Queue depth supported by controller
* @ ufs_version : UFS Version to which controller complies
* @ irq : Irq number of the controller
* @ active_uic_cmd : handle of active UIC command
2013-06-26 21:09:29 +04:00
* @ uic_cmd_mutex : mutex for uic command
2013-02-25 20:14:33 +04:00
* @ ufshcd_tm_wait_queue : wait queue for task management
* @ tm_condition : condition variable for task management
* @ ufshcd_state : UFSHCD states
2013-06-26 21:09:27 +04:00
* @ intr_mask : Interrupt Mask Bits
2013-07-29 23:05:59 +04:00
* @ ee_ctrl_mask : Exception event control mask
2013-02-25 20:14:33 +04:00
* @ feh_workq : Work queue for fatal controller error handling
2013-07-29 23:05:59 +04:00
* @ eeh_work : Worker to handle exception events
2013-02-25 20:14:33 +04:00
* @ errors : HBA errors
2013-07-29 23:05:57 +04:00
* @ dev_cmd : ufs device management command information
2013-07-29 23:05:59 +04:00
* @ auto_bkops_enabled : to track whether bkops is enabled in device
2013-02-25 20:14:33 +04:00
*/
struct ufs_hba {
void __iomem * mmio_base ;
/* Virtual memory reference */
struct utp_transfer_cmd_desc * ucdl_base_addr ;
struct utp_transfer_req_desc * utrdl_base_addr ;
struct utp_task_req_desc * utmrdl_base_addr ;
/* DMA memory reference */
dma_addr_t ucdl_dma_addr ;
dma_addr_t utrdl_dma_addr ;
dma_addr_t utmrdl_dma_addr ;
struct Scsi_Host * host ;
struct device * dev ;
struct ufshcd_lrb * lrb ;
2013-07-29 23:05:57 +04:00
unsigned long lrb_in_use ;
2013-02-25 20:14:33 +04:00
unsigned long outstanding_tasks ;
unsigned long outstanding_reqs ;
u32 capabilities ;
int nutrs ;
int nutmrs ;
u32 ufs_version ;
unsigned int irq ;
2013-06-26 21:09:29 +04:00
struct uic_command * active_uic_cmd ;
struct mutex uic_cmd_mutex ;
2013-02-25 20:14:33 +04:00
wait_queue_head_t ufshcd_tm_wait_queue ;
unsigned long tm_condition ;
u32 ufshcd_state ;
2013-06-26 21:09:27 +04:00
u32 intr_mask ;
2013-07-29 23:05:59 +04:00
u16 ee_ctrl_mask ;
2013-02-25 20:14:33 +04:00
/* Work Queues */
struct work_struct feh_workq ;
2013-07-29 23:05:59 +04:00
struct work_struct eeh_work ;
2013-02-25 20:14:33 +04:00
/* HBA Errors */
u32 errors ;
2013-07-29 23:05:57 +04:00
/* Device management request data */
struct ufs_dev_cmd dev_cmd ;
2013-07-29 23:05:59 +04:00
bool auto_bkops_enabled ;
2013-02-25 20:14:33 +04:00
} ;
2013-06-26 21:09:26 +04:00
# define ufshcd_writel(hba, val, reg) \
writel ( ( val ) , ( hba ) - > mmio_base + ( reg ) )
# define ufshcd_readl(hba, reg) \
readl ( ( hba ) - > mmio_base + ( reg ) )
2013-02-25 20:14:33 +04:00
int ufshcd_init ( struct device * , struct ufs_hba * * , void __iomem * ,
unsigned int ) ;
void ufshcd_remove ( struct ufs_hba * ) ;
/**
* ufshcd_hba_stop - Send controller to reset state
* @ hba : per adapter instance
*/
static inline void ufshcd_hba_stop ( struct ufs_hba * hba )
{
2013-06-26 21:09:26 +04:00
ufshcd_writel ( hba , CONTROLLER_DISABLE , REG_CONTROLLER_ENABLE ) ;
2013-02-25 20:14:33 +04:00
}
2013-07-29 23:05:58 +04:00
static inline void check_upiu_size ( void )
{
BUILD_BUG_ON ( ALIGNED_UPIU_SIZE <
GENERAL_UPIU_REQUEST_SIZE + QUERY_DESC_MAX_SIZE ) ;
}
2013-07-29 23:05:59 +04:00
extern int ufshcd_runtime_suspend ( struct ufs_hba * hba ) ;
extern int ufshcd_runtime_resume ( struct ufs_hba * hba ) ;
extern int ufshcd_runtime_idle ( struct ufs_hba * hba ) ;
2013-08-31 20:10:21 +04:00
extern int ufshcd_dme_set_attr ( struct ufs_hba * hba , u32 attr_sel ,
u8 attr_set , u32 mib_val , u8 peer ) ;
extern int ufshcd_dme_get_attr ( struct ufs_hba * hba , u32 attr_sel ,
u32 * mib_val , u8 peer ) ;
/* UIC command interfaces for DME primitives */
# define DME_LOCAL 0
# define DME_PEER 1
# define ATTR_SET_NOR 0 /* NORMAL */
# define ATTR_SET_ST 1 /* STATIC */
static inline int ufshcd_dme_set ( struct ufs_hba * hba , u32 attr_sel ,
u32 mib_val )
{
return ufshcd_dme_set_attr ( hba , attr_sel , ATTR_SET_NOR ,
mib_val , DME_LOCAL ) ;
}
static inline int ufshcd_dme_st_set ( struct ufs_hba * hba , u32 attr_sel ,
u32 mib_val )
{
return ufshcd_dme_set_attr ( hba , attr_sel , ATTR_SET_ST ,
mib_val , DME_LOCAL ) ;
}
static inline int ufshcd_dme_peer_set ( struct ufs_hba * hba , u32 attr_sel ,
u32 mib_val )
{
return ufshcd_dme_set_attr ( hba , attr_sel , ATTR_SET_NOR ,
mib_val , DME_PEER ) ;
}
static inline int ufshcd_dme_peer_st_set ( struct ufs_hba * hba , u32 attr_sel ,
u32 mib_val )
{
return ufshcd_dme_set_attr ( hba , attr_sel , ATTR_SET_ST ,
mib_val , DME_PEER ) ;
}
static inline int ufshcd_dme_get ( struct ufs_hba * hba ,
u32 attr_sel , u32 * mib_val )
{
return ufshcd_dme_get_attr ( hba , attr_sel , mib_val , DME_LOCAL ) ;
}
static inline int ufshcd_dme_peer_get ( struct ufs_hba * hba ,
u32 attr_sel , u32 * mib_val )
{
return ufshcd_dme_get_attr ( hba , attr_sel , mib_val , DME_PEER ) ;
}
2013-02-25 20:14:33 +04:00
# endif /* End of Header */