mirror of
https://github.com/AetherDroid/android_kernel_samsung_on5xelte.git
synced 2025-09-09 01:28:05 -04:00
Fixed MTP to work with TWRP
This commit is contained in:
commit
f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions
92
drivers/scsi/ufs/Kconfig
Normal file
92
drivers/scsi/ufs/Kconfig
Normal file
|
@ -0,0 +1,92 @@
|
|||
#
|
||||
# Kernel configuration file for the UFS Host Controller
|
||||
#
|
||||
# This code is based on drivers/scsi/ufs/Kconfig
|
||||
# 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.
|
||||
|
||||
config SCSI_UFSHCD
|
||||
tristate "Universal Flash Storage Controller Driver Core"
|
||||
depends on SCSI && SCSI_DMA
|
||||
---help---
|
||||
This selects the support for UFS devices in Linux, say Y and make
|
||||
sure that you know the name of your UFS host adapter (the card
|
||||
inside your computer that "speaks" the UFS protocol, also
|
||||
called UFS Host Controller), because you will be asked for it.
|
||||
The module will be called ufshcd.
|
||||
|
||||
To compile this driver as a module, choose M here and read
|
||||
<file:Documentation/scsi/ufs.txt>.
|
||||
However, do not compile this as a module if your root file system
|
||||
(the one containing the directory /) is located on a UFS device.
|
||||
|
||||
config UFS_DYNAMIC_H8
|
||||
bool "UFS Dynamic Hibernation (EXPERIMENTAL)"
|
||||
depends on SCSI_UFSHCD
|
||||
|
||||
config SCSI_UFSHCD_PCI
|
||||
tristate "PCI bus based UFS Controller support"
|
||||
depends on SCSI_UFSHCD && PCI
|
||||
---help---
|
||||
This selects the PCI UFS Host Controller Interface. Select this if
|
||||
you have UFS Host Controller with PCI Interface.
|
||||
|
||||
If you have a controller with this interface, say Y or M here.
|
||||
|
||||
config SCSI_SKIP_CACHE_OP
|
||||
bool "Skip operations for cache coherency"
|
||||
depends on SCSI_UFSHCD
|
||||
---help---
|
||||
This selects support for skipping operations for cache coherency
|
||||
|
||||
to reduce I/O overhead if file system layer do same thing.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config SCSI_UFSHCD_PLATFORM
|
||||
tristate "Platform bus based UFS Controller support"
|
||||
depends on SCSI_UFSHCD
|
||||
---help---
|
||||
This selects the UFS host controller support. Select this if
|
||||
you have an UFS controller on Platform bus.
|
||||
|
||||
If you have a controller with this interface, say Y or M here.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config SCSI_UFS_EXYNOS
|
||||
tristate "EXYNOS UFS Host Controller Driver"
|
||||
depends on SCSI_UFSHCD && SCSI_UFSHCD_PLATFORM
|
||||
---help---
|
||||
This selects the EXYNOS UFS host controller driver.
|
||||
|
||||
If you have a controller with this interface, say Y or M here.
|
||||
|
||||
If unsure, say N.
|
5
drivers/scsi/ufs/Makefile
Normal file
5
drivers/scsi/ufs/Makefile
Normal file
|
@ -0,0 +1,5 @@
|
|||
# UFSHCD makefile
|
||||
obj-$(CONFIG_SCSI_UFSHCD) += ufshcd.o ufs_quirks.o
|
||||
obj-$(CONFIG_SCSI_UFSHCD_PCI) += ufshcd-pci.o
|
||||
obj-$(CONFIG_SCSI_UFSHCD_PLATFORM) += ufshcd-pltfrm.o
|
||||
obj-$(CONFIG_SCSI_UFS_EXYNOS) += ufs-exynos.o
|
434
drivers/scsi/ufs/fips-fmp-ufs.c
Normal file
434
drivers/scsi/ufs/fips-fmp-ufs.c
Normal file
|
@ -0,0 +1,434 @@
|
|||
/*
|
||||
* Exynos FMP UFS driver for FIPS
|
||||
*
|
||||
* Copyright (C) 2014 Samsung Electronics Co., Ltd.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/syscalls.h>
|
||||
#include <linux/file.h>
|
||||
#include <linux/buffer_head.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/kdev_t.h>
|
||||
#include <fmpdev_int.h>
|
||||
|
||||
#include <scsi/scsi_device.h>
|
||||
#include <scsi/scsi_host.h>
|
||||
#include <scsi/scsi_cmnd.h>
|
||||
#include "ufshcd.h"
|
||||
#include "../scsi_priv.h"
|
||||
|
||||
#define byte2word(b0, b1, b2, b3) \
|
||||
((unsigned int)(b0) << 24) | ((unsigned int)(b1) << 16) | ((unsigned int)(b2) << 8) | (b3)
|
||||
#define get_word(x, c) byte2word(((unsigned char *)(x) + 4 * (c))[0], ((unsigned char *)(x) + 4 * (c))[1], \
|
||||
((unsigned char *)(x) + 4 * (c))[2], ((unsigned char *)(x) + 4 * (c))[3])
|
||||
|
||||
#define SF_BLK_OFFSET (5)
|
||||
#define MAX_SCAN_PART (50)
|
||||
|
||||
struct ufs_fmp_work {
|
||||
struct Scsi_Host *host;
|
||||
struct scsi_device *sdev;
|
||||
struct block_device *bdev;
|
||||
sector_t sector;
|
||||
dev_t devt;
|
||||
};
|
||||
|
||||
struct ufshcd_sg_entry *prd_table;
|
||||
struct ufshcd_sg_entry *ucd_prdt_ptr_st;
|
||||
|
||||
static int ufs_fmp_init(struct device *dev, uint32_t mode)
|
||||
{
|
||||
struct ufs_hba *hba;
|
||||
struct ufs_fmp_work *work;
|
||||
struct Scsi_Host *host;
|
||||
|
||||
work = dev_get_drvdata(dev);
|
||||
if (!work) {
|
||||
dev_err(dev, "Fail to get work from platform device\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
host = work->host;
|
||||
hba = shost_priv(host);
|
||||
|
||||
ucd_prdt_ptr_st = kmalloc(sizeof(struct ufshcd_sg_entry), GFP_KERNEL);
|
||||
if (!ucd_prdt_ptr_st) {
|
||||
dev_err(dev, "Fail to alloc prdt ptr for self test\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
hba->ucd_prdt_ptr_st = ucd_prdt_ptr_st;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ufs_fmp_set_key(struct device *dev, uint32_t mode, uint8_t *key, uint32_t key_len)
|
||||
{
|
||||
struct ufs_hba *hba;
|
||||
struct ufs_fmp_work *work;
|
||||
struct Scsi_Host *host;
|
||||
struct ufshcd_sg_entry *prd_table;
|
||||
|
||||
work = dev_get_drvdata(dev);
|
||||
if (!work) {
|
||||
dev_err(dev, "Fail to get work from platform device\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
host = work->host;
|
||||
hba = shost_priv(host);
|
||||
if (!hba->ucd_prdt_ptr_st) {
|
||||
dev_err(dev, "prdt ptr for fips is not allocated\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
prd_table = hba->ucd_prdt_ptr_st;
|
||||
|
||||
if (mode == CBC_MODE) {
|
||||
SET_FAS(prd_table, CBC_MODE);
|
||||
|
||||
switch (key_len) {
|
||||
case 32:
|
||||
prd_table->size = 32;
|
||||
/* encrypt key */
|
||||
prd_table->file_enckey0 = get_word(key, 7);
|
||||
prd_table->file_enckey1 = get_word(key, 6);
|
||||
prd_table->file_enckey2 = get_word(key, 5);
|
||||
prd_table->file_enckey3 = get_word(key, 4);
|
||||
prd_table->file_enckey4 = get_word(key, 3);
|
||||
prd_table->file_enckey5 = get_word(key, 2);
|
||||
prd_table->file_enckey6 = get_word(key, 1);
|
||||
prd_table->file_enckey7 = get_word(key, 0);
|
||||
break;
|
||||
case 16:
|
||||
prd_table->size = 16;
|
||||
/* encrypt key */
|
||||
prd_table->file_enckey0 = get_word(key, 3);
|
||||
prd_table->file_enckey1 = get_word(key, 2);
|
||||
prd_table->file_enckey2 = get_word(key, 1);
|
||||
prd_table->file_enckey3 = get_word(key, 0);
|
||||
prd_table->file_enckey4 = 0;
|
||||
prd_table->file_enckey5 = 0;
|
||||
prd_table->file_enckey6 = 0;
|
||||
prd_table->file_enckey7 = 0;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "Invalid key length : %d\n", key_len);
|
||||
return -EINVAL;
|
||||
}
|
||||
} else if (mode == XTS_MODE) {
|
||||
SET_FAS(prd_table, XTS_MODE);
|
||||
|
||||
switch (key_len) {
|
||||
case 64:
|
||||
prd_table->size = 32;
|
||||
/* encrypt key */
|
||||
prd_table->file_enckey0 = get_word(key, 7);
|
||||
prd_table->file_enckey1 = get_word(key, 6);
|
||||
prd_table->file_enckey2 = get_word(key, 5);
|
||||
prd_table->file_enckey3 = get_word(key, 4);
|
||||
prd_table->file_enckey4 = get_word(key, 3);
|
||||
prd_table->file_enckey5 = get_word(key, 2);
|
||||
prd_table->file_enckey6 = get_word(key, 1);
|
||||
prd_table->file_enckey7 = get_word(key, 0);
|
||||
|
||||
/* tweak key */
|
||||
prd_table->file_twkey0 = get_word(key, 15);
|
||||
prd_table->file_twkey1 = get_word(key, 14);
|
||||
prd_table->file_twkey2 = get_word(key, 13);
|
||||
prd_table->file_twkey3 = get_word(key, 12);
|
||||
prd_table->file_twkey4 = get_word(key, 11);
|
||||
prd_table->file_twkey5 = get_word(key, 10);
|
||||
prd_table->file_twkey6 = get_word(key, 9);
|
||||
prd_table->file_twkey7 = get_word(key, 8);
|
||||
break;
|
||||
case 32:
|
||||
prd_table->size = 16;
|
||||
/* encrypt key */
|
||||
prd_table->file_enckey0 = get_word(key, 3);
|
||||
prd_table->file_enckey1 = get_word(key, 2);
|
||||
prd_table->file_enckey2 = get_word(key, 1);
|
||||
prd_table->file_enckey3 = get_word(key, 0);
|
||||
prd_table->file_enckey4 = 0;
|
||||
prd_table->file_enckey5 = 0;
|
||||
prd_table->file_enckey6 = 0;
|
||||
prd_table->file_enckey7 = 0;
|
||||
|
||||
/* tweak key */
|
||||
prd_table->file_twkey0 = get_word(key, 7);
|
||||
prd_table->file_twkey1 = get_word(key, 6);
|
||||
prd_table->file_twkey2 = get_word(key, 5);
|
||||
prd_table->file_twkey3 = get_word(key, 4);
|
||||
prd_table->file_twkey4 = 0;
|
||||
prd_table->file_twkey5 = 0;
|
||||
prd_table->file_twkey6 = 0;
|
||||
prd_table->file_twkey7 = 0;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "Invalid key length : %d\n", key_len);
|
||||
return -EINVAL;
|
||||
}
|
||||
} else if (mode == BYPASS_MODE) {
|
||||
SET_FAS(prd_table, BYPASS_MODE);
|
||||
|
||||
/* enc key */
|
||||
prd_table->file_enckey0 = 0;
|
||||
prd_table->file_enckey1 = 0;
|
||||
prd_table->file_enckey2 = 0;
|
||||
prd_table->file_enckey3 = 0;
|
||||
prd_table->file_enckey4 = 0;
|
||||
prd_table->file_enckey5 = 0;
|
||||
prd_table->file_enckey6 = 0;
|
||||
prd_table->file_enckey7 = 0;
|
||||
|
||||
/* tweak key */
|
||||
prd_table->file_twkey0 = 0;
|
||||
prd_table->file_twkey1 = 0;
|
||||
prd_table->file_twkey2 = 0;
|
||||
prd_table->file_twkey3 = 0;
|
||||
prd_table->file_twkey4 = 0;
|
||||
prd_table->file_twkey5 = 0;
|
||||
prd_table->file_twkey6 = 0;
|
||||
prd_table->file_twkey7 = 0;
|
||||
} else {
|
||||
dev_err(dev, "Invalid mode : %d\n", mode);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev_info(dev, "%s: ufs fmp key set is done.\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ufs_fmp_set_iv(struct device *dev, uint32_t mode, uint8_t *iv, uint32_t iv_len)
|
||||
{
|
||||
struct ufs_hba *hba;
|
||||
struct ufs_fmp_work *work;
|
||||
struct Scsi_Host *host;
|
||||
struct ufshcd_sg_entry *prd_table;
|
||||
|
||||
work = dev_get_drvdata(dev);
|
||||
if (!work) {
|
||||
dev_err(dev, "Fail to get work from platform device\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
host = work->host;
|
||||
hba = shost_priv(host);
|
||||
if (!hba->ucd_prdt_ptr_st) {
|
||||
dev_err(dev, "prdt ptr for fips is not allocated\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
prd_table = hba->ucd_prdt_ptr_st;
|
||||
|
||||
if (mode == CBC_MODE || mode == XTS_MODE) {
|
||||
prd_table->file_iv0 = get_word(iv, 3);
|
||||
prd_table->file_iv1 = get_word(iv, 2);
|
||||
prd_table->file_iv2 = get_word(iv, 1);
|
||||
prd_table->file_iv3 = get_word(iv, 0);
|
||||
} else if (mode == BYPASS_MODE) {
|
||||
prd_table->file_iv0 = 0;
|
||||
prd_table->file_iv1 = 0;
|
||||
prd_table->file_iv2 = 0;
|
||||
prd_table->file_iv3 = 0;
|
||||
} else {
|
||||
dev_err(dev, "Invalid mode : %d\n", mode);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static dev_t find_devt_for_selftest(void)
|
||||
{
|
||||
int i, idx = 0;
|
||||
uint64_t size;
|
||||
uint64_t size_list[MAX_SCAN_PART];
|
||||
dev_t devt_list[MAX_SCAN_PART];
|
||||
dev_t devt_scan, devt;
|
||||
struct block_device *bdev;
|
||||
fmode_t fmode = FMODE_WRITE | FMODE_READ;
|
||||
|
||||
for (i = 0; i < MAX_SCAN_PART; i++) {
|
||||
devt_scan = blk_lookup_devt("sda", i);
|
||||
bdev = blkdev_get_by_dev(devt_scan, fmode, NULL);
|
||||
if (IS_ERR(bdev))
|
||||
continue;
|
||||
else {
|
||||
size_list[idx++] = (uint64_t)i_size_read(bdev->bd_inode);
|
||||
devt_list[idx++] = devt_scan;
|
||||
}
|
||||
}
|
||||
|
||||
if (!idx)
|
||||
goto err;
|
||||
|
||||
for (i = 0; i < idx; i++) {
|
||||
if (i == 0) {
|
||||
size = size_list[i];
|
||||
devt = devt_list[i];
|
||||
} else {
|
||||
if (size < size_list[i])
|
||||
devt = devt_list[i];
|
||||
}
|
||||
}
|
||||
|
||||
return devt;
|
||||
|
||||
err:
|
||||
return (dev_t)0;
|
||||
}
|
||||
|
||||
static int ufs_fmp_run(struct device *dev, uint32_t mode, uint8_t *data,
|
||||
uint32_t len, uint32_t write)
|
||||
{
|
||||
int ret = 0;
|
||||
struct ufs_hba *hba;
|
||||
struct ufs_fmp_work *work;
|
||||
struct Scsi_Host *host;
|
||||
static struct buffer_head *bh;
|
||||
|
||||
work = dev_get_drvdata(dev);
|
||||
if (!work) {
|
||||
dev_err(dev, "Fail to get work from platform device\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
host = work->host;
|
||||
hba = shost_priv(host);
|
||||
hba->self_test_mode = mode;
|
||||
|
||||
bh = __getblk(work->bdev, work->sector, FMP_BLK_SIZE);
|
||||
if (!bh) {
|
||||
dev_err(dev, "Fail to get block from bdev\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
hba->self_test_bh = bh;
|
||||
|
||||
get_bh(bh);
|
||||
if (write == WRITE_MODE) {
|
||||
memcpy(bh->b_data, data, len);
|
||||
set_buffer_dirty(bh);
|
||||
sync_dirty_buffer(bh);
|
||||
if (buffer_req(bh) && !buffer_uptodate(bh)) {
|
||||
dev_err(dev, "IO error syncing for FMP fips write\n");
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
memset(bh->b_data, 0, FMP_BLK_SIZE);
|
||||
} else {
|
||||
lock_buffer(bh);
|
||||
bh->b_end_io = end_buffer_read_sync;
|
||||
submit_bh(READ_SYNC, bh);
|
||||
wait_on_buffer(bh);
|
||||
if (unlikely(!buffer_uptodate(bh))) {
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
memcpy(data, bh->b_data, len);
|
||||
}
|
||||
out:
|
||||
hba->self_test_mode = 0;
|
||||
hba->self_test_bh = NULL;
|
||||
put_bh(bh);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ufs_fmp_exit(void)
|
||||
{
|
||||
if (ucd_prdt_ptr_st)
|
||||
kfree(ucd_prdt_ptr_st);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct fips_fmp_ops fips_fmp_fops = {
|
||||
.init = ufs_fmp_init,
|
||||
.set_key = ufs_fmp_set_key,
|
||||
.set_iv = ufs_fmp_set_iv,
|
||||
.run = ufs_fmp_run,
|
||||
.exit = ufs_fmp_exit,
|
||||
};
|
||||
|
||||
int fips_fmp_init(struct device *dev)
|
||||
{
|
||||
struct ufs_fmp_work *work;
|
||||
struct device_node *dev_node;
|
||||
struct platform_device *pdev_ufs;
|
||||
struct device *dev_ufs;
|
||||
struct ufs_hba *hba;
|
||||
struct Scsi_Host *host;
|
||||
struct inode *inode;
|
||||
struct scsi_device *sdev;
|
||||
struct super_block *sb;
|
||||
unsigned long blocksize;
|
||||
unsigned char blocksize_bits;
|
||||
|
||||
sector_t self_test_block;
|
||||
fmode_t fmode = FMODE_WRITE | FMODE_READ;
|
||||
|
||||
work = kmalloc(sizeof(*work), GFP_KERNEL);
|
||||
if (!work) {
|
||||
dev_err(dev, "Fail to alloc fmp work buffer\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
dev_node = of_find_compatible_node(NULL, NULL, "samsung,exynos-ufs");
|
||||
if (!dev_node) {
|
||||
dev_err(dev, "Fail to find exynos ufs device node\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
pdev_ufs = of_find_device_by_node(dev_node);
|
||||
if (!pdev_ufs) {
|
||||
dev_err(dev, "Fail to find exynos ufs pdev\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
dev_ufs = &pdev_ufs->dev;
|
||||
hba = dev_get_drvdata(dev_ufs);
|
||||
if (!hba) {
|
||||
dev_err(dev, "Fail to find hba from dev\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
host = hba->host;
|
||||
sdev = to_scsi_device(dev_ufs);
|
||||
work->host = host;
|
||||
work->sdev = sdev;
|
||||
|
||||
work->devt = find_devt_for_selftest();
|
||||
if (!work->devt) {
|
||||
dev_err(dev, "Fail to find devt for self test\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
work->bdev = blkdev_get_by_dev(work->devt, fmode, NULL);
|
||||
if (IS_ERR(work->bdev)) {
|
||||
dev_err(dev, "Fail to open block device\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
inode = work->bdev->bd_inode;
|
||||
sb = inode->i_sb;
|
||||
blocksize = sb->s_blocksize;
|
||||
blocksize_bits = sb->s_blocksize_bits;
|
||||
self_test_block = (i_size_read(inode) - (blocksize * SF_BLK_OFFSET)) >> blocksize_bits;
|
||||
work->sector = self_test_block;
|
||||
|
||||
dev_set_drvdata(dev, work);
|
||||
|
||||
return 0;
|
||||
|
||||
out:
|
||||
if (work)
|
||||
kfree(work);
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fips_fmp_init);
|
35
drivers/scsi/ufs/mphy.h
Normal file
35
drivers/scsi/ufs/mphy.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* drivers/scsi/ufs/mphy.h
|
||||
*
|
||||
* Copyright (C) 2014 Samsung Electronics Co., Ltd.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _MPHY_H_
|
||||
#define _MPHY_H_
|
||||
|
||||
#define TX_MIN_ACTIVATE_TIME 0x33
|
||||
|
||||
#define RX_HS_G1_SYNC_LENGTH_CAP 0x8b
|
||||
#define RX_HS_G1_PREP_LENGTH_CAP 0x8c
|
||||
#define RX_HS_G2_SYNC_LENGTH_CAP 0x94
|
||||
#define RX_HS_G3_SYNC_LENGTH_CAP 0x95
|
||||
#define RX_HS_G2_PREP_LENGTH_CAP 0x96
|
||||
#define RX_HS_G3_PREP_LENGTH_CAP 0x97
|
||||
#define SYNC_RANGE_FINE (0 << 6)
|
||||
#define SYNC_RANGE_COARSE (1 << 6)
|
||||
#define SYNC_LEN(x) ((x) & 0x3f)
|
||||
#define PREP_LEN(x) ((x) & 0xf)
|
||||
#define RX_ADV_GRANULARITY_CAP 0x98
|
||||
#define RX_ADV_FINE_GRAN_STEP(x) ((((x) & 0x3) << 1) | 0x1)
|
||||
#define RX_MIN_ACTIVATETIME_CAP 0x8f
|
||||
#define RX_HIBERN8TIME_CAP 0x92
|
||||
#define RX_ADV_HIBERN8TIME_CAP 0x99
|
||||
#define RX_ADV_MIN_ACTIVATETIME_CAP 0x9a
|
||||
|
||||
#endif /* _MPHY_H_ */
|
||||
|
2674
drivers/scsi/ufs/ufs-exynos.c
Normal file
2674
drivers/scsi/ufs/ufs-exynos.c
Normal file
File diff suppressed because it is too large
Load diff
527
drivers/scsi/ufs/ufs-exynos.h
Normal file
527
drivers/scsi/ufs/ufs-exynos.h
Normal file
|
@ -0,0 +1,527 @@
|
|||
/*
|
||||
* UFS Host Controller driver for Exynos specific extensions
|
||||
*
|
||||
* Copyright (C) 2013-2014 Samsung Electronics Co., Ltd.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _UFS_EXYNOS_H_
|
||||
#define _UFS_EXYNOS_H_
|
||||
|
||||
#include <linux/pm_qos.h>
|
||||
|
||||
/*
|
||||
* Exynos's Vendor specific registers for UFSHCI
|
||||
*/
|
||||
#define HCI_TXPRDT_ENTRY_SIZE 0x00
|
||||
#define HCI_RXPRDT_ENTRY_SIZE 0x04
|
||||
#define HCI_TO_CNT_DIV_VAL 0x08
|
||||
#define HCI_1US_TO_CNT_VAL 0x0C
|
||||
#define CNT_VAL_1US_MASK 0x3ff
|
||||
#define HCI_INVALID_UPIU_CTRL 0x10
|
||||
#define HCI_INVALID_UPIU_BADDR 0x14
|
||||
#define HCI_INVALID_UPIU_UBADDR 0x18
|
||||
#define HCI_INVALID_UTMR_OFFSET_ADDR 0x1C
|
||||
#define HCI_INVALID_UTR_OFFSET_ADDR 0x20
|
||||
#define HCI_INVALID_DIN_OFFSET_ADDR 0x24
|
||||
#define HCI_DBR_TIMER_CONFIG 0x28
|
||||
#define HCI_DBR_TIMER_STATUS 0x2C
|
||||
#define HCI_VENDOR_SPECIFIC_IS 0x38
|
||||
#define HCI_VENDOR_SPECIFIC_IE 0x3C
|
||||
#define HCI_UTRL_NEXUS_TYPE 0x40
|
||||
#define HCI_UTMRL_NEXUS_TYPE 0x44
|
||||
#define HCI_E2EFC_CTRL 0x48
|
||||
#define HCI_SW_RST 0x50
|
||||
#define UFS_LINK_SW_RST (1 << 0)
|
||||
#define UFS_UNIPRO_SW_RST (1 << 1)
|
||||
#define UFS_SW_RST_MASK (UFS_UNIPRO_SW_RST | UFS_LINK_SW_RST)
|
||||
#define HCI_LINK_VERSION 0x54
|
||||
#define HCI_IDLE_TIMER_CONFIG 0x58
|
||||
#define HCI_RX_UPIU_MATCH_ERROR_CODE 0x5C
|
||||
#define HCI_DATA_REORDER 0x60
|
||||
#define HCI_MAX_DOUT_DATA_SIZE 0x64
|
||||
#define HCI_UNIPRO_APB_CLK_CTRL 0x68
|
||||
#define HCI_AXIDMA_RWDATA_BURST_LEN 0x6C
|
||||
#define HCI_GPIO_OUT 0x70
|
||||
#define HCI_WRITE_DMA_CTRL 0x74
|
||||
#define HCI_ERROR_EN_PA_LAYER 0x78
|
||||
#define HCI_ERROR_EN_DL_LAYER 0x7C
|
||||
#define HCI_ERROR_EN_N_LAYER 0x80
|
||||
#define HCI_ERROR_EN_T_LAYER 0x84
|
||||
#define HCI_ERROR_EN_DME_LAYER 0x88
|
||||
#define HCI_REQ_HOLD_EN 0xAC
|
||||
#define HCI_CLKSTOP_CTRL 0xB0
|
||||
#define REFCLK_STOP BIT(2)
|
||||
#define UNIPRO_MCLK_STOP BIT(1)
|
||||
#define UNIPRO_PCLK_STOP BIT(0)
|
||||
#define CLK_STOP_ALL (REFCLK_STOP |\
|
||||
UNIPRO_MCLK_STOP |\
|
||||
UNIPRO_PCLK_STOP)
|
||||
#define HCI_FORCE_HCS 0xB4
|
||||
#define REFCLK_STOP_EN BIT(7)
|
||||
#define UNIPRO_PCLK_STOP_EN BIT(6)
|
||||
#define UNIPRO_MCLK_STOP_EN BIT(5)
|
||||
#define HCI_CORECLK_STOP_EN BIT(4)
|
||||
#define CLK_STOP_CTRL_EN_ALL (REFCLK_STOP_EN |\
|
||||
UNIPRO_PCLK_STOP_EN |\
|
||||
UNIPRO_MCLK_STOP_EN)
|
||||
#define HCI_FSM_MONITOR 0xC0
|
||||
#define HCI_PRDT_HIT_RATIO 0xC4
|
||||
#define HCI_DMA0_MONITOR_STATE 0xC8
|
||||
#define HCI_DMA0_MONITOR_CNT 0xCC
|
||||
#define HCI_DMA1_MONITOR_STATE 0xD0
|
||||
#define HCI_DMA1_MONITOR_CNT 0xD4
|
||||
|
||||
/* Device fatal error */
|
||||
#define DFES_ERR_EN BIT(31)
|
||||
#define DFES_DEF_DL_ERRS (UIC_DATA_LINK_LAYER_ERROR_RX_BUF_OF |\
|
||||
UIC_DATA_LINK_LAYER_ERROR_PA_INIT)
|
||||
#define DFES_DEF_N_ERRS (UIC_NETWORK_UNSUPPORTED_HEADER_TYPE |\
|
||||
UIC_NETWORK_BAD_DEVICEID_ENC |\
|
||||
UIC_NETWORK_LHDR_TRAP_PACKET_DROPPING)
|
||||
#define DFES_DEF_T_ERRS (UIC_TRANSPORT_UNSUPPORTED_HEADER_TYPE |\
|
||||
UIC_TRANSPORT_UNKNOWN_CPORTID |\
|
||||
UIC_TRANSPORT_NO_CONNECTION_RX |\
|
||||
UIC_TRANSPORT_BAD_TC)
|
||||
|
||||
/* TXPRDT defines */
|
||||
#define PRDT_PREFECT_EN BIT(31)
|
||||
#define PRDT_SET_SIZE(x) ((x) & 0x1F)
|
||||
|
||||
enum {
|
||||
UNIP_PA_LYR = 0,
|
||||
UNIP_DL_LYR,
|
||||
UNIP_N_LYR,
|
||||
UNIP_T_LYR,
|
||||
UNIP_DME_LYR,
|
||||
};
|
||||
|
||||
/*
|
||||
* UNIPRO registers
|
||||
*/
|
||||
#define UNIP_COMP_VERSION 0x000
|
||||
#define UNIP_COMP_INFO 0x004
|
||||
#define UNIP_COMP_RESET 0x010
|
||||
#define UNIP_DME_POWERON_REQ 0x040
|
||||
#define UNIP_DME_POWERON_CNF_RESULT 0x044
|
||||
#define UNIP_DME_POWEROFF_REQ 0x048
|
||||
#define UNIP_DME_POWEROFF_CNF_RESULT 0x04C
|
||||
#define UNIP_DME_RESET_REQ 0x050
|
||||
#define UNIP_DME_RESET_REQ_LEVEL 0x054
|
||||
#define UNIP_DME_ENABLE_REQ 0x058
|
||||
#define UNIP_DME_ENABLE_CNF_RESULT 0x05C
|
||||
#define UNIP_DME_ENDPOINTRESET_REQ 0x060
|
||||
#define UNIP_DME_ENDPOINTRESET_CNF_RESULT 0x064
|
||||
#define UNIP_DME_LINKSTARTUP_REQ 0x068
|
||||
#define UNIP_DME_LINKSTARTUP_CNF_RESULT 0x06C
|
||||
#define UNIP_DME_HIBERN8_ENTER_REQ 0x070
|
||||
#define UNIP_DME_HIBERN8_ENTER_CNF_RESULT 0x074
|
||||
#define UNIP_DME_HIBERN8_ENTER_IND_RESULT 0x078
|
||||
#define UNIP_DME_HIBERN8_EXIT_REQ 0x080
|
||||
#define UNIP_DME_HIBERN8_EXIT_CNF_RESULT 0x084
|
||||
#define UNIP_DME_HIBERN8_EXIT_IND_RESULT 0x088
|
||||
#define UNIP_DME_PWR_REQ 0x090
|
||||
#define UNIP_DME_PWR_REQ_POWERMODE 0x094
|
||||
#define UNIP_DME_PWR_REQ_LOCALL2TIMER0 0x098
|
||||
#define UNIP_DME_PWR_REQ_LOCALL2TIMER1 0x09C
|
||||
#define UNIP_DME_PWR_REQ_LOCALL2TIMER2 0x0A0
|
||||
#define UNIP_DME_PWR_REQ_REMOTEL2TIMER0 0x0A4
|
||||
#define UNIP_DME_PWR_REQ_REMOTEL2TIMER1 0x0A8
|
||||
#define UNIP_DME_PWR_REQ_REMOTEL2TIMER2 0x0AC
|
||||
#define UNIP_DME_PWR_CNF_RESULT 0x0B0
|
||||
#define UNIP_DME_PWR_IND_RESULT 0x0B4
|
||||
#define UNIP_DME_TEST_MODE_REQ 0x0B8
|
||||
#define UNIP_DME_TEST_MODE_CNF_RESULT 0x0BC
|
||||
#define UNIP_DME_ERROR_IND_LAYER 0x0C0
|
||||
#define UNIP_DME_ERROR_IND_ERRCODE 0x0C4
|
||||
#define UNIP_DME_PACP_CNFBIT 0x0C8
|
||||
#define UNIP_DME_DL_FRAME_IND 0x0D0
|
||||
#define UNIP_DME_INTR_STATUS 0x0E0
|
||||
#define UNIP_DME_INTR_ENABLE 0x0E4
|
||||
#define UNIP_DME_GETSET_ADDR 0x100
|
||||
#define UNIP_DME_GETSET_WDATA 0x104
|
||||
#define UNIP_DME_GETSET_RDATA 0x108
|
||||
#define UNIP_DME_GETSET_CONTROL 0x10C
|
||||
#define UNIP_DME_GETSET_RESULT 0x110
|
||||
#define UNIP_DME_PEER_GETSET_ADDR 0x120
|
||||
#define UNIP_DME_PEER_GETSET_WDATA 0x124
|
||||
#define UNIP_DME_PEER_GETSET_RDATA 0x128
|
||||
#define UNIP_DME_PEER_GETSET_CONTROL 0x12C
|
||||
#define UNIP_DME_PEER_GETSET_RESULT 0x130
|
||||
#define UNIP_DBG_FORCE_DME_CTRL_STATE 0x150
|
||||
#define UNIP_DBG_AUTO_DME_LINKSTARTUP 0x158
|
||||
#define UNIP_DBG_PA_CTRLSTATE 0x15C
|
||||
#define UNIP_DBG_PA_TX_STATE 0x160
|
||||
#define UNIP_DBG_BREAK_DME_CTRL_STATE 0x164
|
||||
#define UNIP_DBG_STEP_DME_CTRL_STATE 0x168
|
||||
#define UNIP_DBG_NEXT_DME_CTRL_STATE 0x16C
|
||||
|
||||
/*
|
||||
* UFS Protector registers
|
||||
*/
|
||||
#define UFSPRCTRL 0x000
|
||||
#define UFSPRSTAT 0x008
|
||||
#define UFSPRSECURITY 0x010
|
||||
#define NSSMU BIT(14)
|
||||
#define UFSPVERSION 0x01C
|
||||
#define UFSPRENCKEY0 0x020
|
||||
#define UFSPRENCKEY1 0x024
|
||||
#define UFSPRENCKEY2 0x028
|
||||
#define UFSPRENCKEY3 0x02C
|
||||
#define UFSPRENCKEY4 0x030
|
||||
#define UFSPRENCKEY5 0x034
|
||||
#define UFSPRENCKEY6 0x038
|
||||
#define UFSPRENCKEY7 0x03C
|
||||
#define UFSPRTWKEY0 0x040
|
||||
#define UFSPRTWKEY1 0x044
|
||||
#define UFSPRTWKEY2 0x048
|
||||
#define UFSPRTWKEY3 0x04C
|
||||
#define UFSPRTWKEY4 0x050
|
||||
#define UFSPRTWKEY5 0x054
|
||||
#define UFSPRTWKEY6 0x058
|
||||
#define UFSPRTWKEY7 0x05C
|
||||
#define UFSPWCTRL 0x100
|
||||
#define UFSPWSTAT 0x108
|
||||
#define UFSPWSECURITY 0x110
|
||||
#define UFSPWENCKEY0 0x120
|
||||
#define UFSPWENCKEY1 0x124
|
||||
#define UFSPWENCKEY2 0x128
|
||||
#define UFSPWENCKEY3 0x12C
|
||||
#define UFSPWENCKEY4 0x130
|
||||
#define UFSPWENCKEY5 0x134
|
||||
#define UFSPWENCKEY6 0x138
|
||||
#define UFSPWENCKEY7 0x13C
|
||||
#define UFSPWTWKEY0 0x140
|
||||
#define UFSPWTWKEY1 0x144
|
||||
#define UFSPWTWKEY2 0x148
|
||||
#define UFSPWTWKEY3 0x14C
|
||||
#define UFSPWTWKEY4 0x150
|
||||
#define UFSPWTWKEY5 0x154
|
||||
#define UFSPWTWKEY6 0x158
|
||||
#define UFSPWTWKEY7 0x15C
|
||||
#define UFSPSBEGIN0 0x200
|
||||
#define UFSPSEND0 0x204
|
||||
#define UFSPSLUN0 0x208
|
||||
#define UFSPSCTRL0 0x20C
|
||||
#define UFSPSBEGIN1 0x210
|
||||
#define UFSPSEND1 0x214
|
||||
#define UFSPSLUN1 0x218
|
||||
#define UFSPSCTRL1 0x21C
|
||||
#define UFSPSBEGIN2 0x220
|
||||
#define UFSPSEND2 0x224
|
||||
#define UFSPSLUN2 0x228
|
||||
#define UFSPSCTRL2 0x22C
|
||||
#define UFSPSBEGIN3 0x230
|
||||
#define UFSPSEND3 0x234
|
||||
#define UFSPSLUN3 0x238
|
||||
#define UFSPSCTRL3 0x23C
|
||||
#define UFSPSBEGIN4 0x240
|
||||
#define UFSPSEND4 0x244
|
||||
#define UFSPSLUN4 0x248
|
||||
#define UFSPSCTRL4 0x24C
|
||||
#define UFSPSBEGIN5 0x250
|
||||
#define UFSPSEND5 0x254
|
||||
#define UFSPSLUN5 0x258
|
||||
#define UFSPSCTRL5 0x25C
|
||||
#define UFSPSBEGIN6 0x260
|
||||
#define UFSPSEND6 0x264
|
||||
#define UFSPSLUN6 0x268
|
||||
#define UFSPSCTRL6 0x26C
|
||||
#define UFSPSBEGIN7 0x270
|
||||
#define UFSPSEND7 0x274
|
||||
#define UFSPSLUN7 0x278
|
||||
#define UFSPSCTRL7 0x27C
|
||||
|
||||
/*
|
||||
* MIBs for PA debug registers
|
||||
*/
|
||||
#define PA_DBG_CLK_PERIOD 0x9514
|
||||
#define PA_DBG_TXPHY_CFGUPDT 0x9518
|
||||
#define PA_DBG_RXPHY_CFGUPDT 0x9519
|
||||
#define PA_DBG_MODE 0x9529
|
||||
#define PA_DBG_TX_PHY_LATENCY 0x952C
|
||||
#define PA_DBG_AUTOMODE_THLD 0x9536
|
||||
#define PA_DBG_OV_TM 0x9540
|
||||
#define PA_DBG_MIB_CAP_SEL 0x9546
|
||||
#define PA_DBG_RESUME_HIBERN8 0x9550
|
||||
#define PA_DBG_TX_PHY_LATENCY_EN 0x9552
|
||||
#define PA_DBG_IGNORE_INCOMING 0x9559
|
||||
#define PA_DBG_LINE_RESET_THLD 0x9561
|
||||
#define PA_DBG_OPTION_SUITE 0x9564
|
||||
|
||||
/*
|
||||
* MIBs for Transport Layer debug registers
|
||||
*/
|
||||
#define T_DBG_SKIP_INIT_HIBERN8_EXIT 0xc001
|
||||
|
||||
/*
|
||||
* Exynos MPHY attributes
|
||||
*/
|
||||
#define TX_LINERESET_N_VAL 0x0277
|
||||
#define TX_LINERESET_N(v) (((v) >> 10) & 0xff)
|
||||
#define TX_LINERESET_P_VAL 0x027D
|
||||
#define TX_LINERESET_P(v) (((v) >> 12) & 0xff)
|
||||
#define TX_OV_SLEEP_CNT_TIMER 0x028E
|
||||
#define TX_OV_H8_ENTER_EN (1 << 7)
|
||||
#define TX_OV_SLEEP_CNT(v) (((v) >> 5) & 0x7f)
|
||||
|
||||
#define TX_HIGH_Z_CNT_11_08 0x028c
|
||||
#define TX_HIGH_Z_CNT_H(v) (((v) >> 8) & 0xf)
|
||||
#define TX_HIGH_Z_CNT_07_00 0x028d
|
||||
#define TX_HIGH_Z_CNT_L(v) ((v) & 0xff)
|
||||
#define TX_BASE_NVAL_07_00 0x0293
|
||||
#define TX_BASE_NVAL_L(v) ((v) & 0xff)
|
||||
#define TX_BASE_NVAL_15_08 0x0294
|
||||
#define TX_BASE_NVAL_H(v) (((v) >> 8) & 0xff)
|
||||
#define TX_GRAN_NVAL_07_00 0x0295
|
||||
#define TX_GRAN_NVAL_L(v) ((v) & 0xff)
|
||||
#define TX_GRAN_NVAL_10_08 0x0296
|
||||
#define TX_GRAN_NVAL_H(v) (((v) >> 8) & 0x3)
|
||||
|
||||
#define RX_FILLER_ENABLE 0x0316
|
||||
#define RX_FILLER_EN (1 << 1)
|
||||
#define RX_LCC_IGNORE 0x0318
|
||||
#define RX_LINERESET_VAL 0x0317
|
||||
#define RX_LINERESET(v) (((v) >> 12) & 0xff)
|
||||
#define RX_SYNC_MASK_LENGTH 0x0321
|
||||
#define RX_HIBERN8_WAIT_VAL_BIT_20_16 0x0331
|
||||
#define RX_HIBERN8_WAIT_VAL_BIT_15_08 0x0332
|
||||
#define RX_HIBERN8_WAIT_VAL_BIT_07_00 0x0333
|
||||
|
||||
#define RX_OV_SLEEP_CNT_TIMER 0x0340
|
||||
#define RX_OV_SLEEP_CNT(v) (((v) >> 6) & 0x1f)
|
||||
#define RX_OV_STALL_CNT_TIMER 0x0341
|
||||
#define RX_OV_STALL_CNT(v) (((v) >> 4) & 0xff)
|
||||
#define RX_BASE_NVAL_07_00 0x0355
|
||||
#define RX_BASE_NVAL_L(v) ((v) & 0xff)
|
||||
#define RX_BASE_NVAL_15_08 0x0354
|
||||
#define RX_BASE_NVAL_H(v) (((v) >> 8) & 0xff)
|
||||
#define RX_GRAN_NVAL_07_00 0x0353
|
||||
#define RX_GRAN_NVAL_L(v) ((v) & 0xff)
|
||||
#define RX_GRAN_NVAL_10_08 0x0352
|
||||
#define RX_GRAN_NVAL_H(v) (((v) >> 8) & 0x3)
|
||||
|
||||
#define CMN_PWM_CMN_CTRL 0x0402
|
||||
#define PWM_CMN_CTRL_MASK 0x3
|
||||
#define CMN_REFCLK_PLL_LOCK 0x0406
|
||||
#define CMN_REFCLK_STREN 0x044C
|
||||
#define CMN_REFCLK_OUT 0x044E
|
||||
#define CMN_REFCLK_SEL_PLL 0x044F
|
||||
|
||||
/*
|
||||
* Driver specific definitions
|
||||
*/
|
||||
|
||||
enum {
|
||||
PHY_CFG_NONE = 0,
|
||||
PHY_PCS_COMN,
|
||||
PHY_PCS_RXTX,
|
||||
PHY_PMA_COMN,
|
||||
PHY_PMA_TRSV,
|
||||
UNIPRO_STD_MIB,
|
||||
UNIPRO_DBG_MIB,
|
||||
UNIPRO_DBG_APB,
|
||||
};
|
||||
|
||||
enum {
|
||||
__PMD_PWM_G1_L1,
|
||||
__PMD_PWM_G1_L2,
|
||||
__PMD_PWM_G2_L1,
|
||||
__PMD_PWM_G2_L2,
|
||||
__PMD_PWM_G3_L1,
|
||||
__PMD_PWM_G3_L2,
|
||||
__PMD_PWM_G4_L1,
|
||||
__PMD_PWM_G4_L2,
|
||||
__PMD_PWM_G5_L1,
|
||||
__PMD_PWM_G5_L2,
|
||||
__PMD_HS_G1_L1,
|
||||
__PMD_HS_G1_L2,
|
||||
__PMD_HS_G2_L1,
|
||||
__PMD_HS_G2_L2,
|
||||
__PMD_HS_G3_L1,
|
||||
__PMD_HS_G3_L2,
|
||||
};
|
||||
|
||||
#define PMD_PWM_G1_L1 (1U << __PMD_PWM_G1_L1)
|
||||
#define PMD_PWM_G1_L2 (1U << __PMD_PWM_G1_L2)
|
||||
#define PMD_PWM_G2_L1 (1U << __PMD_PWM_G2_L1)
|
||||
#define PMD_PWM_G2_L2 (1U << __PMD_PWM_G2_L2)
|
||||
#define PMD_PWM_G3_L1 (1U << __PMD_PWM_G3_L1)
|
||||
#define PMD_PWM_G3_L2 (1U << __PMD_PWM_G3_L2)
|
||||
#define PMD_PWM_G4_L1 (1U << __PMD_PWM_G4_L1)
|
||||
#define PMD_PWM_G4_L2 (1U << __PMD_PWM_G4_L2)
|
||||
#define PMD_PWM_G5_L1 (1U << __PMD_PWM_G5_L1)
|
||||
#define PMD_PWM_G5_L2 (1U << __PMD_PWM_G5_L2)
|
||||
#define PMD_HS_G1_L1 (1U << __PMD_HS_G1_L1)
|
||||
#define PMD_HS_G1_L2 (1U << __PMD_HS_G1_L2)
|
||||
#define PMD_HS_G2_L1 (1U << __PMD_HS_G2_L1)
|
||||
#define PMD_HS_G2_L2 (1U << __PMD_HS_G2_L2)
|
||||
#define PMD_HS_G3_L1 (1U << __PMD_HS_G3_L1)
|
||||
#define PMD_HS_G3_L2 (1U << __PMD_HS_G3_L2)
|
||||
|
||||
#define PMD_ALL (PMD_HS_G3_L2 - 1)
|
||||
#define PMD_PWM (PMD_PWM_G4_L2 - 1)
|
||||
#define PMD_HS (PMD_ALL ^ PMD_PWM)
|
||||
|
||||
struct ufs_phy_cfg {
|
||||
u32 addr;
|
||||
u32 val;
|
||||
u32 flg;
|
||||
u32 lyr;
|
||||
};
|
||||
|
||||
struct exynos_ufs_soc {
|
||||
struct ufs_phy_cfg *tbl_phy_init;
|
||||
struct ufs_phy_cfg *tbl_post_phy_init;
|
||||
struct ufs_phy_cfg *tbl_calib_of_pwm;
|
||||
struct ufs_phy_cfg *tbl_calib_of_hs_rate_a;
|
||||
struct ufs_phy_cfg *tbl_calib_of_hs_rate_b;
|
||||
struct ufs_phy_cfg *tbl_post_calib_of_pwm;
|
||||
struct ufs_phy_cfg *tbl_post_calib_of_hs_rate_a;
|
||||
struct ufs_phy_cfg *tbl_post_calib_of_hs_rate_b;
|
||||
struct ufs_phy_cfg *tbl_pma_restore;
|
||||
};
|
||||
|
||||
struct exynos_ufs_phy {
|
||||
void __iomem *reg_pma;
|
||||
void __iomem *reg_pmu;
|
||||
struct exynos_ufs_soc *soc;
|
||||
};
|
||||
|
||||
struct uic_pwr_mode {
|
||||
u8 lane;
|
||||
u8 gear;
|
||||
u8 mode;
|
||||
u8 hs_series;
|
||||
bool termn;
|
||||
u32 local_l2_timer[3];
|
||||
u32 remote_l2_timer[3];
|
||||
};
|
||||
|
||||
struct exynos_ufs_tp_mon_table {
|
||||
u32 threshold;
|
||||
s32 cluster1_value;
|
||||
#ifdef CONFIG_ARM_EXYNOS_MP_CPUFREQ
|
||||
s32 cluster0_value;
|
||||
#endif
|
||||
s32 mif_value;
|
||||
};
|
||||
|
||||
struct exynos_ufs_clk_info {
|
||||
struct list_head list;
|
||||
struct clk *clk;
|
||||
const char *name;
|
||||
u32 freq;
|
||||
};
|
||||
|
||||
struct exynos_ufs_misc_log {
|
||||
struct list_head clk_list_head;
|
||||
bool isolation;
|
||||
};
|
||||
|
||||
struct exynos_ufs_sfr_log {
|
||||
const char* name;
|
||||
const u32 offset;
|
||||
#define LOG_STD_HCI_SFR 0xFFFFFFF0
|
||||
#define LOG_VS_HCI_SFR 0xFFFFFFF1
|
||||
#define LOG_FMP_SFR 0xFFFFFFF2
|
||||
#define LOG_UNIPRO_SFR 0xFFFFFFF3
|
||||
#define LOG_PMA_SFR 0xFFFFFFF4
|
||||
u32 val;
|
||||
};
|
||||
|
||||
struct exynos_ufs_attr_log {
|
||||
const u32 offset;
|
||||
u32 res;
|
||||
u32 val;
|
||||
};
|
||||
|
||||
struct exynos_ufs_debug {
|
||||
struct exynos_ufs_sfr_log* sfr;
|
||||
struct exynos_ufs_attr_log* attr;
|
||||
struct exynos_ufs_misc_log misc;
|
||||
};
|
||||
|
||||
struct exynos_ufs {
|
||||
struct device *dev;
|
||||
struct ufs_hba *hba;
|
||||
|
||||
void __iomem *reg_hci;
|
||||
void __iomem *reg_unipro;
|
||||
void __iomem *reg_ufsp;
|
||||
|
||||
struct clk *clk_hci;
|
||||
struct clk *pclk;
|
||||
struct clk *clk_unipro;
|
||||
struct clk *clk_refclk_1;
|
||||
struct clk *clk_refclk_2;
|
||||
struct clk *clk_phy_symb[4];
|
||||
u32 pclk_rate;
|
||||
u32 pclk_avail_min;
|
||||
u32 pclk_avail_max;
|
||||
u32 mclk_rate;
|
||||
|
||||
int avail_ln_rx;
|
||||
int avail_ln_tx;
|
||||
|
||||
struct exynos_ufs_phy phy;
|
||||
struct notifier_block lpa_nb;
|
||||
struct uic_pwr_mode req_pmd_parm;
|
||||
struct uic_pwr_mode act_pmd_parm;
|
||||
|
||||
u32 rx_adv_fine_gran_sup_en;
|
||||
u32 rx_adv_fine_gran_step;
|
||||
u32 rx_min_actv_time_cap;
|
||||
u32 rx_hibern8_time_cap;
|
||||
u32 rx_adv_min_actv_time_cap;
|
||||
u32 rx_adv_hibern8_time_cap;
|
||||
|
||||
u32 pa_granularity;
|
||||
u32 pa_tactivate;
|
||||
u32 pa_hibern8time;
|
||||
u32 wait_cdr_lock;
|
||||
|
||||
|
||||
u32 opts;
|
||||
#define EXYNOS_UFS_OPTS_SKIP_CONNECTION_ESTAB BIT(0)
|
||||
#define EXYNOS_UFS_OPTS_USE_SEPERATED_PCLK BIT(1) /* for CAL */
|
||||
|
||||
/* Performance */
|
||||
struct exynos_ufs_tp_mon_table *tp_mon_tbl;
|
||||
struct delayed_work tp_mon;
|
||||
struct pm_qos_request pm_qos_cluster1;
|
||||
struct pm_qos_request pm_qos_cluster0;
|
||||
struct pm_qos_request pm_qos_mif;
|
||||
u32 last_threshold;
|
||||
struct pm_qos_request pm_qos_int;
|
||||
s32 pm_qos_int_value;
|
||||
|
||||
/* Support system power mode */
|
||||
int idle_ip_index;
|
||||
|
||||
/* for miscellaneous control */
|
||||
u32 misc_flags;
|
||||
#define EXYNOS_UFS_MISC_TOGGLE_LOG BIT(0)
|
||||
struct exynos_ufs_debug debug;
|
||||
};
|
||||
|
||||
struct phy_tm_parm {
|
||||
u32 tx_linereset_p;
|
||||
u32 tx_linereset_n;
|
||||
u32 tx_high_z_cnt;
|
||||
u32 tx_base_n_val;
|
||||
u32 tx_gran_n_val;
|
||||
u32 tx_sleep_cnt;
|
||||
|
||||
u32 rx_linereset;
|
||||
u32 rx_hibern8_wait;
|
||||
u32 rx_base_n_val;
|
||||
u32 rx_gran_n_val;
|
||||
u32 rx_sleep_cnt;
|
||||
u32 rx_stall_cnt;
|
||||
};
|
||||
#endif /* _UFS_EXYNOS_H_ */
|
549
drivers/scsi/ufs/ufs.h
Normal file
549
drivers/scsi/ufs/ufs.h
Normal file
|
@ -0,0 +1,549 @@
|
|||
/*
|
||||
* Universal Flash Storage Host controller driver
|
||||
*
|
||||
* This code is based on drivers/scsi/ufs/ufs.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 _UFS_H
|
||||
#define _UFS_H
|
||||
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#define MAX_CDB_SIZE 16
|
||||
#define GENERAL_UPIU_REQUEST_SIZE 32
|
||||
#define QUERY_DESC_MAX_SIZE 255
|
||||
#define QUERY_DESC_MIN_SIZE 2
|
||||
#define QUERY_DESC_HDR_SIZE 2
|
||||
#define QUERY_OSF_SIZE (GENERAL_UPIU_REQUEST_SIZE - \
|
||||
(sizeof(struct utp_upiu_header)))
|
||||
|
||||
#define UPIU_HEADER_DWORD(byte3, byte2, byte1, byte0)\
|
||||
cpu_to_be32((byte3 << 24) | (byte2 << 16) |\
|
||||
(byte1 << 8) | (byte0))
|
||||
/*
|
||||
* UFS device may have standard LUs and LUN id could be from 0x00 to
|
||||
* 0x7F. Standard LUs use "Peripheral Device Addressing Format".
|
||||
* UFS device may also have the Well Known LUs (also referred as W-LU)
|
||||
* which again could be from 0x00 to 0x7F. For W-LUs, device only use
|
||||
* the "Extended Addressing Format" which means the W-LUNs would be
|
||||
* from 0xc100 (SCSI_W_LUN_BASE) onwards.
|
||||
* This means max. LUN number reported from UFS device could be 0xC17F.
|
||||
*/
|
||||
#define UFS_UPIU_MAX_UNIT_NUM_ID 0x7F
|
||||
#define UFS_MAX_LUNS (SCSI_W_LUN_BASE + UFS_UPIU_MAX_UNIT_NUM_ID)
|
||||
#define UFS_UPIU_WLUN_ID (1 << 7)
|
||||
#define UFS_UPIU_MAX_GENERAL_LUN 8
|
||||
|
||||
/* Well known logical unit id in LUN field of UPIU */
|
||||
enum {
|
||||
UFS_UPIU_REPORT_LUNS_WLUN = 0x81,
|
||||
UFS_UPIU_UFS_DEVICE_WLUN = 0xD0,
|
||||
UFS_UPIU_BOOT_WLUN = 0xB0,
|
||||
UFS_UPIU_RPMB_WLUN = 0xC4,
|
||||
};
|
||||
|
||||
/*
|
||||
* 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 = 0x16,
|
||||
};
|
||||
|
||||
/* 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_TRANSACTION_REJECT_UPIU = 0x3F,
|
||||
};
|
||||
|
||||
/* UPIU Read/Write flags */
|
||||
enum {
|
||||
UPIU_CMD_FLAGS_NONE = 0x00,
|
||||
UPIU_CMD_FLAGS_WRITE = 0x20,
|
||||
UPIU_CMD_FLAGS_READ = 0x40,
|
||||
};
|
||||
|
||||
/* UPIU Task Attributes */
|
||||
enum {
|
||||
UPIU_TASK_ATTR_SIMPLE = 0x00,
|
||||
UPIU_TASK_ATTR_ORDERED = 0x01,
|
||||
UPIU_TASK_ATTR_HEADQ = 0x02,
|
||||
UPIU_TASK_ATTR_ACA = 0x03,
|
||||
};
|
||||
|
||||
/* UPIU Query request function */
|
||||
enum {
|
||||
UPIU_QUERY_FUNC_STANDARD_READ_REQUEST = 0x01,
|
||||
UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST = 0x81,
|
||||
};
|
||||
|
||||
/* Flag idn for Query Requests*/
|
||||
enum flag_idn {
|
||||
QUERY_FLAG_IDN_FDEVICEINIT = 0x01,
|
||||
QUERY_FLAG_IDN_PWR_ON_WPE = 0x03,
|
||||
QUERY_FLAG_IDN_BKOPS_EN = 0x04,
|
||||
};
|
||||
|
||||
/* Attribute idn for Query requests */
|
||||
enum attr_idn {
|
||||
QUERY_ATTR_IDN_BOOT_LU_EN = 0x00,
|
||||
QUERY_ATTR_IDN_RESERVED = 0x01,
|
||||
QUERY_ATTR_IDN_POWER_MODE = 0x02,
|
||||
QUERY_ATTR_IDN_ACTIVE_ICC_LVL = 0x03,
|
||||
QUERY_ATTR_IDN_OOO_DATA_EN = 0x04,
|
||||
QUERY_ATTR_IDN_BKOPS_STATUS = 0x05,
|
||||
QUERY_ATTR_IDN_PURGE_STATUS = 0x06,
|
||||
QUERY_ATTR_IDN_MAX_DATA_IN = 0x07,
|
||||
QUERY_ATTR_IDN_MAX_DATA_OUT = 0x08,
|
||||
QUERY_ATTR_IDN_DYN_CAP_NEEDED = 0x09,
|
||||
QUERY_ATTR_IDN_REF_CLK_FREQ = 0x0A,
|
||||
QUERY_ATTR_IDN_CONF_DESC_LOCK = 0x0B,
|
||||
QUERY_ATTR_IDN_MAX_NUM_OF_RTT = 0x0C,
|
||||
QUERY_ATTR_IDN_EE_CONTROL = 0x0D,
|
||||
QUERY_ATTR_IDN_EE_STATUS = 0x0E,
|
||||
QUERY_ATTR_IDN_SECONDS_PASSED = 0x0F,
|
||||
QUERY_ATTR_IDN_CNTX_CONF = 0x10,
|
||||
QUERY_ATTR_IDN_CORR_PRG_BLK_NUM = 0x11,
|
||||
};
|
||||
|
||||
/* Descriptor idn for Query requests */
|
||||
enum desc_idn {
|
||||
QUERY_DESC_IDN_DEVICE = 0x0,
|
||||
QUERY_DESC_IDN_CONFIGURAION = 0x1,
|
||||
QUERY_DESC_IDN_UNIT = 0x2,
|
||||
QUERY_DESC_IDN_RFU_0 = 0x3,
|
||||
QUERY_DESC_IDN_INTERCONNECT = 0x4,
|
||||
QUERY_DESC_IDN_STRING = 0x5,
|
||||
QUERY_DESC_IDN_RFU_1 = 0x6,
|
||||
QUERY_DESC_IDN_GEOMETRY = 0x7,
|
||||
QUERY_DESC_IDN_POWER = 0x8,
|
||||
QUERY_DESC_IDN_HEALTH = 0x9,
|
||||
QUERY_DESC_IDN_RFU_2 = 0xA,
|
||||
QUERY_DESC_IDN_MAX,
|
||||
};
|
||||
|
||||
enum desc_header_offset {
|
||||
QUERY_DESC_LENGTH_OFFSET = 0x00,
|
||||
QUERY_DESC_DESC_TYPE_OFFSET = 0x01,
|
||||
};
|
||||
|
||||
enum ufs_desc_max_size {
|
||||
QUERY_DESC_DEVICE_MAX_SIZE = 0x40,
|
||||
QUERY_DESC_CONFIGURAION_MAX_SIZE = 0x90,
|
||||
QUERY_DESC_UNIT_MAX_SIZE = 0x23,
|
||||
QUERY_DESC_INTERCONNECT_MAX_SIZE = 0x06,
|
||||
/*
|
||||
* Max. 126 UNICODE characters (2 bytes per character) plus 2 bytes
|
||||
* of descriptor header.
|
||||
*/
|
||||
QUERY_DESC_STRING_MAX_SIZE = 0xFE,
|
||||
QUERY_DESC_GEOMETRY_MAZ_SIZE = 0x44,
|
||||
QUERY_DESC_POWER_MAX_SIZE = 0x62,
|
||||
QUERY_DESC_HEALTH_MAX_SIZE = 0x37,
|
||||
QUERY_DESC_RFU_MAX_SIZE = 0x00,
|
||||
};
|
||||
|
||||
/* Unit descriptor parameters offsets in bytes*/
|
||||
enum unit_desc_param {
|
||||
UNIT_DESC_PARAM_LEN = 0x0,
|
||||
UNIT_DESC_PARAM_TYPE = 0x1,
|
||||
UNIT_DESC_PARAM_UNIT_INDEX = 0x2,
|
||||
UNIT_DESC_PARAM_LU_ENABLE = 0x3,
|
||||
UNIT_DESC_PARAM_BOOT_LUN_ID = 0x4,
|
||||
UNIT_DESC_PARAM_LU_WR_PROTECT = 0x5,
|
||||
UNIT_DESC_PARAM_LU_Q_DEPTH = 0x6,
|
||||
UNIT_DESC_PARAM_MEM_TYPE = 0x8,
|
||||
UNIT_DESC_PARAM_DATA_RELIABILITY = 0x9,
|
||||
UNIT_DESC_PARAM_LOGICAL_BLK_SIZE = 0xA,
|
||||
UNIT_DESC_PARAM_LOGICAL_BLK_COUNT = 0xB,
|
||||
UNIT_DESC_PARAM_ERASE_BLK_SIZE = 0x13,
|
||||
UNIT_DESC_PARAM_PROVISIONING_TYPE = 0x17,
|
||||
UNIT_DESC_PARAM_PHY_MEM_RSRC_CNT = 0x18,
|
||||
UNIT_DESC_PARAM_CTX_CAPABILITIES = 0x20,
|
||||
UNIT_DESC_PARAM_LARGE_UNIT_SIZE_M1 = 0x22,
|
||||
};
|
||||
|
||||
/*
|
||||
* Logical Unit Write Protect
|
||||
* 00h: LU not write protected
|
||||
* 01h: LU write protected when fPowerOnWPEn =1
|
||||
* 02h: LU permanently write protected when fPermanentWPEn =1
|
||||
*/
|
||||
enum ufs_lu_wp_type {
|
||||
UFS_LU_NO_WP = 0x00,
|
||||
UFS_LU_POWER_ON_WP = 0x01,
|
||||
UFS_LU_PERM_WP = 0x02,
|
||||
};
|
||||
|
||||
/* bActiveICCLevel parameter current units */
|
||||
enum {
|
||||
UFSHCD_NANO_AMP = 0,
|
||||
UFSHCD_MICRO_AMP = 1,
|
||||
UFSHCD_MILI_AMP = 2,
|
||||
UFSHCD_AMP = 3,
|
||||
};
|
||||
|
||||
#define POWER_DESC_MAX_SIZE 0x62
|
||||
#define POWER_DESC_MAX_ACTV_ICC_LVLS 16
|
||||
|
||||
/* Attribute bActiveICCLevel parameter bit masks definitions */
|
||||
#define ATTR_ICC_LVL_UNIT_OFFSET 14
|
||||
#define ATTR_ICC_LVL_UNIT_MASK (0x3 << ATTR_ICC_LVL_UNIT_OFFSET)
|
||||
#define ATTR_ICC_LVL_VALUE_MASK 0x3FF
|
||||
|
||||
/* Power descriptor parameters offsets in bytes */
|
||||
enum power_desc_param_offset {
|
||||
PWR_DESC_LEN = 0x0,
|
||||
PWR_DESC_TYPE = 0x1,
|
||||
PWR_DESC_ACTIVE_LVLS_VCC_0 = 0x2,
|
||||
PWR_DESC_ACTIVE_LVLS_VCCQ_0 = 0x22,
|
||||
PWR_DESC_ACTIVE_LVLS_VCCQ2_0 = 0x42,
|
||||
};
|
||||
|
||||
/* Exception event mask values */
|
||||
enum {
|
||||
MASK_EE_STATUS = 0xFFFF,
|
||||
MASK_EE_URGENT_BKOPS = (1 << 2),
|
||||
};
|
||||
|
||||
/* Background operation status */
|
||||
enum bkops_status {
|
||||
BKOPS_STATUS_NO_OP = 0x0,
|
||||
BKOPS_STATUS_NON_CRITICAL = 0x1,
|
||||
BKOPS_STATUS_PERF_IMPACT = 0x2,
|
||||
BKOPS_STATUS_CRITICAL = 0x3,
|
||||
BKOPS_STATUS_MAX = BKOPS_STATUS_CRITICAL,
|
||||
};
|
||||
|
||||
/* UTP QUERY Transaction Specific Fields OpCode */
|
||||
enum query_opcode {
|
||||
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,
|
||||
};
|
||||
|
||||
/* Query response result code */
|
||||
enum {
|
||||
QUERY_RESULT_SUCCESS = 0x00,
|
||||
QUERY_RESULT_NOT_READABLE = 0xF6,
|
||||
QUERY_RESULT_NOT_WRITEABLE = 0xF7,
|
||||
QUERY_RESULT_ALREADY_WRITTEN = 0xF8,
|
||||
QUERY_RESULT_INVALID_LENGTH = 0xF9,
|
||||
QUERY_RESULT_INVALID_VALUE = 0xFA,
|
||||
QUERY_RESULT_INVALID_SELECTOR = 0xFB,
|
||||
QUERY_RESULT_INVALID_INDEX = 0xFC,
|
||||
QUERY_RESULT_INVALID_IDN = 0xFD,
|
||||
QUERY_RESULT_INVALID_OPCODE = 0xFE,
|
||||
QUERY_RESULT_GENERAL_FAILURE = 0xFF,
|
||||
};
|
||||
|
||||
/* Device descriptor parameters offsets in bytes*/
|
||||
enum device_desc_param {
|
||||
DEVICE_DESC_PARAM_LEN = 0x0,
|
||||
DEVICE_DESC_PARAM_TYPE = 0x1,
|
||||
DEVICE_DESC_PARAM_DEVICE_TYPE = 0x2,
|
||||
DEVICE_DESC_PARAM_DEVICE_CLASS = 0x3,
|
||||
DEVICE_DESC_PARAM_DEVICE_SUB_CLASS = 0x4,
|
||||
DEVICE_DESC_PARAM_PRTCL = 0x5,
|
||||
DEVICE_DESC_PARAM_NUM_LU = 0x6,
|
||||
DEVICE_DESC_PARAM_NUM_WLU = 0x7,
|
||||
DEVICE_DESC_PARAM_BOOT_ENBL = 0x8,
|
||||
DEVICE_DESC_PARAM_DESC_ACCSS_ENBL = 0x9,
|
||||
DEVICE_DESC_PARAM_INIT_PWR_MODE = 0xA,
|
||||
DEVICE_DESC_PARAM_HIGH_PR_LUN = 0xB,
|
||||
DEVICE_DESC_PARAM_SEC_RMV_TYPE = 0xC,
|
||||
DEVICE_DESC_PARAM_SEC_LU = 0xD,
|
||||
DEVICE_DESC_PARAM_BKOP_TERM_LT = 0xE,
|
||||
DEVICE_DESC_PARAM_ACTVE_ICC_LVL = 0xF,
|
||||
DEVICE_DESC_PARAM_SPEC_VER = 0x10,
|
||||
DEVICE_DESC_PARAM_MANF_DATE = 0x12,
|
||||
DEVICE_DESC_PARAM_MANF_NAME = 0x14,
|
||||
DEVICE_DESC_PARAM_PRDCT_NAME = 0x15,
|
||||
DEVICE_DESC_PARAM_SN = 0x16,
|
||||
DEVICE_DESC_PARAM_OEM_ID = 0x17,
|
||||
DEVICE_DESC_PARAM_MANF_ID = 0x18,
|
||||
DEVICE_DESC_PARAM_UD_OFFSET = 0x1A,
|
||||
DEVICE_DESC_PARAM_UD_LEN = 0x1B,
|
||||
DEVICE_DESC_PARAM_RTT_CAP = 0x1C,
|
||||
DEVICE_DESC_PARAM_FRQ_RTC = 0x1D,
|
||||
};
|
||||
|
||||
enum health_device_desc_param {
|
||||
HEALTH_DEVICE_DESC_PARAM_LEN = 0x0,
|
||||
HEALTH_DEVICE_DESC_PARAM_IDN =0x1,
|
||||
HEALTH_DEVICE_DESC_PARAM_INFO =0x2,
|
||||
HEALTH_DEVICE_DESC_PARAM_LIFETIMEA =0x3,
|
||||
HEALTH_DEVICE_DESC_PARAM_LIFETIMEB =0x4,
|
||||
HEALTH_DEVICE_DESC_PARAM_RESERVED =0x5,
|
||||
};
|
||||
|
||||
/* 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,
|
||||
};
|
||||
|
||||
/* UTP Transfer Request Command Offset */
|
||||
#define UPIU_COMMAND_TYPE_OFFSET 28
|
||||
|
||||
/* Offset of the response code in the UPIU header */
|
||||
#define UPIU_RSP_CODE_OFFSET 8
|
||||
|
||||
enum {
|
||||
MASK_SCSI_STATUS = 0xFF,
|
||||
MASK_TASK_RESPONSE = 0xFF00,
|
||||
MASK_RSP_UPIU_RESULT = 0xFFFF,
|
||||
MASK_QUERY_DATA_SEG_LEN = 0xFFFF,
|
||||
MASK_RSP_UPIU_DATA_SEG_LEN = 0xFFFF,
|
||||
MASK_RSP_EXCEPTION_EVENT = 0x10000,
|
||||
};
|
||||
|
||||
/* Task management service response */
|
||||
enum {
|
||||
UPIU_TASK_MANAGEMENT_FUNC_COMPL = 0x00,
|
||||
UPIU_TASK_MANAGEMENT_FUNC_NOT_SUPPORTED = 0x04,
|
||||
UPIU_TASK_MANAGEMENT_FUNC_SUCCEEDED = 0x08,
|
||||
UPIU_TASK_MANAGEMENT_FUNC_FAILED = 0x05,
|
||||
UPIU_INCORRECT_LOGICAL_UNIT_NO = 0x09,
|
||||
};
|
||||
|
||||
/* UFS device power modes */
|
||||
enum ufs_dev_pwr_mode {
|
||||
UFS_ACTIVE_PWR_MODE = 1,
|
||||
UFS_SLEEP_PWR_MODE = 2,
|
||||
UFS_POWERDOWN_PWR_MODE = 3,
|
||||
};
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
__be32 dword_0;
|
||||
__be32 dword_1;
|
||||
__be32 dword_2;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct utp_upiu_cmd - Command UPIU structure
|
||||
* @data_transfer_len: Data Transfer Length DW-3
|
||||
* @cdb: Command Descriptor Block CDB DW-4 to DW-7
|
||||
*/
|
||||
struct utp_upiu_cmd {
|
||||
__be32 exp_data_transfer_len;
|
||||
u8 cdb[MAX_CDB_SIZE];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct utp_upiu_query - upiu request buffer structure for
|
||||
* query request.
|
||||
* @opcode: command to perform B-0
|
||||
* @idn: a value that indicates the particular type of data B-1
|
||||
* @index: Index to further identify data B-2
|
||||
* @selector: Index to further identify data B-3
|
||||
* @reserved_osf: spec reserved field B-4,5
|
||||
* @length: number of descriptor bytes to read/write B-6,7
|
||||
* @value: Attribute value to be written DW-5
|
||||
* @reserved: spec reserved DW-6,7
|
||||
*/
|
||||
struct utp_upiu_query {
|
||||
u8 opcode;
|
||||
u8 idn;
|
||||
u8 index;
|
||||
u8 selector;
|
||||
__be16 reserved_osf;
|
||||
__be16 length;
|
||||
__be32 value;
|
||||
__be32 reserved[2];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct utp_upiu_req - general upiu request structure
|
||||
* @header:UPIU header structure DW-0 to DW-2
|
||||
* @sc: fields structure for scsi command DW-3 to DW-7
|
||||
* @qr: fields structure for query request DW-3 to DW-7
|
||||
*/
|
||||
struct utp_upiu_req {
|
||||
struct utp_upiu_header header;
|
||||
union {
|
||||
struct utp_upiu_cmd sc;
|
||||
struct utp_upiu_query qr;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* struct utp_cmd_rsp - Response UPIU structure
|
||||
* @residual_transfer_count: Residual transfer count DW-3
|
||||
* @reserved: Reserved double words 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_cmd_rsp {
|
||||
__be32 residual_transfer_count;
|
||||
__be32 reserved[4];
|
||||
__be16 sense_data_len;
|
||||
u8 sense_data[18];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct utp_upiu_rsp - general upiu response structure
|
||||
* @header: UPIU header structure DW-0 to DW-2
|
||||
* @sr: fields structure for scsi command DW-3 to DW-12
|
||||
* @qr: fields structure for query request DW-3 to DW-7
|
||||
*/
|
||||
struct utp_upiu_rsp {
|
||||
struct utp_upiu_header header;
|
||||
union {
|
||||
struct utp_cmd_rsp sr;
|
||||
struct utp_upiu_query qr;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* struct utp_upiu_task_req - Task request UPIU structure
|
||||
* @header - UPIU header structure DW0 to DW-2
|
||||
* @input_param1: Input parameter 1 DW-3
|
||||
* @input_param2: Input parameter 2 DW-4
|
||||
* @input_param3: Input parameter 3 DW-5
|
||||
* @reserved: Reserved double words DW-6 to DW-7
|
||||
*/
|
||||
struct utp_upiu_task_req {
|
||||
struct utp_upiu_header header;
|
||||
__be32 input_param1;
|
||||
__be32 input_param2;
|
||||
__be32 input_param3;
|
||||
__be32 reserved[2];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct utp_upiu_task_rsp - Task Management Response UPIU structure
|
||||
* @header: UPIU header structure DW0-DW-2
|
||||
* @output_param1: Ouput parameter 1 DW3
|
||||
* @output_param2: Output parameter 2 DW4
|
||||
* @reserved: Reserved double words DW-5 to DW-7
|
||||
*/
|
||||
struct utp_upiu_task_rsp {
|
||||
struct utp_upiu_header header;
|
||||
__be32 output_param1;
|
||||
__be32 output_param2;
|
||||
__be32 reserved[3];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ufs_query_req - parameters for building a query request
|
||||
* @query_func: UPIU header query function
|
||||
* @upiu_req: the query request data
|
||||
*/
|
||||
struct ufs_query_req {
|
||||
u8 query_func;
|
||||
struct utp_upiu_query upiu_req;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ufs_query_resp - UPIU QUERY
|
||||
* @response: device response code
|
||||
* @upiu_res: query response data
|
||||
*/
|
||||
struct ufs_query_res {
|
||||
u8 response;
|
||||
struct utp_upiu_query upiu_res;
|
||||
};
|
||||
|
||||
#define UFS_VREG_VCC_MIN_UV 2700000 /* uV */
|
||||
#define UFS_VREG_VCC_MAX_UV 3600000 /* uV */
|
||||
#define UFS_VREG_VCC_1P8_MIN_UV 1700000 /* uV */
|
||||
#define UFS_VREG_VCC_1P8_MAX_UV 1950000 /* uV */
|
||||
#define UFS_VREG_VCCQ_MIN_UV 1100000 /* uV */
|
||||
#define UFS_VREG_VCCQ_MAX_UV 1300000 /* uV */
|
||||
#define UFS_VREG_VCCQ2_MIN_UV 1650000 /* uV */
|
||||
#define UFS_VREG_VCCQ2_MAX_UV 1950000 /* uV */
|
||||
|
||||
/*
|
||||
* VCCQ & VCCQ2 current requirement when UFS device is in sleep state
|
||||
* and link is in Hibern8 state.
|
||||
*/
|
||||
#define UFS_VREG_LPM_LOAD_UA 1000 /* uA */
|
||||
|
||||
struct ufs_vreg {
|
||||
struct regulator *reg;
|
||||
const char *name;
|
||||
bool enabled;
|
||||
int min_uV;
|
||||
int max_uV;
|
||||
int min_uA;
|
||||
int max_uA;
|
||||
};
|
||||
|
||||
struct ufs_vreg_info {
|
||||
struct ufs_vreg *vcc;
|
||||
struct ufs_vreg *vccq;
|
||||
struct ufs_vreg *vccq2;
|
||||
struct ufs_vreg *vdd_hba;
|
||||
};
|
||||
|
||||
struct ufs_dev_info {
|
||||
bool f_power_on_wp_en;
|
||||
/* Keeps information if any of the LU is power on write protected */
|
||||
bool is_lu_power_on_wp;
|
||||
};
|
||||
|
||||
#endif /* End of Header */
|
138
drivers/scsi/ufs/ufs_quirks.c
Normal file
138
drivers/scsi/ufs/ufs_quirks.c
Normal file
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "ufshcd.h"
|
||||
#include "ufs_quirks.h"
|
||||
|
||||
#ifndef UFS_VENDOR_ID_SAMSUNG
|
||||
#define UFS_VENDOR_ID_SAMSUNG 0x1ce
|
||||
#endif
|
||||
|
||||
static struct ufs_card_fix ufs_fixups[] = {
|
||||
/* UFS cards deviations table */
|
||||
UFS_FIX(UFS_VENDOR_ID_SAMSUNG, UFS_ANY_MODEL, UFS_DEVICE_QUIRK_BROKEN_LINEREST),
|
||||
END_FIX
|
||||
};
|
||||
|
||||
int ufs_get_device_info(struct ufs_hba *hba, struct ufs_card_info *card_data)
|
||||
{
|
||||
int err;
|
||||
u8 model_index;
|
||||
u8 serial_num_index;
|
||||
u8 serial_num_buf[6]; /* samsung spec : use only 6 bytes of serial number string descriptor */
|
||||
u8 str_desc_buf[QUERY_DESC_STRING_MAX_SIZE + 1];
|
||||
u8 desc_buf[QUERY_DESC_DEVICE_MAX_SIZE];
|
||||
u8 health_buf[QUERY_DESC_HEALTH_MAX_SIZE];
|
||||
bool ascii_type;
|
||||
|
||||
err = ufshcd_read_device_desc(hba, desc_buf,
|
||||
QUERY_DESC_DEVICE_MAX_SIZE);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
err = ufshcd_read_health_desc(hba, health_buf,
|
||||
QUERY_DESC_HEALTH_MAX_SIZE);
|
||||
if (err)
|
||||
printk("%s: DEVICE_HEALTH desc read fail, err = %d\n", __FUNCTION__, err);
|
||||
|
||||
/* getting Life Time at Device Health DESC*/
|
||||
card_data->lifetime = health_buf[HEALTH_DEVICE_DESC_PARAM_LIFETIMEA];
|
||||
|
||||
/*
|
||||
* getting vendor (manufacturerID) and Bank Index in big endian
|
||||
* format
|
||||
*/
|
||||
card_data->wmanufacturerid = desc_buf[DEVICE_DESC_PARAM_MANF_ID] << 8 |
|
||||
desc_buf[DEVICE_DESC_PARAM_MANF_ID + 1];
|
||||
|
||||
hba->manufacturer_id = card_data->wmanufacturerid;
|
||||
hba->lifetime = card_data->lifetime;
|
||||
|
||||
model_index = desc_buf[DEVICE_DESC_PARAM_PRDCT_NAME];
|
||||
|
||||
memset(str_desc_buf, 0, QUERY_DESC_STRING_MAX_SIZE);
|
||||
err = ufshcd_read_string_desc(hba, model_index, str_desc_buf,
|
||||
QUERY_DESC_STRING_MAX_SIZE, ASCII_STD);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
str_desc_buf[QUERY_DESC_STRING_MAX_SIZE] = '\0';
|
||||
strlcpy(card_data->model, (str_desc_buf + QUERY_DESC_HDR_SIZE),
|
||||
min_t(u8, str_desc_buf[QUERY_DESC_LENGTH_OFFSET],
|
||||
MAX_MODEL_LEN));
|
||||
/* Null terminate the model string */
|
||||
card_data->model[MAX_MODEL_LEN] = '\0';
|
||||
|
||||
/* make unique id with MANUFACTURE DATE & SERIAL NUMBER */
|
||||
serial_num_index = desc_buf[DEVICE_DESC_PARAM_SN];
|
||||
memset(str_desc_buf, 0, QUERY_DESC_STRING_MAX_SIZE);
|
||||
|
||||
/*Samsung device use UTF16*/
|
||||
if (hba->manufacturer_id == 0x1CE)
|
||||
ascii_type = UTF16_STD;
|
||||
else
|
||||
ascii_type = ASCII_STD;
|
||||
|
||||
err = ufshcd_read_string_desc(hba, serial_num_index, str_desc_buf,
|
||||
QUERY_DESC_STRING_MAX_SIZE, ascii_type);
|
||||
|
||||
if (err)
|
||||
goto out;
|
||||
str_desc_buf[QUERY_DESC_STRING_MAX_SIZE] = '\0';
|
||||
|
||||
memset(serial_num_buf, 0, sizeof(serial_num_buf));
|
||||
memcpy(serial_num_buf, str_desc_buf + QUERY_DESC_HDR_SIZE, sizeof(serial_num_buf));
|
||||
|
||||
memset(hba->unique_number, 0, sizeof(hba->unique_number));
|
||||
sprintf(hba->unique_number, "%02x%02x%02x%02x%02x%02x%02x%02x", desc_buf[DEVICE_DESC_PARAM_MANF_DATE], desc_buf[DEVICE_DESC_PARAM_MANF_DATE+1], serial_num_buf[0], serial_num_buf[1], serial_num_buf[2], serial_num_buf[3], serial_num_buf[4], serial_num_buf[5]);
|
||||
|
||||
/* Null terminate the unique number string */
|
||||
hba->unique_number[UFS_UNIQUE_NUMBER_LEN - 1] = '\0';
|
||||
|
||||
printk("%s: UNIQUE NUMBER = %s , Lifetime: 0x%02x \n", __FUNCTION__, hba->unique_number, health_buf[3]<<4|health_buf[4]);
|
||||
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
void ufs_advertise_fixup_device(struct ufs_hba *hba)
|
||||
{
|
||||
int err;
|
||||
struct ufs_card_fix *f;
|
||||
struct ufs_card_info card_data;
|
||||
|
||||
card_data.wmanufacturerid = 0;
|
||||
card_data.model = kmalloc(MAX_MODEL_LEN + 1, GFP_KERNEL);
|
||||
if (!card_data.model)
|
||||
goto out;
|
||||
|
||||
/* get device data*/
|
||||
err = ufs_get_device_info(hba, &card_data);
|
||||
if (err) {
|
||||
dev_err(hba->dev, "%s: Failed getting device info\n", __func__);
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (f = ufs_fixups; f->quirk; f++) {
|
||||
/* if same wmanufacturerid */
|
||||
if (((f->card.wmanufacturerid == card_data.wmanufacturerid) ||
|
||||
(f->card.wmanufacturerid == UFS_ANY_VENDOR)) &&
|
||||
/* and same model */
|
||||
(STR_PRFX_EQUAL(f->card.model, card_data.model) ||
|
||||
!strcmp(f->card.model, UFS_ANY_MODEL)))
|
||||
/* update quirks */
|
||||
hba->dev_quirks |= f->quirk;
|
||||
}
|
||||
out:
|
||||
kfree(card_data.model);
|
||||
}
|
73
drivers/scsi/ufs/ufs_quirks.h
Normal file
73
drivers/scsi/ufs/ufs_quirks.h
Normal file
|
@ -0,0 +1,73 @@
|
|||
/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _UFS_QUIRKS_H_
|
||||
#define _UFS_QUIRKS_H_
|
||||
|
||||
/* return true if s1 is a prefix of s2 */
|
||||
#define STR_PRFX_EQUAL(s1, s2) !strncmp(s1, s2, strlen(s1))
|
||||
|
||||
#define UFS_ANY_VENDOR 0xffff
|
||||
#define UFS_ANY_MODEL "ANY_MODEL"
|
||||
|
||||
#define MAX_MODEL_LEN 16
|
||||
|
||||
#define UFS_VENDOR_TOSHIBA 0x98
|
||||
/* UFS TOSHIBA MODELS */
|
||||
#define UFS_MODEL_TOSHIBA_32GB "THGLF2G8D4KBADR"
|
||||
#define UFS_MODEL_TOSHIBA_64GB "THGLF2G9D8KBADG"
|
||||
|
||||
/**
|
||||
* ufs_card_info - ufs device details
|
||||
* @wmanufacturerid: card details
|
||||
* @model: card model
|
||||
*/
|
||||
struct ufs_card_info {
|
||||
u16 wmanufacturerid;
|
||||
u8 lifetime;
|
||||
char *model;
|
||||
};
|
||||
|
||||
/**
|
||||
* ufs_card_fix - ufs device quirk info
|
||||
* @card: ufs card details
|
||||
* @quirk: device quirk
|
||||
*/
|
||||
struct ufs_card_fix {
|
||||
struct ufs_card_info card;
|
||||
unsigned int quirk;
|
||||
};
|
||||
|
||||
#define END_FIX { { 0 } , 0 }
|
||||
|
||||
/* add specific device quirk */
|
||||
#define UFS_FIX(_vendor, _model, _quirk) \
|
||||
{ \
|
||||
.card.wmanufacturerid = (_vendor),\
|
||||
.card.model = (_model), \
|
||||
.quirk = (_quirk), \
|
||||
}
|
||||
|
||||
/*
|
||||
* If UFS device is having issue in processing LCC (Line Control
|
||||
* Command) coming from UFS host controller then enable this quirk.
|
||||
* When this quirk is enabled, host controller driver should disable
|
||||
* the LCC transmission on UFS host controller (by clearing
|
||||
* TX_LCC_ENABLE attribute of host to 0).
|
||||
*/
|
||||
#define UFS_DEVICE_QUIRK_BROKEN_LCC UFS_BIT(0)
|
||||
#define UFS_DEVICE_QUIRK_BROKEN_LINEREST UFS_BIT(1)
|
||||
|
||||
struct ufs_hba;
|
||||
void ufs_advertise_fixup_device(struct ufs_hba *hba);
|
||||
#endif /* UFS_QUIRKS_H_ */
|
198
drivers/scsi/ufs/ufshcd-pci.c
Normal file
198
drivers/scsi/ufs/ufshcd-pci.c
Normal file
|
@ -0,0 +1,198 @@
|
|||
/*
|
||||
* Universal Flash Storage Host controller PCI glue driver
|
||||
*
|
||||
* This code is based on drivers/scsi/ufs/ufshcd-pci.c
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "ufshcd.h"
|
||||
#include <linux/pci.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
/**
|
||||
* ufshcd_pci_suspend - suspend power management function
|
||||
* @pdev: pointer to PCI device handle
|
||||
* @state: power state
|
||||
*
|
||||
* Returns 0 if successful
|
||||
* Returns non-zero otherwise
|
||||
*/
|
||||
static int ufshcd_pci_suspend(struct device *dev)
|
||||
{
|
||||
return ufshcd_system_suspend(dev_get_drvdata(dev));
|
||||
}
|
||||
|
||||
/**
|
||||
* ufshcd_pci_resume - resume power management function
|
||||
* @pdev: pointer to PCI device handle
|
||||
*
|
||||
* Returns 0 if successful
|
||||
* Returns non-zero otherwise
|
||||
*/
|
||||
static int ufshcd_pci_resume(struct device *dev)
|
||||
{
|
||||
return ufshcd_system_resume(dev_get_drvdata(dev));
|
||||
}
|
||||
#else
|
||||
#define ufshcd_pci_suspend NULL
|
||||
#define ufshcd_pci_resume NULL
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
#ifdef CONFIG_PM_RUNTIME
|
||||
static int ufshcd_pci_runtime_suspend(struct device *dev)
|
||||
{
|
||||
return ufshcd_runtime_suspend(dev_get_drvdata(dev));
|
||||
}
|
||||
static int ufshcd_pci_runtime_resume(struct device *dev)
|
||||
{
|
||||
return ufshcd_runtime_resume(dev_get_drvdata(dev));
|
||||
}
|
||||
static int ufshcd_pci_runtime_idle(struct device *dev)
|
||||
{
|
||||
return ufshcd_runtime_idle(dev_get_drvdata(dev));
|
||||
}
|
||||
#else /* !CONFIG_PM_RUNTIME */
|
||||
#define ufshcd_pci_runtime_suspend NULL
|
||||
#define ufshcd_pci_runtime_resume NULL
|
||||
#define ufshcd_pci_runtime_idle NULL
|
||||
#endif /* CONFIG_PM_RUNTIME */
|
||||
|
||||
/**
|
||||
* ufshcd_pci_shutdown - main function to put the controller in reset state
|
||||
* @pdev: pointer to PCI device handle
|
||||
*/
|
||||
static void ufshcd_pci_shutdown(struct pci_dev *pdev)
|
||||
{
|
||||
ufshcd_shutdown((struct ufs_hba *)pci_get_drvdata(pdev));
|
||||
}
|
||||
|
||||
/**
|
||||
* ufshcd_pci_remove - de-allocate PCI/SCSI host and host memory space
|
||||
* data structure memory
|
||||
* @pdev - pointer to PCI handle
|
||||
*/
|
||||
static void ufshcd_pci_remove(struct pci_dev *pdev)
|
||||
{
|
||||
struct ufs_hba *hba = pci_get_drvdata(pdev);
|
||||
|
||||
pm_runtime_forbid(&pdev->dev);
|
||||
pm_runtime_get_noresume(&pdev->dev);
|
||||
|
||||
disable_irq(pdev->irq);
|
||||
ufshcd_remove(hba);
|
||||
pci_set_drvdata(pdev, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* ufshcd_pci_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
|
||||
ufshcd_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
{
|
||||
struct ufs_hba *hba;
|
||||
void __iomem *mmio_base;
|
||||
int err;
|
||||
|
||||
err = pcim_enable_device(pdev);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "pcim_enable_device failed\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
pci_set_master(pdev);
|
||||
|
||||
err = pcim_iomap_regions(pdev, 1 << 0, UFSHCD);
|
||||
if (err < 0) {
|
||||
dev_err(&pdev->dev, "request and iomap failed\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
mmio_base = pcim_iomap_table(pdev)[0];
|
||||
|
||||
err = ufshcd_alloc_host(&pdev->dev, &hba);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "Allocation failed\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&hba->clk_list_head);
|
||||
|
||||
err = ufshcd_init(hba, mmio_base, pdev->irq);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "Initialization failed\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
pci_set_drvdata(pdev, hba);
|
||||
pm_runtime_put_noidle(&pdev->dev);
|
||||
pm_runtime_allow(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops ufshcd_pci_pm_ops = {
|
||||
.suspend = ufshcd_pci_suspend,
|
||||
.resume = ufshcd_pci_resume,
|
||||
.runtime_suspend = ufshcd_pci_runtime_suspend,
|
||||
.runtime_resume = ufshcd_pci_runtime_resume,
|
||||
.runtime_idle = ufshcd_pci_runtime_idle,
|
||||
};
|
||||
|
||||
static DEFINE_PCI_DEVICE_TABLE(ufshcd_pci_tbl) = {
|
||||
{ PCI_VENDOR_ID_SAMSUNG, 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_pci_probe,
|
||||
.remove = ufshcd_pci_remove,
|
||||
.shutdown = ufshcd_pci_shutdown,
|
||||
.driver = {
|
||||
.pm = &ufshcd_pci_pm_ops
|
||||
},
|
||||
};
|
||||
|
||||
module_pci_driver(ufshcd_pci_driver);
|
||||
|
||||
MODULE_AUTHOR("Santosh Yaragnavi <santosh.sy@samsung.com>");
|
||||
MODULE_AUTHOR("Vinayak Holikatti <h.vinayak@samsung.com>");
|
||||
MODULE_DESCRIPTION("UFS host controller PCI glue driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION(UFSHCD_DRIVER_VERSION);
|
491
drivers/scsi/ufs/ufshcd-pltfrm.c
Normal file
491
drivers/scsi/ufs/ufshcd-pltfrm.c
Normal file
|
@ -0,0 +1,491 @@
|
|||
/*
|
||||
* Universal Flash Storage Host controller Platform bus based glue driver
|
||||
*
|
||||
* This code is based on drivers/scsi/ufs/ufshcd-pltfrm.c
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#include "ufshcd.h"
|
||||
#include "ufshcd-pltfrm.h"
|
||||
|
||||
static const struct of_device_id ufs_of_match[];
|
||||
static struct ufs_hba_variant *get_variant(struct device *dev)
|
||||
{
|
||||
if (dev->of_node) {
|
||||
const struct of_device_id *match;
|
||||
|
||||
match = of_match_node(ufs_of_match, dev->of_node);
|
||||
if (match)
|
||||
return (struct ufs_hba_variant *)match->data;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int ufshcd_parse_clock_info(struct ufs_hba *hba)
|
||||
{
|
||||
int ret = 0;
|
||||
int cnt;
|
||||
int i;
|
||||
struct device *dev = hba->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
char *name;
|
||||
u32 *clkfreq = NULL;
|
||||
struct ufs_clk_info *clki;
|
||||
int len = 0;
|
||||
size_t sz = 0;
|
||||
|
||||
if (!np)
|
||||
goto out;
|
||||
|
||||
INIT_LIST_HEAD(&hba->clk_list_head);
|
||||
|
||||
cnt = of_property_count_strings(np, "clock-names");
|
||||
if (!cnt || (cnt == -EINVAL)) {
|
||||
dev_info(dev, "%s: Unable to find clocks, assuming enabled\n",
|
||||
__func__);
|
||||
} else if (cnt < 0) {
|
||||
dev_err(dev, "%s: count clock strings failed, err %d\n",
|
||||
__func__, cnt);
|
||||
ret = cnt;
|
||||
}
|
||||
|
||||
if (cnt <= 0)
|
||||
goto out;
|
||||
|
||||
if (!of_get_property(np, "freq-table-hz", &len)) {
|
||||
dev_info(dev, "freq-table-hz property not specified\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (len <= 0)
|
||||
goto out;
|
||||
|
||||
sz = len / sizeof(*clkfreq);
|
||||
if (sz != 2 * cnt) {
|
||||
dev_err(dev, "%s len mismatch\n", "freq-table-hz");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
clkfreq = devm_kzalloc(dev, sz * sizeof(*clkfreq),
|
||||
GFP_KERNEL);
|
||||
if (!clkfreq) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32_array(np, "freq-table-hz",
|
||||
clkfreq, sz);
|
||||
if (ret && (ret != -EINVAL)) {
|
||||
dev_err(dev, "%s: error reading array %d\n",
|
||||
"freq-table-hz", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i = 0; i < sz; i += 2) {
|
||||
ret = of_property_read_string_index(np,
|
||||
"clock-names", i/2, (const char **)&name);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
clki = devm_kzalloc(dev, sizeof(*clki), GFP_KERNEL);
|
||||
if (!clki) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
clki->min_freq = clkfreq[i];
|
||||
clki->max_freq = clkfreq[i+1];
|
||||
clki->name = kstrdup(name, GFP_KERNEL);
|
||||
dev_dbg(dev, "%s: min %u max %u name %s\n", "freq-table-hz",
|
||||
clki->min_freq, clki->max_freq, clki->name);
|
||||
list_add_tail(&clki->list, &hba->clk_list_head);
|
||||
}
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define MAX_PROP_SIZE 32
|
||||
static int ufshcd_populate_vreg(struct device *dev, const char *name,
|
||||
struct ufs_vreg **out_vreg)
|
||||
{
|
||||
int ret = 0;
|
||||
char prop_name[MAX_PROP_SIZE];
|
||||
struct ufs_vreg *vreg = NULL;
|
||||
struct device_node *np = dev->of_node;
|
||||
|
||||
if (!np) {
|
||||
dev_err(dev, "%s: non DT initialization\n", __func__);
|
||||
goto out;
|
||||
}
|
||||
|
||||
snprintf(prop_name, MAX_PROP_SIZE, "%s-supply", name);
|
||||
if (!of_parse_phandle(np, prop_name, 0)) {
|
||||
dev_info(dev, "%s: Unable to find %s regulator, assuming enabled\n",
|
||||
__func__, prop_name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL);
|
||||
if (!vreg)
|
||||
return -ENOMEM;
|
||||
|
||||
vreg->name = kstrdup(name, GFP_KERNEL);
|
||||
|
||||
/* if fixed regulator no need further initialization */
|
||||
snprintf(prop_name, MAX_PROP_SIZE, "%s-fixed-regulator", name);
|
||||
if (of_property_read_bool(np, prop_name))
|
||||
goto out;
|
||||
|
||||
snprintf(prop_name, MAX_PROP_SIZE, "%s-max-microamp", name);
|
||||
ret = of_property_read_u32(np, prop_name, &vreg->max_uA);
|
||||
if (ret) {
|
||||
dev_err(dev, "%s: unable to find %s err %d\n",
|
||||
__func__, prop_name, ret);
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
vreg->min_uA = 0;
|
||||
if (!strcmp(name, "vcc")) {
|
||||
if (of_property_read_bool(np, "vcc-supply-1p8")) {
|
||||
vreg->min_uV = UFS_VREG_VCC_1P8_MIN_UV;
|
||||
vreg->max_uV = UFS_VREG_VCC_1P8_MAX_UV;
|
||||
} else {
|
||||
vreg->min_uV = UFS_VREG_VCC_MIN_UV;
|
||||
vreg->max_uV = UFS_VREG_VCC_MAX_UV;
|
||||
}
|
||||
} else if (!strcmp(name, "vccq")) {
|
||||
vreg->min_uV = UFS_VREG_VCCQ_MIN_UV;
|
||||
vreg->max_uV = UFS_VREG_VCCQ_MAX_UV;
|
||||
} else if (!strcmp(name, "vccq2")) {
|
||||
vreg->min_uV = UFS_VREG_VCCQ2_MIN_UV;
|
||||
vreg->max_uV = UFS_VREG_VCCQ2_MAX_UV;
|
||||
}
|
||||
|
||||
goto out;
|
||||
|
||||
out_free:
|
||||
devm_kfree(dev, vreg);
|
||||
vreg = NULL;
|
||||
out:
|
||||
if (!ret)
|
||||
*out_vreg = vreg;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ufshcd_parse_regulator_info - get regulator info from device tree
|
||||
* @hba: per adapter instance
|
||||
*
|
||||
* Get regulator info from device tree for vcc, vccq, vccq2 power supplies.
|
||||
* If any of the supplies are not defined it is assumed that they are always-on
|
||||
* and hence return zero. If the property is defined but parsing is failed
|
||||
* then return corresponding error.
|
||||
*/
|
||||
static int ufshcd_parse_regulator_info(struct ufs_hba *hba)
|
||||
{
|
||||
int err;
|
||||
struct device *dev = hba->dev;
|
||||
struct ufs_vreg_info *info = &hba->vreg_info;
|
||||
|
||||
err = ufshcd_populate_vreg(dev, "vdd-hba", &info->vdd_hba);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
err = ufshcd_populate_vreg(dev, "vcc", &info->vcc);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
err = ufshcd_populate_vreg(dev, "vccq", &info->vccq);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
err = ufshcd_populate_vreg(dev, "vccq2", &info->vccq2);
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ufshcd_parse_pm_lvl_policy(struct ufs_hba *hba)
|
||||
{
|
||||
struct device *dev = hba->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
u32 lvl_def[] = {UFS_PM_LVL_2, UFS_PM_LVL_5};
|
||||
u32 lvl[2], i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(lvl); i++) {
|
||||
if (of_property_read_u32_index(np, "pm_lvl_states", i, lvl +i)) {
|
||||
dev_info(hba->dev,
|
||||
"UFS power management: set default level%d index %d\n",
|
||||
lvl_def[i], i);
|
||||
lvl[i] = lvl_def[i];
|
||||
}
|
||||
|
||||
if (lvl[i] < UFS_PM_LVL_0 || lvl[i] >= UFS_PM_LVL_MAX) {
|
||||
dev_warn(hba->dev,
|
||||
"UFS power management: out of range level%d index %d\n",
|
||||
lvl[i], i);
|
||||
lvl[i] = lvl_def[i];
|
||||
}
|
||||
}
|
||||
|
||||
hba->rpm_lvl = lvl[0];
|
||||
hba->spm_lvl = lvl[1];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ufshcd_parse_caps_info(struct ufs_hba *hba)
|
||||
{
|
||||
struct device *dev = hba->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
|
||||
if (of_find_property(np, "ufs-cap-clk-gating", NULL))
|
||||
hba->caps |= UFSHCD_CAP_CLK_GATING;
|
||||
if (of_find_property(np, "ufs-cap-hibern8-with-clk-gating", NULL))
|
||||
hba->caps |= UFSHCD_CAP_HIBERN8_WITH_CLK_GATING;
|
||||
if (of_find_property(np, "ufs-cap-clk-scaling", NULL))
|
||||
hba->caps |= UFSHCD_CAP_CLK_SCALING;
|
||||
if (of_find_property(np, "ufs-cap-auto-bkops-suspend", NULL))
|
||||
hba->caps |= UFSHCD_CAP_AUTO_BKOPS_SUSPEND;
|
||||
if (of_find_property(np, "ufs-cap-fake-clk-gating", NULL))
|
||||
hba->caps |= UFSHCD_CAP_FAKE_CLK_GATING;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
/**
|
||||
* ufshcd_pltfrm_suspend - suspend power management function
|
||||
* @dev: pointer to device handle
|
||||
*
|
||||
* Returns 0 if successful
|
||||
* Returns non-zero otherwise
|
||||
*/
|
||||
static int ufshcd_pltfrm_suspend(struct device *dev)
|
||||
{
|
||||
return ufshcd_system_suspend(dev_get_drvdata(dev));
|
||||
}
|
||||
|
||||
/**
|
||||
* ufshcd_pltfrm_resume - resume power management function
|
||||
* @dev: pointer to device handle
|
||||
*
|
||||
* Returns 0 if successful
|
||||
* Returns non-zero otherwise
|
||||
*/
|
||||
static int ufshcd_pltfrm_resume(struct device *dev)
|
||||
{
|
||||
return ufshcd_system_resume(dev_get_drvdata(dev));
|
||||
}
|
||||
#else
|
||||
#define ufshcd_pltfrm_suspend NULL
|
||||
#define ufshcd_pltfrm_resume NULL
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PM_RUNTIME
|
||||
static int ufshcd_pltfrm_runtime_suspend(struct device *dev)
|
||||
{
|
||||
return ufshcd_runtime_suspend(dev_get_drvdata(dev));
|
||||
}
|
||||
static int ufshcd_pltfrm_runtime_resume(struct device *dev)
|
||||
{
|
||||
return ufshcd_runtime_resume(dev_get_drvdata(dev));
|
||||
}
|
||||
static int ufshcd_pltfrm_runtime_idle(struct device *dev)
|
||||
{
|
||||
return ufshcd_runtime_idle(dev_get_drvdata(dev));
|
||||
}
|
||||
#else /* !CONFIG_PM_RUNTIME */
|
||||
#define ufshcd_pltfrm_runtime_suspend NULL
|
||||
#define ufshcd_pltfrm_runtime_resume NULL
|
||||
#define ufshcd_pltfrm_runtime_idle NULL
|
||||
#endif /* CONFIG_PM_RUNTIME */
|
||||
|
||||
static void ufshcd_pltfrm_shutdown(struct platform_device *pdev)
|
||||
{
|
||||
ufshcd_shutdown((struct ufs_hba *)platform_get_drvdata(pdev));
|
||||
}
|
||||
|
||||
/**
|
||||
* ufshcd_pltfrm_init - initialize common routine of the driver
|
||||
* @pdev: pointer to Platform device handle
|
||||
*
|
||||
* Returns 0 on success, non-zero value on failure
|
||||
*/
|
||||
int ufshcd_pltfrm_init(struct platform_device *pdev,
|
||||
const struct ufs_hba_variant *var)
|
||||
{
|
||||
struct ufs_hba *hba;
|
||||
void __iomem *mmio_base;
|
||||
struct resource *mem_res;
|
||||
int irq, err;
|
||||
struct device *dev = &pdev->dev;
|
||||
const struct ufs_hba_variant *_var;
|
||||
|
||||
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
mmio_base = devm_ioremap_resource(dev, mem_res);
|
||||
if (IS_ERR(*(void **)&mmio_base)) {
|
||||
err = PTR_ERR(*(void **)&mmio_base);
|
||||
goto out;
|
||||
}
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(dev, "IRQ resource not available\n");
|
||||
err = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = ufshcd_alloc_host(dev, &hba);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "Allocation failed\n");
|
||||
goto out;
|
||||
}
|
||||
_var = (var != NULL) ? var : get_variant(&pdev->dev);
|
||||
if (_var) {
|
||||
hba->vops = _var->ops;
|
||||
hba->quirks= _var->quirks;
|
||||
}
|
||||
|
||||
err = ufshcd_parse_clock_info(hba);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "%s: clock parse failed %d\n",
|
||||
__func__, err);
|
||||
goto out;
|
||||
}
|
||||
err = ufshcd_parse_regulator_info(hba);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "%s: regulator init failed %d\n",
|
||||
__func__, err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ufshcd_parse_pm_lvl_policy(hba);
|
||||
ufshcd_parse_caps_info(hba);
|
||||
|
||||
pm_runtime_set_active(&pdev->dev);
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
err = ufshcd_init(hba, mmio_base, irq);
|
||||
if (err) {
|
||||
dev_err(dev, "Intialization failed\n");
|
||||
goto out_disable_rpm;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, hba);
|
||||
|
||||
return 0;
|
||||
|
||||
out_disable_rpm:
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
pm_runtime_set_suspended(&pdev->dev);
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ufshcd_pltfrm_init);
|
||||
|
||||
/**
|
||||
* ufshcd_pltfrm_exit - exit common routine for platform driver
|
||||
* @pdev: pointer to platform device handle
|
||||
*/
|
||||
void ufshcd_pltfrm_exit(struct platform_device *pdev)
|
||||
{
|
||||
struct ufs_hba *hba = platform_get_drvdata(pdev);
|
||||
|
||||
ufshcd_remove(hba);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ufshcd_pltfrm_exit);
|
||||
|
||||
/**
|
||||
* ufshcd_pltfrm_probe - probe routine of the platform driver
|
||||
* @pdev: pointer to Platform device handle
|
||||
*
|
||||
* Returns 0 on success, non-zero value on failure
|
||||
*/
|
||||
static int ufshcd_pltfrm_probe(struct platform_device *pdev)
|
||||
{
|
||||
return ufshcd_pltfrm_init(pdev, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* ufshcd_pltfrm_remove - remove platform driver routine
|
||||
* @pdev: pointer to platform device handle
|
||||
*
|
||||
* Returns 0 on success, non-zero value on failure
|
||||
*/
|
||||
static int ufshcd_pltfrm_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ufs_hba *hba = platform_get_drvdata(pdev);
|
||||
|
||||
pm_runtime_get_sync(&(pdev)->dev);
|
||||
|
||||
disable_irq(hba->irq);
|
||||
ufshcd_remove(hba);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id ufs_of_match[] = {
|
||||
{ .compatible = "jedec,ufs-1.1"},
|
||||
{},
|
||||
};
|
||||
|
||||
static const struct dev_pm_ops ufshcd_dev_pm_ops = {
|
||||
.suspend = ufshcd_pltfrm_suspend,
|
||||
.resume = ufshcd_pltfrm_resume,
|
||||
.runtime_suspend = ufshcd_pltfrm_runtime_suspend,
|
||||
.runtime_resume = ufshcd_pltfrm_runtime_resume,
|
||||
.runtime_idle = ufshcd_pltfrm_runtime_idle,
|
||||
};
|
||||
|
||||
static struct platform_driver ufshcd_pltfrm_driver = {
|
||||
.probe = ufshcd_pltfrm_probe,
|
||||
.remove = ufshcd_pltfrm_remove,
|
||||
.shutdown = ufshcd_pltfrm_shutdown,
|
||||
.driver = {
|
||||
.name = "ufshcd",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &ufshcd_dev_pm_ops,
|
||||
.of_match_table = ufs_of_match,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(ufshcd_pltfrm_driver);
|
||||
|
||||
MODULE_AUTHOR("Santosh Yaragnavi <santosh.sy@samsung.com>");
|
||||
MODULE_AUTHOR("Vinayak Holikatti <h.vinayak@samsung.com>");
|
||||
MODULE_DESCRIPTION("UFS host controller Pltform bus based glue driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION(UFSHCD_DRIVER_VERSION);
|
19
drivers/scsi/ufs/ufshcd-pltfrm.h
Normal file
19
drivers/scsi/ufs/ufshcd-pltfrm.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Universal Flash Storage Host controller Platform bus based glue driver
|
||||
*
|
||||
* Copyright (C) 2013, Samsung Electronics Co., Ltd.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _UFSHCD_PLTFRM_H_
|
||||
#define _UFSHCD_PLTFRM_H_
|
||||
|
||||
extern int ufshcd_pltfrm_init(struct platform_device *pdev,
|
||||
const struct ufs_hba_variant *var);
|
||||
extern void ufshcd_pltfrm_exit(struct platform_device *pdev);
|
||||
|
||||
#endif /* _UFSHCD_PLTFRM_H_ */
|
6407
drivers/scsi/ufs/ufshcd.c
Normal file
6407
drivers/scsi/ufs/ufshcd.c
Normal file
File diff suppressed because it is too large
Load diff
689
drivers/scsi/ufs/ufshcd.h
Normal file
689
drivers/scsi/ufs/ufshcd.h
Normal file
|
@ -0,0 +1,689 @@
|
|||
/*
|
||||
* 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>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/jiffies.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_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"
|
||||
|
||||
struct ufs_hba;
|
||||
|
||||
|
||||
#define UFS_UNIQUE_NUMBER_LEN 17 /* manufacturer date 4 bytes + serial number 12 bytes + null */
|
||||
|
||||
struct ufs_hba;
|
||||
|
||||
enum dev_cmd_type {
|
||||
DEV_CMD_TYPE_NOP = 0x0,
|
||||
DEV_CMD_TYPE_QUERY = 0x1,
|
||||
};
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @done: UIC command completion
|
||||
*/
|
||||
struct uic_command {
|
||||
u32 command;
|
||||
u32 argument1;
|
||||
u32 argument2;
|
||||
u32 argument3;
|
||||
int cmd_active;
|
||||
int result;
|
||||
struct completion done;
|
||||
};
|
||||
|
||||
/* Used to differentiate the power management options */
|
||||
enum ufs_pm_op {
|
||||
UFS_RUNTIME_PM,
|
||||
UFS_SYSTEM_PM,
|
||||
UFS_SHUTDOWN_PM,
|
||||
};
|
||||
|
||||
#define ufshcd_is_runtime_pm(op) ((op) == UFS_RUNTIME_PM)
|
||||
#define ufshcd_is_system_pm(op) ((op) == UFS_SYSTEM_PM)
|
||||
#define ufshcd_is_shutdown_pm(op) ((op) == UFS_SHUTDOWN_PM)
|
||||
|
||||
/* Host <-> Device UniPro Link state */
|
||||
enum uic_link_state {
|
||||
UIC_LINK_OFF_STATE = 0, /* Link powered down or disabled */
|
||||
UIC_LINK_ACTIVE_STATE = 1, /* Link is in Fast/Slow/Sleep state */
|
||||
UIC_LINK_HIBERN8_STATE = 2, /* Link is in Hibernate state */
|
||||
UIC_LINK_TRANS_ACTIVE_STATE = 3,
|
||||
UIC_LINK_TRANS_HIBERN8_STATE = 4,
|
||||
};
|
||||
|
||||
#define ufshcd_is_link_off(hba) ((hba)->uic_link_state == UIC_LINK_OFF_STATE)
|
||||
#define ufshcd_is_link_active(hba) ((hba)->uic_link_state == \
|
||||
UIC_LINK_ACTIVE_STATE)
|
||||
#define ufshcd_is_link_hibern8(hba) ((hba)->uic_link_state == \
|
||||
UIC_LINK_HIBERN8_STATE)
|
||||
#define ufshcd_set_link_off(hba) ((hba)->uic_link_state = UIC_LINK_OFF_STATE)
|
||||
#define ufshcd_set_link_active(hba) ((hba)->uic_link_state = \
|
||||
UIC_LINK_ACTIVE_STATE)
|
||||
#define ufshcd_set_link_hibern8(hba) ((hba)->uic_link_state = \
|
||||
UIC_LINK_HIBERN8_STATE)
|
||||
#define ufshcd_set_link_trans_active(hba) ((hba)->uic_link_state = \
|
||||
UIC_LINK_TRANS_ACTIVE_STATE)
|
||||
#define ufshcd_set_link_trans_hibern8(hba) ((hba)->uic_link_state = \
|
||||
UIC_LINK_TRANS_HIBERN8_STATE)
|
||||
#define ufshcd_in_link_transition(hba) ( \
|
||||
(hba)->uic_link_state == UIC_LINK_TRANS_ACTIVE_STATE || \
|
||||
(hba)->uic_link_state == UIC_LINK_TRANS_HIBERN8_STATE)
|
||||
|
||||
/*
|
||||
* UFS Power management levels.
|
||||
* Each level is in increasing order of power savings.
|
||||
*/
|
||||
enum ufs_pm_level {
|
||||
UFS_PM_LVL_0, /* UFS_ACTIVE_PWR_MODE, UIC_LINK_ACTIVE_STATE */
|
||||
UFS_PM_LVL_1, /* UFS_ACTIVE_PWR_MODE, UIC_LINK_HIBERN8_STATE */
|
||||
UFS_PM_LVL_2, /* UFS_SLEEP_PWR_MODE, UIC_LINK_ACTIVE_STATE */
|
||||
UFS_PM_LVL_3, /* UFS_SLEEP_PWR_MODE, UIC_LINK_HIBERN8_STATE */
|
||||
UFS_PM_LVL_4, /* UFS_POWERDOWN_PWR_MODE, UIC_LINK_HIBERN8_STATE */
|
||||
UFS_PM_LVL_5, /* UFS_POWERDOWN_PWR_MODE, UIC_LINK_OFF_STATE */
|
||||
UFS_PM_LVL_MAX
|
||||
};
|
||||
|
||||
struct ufs_pm_lvl_states {
|
||||
enum ufs_dev_pwr_mode dev_state;
|
||||
enum uic_link_state link_state;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ufshcd_lrb - local reference block
|
||||
* @utr_descriptor_ptr: UTRD address of the command
|
||||
* @ucd_req_ptr: UCD address of the command
|
||||
* @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
|
||||
* @intr_cmd: Interrupt command (doesn't participate in interrupt aggregation)
|
||||
*/
|
||||
struct ufshcd_lrb {
|
||||
struct utp_transfer_req_desc *utr_descriptor_ptr;
|
||||
struct utp_upiu_req *ucd_req_ptr;
|
||||
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;
|
||||
u8 lun; /* UPIU LUN id field is only 8-bit wide */
|
||||
bool intr_cmd;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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;
|
||||
struct ufs_query query;
|
||||
};
|
||||
|
||||
/**
|
||||
* ufs_hba_variant: host specific data
|
||||
*/
|
||||
struct ufs_hba_variant {
|
||||
const struct ufs_hba_variant_ops *ops;
|
||||
u32 quirks;
|
||||
void *vs_data;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ufs_clk_info - UFS clock related info
|
||||
* @list: list headed by hba->clk_list_head
|
||||
* @clk: clock node
|
||||
* @name: clock name
|
||||
* @max_freq: maximum frequency supported by the clock
|
||||
* @min_freq: min frequency that can be used for clock scaling
|
||||
* @curr_freq: indicates the current frequency that it is set to
|
||||
* @enabled: variable to check against multiple enable/disable
|
||||
*/
|
||||
struct ufs_clk_info {
|
||||
struct list_head list;
|
||||
struct clk *clk;
|
||||
const char *name;
|
||||
u32 max_freq;
|
||||
u32 min_freq;
|
||||
u32 curr_freq;
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
#define PRE_CHANGE 0
|
||||
#define POST_CHANGE 1
|
||||
|
||||
struct ufs_pa_layer_attr {
|
||||
u32 gear_rx;
|
||||
u32 gear_tx;
|
||||
u32 lane_rx;
|
||||
u32 lane_tx;
|
||||
u32 pwr_rx;
|
||||
u32 pwr_tx;
|
||||
u32 hs_rate;
|
||||
};
|
||||
|
||||
struct ufs_pwr_mode_info {
|
||||
bool is_valid;
|
||||
struct ufs_pa_layer_attr info;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ufs_hba_variant_ops - variant specific callbacks
|
||||
* @name: variant name
|
||||
* @init: called when the driver is initialized
|
||||
* @exit: called to cleanup everything done in init
|
||||
* @clk_scale_notify: notifies that clks are scaled up/down
|
||||
* @setup_clocks: called before touching any of the controller registers
|
||||
* @setup_regulators: called before accessing the host controller
|
||||
* @hce_enable_notify: called before and after HCE enable bit is set to allow
|
||||
* variant specific Uni-Pro initialization.
|
||||
* @link_startup_notify: called before and after Link startup is carried out
|
||||
* to allow variant specific Uni-Pro initialization.
|
||||
* @pwr_change_notify: called before and after a power mode change
|
||||
* is carried out to allow vendor spesific capabilities
|
||||
* to be set.
|
||||
* @suspend: called during host controller PM callback
|
||||
* @resume: called during host controller PM callback
|
||||
*/
|
||||
struct ufs_hba_variant_ops {
|
||||
const char *name;
|
||||
int (*init)(struct ufs_hba *);
|
||||
void (*exit)(struct ufs_hba *);
|
||||
void (*clk_scale_notify)(struct ufs_hba *);
|
||||
int (*setup_clocks)(struct ufs_hba *, bool);
|
||||
int (*setup_regulators)(struct ufs_hba *, bool);
|
||||
void (*host_reset)(struct ufs_hba *);
|
||||
int (*hce_enable_notify)(struct ufs_hba *, bool);
|
||||
int (*link_startup_notify)(struct ufs_hba *, bool);
|
||||
int (*pwr_change_notify)(struct ufs_hba *,
|
||||
bool, struct ufs_pa_layer_attr *,
|
||||
struct ufs_pa_layer_attr *);
|
||||
void (*set_nexus_t_xfer_req)(struct ufs_hba *,
|
||||
int, struct scsi_cmnd *);
|
||||
void (*set_nexus_t_task_mgmt)(struct ufs_hba *, int, u8);
|
||||
void (*hibern8_notify)(struct ufs_hba *, u8, bool);
|
||||
void (*clock_control_notify)(struct ufs_hba *, bool, bool);
|
||||
void (*get_debug_info)(struct ufs_hba *);
|
||||
int (*suspend)(struct ufs_hba *, enum ufs_pm_op);
|
||||
int (*resume)(struct ufs_hba *, enum ufs_pm_op);
|
||||
};
|
||||
|
||||
/* clock gating state */
|
||||
enum clk_gating_state {
|
||||
CLKS_OFF,
|
||||
CLKS_ON,
|
||||
REQ_CLKS_OFF,
|
||||
REQ_CLKS_ON,
|
||||
__CLKS_ON,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ufs_clk_gating - UFS clock gating related info
|
||||
* @gate_work: worker to turn off clocks after some delay as specified in
|
||||
* delay_ms
|
||||
* @ungate_work: worker to turn on clocks that will be used in case of
|
||||
* interrupt context
|
||||
* @state: the current clocks state
|
||||
* @delay_ms: gating delay in ms
|
||||
* @is_suspended: clk gating is suspended when set to 1 which can be used
|
||||
* during suspend/resume
|
||||
* @delay_attr: sysfs attribute to control delay_attr
|
||||
* @active_reqs: number of requests that are pending and should be waited for
|
||||
* completion before gating clocks.
|
||||
*/
|
||||
struct ufs_clk_gating {
|
||||
struct delayed_work gate_work;
|
||||
struct work_struct ungate_work;
|
||||
enum clk_gating_state state;
|
||||
unsigned long delay_ms;
|
||||
bool is_suspended;
|
||||
struct device_attribute delay_attr;
|
||||
int active_reqs;
|
||||
};
|
||||
|
||||
struct ufs_clk_scaling {
|
||||
ktime_t busy_start_t;
|
||||
bool is_busy_started;
|
||||
unsigned long tot_busy_t;
|
||||
unsigned long window_start_t;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ufs_init_prefetch - contains data that is pre-fetched once during
|
||||
* initialization
|
||||
* @icc_level: icc level which was read during initialization
|
||||
*/
|
||||
struct ufs_init_prefetch {
|
||||
u32 icc_level;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ufs_debug - monitors ufs driver's behaviors
|
||||
*/
|
||||
struct ufs_debug {
|
||||
struct device_attribute attrs;
|
||||
unsigned long flag;
|
||||
#define UFSHCD_DEBUG_LEVEL1 (1 << 0)
|
||||
#define UFSHCD_DEBUG_LEVEL2 (1 << 1)
|
||||
};
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @lrb_in_use: lrb in use
|
||||
* @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
|
||||
* @vops: pointer to variant specific operations
|
||||
* @priv: pointer to variant specific private data
|
||||
* @irq: Irq number of the controller
|
||||
* @active_uic_cmd: handle of active UIC command
|
||||
* @uic_cmd_mutex: mutex for uic command
|
||||
* @tm_wq: wait queue for task management
|
||||
* @tm_tag_wq: wait queue for free task management slots
|
||||
* @tm_slots_in_use: bit map of task management request slots in use
|
||||
* @pwr_done: completion for power mode change
|
||||
* @tm_condition: condition variable for task management
|
||||
* @ufshcd_state: UFSHCD states
|
||||
* @eh_flags: Error handling flags
|
||||
* @intr_mask: Interrupt Mask Bits
|
||||
* @ee_ctrl_mask: Exception event control mask
|
||||
* @is_powered: flag to check if HBA is powered
|
||||
* @is_init_prefetch: flag to check if data was pre-fetched in initialization
|
||||
* @init_prefetch_data: data pre-fetched during initialization
|
||||
* @eh_work: Worker to handle UFS errors that require s/w attention
|
||||
* @eeh_work: Worker to handle exception events
|
||||
* @errors: HBA errors
|
||||
* @uic_error: UFS interconnect layer error status
|
||||
* @saved_err: sticky error mask
|
||||
* @saved_uic_err: sticky UIC error mask
|
||||
* @dev_cmd: ufs device management command information
|
||||
* @auto_bkops_enabled: to track whether bkops is enabled in device
|
||||
* @vreg_info: UFS device voltage regulator information
|
||||
* @clk_list_head: UFS host controller clocks list node head
|
||||
* @pwr_info: holds current power mode
|
||||
* @max_pwr_info: keeps the device max valid pwm
|
||||
*/
|
||||
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;
|
||||
/*
|
||||
* This field is to keep a reference to "scsi_device" corresponding to
|
||||
* "UFS device" W-LU.
|
||||
*/
|
||||
struct scsi_device *sdev_ufs_device;
|
||||
struct scsi_device *sdev_rpmb;
|
||||
|
||||
enum ufs_dev_pwr_mode curr_dev_pwr_mode;
|
||||
enum uic_link_state uic_link_state;
|
||||
/* Desired UFS power management level during runtime PM */
|
||||
enum ufs_pm_level rpm_lvl;
|
||||
/* Desired UFS power management level during system PM */
|
||||
enum ufs_pm_level spm_lvl;
|
||||
int pm_op_in_progress;
|
||||
|
||||
struct ufshcd_lrb *lrb;
|
||||
volatile unsigned long lrb_in_use;
|
||||
|
||||
unsigned long outstanding_tasks;
|
||||
unsigned long outstanding_reqs;
|
||||
|
||||
u32 capabilities;
|
||||
int nutrs;
|
||||
int nutmrs;
|
||||
u32 ufs_version;
|
||||
const struct ufs_hba_variant_ops *vops;
|
||||
void *priv;
|
||||
unsigned int irq;
|
||||
bool is_irq_enabled;
|
||||
|
||||
|
||||
wait_queue_head_t tm_wq;
|
||||
wait_queue_head_t tm_tag_wq;
|
||||
unsigned long tm_condition;
|
||||
unsigned long tm_slots_in_use;
|
||||
|
||||
struct uic_command *active_uic_cmd;
|
||||
struct mutex uic_cmd_mutex;
|
||||
struct completion *uic_async_done;
|
||||
|
||||
u32 ufshcd_state;
|
||||
u32 eh_flags;
|
||||
u32 intr_mask;
|
||||
u32 transferred_sector;
|
||||
u16 ee_ctrl_mask;
|
||||
bool is_powered;
|
||||
bool is_init_prefetch;
|
||||
struct ufs_init_prefetch init_prefetch_data;
|
||||
|
||||
/* Work Queues */
|
||||
struct workqueue_struct *ufshcd_workq;
|
||||
struct work_struct eh_work;
|
||||
struct work_struct eeh_work;
|
||||
|
||||
/* Performance */
|
||||
u32 tp_per_period;
|
||||
|
||||
/* HBA Errors */
|
||||
u32 errors;
|
||||
u32 uic_error;
|
||||
u32 saved_err;
|
||||
u32 saved_uic_err;
|
||||
u32 tcx_replay_timer_expired_cnt;
|
||||
u32 fcx_protection_timer_expired_cnt;
|
||||
|
||||
/* Device management request data */
|
||||
struct ufs_dev_cmd dev_cmd;
|
||||
|
||||
/* Keeps information of the UFS device connected to this host */
|
||||
struct ufs_dev_info dev_info;
|
||||
bool auto_bkops_enabled;
|
||||
struct ufs_vreg_info vreg_info;
|
||||
struct list_head clk_list_head;
|
||||
|
||||
bool wlun_dev_clr_ua;
|
||||
|
||||
struct ufs_pa_layer_attr pwr_info;
|
||||
struct ufs_pwr_mode_info max_pwr_info;
|
||||
|
||||
struct ufs_clk_gating clk_gating;
|
||||
/* Control to enable/disable host capabilities */
|
||||
u32 caps;
|
||||
/* Allow dynamic clk gating */
|
||||
#define UFSHCD_CAP_CLK_GATING (1 << 0)
|
||||
/* Allow hiberb8 with clk gating */
|
||||
#define UFSHCD_CAP_HIBERN8_WITH_CLK_GATING (1 << 1)
|
||||
/* Allow dynamic clk scaling */
|
||||
#define UFSHCD_CAP_CLK_SCALING (1 << 2)
|
||||
/* Allow auto bkops to enabled during runtime suspend */
|
||||
#define UFSHCD_CAP_AUTO_BKOPS_SUSPEND (1 << 3)
|
||||
/* Allow only hibern8 without clk gating */
|
||||
#define UFSHCD_CAP_FAKE_CLK_GATING (1 << 4)
|
||||
|
||||
struct devfreq *devfreq;
|
||||
struct ufs_clk_scaling clk_scaling;
|
||||
bool is_sys_suspended;
|
||||
|
||||
u32 quirks;
|
||||
|
||||
struct buffer_head *self_test_bh;
|
||||
uint32_t self_test_mode;
|
||||
struct ufshcd_sg_entry *ucd_prdt_ptr_st;
|
||||
|
||||
/* UFSHCI doesn't support DWORD size in UTRD */
|
||||
#define UFSHCI_QUIRK_BROKEN_DWORD_UTRD BIT(0)
|
||||
#define UFSHCI_QUIRK_BROKEN_REQ_LIST_CLR BIT(1)
|
||||
#define UFSHCI_QUIRK_USE_OF_HCE BIT(2)
|
||||
#define UFSHCI_QUIRK_SKIP_INTR_AGGR BIT(3)
|
||||
|
||||
/* Device deviations from standard UFS device spec. */
|
||||
unsigned int dev_quirks;
|
||||
|
||||
struct device_attribute unique_number_attr;
|
||||
struct device_attribute manufacturer_id_attr;
|
||||
char unique_number[UFS_UNIQUE_NUMBER_LEN];
|
||||
u16 manufacturer_id;
|
||||
u8 lifetime;
|
||||
|
||||
struct ufs_debug debug;
|
||||
};
|
||||
|
||||
/* Returns true if clocks can be gated. Otherwise false */
|
||||
static inline bool ufshcd_is_clkgating_allowed(struct ufs_hba *hba)
|
||||
{
|
||||
return hba->caps & UFSHCD_CAP_CLK_GATING;
|
||||
}
|
||||
static inline bool ufshcd_can_hibern8_during_gating(struct ufs_hba *hba)
|
||||
{
|
||||
return hba->caps & UFSHCD_CAP_HIBERN8_WITH_CLK_GATING;
|
||||
}
|
||||
#if defined(CONFIG_PM_DEVFREQ)
|
||||
static inline int ufshcd_is_clkscaling_enabled(struct ufs_hba *hba)
|
||||
{
|
||||
return hba->caps & UFSHCD_CAP_CLK_SCALING;
|
||||
}
|
||||
#endif
|
||||
static inline bool ufshcd_can_autobkops_during_suspend(struct ufs_hba *hba)
|
||||
{
|
||||
return hba->caps & UFSHCD_CAP_AUTO_BKOPS_SUSPEND;
|
||||
}
|
||||
|
||||
static inline bool ufshcd_can_fake_clkgating(struct ufs_hba *hba)
|
||||
{
|
||||
return hba->caps & UFSHCD_CAP_FAKE_CLK_GATING;
|
||||
}
|
||||
|
||||
#define ufshcd_writel(hba, val, reg) \
|
||||
writel((val), (hba)->mmio_base + (reg))
|
||||
#define ufshcd_readl(hba, reg) \
|
||||
readl((hba)->mmio_base + (reg))
|
||||
|
||||
/**
|
||||
* ufshcd_rmwl - read modify write into a register
|
||||
* @hba - per adapter instance
|
||||
* @mask - mask to apply on read value
|
||||
* @val - actual value to write
|
||||
* @reg - register address
|
||||
*/
|
||||
static inline void ufshcd_rmwl(struct ufs_hba *hba, u32 mask, u32 val, u32 reg)
|
||||
{
|
||||
u32 tmp;
|
||||
|
||||
tmp = ufshcd_readl(hba, reg);
|
||||
tmp &= ~mask;
|
||||
tmp |= (val & mask);
|
||||
ufshcd_writel(hba, tmp, reg);
|
||||
}
|
||||
|
||||
int ufshcd_alloc_host(struct device *, struct ufs_hba **);
|
||||
int ufshcd_init(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)
|
||||
{
|
||||
ufshcd_writel(hba, CONTROLLER_DISABLE, REG_CONTROLLER_ENABLE);
|
||||
}
|
||||
|
||||
static inline void check_upiu_size(void)
|
||||
{
|
||||
BUILD_BUG_ON(ALIGNED_UPIU_SIZE <
|
||||
GENERAL_UPIU_REQUEST_SIZE + QUERY_DESC_MAX_SIZE);
|
||||
}
|
||||
|
||||
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);
|
||||
extern int ufshcd_system_suspend(struct ufs_hba *hba);
|
||||
extern int ufshcd_system_resume(struct ufs_hba *hba);
|
||||
extern int ufshcd_shutdown(struct ufs_hba *hba);
|
||||
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);
|
||||
extern int ufshcd_config_pwr_mode(struct ufs_hba *hba,
|
||||
struct ufs_pa_layer_attr *desired_pwr_mode);
|
||||
extern void scsi_softirq_done(struct request *rq);
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
int ufshcd_hold(struct ufs_hba *hba, bool async);
|
||||
void ufshcd_release(struct ufs_hba *hba);
|
||||
|
||||
int ufshcd_read_device_desc(struct ufs_hba *hba, u8 *buf, u32 size);
|
||||
int ufshcd_read_health_desc(struct ufs_hba *hba, u8 *buf, u32 size);
|
||||
|
||||
#define ASCII_STD true
|
||||
#define UTF16_STD false
|
||||
int ufshcd_read_string_desc(struct ufs_hba *hba, int desc_index, u8 *buf,
|
||||
u32 size, bool ascii);
|
||||
#endif /* End of Header */
|
460
drivers/scsi/ufs/ufshci.h
Normal file
460
drivers/scsi/ufs/ufshci.h
Normal file
|
@ -0,0 +1,460 @@
|
|||
/*
|
||||
* Universal Flash Storage Host controller driver
|
||||
*
|
||||
* This code is based on drivers/scsi/ufs/ufshci.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 _UFSHCI_H
|
||||
#define _UFSHCI_H
|
||||
|
||||
enum {
|
||||
TASK_REQ_UPIU_SIZE_DWORDS = 8,
|
||||
TASK_RSP_UPIU_SIZE_DWORDS = 8,
|
||||
ALIGNED_UPIU_SIZE = 512,
|
||||
};
|
||||
|
||||
/* 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_UIC_PWR_MASK (UIC_HIBERNATE_ENTER |\
|
||||
UIC_HIBERNATE_EXIT |\
|
||||
UIC_POWER_MODE)
|
||||
|
||||
#define UFSHCD_UIC_MASK (UIC_COMMAND_COMPL | UFSHCD_UIC_PWR_MASK)
|
||||
|
||||
#define UFSHCD_ERROR_MASK (UIC_ERROR |\
|
||||
DEVICE_FATAL_ERROR |\
|
||||
CONTROLLER_FATAL_ERROR |\
|
||||
SYSTEM_BUS_FATAL_ERROR |\
|
||||
UIC_LINK_LOST)
|
||||
|
||||
#define INT_FATAL_ERRORS (DEVICE_FATAL_ERROR |\
|
||||
CONTROLLER_FATAL_ERROR |\
|
||||
SYSTEM_BUS_FATAL_ERROR |\
|
||||
UIC_LINK_LOST)
|
||||
|
||||
/* 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)
|
||||
|
||||
enum {
|
||||
PWR_OK = 0x0,
|
||||
PWR_LOCAL = 0x01,
|
||||
PWR_REMOTE = 0x02,
|
||||
PWR_BUSY = 0x03,
|
||||
PWR_ERROR_CAP = 0x04,
|
||||
PWR_FATAL_ERROR = 0x05,
|
||||
};
|
||||
|
||||
/* HCE - Host Controller Enable 34h */
|
||||
#define CONTROLLER_ENABLE UFS_BIT(0)
|
||||
#define CONTROLLER_DISABLE 0x0
|
||||
|
||||
/* 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_TCX_REP_TIMER_EXP UFS_BIT(1)
|
||||
#define UIC_DATA_LINK_LAYER_ERROR_AFCX_REQ_TIMER_EXP UFS_BIT(2)
|
||||
#define UIC_DATA_LINK_LAYER_ERROR_FCX_PRO_TIMER_EXP UFS_BIT(3)
|
||||
#define UIC_DATA_LINK_LAYER_ERROR_RX_BUF_OF UFS_BIT(5)
|
||||
#define UIC_DATA_LINK_LAYER_ERROR_PA_INIT UFS_BIT(13)
|
||||
|
||||
/* UECN - Host UIC Error Code Network Layer 40h */
|
||||
#define UIC_NETWORK_LAYER_ERROR UFS_BIT(31)
|
||||
#define UIC_NETWORK_LAYER_ERROR_CODE_MASK 0x7
|
||||
#define UIC_NETWORK_UNSUPPORTED_HEADER_TYPE BIT(0)
|
||||
#define UIC_NETWORK_BAD_DEVICEID_ENC BIT(1)
|
||||
#define UIC_NETWORK_LHDR_TRAP_PACKET_DROPPING BIT(2)
|
||||
|
||||
/* UECT - Host UIC Error Code Transport Layer 44h */
|
||||
#define UIC_TRANSPORT_LAYER_ERROR UFS_BIT(31)
|
||||
#define UIC_TRANSPORT_LAYER_ERROR_CODE_MASK 0x7F
|
||||
#define UIC_TRANSPORT_UNSUPPORTED_HEADER_TYPE BIT(0)
|
||||
#define UIC_TRANSPORT_UNKNOWN_CPORTID BIT(1)
|
||||
#define UIC_TRANSPORT_NO_CONNECTION_RX BIT(2)
|
||||
#define UIC_TRANSPORT_CONTROLLED_SEGMENT_DROPPING BIT(3)
|
||||
#define UIC_TRANSPORT_BAD_TC BIT(4)
|
||||
#define UIC_TRANSPORT_E2E_CREDIT_OVERFOW BIT(5)
|
||||
#define UIC_TRANSPORT_SAFETY_VALUE_DROPPING BIT(6)
|
||||
|
||||
/* 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
|
||||
|
||||
#define UIC_ARG_MIB_SEL(attr, sel) ((((attr) & 0xFFFF) << 16) |\
|
||||
((sel) & 0xFFFF))
|
||||
#define UIC_ARG_MIB(attr) UIC_ARG_MIB_SEL(attr, 0)
|
||||
#define UIC_ARG_ATTR_TYPE(t) (((t) & 0xFF) << 16)
|
||||
#define UIC_GET_ATTR_ID(v) (((v) >> 16) & 0xFFFF)
|
||||
|
||||
/*
|
||||
* UFS Protector configuration
|
||||
*/
|
||||
#define UFS_BYPASS_SECTOR_BEGIN 0x0
|
||||
#define UFS_ENCRYPTION_SECTOR_BEGIN 0x0000FFFF
|
||||
#define UFS_FILE_ENCRYPTION_SECTOR_BEGIN 0xFFFF0000
|
||||
|
||||
#define UFSHCI_SECTOR_SIZE 0x1000
|
||||
#define MIN_SECTOR_SIZE 0x200
|
||||
|
||||
/* UIC Commands */
|
||||
enum uic_cmd_dme {
|
||||
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_THLD_VAL(c) (((c) & 0x1F) << 8)
|
||||
#define INT_AGGR_TIMEOUT_VAL(t) (((t) & 0xFF) << 0)
|
||||
|
||||
/* Interrupt disable masks */
|
||||
enum {
|
||||
/* Interrupt disable mask for UFSHCI v1.0 */
|
||||
INTERRUPT_MASK_ALL_VER_10 = 0x30FFF,
|
||||
INTERRUPT_MASK_RW_VER_10 = 0x30000,
|
||||
|
||||
/* Interrupt disable mask for UFSHCI v1.1 */
|
||||
INTERRUPT_MASK_ALL_VER_11 = 0x31FFF,
|
||||
};
|
||||
|
||||
/*
|
||||
* 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,
|
||||
};
|
||||
|
||||
/* The maximum length of the data byte count field in the PRDT is 256KB */
|
||||
#define PRDT_DATA_BYTE_COUNT_MAX (256 * 1024)
|
||||
/* The granularity of the data byte count field in the PRDT is 32-bit */
|
||||
#define PRDT_DATA_BYTE_COUNT_PAD 4
|
||||
|
||||
/* FMP bypass/encrypt mode */
|
||||
#define CLEAR 0
|
||||
#define AES_CBC 1
|
||||
#define AES_XTS 2
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
__le32 base_addr;
|
||||
__le32 upper_addr;
|
||||
__le32 reserved;
|
||||
__le32 size;
|
||||
#define FKL BIT(26)
|
||||
#define DKL BIT(27)
|
||||
#define SET_FAS(d, v) \
|
||||
((d)->size = ((d)->size & 0xcfffffff) | v << 28)
|
||||
#define SET_DAS(d, v) \
|
||||
((d)->size = ((d)->size & 0x3fffffff) | v << 30)
|
||||
#if defined(CONFIG_UFS_FMP_DM_CRYPT) || defined(CONFIG_UFS_FMP_ECRYPT_FS)
|
||||
__le32 file_iv0;
|
||||
__le32 file_iv1;
|
||||
__le32 file_iv2;
|
||||
__le32 file_iv3;
|
||||
__le32 file_enckey0;
|
||||
__le32 file_enckey1;
|
||||
__le32 file_enckey2;
|
||||
__le32 file_enckey3;
|
||||
__le32 file_enckey4;
|
||||
__le32 file_enckey5;
|
||||
__le32 file_enckey6;
|
||||
__le32 file_enckey7;
|
||||
__le32 file_twkey0;
|
||||
__le32 file_twkey1;
|
||||
__le32 file_twkey2;
|
||||
__le32 file_twkey3;
|
||||
__le32 file_twkey4;
|
||||
__le32 file_twkey5;
|
||||
__le32 file_twkey6;
|
||||
__le32 file_twkey7;
|
||||
__le32 disk_iv0;
|
||||
__le32 disk_iv1;
|
||||
__le32 disk_iv2;
|
||||
__le32 disk_iv3;
|
||||
__le32 reserved0;
|
||||
__le32 reserved1;
|
||||
__le32 reserved2;
|
||||
__le32 reserved3;
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
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 {
|
||||
__le32 dword_0;
|
||||
__le32 dword_1;
|
||||
__le32 dword_2;
|
||||
__le32 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*/
|
||||
__le32 command_desc_base_addr_lo;
|
||||
__le32 command_desc_base_addr_hi;
|
||||
|
||||
/* DW 6 */
|
||||
__le16 response_upiu_length;
|
||||
__le16 response_upiu_offset;
|
||||
|
||||
/* DW 7 */
|
||||
__le16 prd_table_length;
|
||||
__le16 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 */
|
||||
__le32 task_req_upiu[TASK_REQ_UPIU_SIZE_DWORDS];
|
||||
|
||||
/* DW 12-19 */
|
||||
__le32 task_rsp_upiu[TASK_RSP_UPIU_SIZE_DWORDS];
|
||||
};
|
||||
|
||||
#endif /* End of Header */
|
231
drivers/scsi/ufs/unipro.h
Normal file
231
drivers/scsi/ufs/unipro.h
Normal file
|
@ -0,0 +1,231 @@
|
|||
/*
|
||||
* drivers/scsi/ufs/unipro.h
|
||||
*
|
||||
* Copyright (C) 2013 Samsung Electronics Co., Ltd.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _UNIPRO_H_
|
||||
#define _UNIPRO_H_
|
||||
|
||||
/*
|
||||
* M-TX Configuration Attributes
|
||||
*/
|
||||
#define TX_MODE 0x0021
|
||||
#define TX_HSRATE_SERIES 0x0022
|
||||
#define TX_HSGEAR 0x0023
|
||||
#define TX_PWMGEAR 0x0024
|
||||
#define TX_AMPLITUDE 0x0025
|
||||
#define TX_HS_SLEWRATE 0x0026
|
||||
#define TX_SYNC_SOURCE 0x0027
|
||||
#define TX_HS_SYNC_LENGTH 0x0028
|
||||
#define TX_HS_PREPARE_LENGTH 0x0029
|
||||
#define TX_LS_PREPARE_LENGTH 0x002A
|
||||
#define TX_HIBERN8_CONTROL 0x002B
|
||||
#define TX_LCC_ENABLE 0x002C
|
||||
#define TX_PWM_BURST_CLOSURE_EXTENSION 0x002D
|
||||
#define TX_BYPASS_8B10B_ENABLE 0x002E
|
||||
#define TX_DRIVER_POLARITY 0x002F
|
||||
#define TX_HS_UNTERMINATED_LINE_DRIVE_ENABLE 0x0030
|
||||
#define TX_LS_TERMINATED_LINE_DRIVE_ENABLE 0x0031
|
||||
#define TX_LCC_SEQUENCER 0x0032
|
||||
#define TX_MIN_ACTIVATETIME 0x0033
|
||||
#define TX_PWM_G6_G7_SYNC_LENGTH 0x0034
|
||||
|
||||
/*
|
||||
* M-RX Configuration Attributes
|
||||
*/
|
||||
#define RX_MODE 0x00A1
|
||||
#define RX_HSRATE_SERIES 0x00A2
|
||||
#define RX_HSGEAR 0x00A3
|
||||
#define RX_PWMGEAR 0x00A4
|
||||
#define RX_LS_TERMINATED_ENABLE 0x00A5
|
||||
#define RX_HS_UNTERMINATED_ENABLE 0x00A6
|
||||
#define RX_ENTER_HIBERN8 0x00A7
|
||||
#define RX_BYPASS_8B10B_ENABLE 0x00A8
|
||||
#define RX_TERMINATION_FORCE_ENABLE 0x0089
|
||||
|
||||
#define is_mphy_tx_attr(attr) (attr < RX_MODE)
|
||||
/*
|
||||
* PHY Adpater attributes
|
||||
*/
|
||||
#define PA_ACTIVETXDATALANES 0x1560
|
||||
#define PA_ACTIVERXDATALANES 0x1580
|
||||
#define PA_TXTRAILINGCLOCKS 0x1564
|
||||
#define PA_PHY_TYPE 0x1500
|
||||
#define PA_AVAILTXDATALANES 0x1520
|
||||
#define PA_AVAILRXDATALANES 0x1540
|
||||
#define PA_MINRXTRAILINGCLOCKS 0x1543
|
||||
#define PA_TXPWRSTATUS 0x1567
|
||||
#define PA_RXPWRSTATUS 0x1582
|
||||
#define PA_TXFORCECLOCK 0x1562
|
||||
#define PA_TXPWRMODE 0x1563
|
||||
#define PA_LEGACYDPHYESCDL 0x1570
|
||||
#define PA_MAXTXSPEEDFAST 0x1521
|
||||
#define PA_MAXTXSPEEDSLOW 0x1522
|
||||
#define PA_MAXRXSPEEDFAST 0x1541
|
||||
#define PA_MAXRXSPEEDSLOW 0x1542
|
||||
#define PA_TXLINKSTARTUPHS 0x1544
|
||||
#define PA_TXSPEEDFAST 0x1565
|
||||
#define PA_TXSPEEDSLOW 0x1566
|
||||
#define PA_REMOTEVERINFO 0x15A0
|
||||
#define PA_TXGEAR 0x1568
|
||||
#define PA_TXTERMINATION 0x1569
|
||||
#define PA_HSSERIES 0x156A
|
||||
#define PA_PWRMODE 0x1571
|
||||
#define PA_RXGEAR 0x1583
|
||||
#define PA_RXTERMINATION 0x1584
|
||||
#define PA_MAXRXPWMGEAR 0x1586
|
||||
#define PA_MAXRXHSGEAR 0x1587
|
||||
#define PA_RXHSUNTERMCAP 0x15A5
|
||||
#define PA_RXLSTERMCAP 0x15A6
|
||||
#define PA_PACPREQTIMEOUT 0x1590
|
||||
#define PA_PACPREQEOBTIMEOUT 0x1591
|
||||
#define PA_HIBERN8TIME 0x15A7
|
||||
#define PA_LOCALVERINFO 0x15A9
|
||||
#define PA_GRANULARITY 0x15AA
|
||||
#define PA_TACTIVATE 0x15A8
|
||||
#define PA_PACPFRAMECOUNT 0x15C0
|
||||
#define PA_PACPERRORCOUNT 0x15C1
|
||||
#define PA_PHYTESTCONTROL 0x15C2
|
||||
#define PA_PWRMODEUSERDATA0 0x15B0
|
||||
#define PA_PWRMODEUSERDATA1 0x15B1
|
||||
#define PA_PWRMODEUSERDATA2 0x15B2
|
||||
#define PA_PWRMODEUSERDATA3 0x15B3
|
||||
#define PA_PWRMODEUSERDATA4 0x15B4
|
||||
#define PA_PWRMODEUSERDATA5 0x15B5
|
||||
#define PA_PWRMODEUSERDATA6 0x15B6
|
||||
#define PA_PWRMODEUSERDATA7 0x15B7
|
||||
#define PA_PWRMODEUSERDATA8 0x15B8
|
||||
#define PA_PWRMODEUSERDATA9 0x15B9
|
||||
#define PA_PWRMODEUSERDATA10 0x15BA
|
||||
#define PA_PWRMODEUSERDATA11 0x15BB
|
||||
#define PA_CONNECTEDTXDATALANES 0x1561
|
||||
#define PA_CONNECTEDRXDATALANES 0x1581
|
||||
#define PA_LOGICALLANEMAP 0x15A1
|
||||
#define PA_SLEEPNOCONFIGTIME 0x15A2
|
||||
#define PA_STALLNOCONFIGTIME 0x15A3
|
||||
#define PA_SAVECONFIGTIME 0x15A4
|
||||
|
||||
/* PA power modes */
|
||||
enum {
|
||||
FAST_MODE = 1,
|
||||
SLOW_MODE = 2,
|
||||
FASTAUTO_MODE = 4,
|
||||
SLOWAUTO_MODE = 5,
|
||||
UNCHANGED = 7,
|
||||
};
|
||||
|
||||
#define IS_PWR_MODE_HS(m) (((m) == FAST_MODE) || ((m) == FASTAUTO_MODE))
|
||||
#define IS_PWR_MODE_PWM(m) (((m) == SLOW_MODE) || ((m) == SLOWAUTO_MODE))
|
||||
|
||||
/* PA TX/RX Frequency Series */
|
||||
enum {
|
||||
PA_HS_MODE_A = 1,
|
||||
PA_HS_MODE_B = 2,
|
||||
};
|
||||
|
||||
enum ufs_pwm_gear_tag {
|
||||
UFS_PWM_DONT_CHANGE, /* Don't change Gear */
|
||||
UFS_PWM_G1, /* PWM Gear 1 (default for reset) */
|
||||
UFS_PWM_G2, /* PWM Gear 2 */
|
||||
UFS_PWM_G3, /* PWM Gear 3 */
|
||||
UFS_PWM_G4, /* PWM Gear 4 */
|
||||
UFS_PWM_G5, /* PWM Gear 5 */
|
||||
UFS_PWM_G6, /* PWM Gear 6 */
|
||||
UFS_PWM_G7, /* PWM Gear 7 */
|
||||
};
|
||||
|
||||
enum ufs_hs_gear_tag {
|
||||
UFS_HS_DONT_CHANGE, /* Don't change Gear */
|
||||
UFS_HS_G1, /* HS Gear 1 (default for reset) */
|
||||
UFS_HS_G2, /* HS Gear 2 */
|
||||
UFS_HS_G3, /* HS Gear 3 */
|
||||
};
|
||||
|
||||
/*
|
||||
* Data Link Layer Attributes
|
||||
*/
|
||||
#define DL_TC0TXFCTHRESHOLD 0x2040
|
||||
#define DL_FC0PROTTIMEOUTVAL 0x2041
|
||||
#define DL_TC0REPLAYTIMEOUTVAL 0x2042
|
||||
#define DL_AFC0REQTIMEOUTVAL 0x2043
|
||||
#define DL_AFC0CREDITTHRESHOLD 0x2044
|
||||
#define DL_TC0OUTACKTHRESHOLD 0x2045
|
||||
#define DL_TC1TXFCTHRESHOLD 0x2060
|
||||
#define DL_FC1PROTTIMEOUTVAL 0x2061
|
||||
#define DL_TC1REPLAYTIMEOUTVAL 0x2062
|
||||
#define DL_AFC1REQTIMEOUTVAL 0x2063
|
||||
#define DL_AFC1CREDITTHRESHOLD 0x2064
|
||||
#define DL_TC1OUTACKTHRESHOLD 0x2065
|
||||
#define DL_TXPREEMPTIONCAP 0x2000
|
||||
#define DL_TC0TXMAXSDUSIZE 0x2001
|
||||
#define DL_TC0RXINITCREDITVAL 0x2002
|
||||
#define DL_TC0TXBUFFERSIZE 0x2005
|
||||
#define DL_PEERTC0PRESENT 0x2046
|
||||
#define DL_PEERTC0RXINITCREVAL 0x2047
|
||||
#define DL_TC1TXMAXSDUSIZE 0x2003
|
||||
#define DL_TC1RXINITCREDITVAL 0x2004
|
||||
#define DL_TC1TXBUFFERSIZE 0x2006
|
||||
#define DL_PEERTC1PRESENT 0x2066
|
||||
#define DL_PEERTC1RXINITCREVAL 0x2067
|
||||
|
||||
/* Default value of L2 Timer */
|
||||
#define FC0PROTTIMEOUTVAL 8191
|
||||
#define TC0REPLAYTIMEOUTVAL 65535
|
||||
#define AFC0REQTIMEOUTVAL 32767
|
||||
|
||||
/*
|
||||
* Network Layer Attributes
|
||||
*/
|
||||
#define N_DEVICEID 0x3000
|
||||
#define N_DEVICEID_VALID 0x3001
|
||||
#define N_TC0TXMAXSDUSIZE 0x3020
|
||||
#define N_TC1TXMAXSDUSIZE 0x3021
|
||||
|
||||
/*
|
||||
* Transport Layer Attributes
|
||||
*/
|
||||
#define T_NUMCPORTS 0x4000
|
||||
#define T_NUMTESTFEATURES 0x4001
|
||||
#define T_CONNECTIONSTATE 0x4020
|
||||
#define T_PEERDEVICEID 0x4021
|
||||
#define T_PEERCPORTID 0x4022
|
||||
#define T_TRAFFICCLASS 0x4023
|
||||
#define T_PROTOCOLID 0x4024
|
||||
#define T_CPORTFLAGS 0x4025
|
||||
#define T_TXTOKENVALUE 0x4026
|
||||
#define T_RXTOKENVALUE 0x4027
|
||||
#define T_LOCALBUFFERSPACE 0x4028
|
||||
#define T_PEERBUFFERSPACE 0x4029
|
||||
#define T_CREDITSTOSEND 0x402A
|
||||
#define T_CPORTMODE 0x402B
|
||||
#define T_TC0TXMAXSDUSIZE 0x4060
|
||||
#define T_TC1TXMAXSDUSIZE 0x4061
|
||||
|
||||
/* CPort setting */
|
||||
#define E2EFC_ON (1 << 0)
|
||||
#define E2EFC_OFF (0 << 0)
|
||||
#define CSD_N_ON (0 << 1)
|
||||
#define CSD_N_OFF (1 << 1)
|
||||
#define CSV_N_ON (0 << 2)
|
||||
#define CSV_N_OFF (1 << 2)
|
||||
#define CPORT_DEF_FLAGS (CSV_N_OFF | CSD_N_OFF | E2EFC_OFF)
|
||||
|
||||
/* CPort connection state */
|
||||
enum {
|
||||
CPORT_IDLE = 0,
|
||||
CPORT_CONNECTED,
|
||||
};
|
||||
|
||||
/* Boolean attribute values */
|
||||
enum {
|
||||
FALSE = 0,
|
||||
TRUE,
|
||||
};
|
||||
|
||||
#endif /* _UNIPRO_H_ */
|
Loading…
Add table
Add a link
Reference in a new issue