lkml.org 
[lkml]   [2012]   [Feb]   [10]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
/
From
Date
SubjectRe: [PATCH 1/4] [SCSI] ufshcd: UFS Host controller driver
On Fri, Feb 10, 2012 at 12:45 AM, Girish K S
<girish.shivananjappa@linaro.org> wrote:
> On 2 February 2012 10:27, Vinayak Holikatti <vinholikatti@gmail.com> wrote:
>> From: Santosh Yaraganavi <santoshsy@gmail.com>
>>
>> This patch adds support for Universal Flash Storage(UFS)
>> host controllers. The UFS host controller driver
>> includes host controller initialization method.
>>
>> The Initialization process involves following steps:
>>  - Initiate UFS Host Controller initialization process by writing
>>   to Host controller enable register
>>  - Configure UFS Host controller registers with host memory space
>>   datastructure offsets.
>>  - Unipro link startup procedure
>>  - Check for connected device
>>  - Configure UFS host controller to process requests
>>  - Enable required interrupts
>>  - Configure interrupt aggregation
>>
>> Signed-off-by: Santosh Yaraganavi <santoshsy@gmail.com>
>> Signed-off-by: Vinayak Holikatti <vinholikatti@gmail.com>
>> Reviewed-by: Arnd Bergmann <arnd@arndb.de>
>> Reviewed-by: Saugata Das <saugata.das@linaro.org>
>> Reviewed-by: Vishak G <vishak.g@samsung.com>
>> Reviewed-by: Girish K S <girish.shivananjappa@linaro.org>
>> ---
>>  drivers/scsi/Kconfig      |    1 +
>>  drivers/scsi/Makefile     |    1 +
>>  drivers/scsi/ufs/Kconfig  |   49 ++
>>  drivers/scsi/ufs/Makefile |    2 +
>>  drivers/scsi/ufs/ufs.h    |  203 +++++++++
>>  drivers/scsi/ufs/ufshcd.c | 1091 +++++++++++++++++++++++++++++++++++++++++++++
>>  drivers/scsi/ufs/ufshci.h |  360 +++++++++++++++
>>  7 files changed, 1707 insertions(+), 0 deletions(-)
>>  create mode 100644 drivers/scsi/ufs/Kconfig
>>  create mode 100644 drivers/scsi/ufs/Makefile
>>  create mode 100644 drivers/scsi/ufs/ufs.h
>>  create mode 100644 drivers/scsi/ufs/ufshcd.c
>>  create mode 100644 drivers/scsi/ufs/ufshci.h
>>
>> diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
>> index 16570aa..477a91a 100644
>> --- a/drivers/scsi/Kconfig
>> +++ b/drivers/scsi/Kconfig
>> @@ -619,6 +619,7 @@ config SCSI_ARCMSR
>>
>>  source "drivers/scsi/megaraid/Kconfig.megaraid"
>>  source "drivers/scsi/mpt2sas/Kconfig"
>> +source "drivers/scsi/ufs/Kconfig"
>>
>>  config SCSI_HPTIOP
>>        tristate "HighPoint RocketRAID 3xxx/4xxx Controller support"
>> diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
>> index 2b88749..c832974 100644
>> --- a/drivers/scsi/Makefile
>> +++ b/drivers/scsi/Makefile
>> @@ -108,6 +108,7 @@ obj-$(CONFIG_MEGARAID_LEGACY)       += megaraid.o
>>  obj-$(CONFIG_MEGARAID_NEWGEN)  += megaraid/
>>  obj-$(CONFIG_MEGARAID_SAS)     += megaraid/
>>  obj-$(CONFIG_SCSI_MPT2SAS)     += mpt2sas/
>> +obj-$(CONFIG_SCSI_UFSHCD)      += ufs/
>>  obj-$(CONFIG_SCSI_ACARD)       += atp870u.o
>>  obj-$(CONFIG_SCSI_SUNESP)      += esp_scsi.o   sun_esp.o
>>  obj-$(CONFIG_SCSI_GDTH)                += gdth.o
>> diff --git a/drivers/scsi/ufs/Kconfig b/drivers/scsi/ufs/Kconfig
>> new file mode 100644
>> index 0000000..8f27f9d
>> --- /dev/null
>> +++ b/drivers/scsi/ufs/Kconfig
>> @@ -0,0 +1,49 @@
>> +#
>> +# Kernel configuration file for the UFS Host Controller
>> +#
>> +# This code is based on drivers/scsi/ufs/Kconfig
>> +# Copyright (C) 2011  Samsung Samsung India Software Operations
>> +#
>> +# 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.
>> +
>> +# 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.
>> +
>> +# NO WARRANTY
>> +# THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
>> +# CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
>> +# LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
>> +# MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
>> +# solely responsible for determining the appropriateness of using and
>> +# distributing the Program and assumes all risks associated with its
>> +# exercise of rights under this Agreement, including but not limited to
>> +# the risks and costs of program errors, damage to or loss of data,
>> +# programs or equipment, and unavailability or interruption of operations.
>> +
>> +# DISCLAIMER OF LIABILITY
>> +# NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
>> +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
>> +# DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
>> +# HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
>> +
>> +# You should have received a copy of the GNU General Public License
>> +# along with this program; if not, write to the Free Software
>> +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
>> +# USA.
>> +
>> +config SCSI_UFSHCD
>> +       tristate "Universal Flash Storage host controller driver"
>> +       depends on PCI && SCSI
>> +       ---help---
>> +       This is a generic driver which supports PCIe UFS Host controllers.
>> diff --git a/drivers/scsi/ufs/Makefile b/drivers/scsi/ufs/Makefile
>> new file mode 100644
>> index 0000000..adf7895
>> --- /dev/null
>> +++ b/drivers/scsi/ufs/Makefile
>> @@ -0,0 +1,2 @@
>> +# UFSHCD makefile
>> +obj-$(CONFIG_SCSI_UFSHCD) += ufshcd.o
>> diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
>> new file mode 100644
>> index 0000000..96b5cae
>> --- /dev/null
>> +++ b/drivers/scsi/ufs/ufs.h
>> @@ -0,0 +1,203 @@
>> +/*
>> + * Universal Flash Storage Host controller driver
>> + *
>> + * This code is based on drivers/scsi/ufs/ufs.h
>> + * Copyright (C) 2011-2012 Samsung India Software Operations
>> + *
>> + * 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.
>> + *
>> + * 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.
>> + *
>> + * NO WARRANTY
>> + * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
>> + * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
>> + * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
>> + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
>> + * solely responsible for determining the appropriateness of using and
>> + * distributing the Program and assumes all risks associated with its
>> + * exercise of rights under this Agreement, including but not limited to
>> + * the risks and costs of program errors, damage to or loss of data,
>> + * programs or equipment, and unavailability or interruption of operations.
>> +
>> + * DISCLAIMER OF LIABILITY
>> + * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
>> + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
>> + * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
>> + * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
>> +
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program; if not, write to the Free Software
>> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
>> + * USA.
>> + */
>> +
>> +#ifndef _UFS_H
>> +#define _UFS_H
>> +
>> +#define TASK_REQ_UPIU_SIZE_DWORDS      8
>> +#define TASK_RSP_UPIU_SIZE_DWORDS      8
>> +
>> +#define MAX_CDB_SIZE           16
>> +#define ALIGNED_UPIU_SIZE      128
>> +
>> +#define UPIU_HEADER_DWORD(byte3, byte2, byte1, byte0)\
>> +                       ((byte3 << 24) | (byte2 << 16) |\
>> +                        (byte1 << 8) | (byte0))
>> +
>> +/*
>> + * UFS Protocol Information Unit related definitions
>> + */
>> +
>> +/* Task management functions */
>> +enum {
>> +       UFS_ABORT_TASK          = 0x01,
>> +       UFS_ABORT_TASK_SET      = 0x02,
>> +       UFS_CLEAR_TASK_SET      = 0x04,
>> +       UFS_LOGICAL_RESET       = 0x08,
>> +       UFS_QUERY_TASK          = 0x80,
>> +       UFS_QUERY_TASK_SET      = 0x81
>> +};
>> +
>> +/* UTP UPIU Transaction Codes Initiator to Target */
>> +enum {
>> +       UPIU_TRANSACTION_NOP_OUT        = 0x00,
>> +       UPIU_TRANSACTION_COMMAND        = 0x01,
>> +       UPIU_TRANSACTION_DATA_OUT       = 0x02,
>> +       UPIU_TRANSACTION_TASK_REQ       = 0x04,
>> +       UPIU_TRANSACTION_QUERY_REQ      = 0x26
>> +};
>> +
>> +/* UTP UPIU Transaction Codes Target to Initiator */
>> +enum {
>> +       UPIU_TRANSACTION_NOP_IN         = 0x20,
>> +       UPIU_TRANSACTION_RESPONSE       = 0x21,
>> +       UPIU_TRANSACTION_DATA_IN        = 0x22,
>> +       UPIU_TRANSACTION_TASK_RSP       = 0x24,
>> +       UPIU_TRANSACTION_READY_XFER     = 0x31,
>> +       UPIU_TRANSACTION_QUERY_RSP      = 0x36
>> +};
>> +
>> +/* UPIU Read/Write flags */
>> +enum {
>> +       UPIU_CMD_FLAGS_READ     = 0x40,
>> +       UPIU_CMD_FLAGS_WRITE    = 0x20
>> +
>> +};
>> +
>> +/* UPIU Task Attributes */
>> +enum {
>> +       UPIU_TASK_ATTR_SIMPLE   = 0x00,
>> +       UPIU_TASK_ATTR_ORDERED  = 0x01,
>> +       UPIU_TASK_ATTR_HEADQ    = 0x02,
>> +       UPIU_TASK_ATTR_ACA      = 0x03
>> +};
>> +
>> +/* UTP QUERY Transaction Specific Fields OpCode */
>> +enum {
>> +       UPIU_QUERY_OPCODE_NOP           = 0x0,
>> +       UPIU_QUERY_OPCODE_READ_DESC     = 0x1,
>> +       UPIU_QUERY_OPCODE_WRITE_DESC    = 0x2,
>> +       UPIU_QUERY_OPCODE_READ_ATTR     = 0x3,
>> +       UPIU_QUERY_OPCODE_WRITE_ATTR    = 0x4,
>> +       UPIU_QUERY_OPCODE_READ_FLAG     = 0x5,
>> +       UPIU_QUERY_OPCODE_SET_FLAG      = 0x6,
>> +       UPIU_QUERY_OPCODE_CLEAR_FLAG    = 0x7,
>> +       UPIU_QUERY_OPCODE_TOGGLE_FLAG   = 0x8
>> +};
>> +
>> +/* UTP Transfer Request Command Type (CT) */
>> +enum {
>> +       UPIU_COMMAND_SET_TYPE_SCSI      = 0x0,
>> +       UPIU_COMMAND_SET_TYPE_UFS       = 0x1,
>> +       UPIU_COMMAND_SET_TYPE_QUERY     = 0x2
>> +};
>> +
>> +enum {
>> +       MASK_SCSI_STATUS        = 0xFF,
>> +       MASK_TASK_RESPONSE      = 0xFF00,
>> +       MASK_RSP_UPIU_RESULT    = 0xFFFF
>> +};
>> +
>> +/**
>> + * struct utp_upiu_header - UPIU header structure
>> + * @dword_0: UPIU header DW-0
>> + * @dword_1: UPIU header DW-1
>> + * @dword_2: UPIU header DW-2
>> + */
>> +struct utp_upiu_header {
>> +       u32 dword_0;
>> +       u32 dword_1;
>> +       u32 dword_2;
>> +};
>> +
>> +/**
>> + * struct utp_upiu_cmd - Command UPIU structure
>> + * @header: UPIU header structure DW-0 to DW-2
>> + * @data_transfer_len: Data Transfer Length DW-3
>> + * @cdb: Command Descriptor Block CDB DW-4 to DW-7
>> + */
>> +struct utp_upiu_cmd {
>> +       struct utp_upiu_header header;
>> +       u32 exp_data_transfer_len;
>> +       u8 cdb[MAX_CDB_SIZE];
>> +};
>> +
>> +/**
>> + * struct utp_upiu_rsp - Response UPIU structure
>> + * @header: UPIU header DW-0 to DW-2
>> + * @residual_transfer_count: Residual transfer count DW-3
>> + * @reserved: Reserver DW-4 to DW-7
>> + * @sense_data_len: Sense data length DW-8 U16
>> + * @sense_data: Sense data field DW-8 to DW-12
>> + */
>> +struct utp_upiu_rsp {
>> +       struct utp_upiu_header header;
>> +       u32 residual_transfer_count;
>> +       u32 reserved[4];
>> +       u16 sense_data_len;
>> +       u8 sense_data[18];
>> +};
>> +
>> +/**
>> + * struct utp_upiu_task_req - Task request UPIU structure
>> + * @header - UPIU header structure DW0 to DW-2
>> + * @input_param1: Input param 1 DW-3
>> + * @input_param2: Input param 2 DW-4
>> + * @input_param3: Input param 3 DW-5
>> + * @reserved: Reserver DW-6 to DW-7
>> + */
>> +struct utp_upiu_task_req {
>> +       struct utp_upiu_header header;
>> +       u32 input_param1;
>> +       u32 input_param2;
>> +       u32 input_param3;
>> +       u32 reserved[2];
>> +};
>> +
>> +/**
>> + * struct utp_upiu_task_rsp - Task Management Response UPIU structure
>> + * @header: UPIU header structure DW0-DW-2
>> + * @output_param1: Ouput param 1 DW3
>> + * @output_param2: Output param 2 DW4
>> + * @reserved: Reserver DW-5 to DW-7
>> + */
>> +struct utp_upiu_task_rsp {
>> +       struct utp_upiu_header header;
>> +       u32 output_param1;
>> +       u32 output_param2;
>> +       u32 reserved[3];
>> +};
>> +
>> +#endif /* End of Header */
>> diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
>> new file mode 100644
>> index 0000000..c82eeea
>> --- /dev/null
>> +++ b/drivers/scsi/ufs/ufshcd.c
>> @@ -0,0 +1,1091 @@
>> +/*
>> + * Universal Flash Storage Host controller driver
>> + *
>> + * This code is based on drivers/scsi/ufs/ufshcd.c
>> + * Copyright (C) 2011-2012 Samsung India Software Operations
>> + *
>> + * 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.
>> + *
>> + * 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.
>> + *
>> + * NO WARRANTY
>> + * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
>> + * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
>> + * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
>> + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
>> + * solely responsible for determining the appropriateness of using and
>> + * distributing the Program and assumes all risks associated with its
>> + * exercise of rights under this Agreement, including but not limited to
>> + * the risks and costs of program errors, damage to or loss of data,
>> + * programs or equipment, and unavailability or interruption of operations.
>> +
>> + * DISCLAIMER OF LIABILITY
>> + * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
>> + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
>> + * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
>> + * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
>> +
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program; if not, write to the Free Software
>> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
>> + * USA.
>> + */
>> +
>> +#include <linux/module.h>
>> +#include <linux/kernel.h>
>> +#include <linux/init.h>
>> +#include <linux/pci.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 <asm/irq.h>
>> +#include <asm/byteorder.h>
>> +#include <scsi/scsi.h>
>> +#include <scsi/scsi_cmnd.h>
>> +#include <scsi/scsi_host.h>
>> +#include <scsi/scsi_dbg.h>
>> +
>> +#include "ufs.h"
>> +#include "ufshci.h"
>> +
>> +#define UFSHCD "ufshcd"
>> +#define UFSHCD_DRIVER_VERSION "0.1"
>> +
>> +#ifndef NULL
>> +#define NULL 0
>> +#endif  /* NULL */
>> +
>> +#define BYTES_TO_DWORDS(p)     (p >> 2)
>> +#define UFSHCD_MMIO_BASE       (hba->mmio_base)
>> +
>> +enum {
>> +       UFSHCD_MAX_CHANNEL      = 1,
>> +       UFSHCD_MAX_ID           = 1,
>> +       UFSHCD_MAX_LUNS         = 8,
>> +       UFSHCD_CAN_QUEUE        = 32,
>> +       BYTES_128               = 128,
>> +       BYTES_1024              = 1024
>> +};
>> +
>> +/* UFSHCD states */
>> +enum {
>> +       UFSHCD_STATE_OPERATIONAL,
>> +       UFSHCD_STATE_RESET,
>> +       UFSHCD_STATE_ERROR
>> +};
>> +
>> +/* Interrupt configuration options */
>> +enum {
>> +       UFSHCD_INT_DISABLE,
>> +       UFSHCD_INT_ENABLE,
>> +       UFSHCD_INT_CLEAR
>> +};
>> +
>> +/* Interrupt aggregation options */
>> +enum {
>> +       INT_AGGR_RESET,
>> +       INT_AGGR_CONFIG
>> +};
>> +
>> +/**
>> + * 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
>> + * @callback: routine to be called when UIC command completes
>> + */
>> +struct uic_command {
>> +       u32 command;
>> +       u32 argument1;
>> +       u32 argument2;
>> +       u32 argument3;
>> +       int cmd_active;
>> +       int result;
>> +};
>> +
>> +/**
>> + * struct ufs_hba - per adapter private structure
>> + * @mmio_base: UFSHCI base register address
>> + * @ucdl_virt_addr: UFS Command Descriptor virtual address
>> + * @utrdl_virt_addr: UTP Transfer Request Descriptor virtual address
>> + * @utmrdl_virt_addr: UTP Task Management Descriptor virtual address
>> + * @utrdl_virt_addr_aligned: UTRD Aligned vitual address
>> + * @utmrdl_virt_addr_aligned: UTMRD Aligned virtual address
>> + * @ucdl_size: Memory size of UCD command block
>> + * @utrdl_size: Memory size of UTRDL block
>> + * @utmrdl_size: Memory size of UTMRDL block
>> + * @ucdl_dma_addr: UFS Command Descriptor DMA address
>> + * @utrdl_dma_addr: UTRDL DMA address
>> + * @utmrdl_dma_addr: UTMRDL DMA address
>> + * @utrdl_dma_addr_aligned: UTRDL aligned DMA address
>> + * @utmrdl_dma_addr_aligned: UTMRDL aligned DMA address
>> + * @ucdl_dma_addr_aligned: UCD aligned DMA address
>> + * @dma_size:
>> + * @host: Scsi_Host instance of the driver
>> + * @pdev: PCI device handle
>> + * @lrb: local reference block
>> + * @capabilities: UFS Controller Capabilities
>> + * @nutrs: Transfer Request Queue depth supported by controller
>> + * @nutmrs: Task Management Queue depth supported by controller
>> + * @active_uic_cmd: handle of active UIC command
>> + * @ufshcd_state: UFSHCD states
>> + * @int_enable_mask: Interrupt Mask Bits
>> + * @uic_workq: Work queue for UIC completion handling
>> + */
>> +struct ufs_hba {
>> +       void __iomem *mmio_base;
>> +
>> +       /* Virtual memory reference */
>> +       void *ucdl_virt_addr;
>> +       void *utrdl_virt_addr;
>> +       void *utmrdl_virt_addr;
>> +       void *utrdl_virt_addr_aligned;
>> +       void *utmrdl_virt_addr_aligned;
>> +       void *ucdl_virt_addr_aligned;
>> +
>> +       size_t ucdl_size;
>> +       size_t utrdl_size;
>> +       size_t utmrdl_size;
>> +
>> +       /* DMA memory reference */
>> +       dma_addr_t ucdl_dma_addr;
>> +       dma_addr_t utrdl_dma_addr;
>> +       dma_addr_t utmrdl_dma_addr;
>> +       dma_addr_t utrdl_dma_addr_aligned;
>> +       dma_addr_t utmrdl_dma_addr_aligned;
>> +       dma_addr_t ucdl_dma_addr_aligned;
>> +
>> +       size_t dma_size;
>> +
>> +       struct Scsi_Host *host;
>> +       struct pci_dev *pdev;
>> +
>> +       struct ufshcd_lrb *lrb;
>> +
>> +       u32 capabilities;
>> +       int nutrs;
>> +       int nutmrs;
>> +       u32 ufs_version;
>> +
>> +       struct uic_command active_uic_cmd;
>> +
>> +       u32 ufshcd_state;
>> +       u32 int_enable_mask;
>> +
>> +       /* Work Queues */
>> +       struct work_struct uic_workq;
>> +};
>> +
>> +/**
>> + * struct ufshcd_lrb - command control block
>> + * @utr_descriptor_ptr: UTRD address of the command
>> + * @ucd_cmd_ptr: UCD address of the command
>> + * @ucd_rsp_ptr: Response UPIU address for this command
>> + * @ucd_prdt_ptr: PRDT address of the command
>> + */
>> +struct ufshcd_lrb {
>> +       struct utp_transfer_req_desc *utr_descriptor_ptr;
>> +       struct utp_upiu_cmd *ucd_cmd_ptr;
>> +       struct utp_upiu_rsp *ucd_rsp_ptr;
>> +       struct ufshcd_sg_entry *ucd_prdt_ptr;
>> +};
>> +
>> +/**
>> + * ufshcd_get_ufs_version - Get the UFS version supported by the HBA
>> + * @hba - Pointer to adapter instance
>> + *
>> + * Returns UFSHCI version supported by the controller
>> + */
>> +static inline u32 ufshcd_get_ufs_version(struct ufs_hba *hba)
>> +{
>> +       return readl(UFSHCD_MMIO_BASE + REG_UFS_VERSION);
>> +}
>> +
>> +/**
>> + * ufshcd_is_device_present - Check if any device connected to
>> + *                           the host controller
>> + * @reg_hcs - host controller status register value
>> + *
>> + * Returns 0 if device present, non-zeo if no device detected
>> + */
>> +static inline int ufshcd_is_device_present(u32 reg_hcs)
>> +{
>> +       return (DEVICE_PRESENT & reg_hcs) ? 0 : -1;
>> +}
>> +
>> +/**
>> + * ufshcd_get_lists_status - Check UCRDY, UTRLRDY and UTMRLRDY
>> + * @reg: Register value of host controller status
>> + *
>> + * Returns integer, 0 on Success and positive value if failed
>> + */
>> +static inline int ufshcd_get_lists_status(u32 reg)
>> +{
>> +       /*
>> +        * The mask 0xFF is for the following HCS register bits
>> +        * Bit          Description
>> +        *  0           Device Present
>> +        *  1           UTRLRDY
>> +        *  2           UTMRLRDY
>> +        *  3           UCRDY
>> +        *  4           HEI
>> +        *  5           DEI
>> +        * 6-7          reserved
>> +        */
>> +       return (((reg) & (0xFF)) >> 1) ^ (0x07);
>> +}
>> +
>> +/**
>> + * ufshcd_get_uic_cmd_result - Get the UIC command result
>> + * @hba: Pointer to adapter instance
>> + *
>> + * This function gets the result of UIC command completion
>> + * Returns 0 on success, non zero value on error
>> + */
>> +static inline int ufshcd_get_uic_cmd_result(struct ufs_hba *hba)
>> +{
>> +       return readl(UFSHCD_MMIO_BASE + REG_UIC_COMMAND_ARG_2) &
>> +              MASK_UIC_COMMAND_RESULT;
>> +}
>> +
>> +/**
>> + * ufshcd_free_hba_memory - Free allocated memory for LRB request
>> + *                         and task lists
>> + * @hba: Pointer to adapter instance
>> + */
>> +static inline void ufshcd_free_hba_memory(struct ufs_hba *hba)
>> +{
>> +       kfree(hba->lrb);
>> +       hba->lrb = NULL;
>> +
>> +       if (hba->utmrdl_virt_addr_aligned) {
>> +               dma_free_coherent(&hba->pdev->dev, hba->utmrdl_size,
>> +                                 hba->utmrdl_virt_addr, hba->utmrdl_dma_addr);
>> +               hba->utmrdl_virt_addr = NULL;
>> +               hba->utmrdl_virt_addr_aligned = NULL;
>> +       }
>> +
>> +       if (hba->utrdl_virt_addr_aligned) {
>> +               dma_free_coherent(&hba->pdev->dev, hba->utrdl_size,
>> +                                 hba->utrdl_virt_addr, hba->utrdl_dma_addr);
>> +               hba->utrdl_virt_addr = NULL;
>> +               hba->utrdl_virt_addr_aligned = NULL;
>> +       }
>> +
>> +       if (hba->ucdl_virt_addr_aligned) {
>> +               dma_free_coherent(&hba->pdev->dev, hba->ucdl_size,
>> +                                 hba->ucdl_virt_addr, hba->ucdl_dma_addr);
>> +               hba->ucdl_virt_addr = NULL;
>> +               hba->ucdl_virt_addr_aligned = NULL;
>> +       }
>> +}
>> +
>> +/**
>> + * ufshcd_config_int_aggr - Configure interrupt aggregation values
>> + *             currently there is no use case where we want to configure
>> + *             interrupt aggregation dynamically. So to configure interrupt
>> + *             aggregation, #define INT_AGGR_COUNTER_THRESHOLD_VALUE and
>> + *             INT_AGGR_TIMEOUT_VALUE are used.
>> + * @hba: per adapter instance
>> + * @option: Interrupt aggregation option
>> + */
>> +static inline void
>> +ufshcd_config_int_aggr(struct ufs_hba *hba, int option)
>> +{
>> +       switch (option) {
>> +       case INT_AGGR_RESET:
>> +               writel((INT_AGGR_ENABLE |
>> +                       INT_AGGR_COUNTER_AND_TIMER_RESET),
>> +                       (UFSHCD_MMIO_BASE +
>> +                        REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL));
>> +               break;
>> +       case INT_AGGR_CONFIG:
>> +               writel((INT_AGGR_ENABLE |
>> +                       INT_AGGR_PARAM_WRITE |
>> +                       INT_AGGR_COUNTER_THRESHOLD_VALUE |
>> +                       INT_AGGR_TIMEOUT_VALUE),
>> +                       (UFSHCD_MMIO_BASE +
>> +                        REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL));
>> +               break;
>> +       }
>> +}
>> +
>> +/**
>> + * ufshcd_hba_stop - put the controller in reset state
>> + * @hba: per adapter instance
>> + */
>> +static inline void ufshcd_hba_stop(struct ufs_hba *hba)
>> +{
>> +       writel(0, (UFSHCD_MMIO_BASE + REG_CONTROLLER_ENABLE));
>> +}
>> +
>> +/**
>> + * ufshcd_hba_capabilities - Read controller capabilities
>> + * @hba: per adapter instance
>> + */
>> +static inline void ufshcd_hba_capabilities(struct ufs_hba *hba)
>> +{
>> +       u32 capabilities;
>> +
>> +       capabilities =
>> +               readl(UFSHCD_MMIO_BASE + REG_CONTROLLER_CAPABILITIES);
>> +       hba->capabilities = capabilities;
>> +
>> +       /* nutrs and nutmrs are 0 based values */
>> +       hba->nutrs = (capabilities & MASK_TRANSFER_REQUESTS_SLOTS) + 1;
>> +       hba->nutmrs =
>> +       ((capabilities & MASK_TASK_MANAGEMENT_REQUEST_SLOTS) >> 16) + 1;
>> +}
>> +
>> +/**
>> + * ufshcd_send_uic_command - Send UIC commands to unipro layers
>> + * @hba: per adapter instance
>> + * @uic_command: UIC command
>> + */
>> +static inline void
>> +ufshcd_send_uic_command(struct ufs_hba *hba, struct uic_command *uic_cmnd)
>> +{
>> +       /* Clear interrupt status register */
>> +       writel((readl(UFSHCD_MMIO_BASE + REG_INTERRUPT_STATUS)),
>> +              (UFSHCD_MMIO_BASE + REG_INTERRUPT_STATUS));
>> +
>> +       /* Write Args */
>> +       writel(uic_cmnd->argument1,
>> +             (UFSHCD_MMIO_BASE + REG_UIC_COMMAND_ARG_1));
>> +       writel(uic_cmnd->argument2,
>> +             (UFSHCD_MMIO_BASE + REG_UIC_COMMAND_ARG_2));
>> +       writel(uic_cmnd->argument3,
>> +             (UFSHCD_MMIO_BASE + REG_UIC_COMMAND_ARG_3));
>> +
>> +       /* Write UIC Cmd */
>> +       writel((uic_cmnd->command & COMMAND_OPCODE_MASK),
>> +              (UFSHCD_MMIO_BASE + REG_UIC_COMMAND));
>> +}
>> +
>> +/**
>> + * ufshcd_int_config - enable/disable interrupts
>> + * @hba: per adapter instance
>> + * @option: interrupt option
>> + */
>> +static void ufshcd_int_config(struct ufs_hba *hba, u32 option)
>> +{
>> +       switch (option) {
>> +       case UFSHCD_INT_ENABLE:
>> +               writel(hba->int_enable_mask,
>> +                     (UFSHCD_MMIO_BASE + REG_INTERRUPT_ENABLE));
>> +               break;
>> +       case UFSHCD_INT_DISABLE:
>> +               if (UFSHCI_VERSION_10 == hba->ufs_version)
>> +                       writel(readl(UFSHCD_MMIO_BASE + REG_INTERRUPT_ENABLE),
>> +                             (UFSHCD_MMIO_BASE + REG_INTERRUPT_ENABLE));
>> +               else
>> +                       writel(0, (UFSHCD_MMIO_BASE + REG_INTERRUPT_ENABLE));
>> +               break;
>> +       default:
>> +               dev_err(&hba->pdev->dev, "Invalid interrupt option\n");
>> +               break;
>> +       } /* end of switch */
>> +}
>> +
>> +/**
>> + * ufshcd_memory_alloc - allocate memory for host memory space data structures
>> + * @hba: per adapter instance
>> + *
>> + * 1) Allocate DMA memory for Command Descriptor array
>> + *     Each command descriptor consist of Command UPIU, Response UPIU and PRDT
>> + * 2) Align allocated command descriptor address to 128 byte align.
>> + * 3) Allocate DMA memory for UTP Transfer Request Descriptor List (UTRDL).
>> + * 4) Align UTRDL address to 1KB (UFSHCI spec)
>> + * 5) Allocate DMA memory for UTP Task Management Request Descriptor List
>> + *     (UTMRDL)
>> + * 6) Align UTMRDL address to 1KB (UFSHCI spec)
>> + * 7) Allocate the memory for local reference block(lrb).
>> + *
>> + * Returns 0 for success, non-zero in case of failure
>> + */
>> +static int ufshcd_memory_alloc(struct ufs_hba *hba)
>> +{
>> +       /*
>> +        * Allocate memory for UTP command descriptors.
>> +        * UFSHCI requires 128 byte alignement of UCD and
>> +        * 64 byte alignement for PRDT. So allocating extra 128 bytes
>> +        */
>> +       hba->ucdl_size =
>> +       (sizeof(struct utp_transfer_cmd_desc) * hba->nutrs) + BYTES_128;
>> +       hba->ucdl_virt_addr = dma_alloc_coherent(&hba->pdev->dev,
>> +                                                hba->ucdl_size,
>> +                                                &hba->ucdl_dma_addr,
>> +                                                GFP_KERNEL);
>> +       if (NULL == hba->ucdl_virt_addr) {
>> +               dev_err(&hba->pdev->dev,
>> +                       "Command Descriptor Memory allocation failed\n");
>> +               goto ucd_fail;
>> +       }
>> +
>> +       /* Align UCD to 128 bytes */
>> +       hba->ucdl_virt_addr_aligned =
>> +       (void *) ALIGN((unsigned long) hba->ucdl_virt_addr, BYTES_128);
>> +       hba->ucdl_dma_addr_aligned = ALIGN(hba->ucdl_dma_addr, BYTES_128);
>> +
>> +       /*
>> +        * Allocate memory for UTP Transfer descriptors.
>> +        * UFSHCI requires 1kb alignement of UTRD. So allocating
>> +        * extra 1024 bytes
>> +        */
>> +       hba->utrdl_size =
>> +       (sizeof(struct utp_transfer_req_desc) * hba->nutrs) + BYTES_1024;
>> +       hba->utrdl_virt_addr = dma_alloc_coherent(&hba->pdev->dev,
>> +                                                 hba->utrdl_size,
>> +                                                 &hba->utrdl_dma_addr,
>> +                                                 GFP_KERNEL);
>> +       if (NULL == hba->utrdl_virt_addr) {
>> +               dev_err(&hba->pdev->dev,
>> +                       "Transfer Descriptor Memory allocation failed\n");
>> +               goto utrd_fail;
>> +       }
>> +
>> +       /* alignement UTRD to 1kb */
>> +       hba->utrdl_virt_addr_aligned =
>> +       (void *) ALIGN((unsigned long) hba->utrdl_virt_addr, BYTES_1024);
>> +       hba->utrdl_dma_addr_aligned = ALIGN(hba->utrdl_dma_addr, BYTES_1024);
>> +
>> +       /*
>> +        * Allocate memory for UTP Task Management descriptors
>> +        * UFSHCI requires 1kb alignement of UTMRD. So allocating
>> +        * extra 1024 bytes
>> +        */
>> +       hba->utmrdl_size =
>> +       sizeof(struct utp_task_req_desc) * hba->nutmrs + BYTES_1024;
>> +       hba->utmrdl_virt_addr = dma_alloc_coherent(&hba->pdev->dev,
>> +                                                  hba->utmrdl_size,
>> +                                                  &hba->utmrdl_dma_addr,
>> +                                                  GFP_KERNEL);
>> +       if (NULL == hba->utmrdl_virt_addr) {
>> +               dev_err(&hba->pdev->dev,
>> +               "Task Management Descriptor Memory allocation failed\n");
>> +               goto utmrd_fail;
>> +       }
>> +
>> +       /* alignement UTMRD to 1kb */
>> +       hba->utmrdl_virt_addr_aligned =
>> +       (void *) ALIGN((unsigned long) hba->utmrdl_virt_addr, BYTES_1024);
>> +       hba->utmrdl_dma_addr_aligned = ALIGN(hba->utmrdl_dma_addr, BYTES_1024);
>> +
>> +       /* Allocate memory for local reference block */
>> +       hba->lrb = kcalloc(hba->nutrs, sizeof(struct ufshcd_lrb), GFP_KERNEL);
>> +       if (NULL == hba->lrb) {
>> +               dev_err(&hba->pdev->dev, "LRB Memory allocation failed\n");
>> +               goto lrb_fail;
>> +       }
>> +
>> +       return 0;
>> +
>> +lrb_fail:
>> +       dma_free_coherent(&hba->pdev->dev, hba->utmrdl_size,
>> +                         hba->utmrdl_virt_addr, hba->utmrdl_dma_addr);
>> +       hba->utmrdl_virt_addr = NULL;
>> +       hba->utmrdl_virt_addr_aligned = NULL;
>> +utmrd_fail:
>> +       dma_free_coherent(&hba->pdev->dev, hba->utrdl_size,
>> +                         hba->utrdl_virt_addr, hba->utrdl_dma_addr);
>> +       hba->utrdl_virt_addr = NULL;
>> +       hba->utrdl_virt_addr_aligned = NULL;
>> +utrd_fail:
>> +       dma_free_coherent(&hba->pdev->dev, hba->ucdl_size,
>> +                         hba->ucdl_virt_addr, hba->ucdl_dma_addr);
>> +       hba->ucdl_virt_addr = NULL;
>> +       hba->ucdl_virt_addr_aligned = NULL;
>> +ucd_fail:
>> +       return -ENOMEM;
>> +}
>> +
>> +/**
>> + * ufshcd_host_memory_configure - configure local reference block with
>> + *                             memory offsets
>> + * @hba: per adapter instance
>> + *
>> + * Configure Host memory space
>> + * 1) Update Corresponding UTRD.UCDBA and UTRD.UCDBAU with UCD DMA
>> + * address.
>> + * 2) Update each UTRD with Response UPIU offset, Response UPIU length
>> + * and PRDT offset.
>> + * 3) Save the corresponding addresses of UTRD, UCD.CMD, UCD.RSP and UCD.PRDT
>> + * into local reference block.
>> + */
>> +static void ufshcd_host_memory_configure(struct ufs_hba *hba)
>> +{
>> +       struct utp_transfer_cmd_desc *cmd_descp;
>> +       struct utp_transfer_req_desc *utrdlp;
>> +       dma_addr_t cmd_desc_dma_addr;
>> +       dma_addr_t cmd_desc_element_addr;
>> +       u16 response_offset;
>> +       u16 prdt_offset;
>> +       int cmd_desc_size;
>> +       int i;
>> +
>> +       utrdlp = (struct utp_transfer_req_desc *)hba->utrdl_virt_addr_aligned;
>> +       cmd_descp =
>> +               (struct utp_transfer_cmd_desc *)hba->ucdl_virt_addr_aligned;
>> +
>> +       response_offset =
>> +               offsetof(struct utp_transfer_cmd_desc, response_upiu);
>> +       prdt_offset =
>> +               offsetof(struct utp_transfer_cmd_desc, prd_table);
>> +
>> +       cmd_desc_size = sizeof(struct utp_transfer_cmd_desc);
>> +       cmd_desc_dma_addr = hba->ucdl_dma_addr_aligned;
>> +
>> +       for (i = 0; i < hba->nutrs; i++) {
>> +               /* Configure UTRD with command descriptor base address */
>> +               cmd_desc_element_addr =
>> +                               (cmd_desc_dma_addr + (cmd_desc_size * i));
>> +               utrdlp[i].command_desc_base_addr_lo =
>> +                               cpu_to_le32(cmd_desc_element_addr);
>> +               utrdlp[i].command_desc_base_addr_hi =
>> +                               cpu_to_le32(cmd_desc_element_addr >> 32);
>> +
>> +               /* Response upiu and prdt offset should be in double words */
>> +               utrdlp[i].response_upiu_offset =
>> +                               cpu_to_le16(BYTES_TO_DWORDS(response_offset));
>> +               utrdlp[i].prd_table_offset =
>> +                               cpu_to_le16(BYTES_TO_DWORDS(prdt_offset));
>> +               utrdlp[i].response_upiu_length =
>> +                               cpu_to_le16(ALIGNED_UPIU_SIZE);
>> +
>> +               hba->lrb[i].utr_descriptor_ptr = (utrdlp + i);
>> +               hba->lrb[i].ucd_cmd_ptr =
>> +                       (struct utp_upiu_cmd *)(cmd_descp + i);
>> +               hba->lrb[i].ucd_rsp_ptr =
>> +                       (struct utp_upiu_rsp *)cmd_descp[i].response_upiu;
>> +               hba->lrb[i].ucd_prdt_ptr =
>> +                       (struct ufshcd_sg_entry *)cmd_descp[i].prd_table;
>> +       }
>> +}
>> +
>> +/**
>> + * ufshcd_dme_link_startup - Notify Unipro to perform link startup
>> + * @hba: per adapter instance
>> + *
>> + * UIC_CMD_DME_LINK_STARTUP command must be issued to Unipro layer,
>> + * in order to intitialize the Unipro link startup procedure.
>> + * Once the Unipro links are up, the device connected to the controller
>> + * is detected.
>> + *
>> + * Returns 0 on success, non-zero value on failure
>> + */
>> +static int ufshcd_dme_link_startup(struct ufs_hba *hba)
>> +{
>> +       struct uic_command *uic_cmd;
>> +       unsigned long flags;
>> +
>> +       /* check if controller is ready to accept UIC commands */
>> +       if (((readl(UFSHCD_MMIO_BASE + REG_CONTROLLER_STATUS)) &
>> +           UIC_COMMAND_READY) == 0x0) {
>> +               dev_err(&hba->pdev->dev,
>> +                       "Controller not ready"
>> +                       " to accept UIC commands\n");
>> +               return -EINVAL;
>> +       }
>> +
>> +       spin_lock_irqsave(hba->host->host_lock, flags);
>> +       uic_cmd = &hba->active_uic_cmd;
>> +       uic_cmd->command = UIC_CMD_DME_LINK_STARTUP;
>> +       uic_cmd->argument1 = 0;
>> +       uic_cmd->argument2 = 0;
>> +       uic_cmd->argument3 = 0;
>> +
>> +       /* Enable UIC related interrupts */
>> +       hba->int_enable_mask |= UIC_COMMAND_COMPL;
>> +       ufshcd_int_config(hba, UFSHCD_INT_ENABLE);
>> +
>> +       /* sending UIC commands to controller */
>> +       ufshcd_send_uic_command(hba, uic_cmd);
>> +       spin_unlock_irqrestore(hba->host->host_lock, flags);
>> +
>> +       return 0;
>> +}
>> +
>> +/**
>> + * ufshcd_make_hba_operational - Make UFS controller operatinal
>> + * @hba: per adapter instance
>> + *
>> + * To bring UFS host controller to operational state,
>> + * 1. Check if device is present
>> + * 2. Configure run-stop-registers
>> + * 3. Enable required interrupts
>> + * 4. Configure interrupt aggregation
>> + *
>> + * Returns 0 on success, non-zero value on failure
>> + */
>> +static int ufshcd_make_hba_operational(struct ufs_hba *hba)
>> +{
>> +       u32 reg;
>> +
>> +       /* check if device present */
>> +       reg = readl((UFSHCD_MMIO_BASE + REG_CONTROLLER_STATUS));
>> +       if (ufshcd_is_device_present(reg)) {
>> +               dev_err(&hba->pdev->dev, "cc: Device not present\n");
>> +               return -EINVAL;
>> +       }
>> +
>> +       /*
>> +        * UCRDY, UTMRLDY and UTRLRDY bits must be 1
>> +        * DEI, HEI bits must be 0
>> +        */
>> +       if (!(ufshcd_get_lists_status(reg))) {
>> +               writel(UTP_TASK_REQ_LIST_RUN_STOP_BIT,
>> +                      (UFSHCD_MMIO_BASE +
>> +                       REG_UTP_TASK_REQ_LIST_RUN_STOP));
>> +               writel(UTP_TRANSFER_REQ_LIST_RUN_STOP_BIT,
>> +                      (UFSHCD_MMIO_BASE +
>> +                       REG_UTP_TRANSFER_REQ_LIST_RUN_STOP));
>> +       } else {
>> +               dev_err(&hba->pdev->dev,
>> +                       "Host controller not ready to process requests");
>> +               return -EINVAL;
>> +       }
>> +
>> +       /* Enable required interrupts */
>> +       hba->int_enable_mask |= (UTP_TRANSFER_REQ_COMPL |
>> +                                UIC_ERROR |
>> +                                UTP_TASK_REQ_COMPL |
>> +                                DEVICE_FATAL_ERROR |
>> +                                CONTROLLER_FATAL_ERROR |
>> +                                SYSTEM_BUS_FATAL_ERROR);
>> +       ufshcd_int_config(hba, UFSHCD_INT_ENABLE);
>
> UFS host controller specification Section 7.2.1, step 11,  mentions
> that the aggregation control register should be set if run/stop bit is
> not enabled.
> But In this case the run/ stop bit is set above before configuring the
> aggregation register. Please check for the same in other places from
> where it is called.
>

The spec mentions, (Section 7.2.1, step 11)
"UTRIACR initialization may be executed at any time when the Run/Stop
register (UTRLRSR)
is not enabled or when no requests are outstanding."

At this point in the code, during execution, there will not be any
outstanding requests.

>> +
>> +       /* Configure interrupt aggregation */
>> +       ufshcd_config_int_aggr(hba, INT_AGGR_CONFIG);
>> +
>> +       hba->ufshcd_state = UFSHCD_STATE_OPERATIONAL;
>> +
>> +       return 0;
>> +}
>> +
>> +/**
>> + * ufshcd_controller_enable - initialize the controller
>> + * @hba: per adapter instance
>> + *
>> + * The controller resets its self and controller firmware start of day is
>> + * kickes off. When controller is ready it will set the Host Controller
>> + * Status bit to 1.
>> + *
>> + * Returns 0 on success, non-zero value on failure
>> + */
>> +static int ufshcd_controller_enable(struct ufs_hba *hba)
>> +{
>> +       int retry;
>> +
>> +       /*
>> +        * msleep of 1 and 5 used in this function might result in msleep(20),
>> +        * but it was necessary to send the UFS FPGA to reset mode during
>> +        * development and testing of this driver. msleep can be changed to
>> +        * mdelay and retry count can be reduced based on the controller.
>> +        */
>> +
>> +       /* change controller state to "reset state" */
>> +       writel(0, (UFSHCD_MMIO_BASE + REG_CONTROLLER_ENABLE));
>> +       msleep(5);
>> +
>> +       writel(CONTROLLER_ENABLE,
>> +              (UFSHCD_MMIO_BASE + REG_CONTROLLER_ENABLE));
>> +       msleep(1);
>> +
>> +       /* wait for the host controller to complete initialization */
>> +       retry = 10;
>> +       while (((readl(UFSHCD_MMIO_BASE + REG_CONTROLLER_ENABLE)) &
>> +              CONTROLLER_ENABLE) != 0x1) {
>> +               if (retry) {
>> +                       retry--;
>> +               } else {
>> +                       dev_err(&hba->pdev->dev,
>> +                               "Controller enable failed\n");
>> +                       return -EINVAL;
>> +               }
>> +               msleep(5);
>> +       }
>> +       return 0;
>> +}
>> +
>> +/**
>> + * ufshcd_initialize_hba - start the initialization process
>> + * @hba: per adapter instance
>> + *
>> + * Initialize the Controller
>> + * 1) Enable the controller via ufshcd_controller_enable.
>> + * 2) Program the Transfer Request List Address with the starting address of
>> + * UTRDL.
>> + *
>> + * 3) Program the Task Management Request List Address with starting address
>> + * of UTMRDL.
>> + *
>> + * Returns 0 on success, non-zero value on failure.
>> + */
>> +static int ufshcd_initialize_hba(struct ufs_hba *hba)
>> +{
>> +       if (ufshcd_controller_enable(hba))
>> +               return -1;
>> +
>> +       /* Configure TR/TM address registers */
>> +       writel(hba->utrdl_dma_addr_aligned,
>> +              (UFSHCD_MMIO_BASE + REG_UTP_TRANSFER_REQ_LIST_BASE_L));
>> +       writel((hba->utrdl_dma_addr_aligned >> 32),
>> +              (UFSHCD_MMIO_BASE + REG_UTP_TRANSFER_REQ_LIST_BASE_H));
>> +       writel(hba->utmrdl_dma_addr_aligned,
>> +              (UFSHCD_MMIO_BASE + REG_UTP_TASK_REQ_LIST_BASE_L));
>> +       writel((hba->utmrdl_dma_addr_aligned >> 32),
>> +              (UFSHCD_MMIO_BASE + REG_UTP_TASK_REQ_LIST_BASE_H));
>> +
>> +       /* Initialize unipro link startup procedure */
>> +       return ufshcd_dme_link_startup(hba);
>> +}
>> +
>> +/**
>> + * ufshcd_uic_cc_handler - handle UIC command completion
>> + * @work: pointer to a work queue structure
>> + *
>> + * Returns 0 on success, non-zero value on failure
>> + */
>> +static void ufshcd_uic_cc_handler (struct work_struct *work)
>> +{
>> +       struct ufs_hba *hba;
>> +
>> +       hba = container_of(work, struct ufs_hba, uic_workq);
>> +
>> +       if ((UIC_CMD_DME_LINK_STARTUP == hba->active_uic_cmd.command) &&
>> +           !(ufshcd_get_uic_cmd_result(hba))) {
>> +
>> +               if (ufshcd_make_hba_operational(hba))
>> +                       dev_err(&hba->pdev->dev,
>> +                               "cc: hba not operational state\n");
>> +               return;
>> +       }
>> +}
>> +
>> +/**
>> + * ufshcd_sl_intr - Interrupt service routine
>> + * @hba: per adapter instance
>> + * @intr_status: contains interrupts generated by the controller
>> + */
>> +static void ufshcd_sl_intr(struct ufs_hba *hba, u32 intr_status)
>> +{
>> +       if (intr_status & UIC_COMMAND_COMPL)
>> +               schedule_work(&hba->uic_workq);
>> +}
>> +
>> +/**
>> + * ufshcd_intr - Main interrupt service routine
>> + * @irq: irq number
>> + * @__hba: pointer to adapter instance
>> + *
>> + * Returns IRQ_HANDLED - If interrupt is valid
>> + *             IRQ_NONE - If invalid interrupt
>> + */
>> +static irqreturn_t ufshcd_intr(int irq, void *__hba)
>> +{
>> +       unsigned long flags;
>> +       u32 intr_status;
>> +       irqreturn_t retval = IRQ_NONE;
>> +       struct ufs_hba *hba = __hba;
>> +
>> +       spin_lock_irqsave(hba->host->host_lock, flags);
>> +       intr_status = readl(UFSHCD_MMIO_BASE + REG_INTERRUPT_STATUS);
>> +
>> +       if (intr_status) {
>> +               ufshcd_sl_intr(hba, intr_status);
>> +
>> +               /* If UFSHCI 1.0 then clear interrupt status register */
>> +               if (UFSHCI_VERSION_10 == hba->ufs_version)
>> +                       writel(intr_status,
>> +                              (UFSHCD_MMIO_BASE + REG_INTERRUPT_STATUS));
>> +               retval = IRQ_HANDLED;
>> +       }
>> +       spin_unlock_irqrestore(hba->host->host_lock, flags);
>> +       return retval;
>> +}
>> +
>> +static struct scsi_host_template ufshcd_driver_template = {
>> +       .module                 = THIS_MODULE,
>> +       .name                   = UFSHCD,
>> +       .proc_name              = UFSHCD,
>> +       .this_id                = -1,
>> +};
>> +
>> +/**
>> + * ufshcd_shutdown - main funciton to put the controller in reset state
>> + * @pdev: pointer to PCI device handle
>> + */
>> +static void ufshcd_shutdown(struct pci_dev *pdev)
>> +{
>> +       ufshcd_hba_stop((struct ufs_hba *)pci_get_drvdata(pdev));
>> +}
>> +
>> +#ifdef CONFIG_PM
>> +/**
>> + * ufshcd_suspend - suspend power management function
>> + * @pdev: pointer to PCI device handle
>> + * @state: power state
>> + *
>> + * Returns -ENOSYS
>> + */
>> +static int ufshcd_suspend(struct pci_dev *pdev, pm_message_t state)
>> +{
>> +       return -ENOSYS;
>> +}
>> +
>> +/**
>> + * ufshcd_resume - resume power management function
>> + * @pdev: pointer to PCI device handle
>> + *
>> + * Returns -ENOSYS
>> + */
>> +static int ufshcd_resume(struct pci_dev *pdev)
>> +{
>> +       return -ENOSYS;
>> +}
>> +#endif /* CONFIG_PM */
>> +
>> +/**
>> + * ufshcd_hba_free - free allocated memory for
>> + *                     host memory space data structures
>> + * @hba: per adapter instance
>> + */
>> +static void ufshcd_hba_free(struct ufs_hba *hba)
>> +{
>> +       iounmap(UFSHCD_MMIO_BASE);
>> +       ufshcd_free_hba_memory(hba);
>> +       pci_release_regions(hba->pdev);
>> +}
>> +
>> +/**
>> + * ufshcd_remove - deallocate PCI/SCSI host and host memory space
>> + *             data structure memory
>> + * @pdev - pointer to PCI handle
>> + */
>> +static void ufshcd_remove(struct pci_dev *pdev)
>> +{
>> +       struct ufs_hba *hba = pci_get_drvdata(pdev);
>> +
>> +       /* disable interrupts */
>> +       ufshcd_int_config(hba, UFSHCD_INT_DISABLE);
>> +       free_irq(pdev->irq, hba);
>> +
>> +       ufshcd_hba_stop(hba);
>> +       ufshcd_hba_free(hba);
>> +
>> +       scsi_remove_host(hba->host);
>> +       scsi_host_put(hba->host);
>> +       pci_set_drvdata(pdev, NULL);
>> +       pci_clear_master(pdev);
>> +       pci_disable_device(pdev);
>> +}
>> +
>> +/**
>> + * ufshcd_set_dma_mask - Set dma addressing
>> + * @pdev: PCI device struct
>> + *
>> + * Returns 0 for success, non-zero for failure
>> + */
>> +static int ufshcd_set_dma_mask(struct pci_dev *pdev)
>> +{
>> +       int err;
>> +
>> +       do {
>> +               err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
>> +               if (!err) {
>> +                       err = pci_set_consistent_dma_mask(pdev,
>> +                                                         DMA_BIT_MASK(64));
>> +                       break;
>> +               }
>> +               err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
>> +               if (!err)
>> +                       err = pci_set_consistent_dma_mask(pdev,
>> +                                                         DMA_BIT_MASK(32));
>> +       } while (0);
>> +
>> +       return err;
>> +}
>> +
>> +/**
>> + * ufshcd_probe - probe routine of the driver
>> + * @pdev: pointer to PCI device handle
>> + * @id: PCI device id
>> + *
>> + * Returns 0 on success, non-zero value on failure
>> + */
>> +static int __devinit
>> +ufshcd_probe(struct pci_dev *pdev, const struct pci_device_id *id)
>> +{
>> +       struct Scsi_Host *host;
>> +       struct ufs_hba *hba;
>> +       int ufs_hba_len;
>> +       int err;
>> +
>> +       ufs_hba_len = sizeof(struct ufs_hba);
>> +       err = pci_enable_device(pdev);
>> +       if (err) {
>> +               dev_err(&pdev->dev, "pci_enable_device failed\n");
>> +               goto out_error;
>> +       }
>> +
>> +       pci_set_master(pdev);
>> +
>> +       host = scsi_host_alloc(&ufshcd_driver_template, ufs_hba_len);
>> +       if (!host) {
>> +               dev_err(&pdev->dev, "scsi_host_alloc failed\n");
>> +               err = -ENOMEM;
>> +               goto out_disable;
>> +       }
>> +       hba = (struct ufs_hba *)host->hostdata;
>> +
>> +       err = pci_request_regions(pdev, UFSHCD);
>> +       if (err < 0) {
>> +               dev_err(&pdev->dev, "request regions failed\n");
>> +               goto out_disable;
>> +       }
>> +
>> +       hba->mmio_base = pci_ioremap_bar(pdev, 0);
>> +       if (!hba->mmio_base) {
>> +               dev_err(&pdev->dev, "memory map failed\n");
>> +               err = -ENOMEM;
>> +               goto out_release_regions;
>> +       }
>> +
>> +       err = ufshcd_set_dma_mask(pdev);
>> +       if (err) {
>> +               dev_err(&pdev->dev, "set dma mask failed\n");
>> +               goto out_iounmap;
>> +       }
>> +
>> +       hba->host = host;
>> +       hba->pdev = pdev;
>> +
>> +       /* Read capabilities registers */
>> +       ufshcd_hba_capabilities(hba);
>> +
>> +       /* Get UFS version supported by the controller */
>> +       hba->ufs_version = ufshcd_get_ufs_version(hba);
>> +
>> +       /* Allocate memory for host memory space */
>> +       err = ufshcd_memory_alloc(hba);
>> +       if (err) {
>> +               dev_err(&pdev->dev, "Memory allocation failed\n");
>> +               goto out_iounmap;
>> +       }
>> +
>> +       /* Configure LRB */
>> +       ufshcd_host_memory_configure(hba);
>> +
>> +       host->can_queue = hba->nutrs;
>> +       host->max_id = UFSHCD_MAX_ID;
>> +       host->max_lun = UFSHCD_MAX_LUNS;
>> +       host->max_channel = UFSHCD_MAX_CHANNEL;
>> +       host->unique_id = host->host_no;
>> +
>> +       /* Initialize work queues */
>> +       INIT_WORK(&hba->uic_workq, ufshcd_uic_cc_handler);
>> +
>> +       /* IRQ registration */
>> +       err = request_irq(pdev->irq, ufshcd_intr, IRQF_SHARED, UFSHCD, hba);
>> +       if (err) {
>> +               dev_err(&pdev->dev, "request irq failed\n");
>> +               goto out_lrb_free;
>> +       }
>> +
>> +       pci_set_drvdata(pdev, hba);
>> +
>> +       err = scsi_add_host(host, &pdev->dev);
>> +       if (err) {
>> +               dev_err(&pdev->dev, "scsi_add_host failed\n");
>> +               goto out_free_irq;
>> +       }
>> +
>> +       /* Initialization routine */
>> +       err = ufshcd_initialize_hba(hba);
>> +       if (err) {
>> +               dev_err(&pdev->dev, "Initialization failed\n");
>> +               goto out_free_irq;
>> +       }
>> +
>> +       return 0;
>> +
>> +out_free_irq:
>> +       free_irq(pdev->irq, hba);
>> +out_lrb_free:
>> +       ufshcd_free_hba_memory(hba);
>> +out_iounmap:
>> +       iounmap(hba->mmio_base);
>> +out_release_regions:
>> +       pci_release_regions(pdev);
>> +out_disable:
>> +       scsi_host_put(host);
>> +       pci_clear_master(pdev);
>> +       pci_disable_device(pdev);
>> +out_error:
>> +       return err;
>> +}
>> +
>> +static DEFINE_PCI_DEVICE_TABLE(ufshcd_pci_tbl) = {
>> +       { 0x144D, 0xC00C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
>> +       { }     /* terminate list */
>> +};
>> +
>> +MODULE_DEVICE_TABLE(pci, ufshcd_pci_tbl);
>> +
>> +static struct pci_driver ufshcd_pci_driver = {
>> +       .name = UFSHCD,
>> +       .id_table = ufshcd_pci_tbl,
>> +       .probe = ufshcd_probe,
>> +       .remove = __devexit_p(ufshcd_remove),
>> +       .shutdown = ufshcd_shutdown,
>> +#ifdef CONFIG_PM
>> +       .suspend = ufshcd_suspend,
>> +       .resume = ufshcd_resume,
>> +#endif
>> +};
>> +
>> +/**
>> + * ufshcd_init - Driver registration routine
>> + */
>> +static int __init ufshcd_init(void)
>> +{
>> +       return pci_register_driver(&ufshcd_pci_driver);
>> +}
>> +module_init(ufshcd_init);
>> +
>> +/**
>> + * ufshcd_exit - Driver exit clean-up routine
>> + */
>> +static void __exit ufshcd_exit(void)
>> +{
>> +       pci_unregister_driver(&ufshcd_pci_driver);
>> +}
>> +module_exit(ufshcd_exit);
>> +
>> +
>> +MODULE_AUTHOR("Santosh Yaragnavi, Vinayak Holikatti");
>> +MODULE_DESCRIPTION("Generic UFS host controller driver");
>> +MODULE_LICENSE("GPL");
>> +MODULE_VERSION(UFSHCD_DRIVER_VERSION);
>> diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h
>> new file mode 100644
>> index 0000000..f8701b7
>> --- /dev/null
>> +++ b/drivers/scsi/ufs/ufshci.h
>> @@ -0,0 +1,360 @@
>> +/*
>> + * Universal Flash Storage Host controller driver
>> + *
>> + * This code is based on drivers/scsi/ufs/ufshci.h
>> + * Copyright (C) 2011-2012 Samsung India Software Operations
>> + *
>> + * 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.
>> + *
>> + * 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.
>> + *
>> + * NO WARRANTY
>> + * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
>> + * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
>> + * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
>> + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
>> + * solely responsible for determining the appropriateness of using and
>> + * distributing the Program and assumes all risks associated with its
>> + * exercise of rights under this Agreement, including but not limited to
>> + * the risks and costs of program errors, damage to or loss of data,
>> + * programs or equipment, and unavailability or interruption of operations.
>> +
>> + * DISCLAIMER OF LIABILITY
>> + * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
>> + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
>> + * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
>> + * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
>> +
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program; if not, write to the Free Software
>> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
>> + * USA.
>> + */
>> +
>> +#ifndef _UFSHCI_H
>> +#define _UFSHCI_H
>> +
>> +/* UFSHCI Registers */
>> +enum {
>> +       REG_CONTROLLER_CAPABILITIES             = 0x00,
>> +       REG_UFS_VERSION                         = 0x08,
>> +       REG_CONTROLLER_DEV_ID                   = 0x10,
>> +       REG_CONTROLLER_PROD_ID                  = 0x14,
>> +       REG_INTERRUPT_STATUS                    = 0x20,
>> +       REG_INTERRUPT_ENABLE                    = 0x24,
>> +       REG_CONTROLLER_STATUS                   = 0x30,
>> +       REG_CONTROLLER_ENABLE                   = 0x34,
>> +       REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER    = 0x38,
>> +       REG_UIC_ERROR_CODE_DATA_LINK_LAYER      = 0x3C,
>> +       REG_UIC_ERROR_CODE_NETWORK_LAYER        = 0x40,
>> +       REG_UIC_ERROR_CODE_TRANSPORT_LAYER      = 0x44,
>> +       REG_UIC_ERROR_CODE_DME                  = 0x48,
>> +       REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL    = 0x4C,
>> +       REG_UTP_TRANSFER_REQ_LIST_BASE_L        = 0x50,
>> +       REG_UTP_TRANSFER_REQ_LIST_BASE_H        = 0x54,
>> +       REG_UTP_TRANSFER_REQ_DOOR_BELL          = 0x58,
>> +       REG_UTP_TRANSFER_REQ_LIST_CLEAR         = 0x5C,
>> +       REG_UTP_TRANSFER_REQ_LIST_RUN_STOP      = 0x60,
>> +       REG_UTP_TASK_REQ_LIST_BASE_L            = 0x70,
>> +       REG_UTP_TASK_REQ_LIST_BASE_H            = 0x74,
>> +       REG_UTP_TASK_REQ_DOOR_BELL              = 0x78,
>> +       REG_UTP_TASK_REQ_LIST_CLEAR             = 0x7C,
>> +       REG_UTP_TASK_REQ_LIST_RUN_STOP          = 0x80,
>> +       REG_UIC_COMMAND                         = 0x90,
>> +       REG_UIC_COMMAND_ARG_1                   = 0x94,
>> +       REG_UIC_COMMAND_ARG_2                   = 0x98,
>> +       REG_UIC_COMMAND_ARG_3                   = 0x9C
>> +};
>> +
>> +/* Controller capability masks */
>> +enum {
>> +       MASK_TRANSFER_REQUESTS_SLOTS            = 0x0000001F,
>> +       MASK_TASK_MANAGEMENT_REQUEST_SLOTS      = 0x00070000,
>> +       MASK_64_ADDRESSING_SUPPORT              = 0x01000000,
>> +       MASK_OUT_OF_ORDER_DATA_DELIVERY_SUPPORT = 0x02000000,
>> +       MASK_UIC_DME_TEST_MODE_SUPPORT          = 0x04000000
>> +};
>> +
>> +/* UFS Version 08h */
>> +#define MINOR_VERSION_NUM_MASK         UFS_MASK(0xFFFF, 0)
>> +#define MAJOR_VERSION_NUM_MASK         UFS_MASK(0xFFFF, 16)
>> +
>> +/* Controller UFSHCI version */
>> +enum {
>> +       UFSHCI_VERSION_10 = 0x00010000,
>> +       UFSHCI_VERSION_11 = 0x00010100
>> +};
>> +
>> +/*
>> + * HCDDID - Host Controller Identification Descriptor
>> + *       - Device ID and Device Class 10h
>> + */
>> +#define DEVICE_CLASS   UFS_MASK(0xFFFF, 0)
>> +#define DEVICE_ID      UFS_MASK(0xFF, 24)
>> +
>> +/*
>> + * HCPMID - Host Controller Identification Descriptor
>> + *       - Product/Manufacturer ID  14h
>> + */
>> +#define MANUFACTURE_ID_MASK    UFS_MASK(0xFFFF, 0)
>> +#define PRODUCT_ID_MASK                UFS_MASK(0xFFFF, 16)
>> +
>> +#define UFS_BIT(x)     (1L << (x))
>> +
>> +#define UTP_TRANSFER_REQ_COMPL                 UFS_BIT(0)
>> +#define UIC_DME_END_PT_RESET                   UFS_BIT(1)
>> +#define UIC_ERROR                              UFS_BIT(2)
>> +#define UIC_TEST_MODE                          UFS_BIT(3)
>> +#define UIC_POWER_MODE                         UFS_BIT(4)
>> +#define UIC_HIBERNATE_EXIT                     UFS_BIT(5)
>> +#define UIC_HIBERNATE_ENTER                    UFS_BIT(6)
>> +#define UIC_LINK_LOST                          UFS_BIT(7)
>> +#define UIC_LINK_STARTUP                       UFS_BIT(8)
>> +#define UTP_TASK_REQ_COMPL                     UFS_BIT(9)
>> +#define UIC_COMMAND_COMPL                      UFS_BIT(10)
>> +#define DEVICE_FATAL_ERROR                     UFS_BIT(11)
>> +#define CONTROLLER_FATAL_ERROR                 UFS_BIT(16)
>> +#define SYSTEM_BUS_FATAL_ERROR                 UFS_BIT(17)
>> +
>> +#define UFSHCD_ERROR_MASK      (UIC_ERROR |\
>> +                               DEVICE_FATAL_ERROR |\
>> +                               CONTROLLER_FATAL_ERROR |\
>> +                               SYSTEM_BUS_FATAL_ERROR)
>> +
>> +#define INT_FATAL_ERRORS       (DEVICE_FATAL_ERROR |\
>> +                               CONTROLLER_FATAL_ERROR |\
>> +                               SYSTEM_BUS_FATAL_ERROR)
>> +
>> +/* HCS - Host Controller Status 30h */
>> +#define DEVICE_PRESENT                         UFS_BIT(0)
>> +#define UTP_TRANSFER_REQ_LIST_READY            UFS_BIT(1)
>> +#define UTP_TASK_REQ_LIST_READY                        UFS_BIT(2)
>> +#define UIC_COMMAND_READY                      UFS_BIT(3)
>> +#define HOST_ERROR_INDICATOR                   UFS_BIT(4)
>> +#define DEVICE_ERROR_INDICATOR                 UFS_BIT(5)
>> +#define UIC_POWER_MODE_CHANGE_REQ_STATUS_MASK  UFS_MASK(0x7, 8)
>> +
>> +/* HCE - Host Controller Enable 34h */
>> +#define CONTROLLER_ENABLE      UFS_BIT(0)
>> +
>> +/* UECPA - Host UIC Error Code PHY Adapter Layer 38h */
>> +#define UIC_PHY_ADAPTER_LAYER_ERROR                    UFS_BIT(31)
>> +#define UIC_PHY_ADAPTER_LAYER_ERROR_CODE_MASK          0x1F
>> +
>> +/* UECDL - Host UIC Error Code Data Link Layer 3Ch */
>> +#define UIC_DATA_LINK_LAYER_ERROR              UFS_BIT(31)
>> +#define UIC_DATA_LINK_LAYER_ERROR_CODE_MASK    0x7FFF
>> +#define UIC_DATA_LINK_LAYER_ERROR_PA_INIT      0x2000
>> +
>> +/* UECN - Host UIC Error Code Network Layer 40h */
>> +#define UIC_NETWORK_LAYER_ERROR                        UFS_BIT(31)
>> +#define UIC_NETWORK_LAYER_ERROR_CODE_MASK      0x7
>> +
>> +/* UECT - Host UIC Error Code Transport Layer 44h */
>> +#define UIC_TRANSPORT_LAYER_ERROR              UFS_BIT(31)
>> +#define UIC_TRANSPORT_LAYER_ERROR_CODE_MASK    0x7F
>> +
>> +/* UECDME - Host UIC Error Code DME 48h */
>> +#define UIC_DME_ERROR                  UFS_BIT(31)
>> +#define UIC_DME_ERROR_CODE_MASK                0x1
>> +
>> +#define INT_AGGR_TIMEOUT_VAL_MASK              0xFF
>> +#define INT_AGGR_COUNTER_THRESHOLD_MASK                UFS_MASK(0x1F, 8)
>> +#define INT_AGGR_COUNTER_AND_TIMER_RESET       UFS_BIT(16)
>> +#define INT_AGGR_STATUS_BIT                    UFS_BIT(20)
>> +#define INT_AGGR_PARAM_WRITE                   UFS_BIT(24)
>> +#define INT_AGGR_ENABLE                                UFS_BIT(31)
>> +
>> +/* UTRLRSR - UTP Transfer Request Run-Stop Register 60h */
>> +#define UTP_TRANSFER_REQ_LIST_RUN_STOP_BIT     UFS_BIT(0)
>> +
>> +/* UTMRLRSR - UTP Task Management Request Run-Stop Register 80h */
>> +#define UTP_TASK_REQ_LIST_RUN_STOP_BIT         UFS_BIT(0)
>> +
>> +/* UICCMD - UIC Command */
>> +#define COMMAND_OPCODE_MASK            0xFF
>> +#define GEN_SELECTOR_INDEX_MASK                0xFFFF
>> +
>> +#define MIB_ATTRIBUTE_MASK             UFS_MASK(0xFFFF, 16)
>> +#define RESET_LEVEL                    0xFF
>> +
>> +#define ATTR_SET_TYPE_MASK             UFS_MASK(0xFF, 16)
>> +#define CONFIG_RESULT_CODE_MASK                0xFF
>> +#define GENERIC_ERROR_CODE_MASK                0xFF
>> +
>> +/* UIC Commands */
>> +enum {
>> +       UIC_CMD_DME_GET                 = 0x01,
>> +       UIC_CMD_DME_SET                 = 0x02,
>> +       UIC_CMD_DME_PEER_GET            = 0x03,
>> +       UIC_CMD_DME_PEER_SET            = 0x04,
>> +       UIC_CMD_DME_POWERON             = 0x10,
>> +       UIC_CMD_DME_POWEROFF            = 0x11,
>> +       UIC_CMD_DME_ENABLE              = 0x12,
>> +       UIC_CMD_DME_RESET               = 0x14,
>> +       UIC_CMD_DME_END_PT_RST          = 0x15,
>> +       UIC_CMD_DME_LINK_STARTUP        = 0x16,
>> +       UIC_CMD_DME_HIBER_ENTER         = 0x17,
>> +       UIC_CMD_DME_HIBER_EXIT          = 0x18,
>> +       UIC_CMD_DME_TEST_MODE           = 0x1A
>> +};
>> +
>> +/* UIC Config result code / Generic error code */
>> +enum {
>> +       UIC_CMD_RESULT_SUCCESS                  = 0x00,
>> +       UIC_CMD_RESULT_INVALID_ATTR             = 0x01,
>> +       UIC_CMD_RESULT_FAILURE                  = 0x01,
>> +       UIC_CMD_RESULT_INVALID_ATTR_VALUE       = 0x02,
>> +       UIC_CMD_RESULT_READ_ONLY_ATTR           = 0x03,
>> +       UIC_CMD_RESULT_WRITE_ONLY_ATTR          = 0x04,
>> +       UIC_CMD_RESULT_BAD_INDEX                = 0x05,
>> +       UIC_CMD_RESULT_LOCKED_ATTR              = 0x06,
>> +       UIC_CMD_RESULT_BAD_TEST_FEATURE_INDEX   = 0x07,
>> +       UIC_CMD_RESULT_PEER_COMM_FAILURE        = 0x08,
>> +       UIC_CMD_RESULT_BUSY                     = 0x09,
>> +       UIC_CMD_RESULT_DME_FAILURE              = 0x0A
>> +};
>> +
>> +#define MASK_UIC_COMMAND_RESULT                        0xFF
>> +
>> +#define INT_AGGR_COUNTER_THRESHOLD_VALUE       (0x1F << 8)
>> +#define INT_AGGR_TIMEOUT_VALUE                 (0x02)
>> +
>> +/*
>> + * Request Descriptor Definitions
>> + */
>> +
>> +/* Transfer request command type */
>> +enum {
>> +       UTP_CMD_TYPE_SCSI               = 0x0,
>> +       UTP_CMD_TYPE_UFS                = 0x1,
>> +       UTP_CMD_TYPE_DEV_MANAGE         = 0x2
>> +};
>> +
>> +enum {
>> +       UTP_SCSI_COMMAND                = 0x00000000,
>> +       UTP_NATIVE_UFS_COMMAND          = 0x10000000,
>> +       UTP_DEVICE_MANAGEMENT_FUNCTION  = 0x20000000,
>> +       UTP_REQ_DESC_INT_CMD            = 0x01000000
>> +};
>> +
>> +/* UTP Transfer Request Data Direction (DD) */
>> +enum {
>> +       UTP_NO_DATA_TRANSFER    = 0x00000000,
>> +       UTP_HOST_TO_DEVICE      = 0x02000000,
>> +       UTP_DEVICE_TO_HOST      = 0x04000000
>> +};
>> +
>> +/* Overall command status values */
>> +enum {
>> +       OCS_SUCCESS                     = 0x0,
>> +       OCS_INVALID_CMD_TABLE_ATTR      = 0x1,
>> +       OCS_INVALID_PRDT_ATTR           = 0x2,
>> +       OCS_MISMATCH_DATA_BUF_SIZE      = 0x3,
>> +       OCS_MISMATCH_RESP_UPIU_SIZE     = 0x4,
>> +       OCS_PEER_COMM_FAILURE           = 0x5,
>> +       OCS_ABORTED                     = 0x6,
>> +       OCS_FATAL_ERROR                 = 0x7,
>> +       OCS_INVALID_COMMAND_STATUS      = 0x0F,
>> +       MASK_OCS                        = 0x0F
>> +};
>> +
>> +/**
>> + * struct ufshcd_sg_entry - UFSHCI 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
>> + */
>> +struct ufshcd_sg_entry {
>> +       u32    base_addr;
>> +       u32    upper_addr;
>> +       u32    reserved;
>> +       u32    size;
>> +};
>> +
>> +/**
>> + * struct utp_transfer_cmd_desc - UFS Commad Descriptor structure
>> + * @command_upiu: Command UPIU Frame address
>> + * @response_upiu: Response UPIU Frame address
>> + * @prd_table: Physcial Region Descriptor
>> + */
>> +struct utp_transfer_cmd_desc {
>> +       u8 command_upiu[ALIGNED_UPIU_SIZE];
>> +       u8 response_upiu[ALIGNED_UPIU_SIZE];
>> +       struct ufshcd_sg_entry    prd_table[SG_ALL];
>> +};
>> +
>> +/**
>> + * struct request_desc_header - Descriptor Header common to both UTRD and UTMRD
>> + * @dword0: Descriptor Header DW0
>> + * @dword1: Descriptor Header DW1
>> + * @dword2: Descriptor Header DW2
>> + * @dword3: Descriptor Header DW3
>> + */
>> +struct request_desc_header {
>> +       u32 dword_0;
>> +       u32 dword_1;
>> +       u32 dword_2;
>> +       u32 dword_3;
>> +};
>> +
>> +/**
>> + * struct utp_transfer_req_desc - UTRD structure
>> + * @header: UTRD header DW-0 to DW-3
>> + * @command_desc_base_addr_lo: UCD base address low DW-4
>> + * @command_desc_base_addr_hi: UCD base address high DW-5
>> + * @response_upiu_length: response UPIU length DW-6
>> + * @response_upiu_offset: response UPIU offset DW-6
>> + * @prd_table_length: Physical region descriptor length DW-7
>> + * @prd_table_offset: Physical region descriptor offset DW-7
>> + */
>> +struct utp_transfer_req_desc {
>> +
>> +       /* DW 0-3 */
>> +       struct request_desc_header header;
>> +
>> +       /* DW 4-5*/
>> +       u32  command_desc_base_addr_lo;
>> +       u32  command_desc_base_addr_hi;
>> +
>> +       /* DW 6 */
>> +       u16  response_upiu_length;
>> +       u16  response_upiu_offset;
>> +
>> +       /* DW 7 */
>> +       u16  prd_table_length;
>> +       u16  prd_table_offset;
>> +};
>> +
>> +/**
>> + * struct utp_task_req_desc - UTMRD structure
>> + * @header: UTMRD header DW-0 to DW-3
>> + * @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
>> + */
>> +struct utp_task_req_desc {
>> +
>> +       /* DW 0-3 */
>> +       struct request_desc_header header;
>> +
>> +       /* DW 4-11 */
>> +       u32 task_req_upiu[TASK_REQ_UPIU_SIZE_DWORDS];
>> +
>> +       /* DW 12-19 */
>> +       u32 task_rsp_upiu[TASK_RSP_UPIU_SIZE_DWORDS];
>> +};
>> +
>> +#endif /* End of Header */
>> --
>> 1.7.5.4
>>



--
~Santosh
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

\
 
 \ /
  Last update: 2012-02-10 08:09    [W:0.137 / U:8.896 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site