mirror of
https://github.com/torvalds/linux.git
synced 2026-05-24 23:22:31 +02:00
staging: rts5208: Remove unused driver
Wei Wang from Realsil contributed this driver in 2011. The following reasons lead to the removal: - This driver generates maintenance workload - Did not find minimal documentation on the web. - No blog entries about anyone using the rts5208 and rts5288 during the last years. - Did not find any device that may has it in and is still available on the market. Link: https://lore.kernel.org/linux-staging/2024100943-shank-washed-a765@gregkh/T/#t Signed-off-by: Philipp Hortmann <philipp.g.hortmann@gmail.com> Link: https://lore.kernel.org/r/20241009193250.6211-1-philipp.g.hortmann@gmail.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
31d2ad610c
commit
f11192a246
|
|
@ -30,8 +30,6 @@ source "drivers/staging/rtl8723bs/Kconfig"
|
|||
|
||||
source "drivers/staging/rtl8712/Kconfig"
|
||||
|
||||
source "drivers/staging/rts5208/Kconfig"
|
||||
|
||||
source "drivers/staging/octeon/Kconfig"
|
||||
|
||||
source "drivers/staging/vt6655/Kconfig"
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ obj-y += media/
|
|||
obj-$(CONFIG_FB_OLPC_DCON) += olpc_dcon/
|
||||
obj-$(CONFIG_RTL8723BS) += rtl8723bs/
|
||||
obj-$(CONFIG_R8712U) += rtl8712/
|
||||
obj-$(CONFIG_RTS5208) += rts5208/
|
||||
obj-$(CONFIG_OCTEON_ETHERNET) += octeon/
|
||||
obj-$(CONFIG_VT6655) += vt6655/
|
||||
obj-$(CONFIG_VT6656) += vt6656/
|
||||
|
|
|
|||
|
|
@ -1,9 +0,0 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
config RTS5208
|
||||
tristate "Realtek PCI-E Card Reader RTS5208/5288 support"
|
||||
depends on PCI && SCSI
|
||||
help
|
||||
Say Y here to include driver code to support the Realtek
|
||||
PCI-E card reader rts5208/rts5288.
|
||||
|
||||
If this driver is compiled as a module, it will be named rts5208.
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
obj-$(CONFIG_RTS5208) := rts5208.o
|
||||
|
||||
rts5208-y := rtsx.o rtsx_chip.o rtsx_transport.o rtsx_scsi.o \
|
||||
rtsx_card.o general.o sd.o xd.o ms.o spi.o
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
TODO:
|
||||
- use kernel coding style
|
||||
- checkpatch.pl fixes
|
||||
- We will use the stack in drivers/mmc to implement
|
||||
rts5208/5288 in the future
|
||||
|
||||
Micky Ching <micky_ching@realsil.com.cn>
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Driver for Realtek PCI-Express card reader
|
||||
*
|
||||
* Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
|
||||
*
|
||||
* Author:
|
||||
* Wei WANG (wei_wang@realsil.com.cn)
|
||||
* Micky Ching (micky_ching@realsil.com.cn)
|
||||
*/
|
||||
|
||||
#include "general.h"
|
||||
|
||||
int bit1cnt_long(u32 data)
|
||||
{
|
||||
int i, cnt = 0;
|
||||
|
||||
for (i = 0; i < 32; i++) {
|
||||
if (data & 0x01)
|
||||
cnt++;
|
||||
data >>= 1;
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Driver for Realtek PCI-Express card reader
|
||||
*
|
||||
* Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
|
||||
*
|
||||
* Author:
|
||||
* Wei WANG (wei_wang@realsil.com.cn)
|
||||
* Micky Ching (micky_ching@realsil.com.cn)
|
||||
*/
|
||||
|
||||
#ifndef __RTSX_GENERAL_H
|
||||
#define __RTSX_GENERAL_H
|
||||
|
||||
#include "rtsx.h"
|
||||
|
||||
int bit1cnt_long(u32 data);
|
||||
|
||||
#endif /* __RTSX_GENERAL_H */
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,214 +0,0 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Driver for Realtek PCI-Express card reader
|
||||
*
|
||||
* Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
|
||||
*
|
||||
* Author:
|
||||
* Wei WANG (wei_wang@realsil.com.cn)
|
||||
* Micky Ching (micky_ching@realsil.com.cn)
|
||||
*/
|
||||
|
||||
#ifndef __REALTEK_RTSX_MS_H
|
||||
#define __REALTEK_RTSX_MS_H
|
||||
|
||||
#define MS_DELAY_WRITE
|
||||
|
||||
#define MS_MAX_RETRY_COUNT 3
|
||||
|
||||
#define MS_EXTRA_SIZE 0x9
|
||||
|
||||
#define WRT_PRTCT 0x01
|
||||
|
||||
/* Error Code */
|
||||
#define MS_NO_ERROR 0x00
|
||||
#define MS_CRC16_ERROR 0x80
|
||||
#define MS_TO_ERROR 0x40
|
||||
#define MS_NO_CARD 0x20
|
||||
#define MS_NO_MEMORY 0x10
|
||||
#define MS_CMD_NK 0x08
|
||||
#define MS_FLASH_READ_ERROR 0x04
|
||||
#define MS_FLASH_WRITE_ERROR 0x02
|
||||
#define MS_BREQ_ERROR 0x01
|
||||
#define MS_NOT_FOUND 0x03
|
||||
|
||||
/* Transfer Protocol Command */
|
||||
#define READ_PAGE_DATA 0x02
|
||||
#define READ_REG 0x04
|
||||
#define GET_INT 0x07
|
||||
#define WRITE_PAGE_DATA 0x0D
|
||||
#define WRITE_REG 0x0B
|
||||
#define SET_RW_REG_ADRS 0x08
|
||||
#define SET_CMD 0x0E
|
||||
|
||||
#define PRO_READ_LONG_DATA 0x02
|
||||
#define PRO_READ_SHORT_DATA 0x03
|
||||
#define PRO_READ_REG 0x04
|
||||
#define PRO_READ_QUAD_DATA 0x05
|
||||
#define PRO_GET_INT 0x07
|
||||
#define PRO_WRITE_LONG_DATA 0x0D
|
||||
#define PRO_WRITE_SHORT_DATA 0x0C
|
||||
#define PRO_WRITE_QUAD_DATA 0x0A
|
||||
#define PRO_WRITE_REG 0x0B
|
||||
#define PRO_SET_RW_REG_ADRS 0x08
|
||||
#define PRO_SET_CMD 0x0E
|
||||
#define PRO_EX_SET_CMD 0x09
|
||||
|
||||
#ifdef SUPPORT_MAGIC_GATE
|
||||
|
||||
#define MG_GET_ID 0x40
|
||||
#define MG_SET_LID 0x41
|
||||
#define MG_GET_LEKB 0x42
|
||||
#define MG_SET_RD 0x43
|
||||
#define MG_MAKE_RMS 0x44
|
||||
#define MG_MAKE_KSE 0x45
|
||||
#define MG_SET_IBD 0x46
|
||||
#define MG_GET_IBD 0x47
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef XC_POWERCLASS
|
||||
#define XC_CHG_POWER 0x16
|
||||
#endif
|
||||
|
||||
#define BLOCK_READ 0xAA
|
||||
#define BLOCK_WRITE 0x55
|
||||
#define BLOCK_END 0x33
|
||||
#define BLOCK_ERASE 0x99
|
||||
#define FLASH_STOP 0xCC
|
||||
|
||||
#define SLEEP 0x5A
|
||||
#define CLEAR_BUF 0xC3
|
||||
#define MS_RESET 0x3C
|
||||
|
||||
#define PRO_READ_DATA 0x20
|
||||
#define PRO_WRITE_DATA 0x21
|
||||
#define PRO_READ_ATRB 0x24
|
||||
#define PRO_STOP 0x25
|
||||
#define PRO_ERASE 0x26
|
||||
#define PRO_READ_2K_DATA 0x27
|
||||
#define PRO_WRITE_2K_DATA 0x28
|
||||
|
||||
#define PRO_FORMAT 0x10
|
||||
#define PRO_SLEEP 0x11
|
||||
|
||||
#define INT_REG 0x01
|
||||
#define STATUS_REG0 0x02
|
||||
#define STATUS_REG1 0x03
|
||||
|
||||
#define SYSTEM_PARAM 0x10
|
||||
#define BLOCK_ADRS 0x11
|
||||
#define CMD_PARM 0x14
|
||||
#define PAGE_ADRS 0x15
|
||||
|
||||
#define OVERWRITE_FLAG 0x16
|
||||
#define MANAGEMEN_FLAG 0x17
|
||||
#define LOGICAL_ADRS 0x18
|
||||
#define RESERVE_AREA 0x1A
|
||||
|
||||
#define PRO_INT_REG 0x01
|
||||
#define PRO_STATUS_REG 0x02
|
||||
#define PRO_TYPE_REG 0x04
|
||||
#define PRO_IF_mode_REG 0x05
|
||||
#define PRO_CATEGORY_REG 0x06
|
||||
#define PRO_CLASS_REG 0x07
|
||||
|
||||
#define PRO_SYSTEM_PARAM 0x10
|
||||
#define PRO_DATA_COUNT1 0x11
|
||||
#define PRO_DATA_COUNT0 0x12
|
||||
#define PRO_DATA_ADDR3 0x13
|
||||
#define PRO_DATA_ADDR2 0x14
|
||||
#define PRO_DATA_ADDR1 0x15
|
||||
#define PRO_DATA_ADDR0 0x16
|
||||
|
||||
#define PRO_TPC_PARM 0x17
|
||||
#define PRO_CMD_PARM 0x18
|
||||
|
||||
#define INT_REG_CED 0x80
|
||||
#define INT_REG_ERR 0x40
|
||||
#define INT_REG_BREQ 0x20
|
||||
#define INT_REG_CMDNK 0x01
|
||||
|
||||
#define BLOCK_BOOT 0xC0
|
||||
#define BLOCK_OK 0x80
|
||||
#define PAGE_OK 0x60
|
||||
#define DATA_COMPL 0x10
|
||||
|
||||
#define NOT_BOOT_BLOCK 0x4
|
||||
#define NOT_TRANSLATION_TABLE 0x8
|
||||
|
||||
#define HEADER_ID0 PPBUF_BASE2
|
||||
#define HEADER_ID1 (PPBUF_BASE2 + 1)
|
||||
#define DISABLED_BLOCK0 (PPBUF_BASE2 + 0x170 + 4)
|
||||
#define DISABLED_BLOCK1 (PPBUF_BASE2 + 0x170 + 5)
|
||||
#define DISABLED_BLOCK2 (PPBUF_BASE2 + 0x170 + 6)
|
||||
#define DISABLED_BLOCK3 (PPBUF_BASE2 + 0x170 + 7)
|
||||
#define BLOCK_SIZE_0 (PPBUF_BASE2 + 0x1a0 + 2)
|
||||
#define BLOCK_SIZE_1 (PPBUF_BASE2 + 0x1a0 + 3)
|
||||
#define BLOCK_COUNT_0 (PPBUF_BASE2 + 0x1a0 + 4)
|
||||
#define BLOCK_COUNT_1 (PPBUF_BASE2 + 0x1a0 + 5)
|
||||
#define EBLOCK_COUNT_0 (PPBUF_BASE2 + 0x1a0 + 6)
|
||||
#define EBLOCK_COUNT_1 (PPBUF_BASE2 + 0x1a0 + 7)
|
||||
#define PAGE_SIZE_0 (PPBUF_BASE2 + 0x1a0 + 8)
|
||||
#define PAGE_SIZE_1 (PPBUF_BASE2 + 0x1a0 + 9)
|
||||
|
||||
#define MS_device_type (PPBUF_BASE2 + 0x1D8)
|
||||
|
||||
#define MS_4bit_support (PPBUF_BASE2 + 0x1D3)
|
||||
|
||||
#define set_PS_NG 1
|
||||
#define set_PS_error 0
|
||||
|
||||
#define PARALLEL_8BIT_IF 0x40
|
||||
#define PARALLEL_4BIT_IF 0x00
|
||||
#define SERIAL_IF 0x80
|
||||
|
||||
#define BUF_FULL 0x10
|
||||
#define BUF_EMPTY 0x20
|
||||
|
||||
#define MEDIA_BUSY 0x80
|
||||
#define FLASH_BUSY 0x40
|
||||
#define DATA_ERROR 0x20
|
||||
#define STS_UCDT 0x10
|
||||
#define EXTRA_ERROR 0x08
|
||||
#define STS_UCEX 0x04
|
||||
#define FLAG_ERROR 0x02
|
||||
#define STS_UCFG 0x01
|
||||
|
||||
#define MS_SHORT_DATA_LEN 32
|
||||
|
||||
#define FORMAT_SUCCESS 0
|
||||
#define FORMAT_FAIL 1
|
||||
#define FORMAT_IN_PROGRESS 2
|
||||
|
||||
#define MS_SET_BAD_BLOCK_FLG(ms_card) ((ms_card)->multi_flag |= 0x80)
|
||||
#define MS_CLR_BAD_BLOCK_FLG(ms_card) ((ms_card)->multi_flag &= 0x7F)
|
||||
#define MS_TST_BAD_BLOCK_FLG(ms_card) ((ms_card)->multi_flag & 0x80)
|
||||
|
||||
void mspro_polling_format_status(struct rtsx_chip *chip);
|
||||
|
||||
void mspro_stop_seq_mode(struct rtsx_chip *chip);
|
||||
int reset_ms_card(struct rtsx_chip *chip);
|
||||
int ms_rw(struct scsi_cmnd *srb, struct rtsx_chip *chip,
|
||||
u32 start_sector, u16 sector_cnt);
|
||||
int mspro_format(struct scsi_cmnd *srb, struct rtsx_chip *chip,
|
||||
int short_data_len, bool quick_format);
|
||||
void ms_free_l2p_tbl(struct rtsx_chip *chip);
|
||||
void ms_cleanup_work(struct rtsx_chip *chip);
|
||||
int ms_power_off_card3v3(struct rtsx_chip *chip);
|
||||
int release_ms_card(struct rtsx_chip *chip);
|
||||
#ifdef MS_DELAY_WRITE
|
||||
int ms_delay_write(struct rtsx_chip *chip);
|
||||
#endif
|
||||
|
||||
#ifdef SUPPORT_MAGIC_GATE
|
||||
int mg_set_leaf_id(struct scsi_cmnd *srb, struct rtsx_chip *chip);
|
||||
int mg_get_local_EKB(struct scsi_cmnd *srb, struct rtsx_chip *chip);
|
||||
int mg_chg(struct scsi_cmnd *srb, struct rtsx_chip *chip);
|
||||
int mg_get_rsp_chg(struct scsi_cmnd *srb, struct rtsx_chip *chip);
|
||||
int mg_rsp(struct scsi_cmnd *srb, struct rtsx_chip *chip);
|
||||
int mg_get_ICV(struct scsi_cmnd *srb, struct rtsx_chip *chip);
|
||||
int mg_set_ICV(struct scsi_cmnd *srb, struct rtsx_chip *chip);
|
||||
#endif
|
||||
|
||||
#endif /* __REALTEK_RTSX_MS_H */
|
||||
|
|
@ -1,987 +0,0 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Driver for Realtek PCI-Express card reader
|
||||
*
|
||||
* Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
|
||||
*
|
||||
* Author:
|
||||
* Wei WANG (wei_wang@realsil.com.cn)
|
||||
* Micky Ching (micky_ching@realsil.com.cn)
|
||||
*/
|
||||
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include "rtsx.h"
|
||||
#include "ms.h"
|
||||
#include "sd.h"
|
||||
#include "xd.h"
|
||||
|
||||
MODULE_DESCRIPTION("Realtek PCI-Express card reader rts5208/rts5288 driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static unsigned int delay_use = 1;
|
||||
module_param(delay_use, uint, 0644);
|
||||
MODULE_PARM_DESC(delay_use, "seconds to delay before using a new device");
|
||||
|
||||
static int ss_en;
|
||||
module_param(ss_en, int, 0644);
|
||||
MODULE_PARM_DESC(ss_en, "enable selective suspend");
|
||||
|
||||
static int ss_interval = 50;
|
||||
module_param(ss_interval, int, 0644);
|
||||
MODULE_PARM_DESC(ss_interval, "Interval to enter ss state in seconds");
|
||||
|
||||
static int auto_delink_en;
|
||||
module_param(auto_delink_en, int, 0644);
|
||||
MODULE_PARM_DESC(auto_delink_en, "enable auto delink");
|
||||
|
||||
static unsigned char aspm_l0s_l1_en;
|
||||
module_param(aspm_l0s_l1_en, byte, 0644);
|
||||
MODULE_PARM_DESC(aspm_l0s_l1_en, "enable device aspm");
|
||||
|
||||
static int msi_en;
|
||||
module_param(msi_en, int, 0644);
|
||||
MODULE_PARM_DESC(msi_en, "enable msi");
|
||||
|
||||
static irqreturn_t rtsx_interrupt(int irq, void *dev_id);
|
||||
|
||||
/***********************************************************************
|
||||
* Host functions
|
||||
***********************************************************************/
|
||||
|
||||
static const char *host_info(struct Scsi_Host *host)
|
||||
{
|
||||
return "SCSI emulation for PCI-Express Mass Storage devices";
|
||||
}
|
||||
|
||||
static int slave_alloc(struct scsi_device *sdev)
|
||||
{
|
||||
/*
|
||||
* Set the INQUIRY transfer length to 36. We don't use any of
|
||||
* the extra data and many devices choke if asked for more or
|
||||
* less than 36 bytes.
|
||||
*/
|
||||
sdev->inquiry_len = 36;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int slave_configure(struct scsi_device *sdev)
|
||||
{
|
||||
/* Set the SCSI level to at least 2. We'll leave it at 3 if that's
|
||||
* what is originally reported. We need this to avoid confusing
|
||||
* the SCSI layer with devices that report 0 or 1, but need 10-byte
|
||||
* commands (ala ATAPI devices behind certain bridges, or devices
|
||||
* which simply have broken INQUIRY data).
|
||||
*
|
||||
* NOTE: This means /dev/sg programs (ala cdrecord) will get the
|
||||
* actual information. This seems to be the preference for
|
||||
* programs like that.
|
||||
*
|
||||
* NOTE: This also means that /proc/scsi/scsi and sysfs may report
|
||||
* the actual value or the modified one, depending on where the
|
||||
* data comes from.
|
||||
*/
|
||||
if (sdev->scsi_level < SCSI_2) {
|
||||
sdev->scsi_level = SCSI_2;
|
||||
sdev->sdev_target->scsi_level = SCSI_2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* /proc/scsi/ functions
|
||||
***********************************************************************/
|
||||
|
||||
/* we use this macro to help us write into the buffer */
|
||||
#undef SPRINTF
|
||||
#define SPRINTF(args...) \
|
||||
do { \
|
||||
if (pos < buffer + length) \
|
||||
pos += sprintf(pos, ## args); \
|
||||
} while (0)
|
||||
|
||||
/* queue a command */
|
||||
/* This is always called with spin_lock_irq(host->host_lock) held */
|
||||
static int queuecommand_lck(struct scsi_cmnd *srb)
|
||||
{
|
||||
void (*done)(struct scsi_cmnd *) = scsi_done;
|
||||
struct rtsx_dev *dev = host_to_rtsx(srb->device->host);
|
||||
struct rtsx_chip *chip = dev->chip;
|
||||
|
||||
/* check for state-transition errors */
|
||||
if (chip->srb) {
|
||||
dev_err(&dev->pci->dev, "Error: chip->srb = %p\n",
|
||||
chip->srb);
|
||||
return SCSI_MLQUEUE_HOST_BUSY;
|
||||
}
|
||||
|
||||
/* fail the command if we are disconnecting */
|
||||
if (rtsx_chk_stat(chip, RTSX_STAT_DISCONNECT)) {
|
||||
dev_info(&dev->pci->dev, "Fail command during disconnect\n");
|
||||
srb->result = DID_NO_CONNECT << 16;
|
||||
done(srb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* enqueue the command and wake up the control thread */
|
||||
chip->srb = srb;
|
||||
complete(&dev->cmnd_ready);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static DEF_SCSI_QCMD(queuecommand)
|
||||
|
||||
/***********************************************************************
|
||||
* Error handling functions
|
||||
***********************************************************************/
|
||||
|
||||
/* Command timeout and abort */
|
||||
static int command_abort(struct scsi_cmnd *srb)
|
||||
{
|
||||
struct Scsi_Host *host = srb->device->host;
|
||||
struct rtsx_dev *dev = host_to_rtsx(host);
|
||||
struct rtsx_chip *chip = dev->chip;
|
||||
|
||||
spin_lock_irq(host->host_lock);
|
||||
|
||||
/* Is this command still active? */
|
||||
if (chip->srb != srb) {
|
||||
spin_unlock_irq(host->host_lock);
|
||||
dev_info(&dev->pci->dev, "-- nothing to abort\n");
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
rtsx_set_stat(chip, RTSX_STAT_ABORT);
|
||||
|
||||
spin_unlock_irq(host->host_lock);
|
||||
|
||||
/* Wait for the aborted command to finish */
|
||||
wait_for_completion(&dev->notify);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* This invokes the transport reset mechanism to reset the state of the
|
||||
* device
|
||||
*/
|
||||
static int device_reset(struct scsi_cmnd *srb)
|
||||
{
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* this defines our host template, with which we'll allocate hosts
|
||||
*/
|
||||
|
||||
static const struct scsi_host_template rtsx_host_template = {
|
||||
/* basic userland interface stuff */
|
||||
.name = CR_DRIVER_NAME,
|
||||
.proc_name = CR_DRIVER_NAME,
|
||||
.info = host_info,
|
||||
|
||||
/* command interface -- queued only */
|
||||
.queuecommand = queuecommand,
|
||||
|
||||
/* error and abort handlers */
|
||||
.eh_abort_handler = command_abort,
|
||||
.eh_device_reset_handler = device_reset,
|
||||
|
||||
/* queue commands only, only one command per LUN */
|
||||
.can_queue = 1,
|
||||
|
||||
/* unknown initiator id */
|
||||
.this_id = -1,
|
||||
|
||||
.slave_alloc = slave_alloc,
|
||||
.slave_configure = slave_configure,
|
||||
|
||||
/* lots of sg segments can be handled */
|
||||
.sg_tablesize = SG_ALL,
|
||||
|
||||
/* limit the total size of a transfer to 120 KB */
|
||||
.max_sectors = 240,
|
||||
|
||||
/*
|
||||
* Scatter-gather buffers (all but the last) must have a length
|
||||
* divisible by the bulk maxpacket size. Otherwise a data packet
|
||||
* would end up being short, causing a premature end to the data
|
||||
* transfer. Since high-speed bulk pipes have a maxpacket size
|
||||
* of 512, we'll use that as the scsi device queue's DMA alignment
|
||||
* mask. Guaranteeing proper alignment of the first buffer will
|
||||
* have the desired effect because, except at the beginning and
|
||||
* the end, scatter-gather buffers follow page boundaries.
|
||||
*/
|
||||
.dma_alignment = 511,
|
||||
|
||||
/* emulated HBA */
|
||||
.emulated = 1,
|
||||
|
||||
/* we do our own delay after a device or bus reset */
|
||||
.skip_settle_delay = 1,
|
||||
|
||||
/* module management */
|
||||
.module = THIS_MODULE
|
||||
};
|
||||
|
||||
static int rtsx_acquire_irq(struct rtsx_dev *dev)
|
||||
{
|
||||
struct rtsx_chip *chip = dev->chip;
|
||||
|
||||
dev_info(&dev->pci->dev, "%s: chip->msi_en = %d, pci->irq = %d\n",
|
||||
__func__, chip->msi_en, dev->pci->irq);
|
||||
|
||||
if (request_irq(dev->pci->irq, rtsx_interrupt,
|
||||
chip->msi_en ? 0 : IRQF_SHARED,
|
||||
CR_DRIVER_NAME, dev)) {
|
||||
dev_err(&dev->pci->dev,
|
||||
"rtsx: unable to grab IRQ %d, disabling device\n",
|
||||
dev->pci->irq);
|
||||
return -1;
|
||||
}
|
||||
|
||||
dev->irq = dev->pci->irq;
|
||||
pci_intx(dev->pci, !chip->msi_en);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* power management
|
||||
*/
|
||||
static int __maybe_unused rtsx_suspend(struct device *dev_d)
|
||||
{
|
||||
struct pci_dev *pci = to_pci_dev(dev_d);
|
||||
struct rtsx_dev *dev = pci_get_drvdata(pci);
|
||||
struct rtsx_chip *chip;
|
||||
|
||||
if (!dev)
|
||||
return 0;
|
||||
|
||||
/* lock the device pointers */
|
||||
mutex_lock(&dev->dev_mutex);
|
||||
|
||||
chip = dev->chip;
|
||||
|
||||
rtsx_do_before_power_down(chip, PM_S3);
|
||||
|
||||
if (dev->irq >= 0) {
|
||||
free_irq(dev->irq, (void *)dev);
|
||||
dev->irq = -1;
|
||||
}
|
||||
|
||||
if (chip->msi_en)
|
||||
pci_free_irq_vectors(pci);
|
||||
|
||||
device_wakeup_enable(dev_d);
|
||||
|
||||
/* unlock the device pointers */
|
||||
mutex_unlock(&dev->dev_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused rtsx_resume(struct device *dev_d)
|
||||
{
|
||||
struct pci_dev *pci = to_pci_dev(dev_d);
|
||||
struct rtsx_dev *dev = pci_get_drvdata(pci);
|
||||
struct rtsx_chip *chip;
|
||||
|
||||
if (!dev)
|
||||
return 0;
|
||||
|
||||
chip = dev->chip;
|
||||
|
||||
/* lock the device pointers */
|
||||
mutex_lock(&dev->dev_mutex);
|
||||
|
||||
pci_set_master(pci);
|
||||
|
||||
if (chip->msi_en) {
|
||||
if (pci_alloc_irq_vectors(pci, 1, 1, PCI_IRQ_MSI) < 0)
|
||||
chip->msi_en = 0;
|
||||
}
|
||||
|
||||
if (rtsx_acquire_irq(dev) < 0) {
|
||||
/* unlock the device pointers */
|
||||
mutex_unlock(&dev->dev_mutex);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
rtsx_write_register(chip, HOST_SLEEP_STATE, 0x03, 0x00);
|
||||
rtsx_init_chip(chip);
|
||||
|
||||
/* unlock the device pointers */
|
||||
mutex_unlock(&dev->dev_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rtsx_shutdown(struct pci_dev *pci)
|
||||
{
|
||||
struct rtsx_dev *dev = pci_get_drvdata(pci);
|
||||
struct rtsx_chip *chip;
|
||||
|
||||
if (!dev)
|
||||
return;
|
||||
|
||||
chip = dev->chip;
|
||||
|
||||
rtsx_do_before_power_down(chip, PM_S1);
|
||||
|
||||
if (dev->irq >= 0) {
|
||||
free_irq(dev->irq, (void *)dev);
|
||||
dev->irq = -1;
|
||||
}
|
||||
|
||||
if (chip->msi_en)
|
||||
pci_free_irq_vectors(pci);
|
||||
|
||||
pci_disable_device(pci);
|
||||
}
|
||||
|
||||
static int rtsx_control_thread(void *__dev)
|
||||
{
|
||||
struct rtsx_dev *dev = __dev;
|
||||
struct rtsx_chip *chip = dev->chip;
|
||||
struct Scsi_Host *host = rtsx_to_host(dev);
|
||||
|
||||
for (;;) {
|
||||
if (wait_for_completion_interruptible(&dev->cmnd_ready))
|
||||
break;
|
||||
|
||||
/* lock the device pointers */
|
||||
mutex_lock(&dev->dev_mutex);
|
||||
|
||||
/* if the device has disconnected, we are free to exit */
|
||||
if (rtsx_chk_stat(chip, RTSX_STAT_DISCONNECT)) {
|
||||
dev_info(&dev->pci->dev, "-- rtsx-control exiting\n");
|
||||
mutex_unlock(&dev->dev_mutex);
|
||||
break;
|
||||
}
|
||||
|
||||
/* lock access to the state */
|
||||
spin_lock_irq(host->host_lock);
|
||||
|
||||
/* has the command aborted ? */
|
||||
if (rtsx_chk_stat(chip, RTSX_STAT_ABORT)) {
|
||||
chip->srb->result = DID_ABORT << 16;
|
||||
goto skip_for_abort;
|
||||
}
|
||||
|
||||
spin_unlock_irq(host->host_lock);
|
||||
|
||||
/* reject the command if the direction indicator
|
||||
* is UNKNOWN
|
||||
*/
|
||||
if (chip->srb->sc_data_direction == DMA_BIDIRECTIONAL) {
|
||||
dev_err(&dev->pci->dev, "UNKNOWN data direction\n");
|
||||
chip->srb->result = DID_ERROR << 16;
|
||||
} else if (chip->srb->device->id) {
|
||||
/* reject if target != 0 or if LUN is higher than
|
||||
* the maximum known LUN
|
||||
*/
|
||||
dev_err(&dev->pci->dev, "Bad target number (%d:%d)\n",
|
||||
chip->srb->device->id,
|
||||
(u8)chip->srb->device->lun);
|
||||
chip->srb->result = DID_BAD_TARGET << 16;
|
||||
} else if (chip->srb->device->lun > chip->max_lun) {
|
||||
dev_err(&dev->pci->dev, "Bad LUN (%d:%d)\n",
|
||||
chip->srb->device->id,
|
||||
(u8)chip->srb->device->lun);
|
||||
chip->srb->result = DID_BAD_TARGET << 16;
|
||||
} else {
|
||||
/* we've got a command, let's do it! */
|
||||
scsi_show_command(chip);
|
||||
rtsx_invoke_transport(chip->srb, chip);
|
||||
}
|
||||
|
||||
/* lock access to the state */
|
||||
spin_lock_irq(host->host_lock);
|
||||
|
||||
/* did the command already complete because of a disconnect? */
|
||||
if (!chip->srb)
|
||||
; /* nothing to do */
|
||||
|
||||
/* indicate that the command is done */
|
||||
else if (chip->srb->result != DID_ABORT << 16) {
|
||||
scsi_done(chip->srb);
|
||||
} else {
|
||||
skip_for_abort:
|
||||
dev_err(&dev->pci->dev, "scsi command aborted\n");
|
||||
}
|
||||
|
||||
if (rtsx_chk_stat(chip, RTSX_STAT_ABORT)) {
|
||||
complete(&dev->notify);
|
||||
|
||||
rtsx_set_stat(chip, RTSX_STAT_IDLE);
|
||||
}
|
||||
|
||||
/* finished working on this command */
|
||||
chip->srb = NULL;
|
||||
spin_unlock_irq(host->host_lock);
|
||||
|
||||
/* unlock the device pointers */
|
||||
mutex_unlock(&dev->dev_mutex);
|
||||
} /* for (;;) */
|
||||
|
||||
/* notify the exit routine that we're actually exiting now
|
||||
*
|
||||
* complete()/wait_for_completion() is similar to up()/down(),
|
||||
* except that complete() is safe in the case where the structure
|
||||
* is getting deleted in a parallel mode of execution (i.e. just
|
||||
* after the down() -- that's necessary for the thread-shutdown
|
||||
* case.
|
||||
*
|
||||
* kthread_complete_and_exit() goes even further than this --
|
||||
* it is safe in the case that the thread of the caller is going away
|
||||
* (not just the structure) -- this is necessary for the module-remove
|
||||
* case. This is important in preemption kernels, which transfer the
|
||||
* flow of execution immediately upon a complete().
|
||||
*/
|
||||
kthread_complete_and_exit(&dev->control_exit, 0);
|
||||
}
|
||||
|
||||
static int rtsx_polling_thread(void *__dev)
|
||||
{
|
||||
struct rtsx_dev *dev = __dev;
|
||||
struct rtsx_chip *chip = dev->chip;
|
||||
struct sd_info *sd_card = &chip->sd_card;
|
||||
struct xd_info *xd_card = &chip->xd_card;
|
||||
struct ms_info *ms_card = &chip->ms_card;
|
||||
|
||||
sd_card->cleanup_counter = 0;
|
||||
xd_card->cleanup_counter = 0;
|
||||
ms_card->cleanup_counter = 0;
|
||||
|
||||
/* Wait until SCSI scan finished */
|
||||
wait_timeout((delay_use + 5) * 1000);
|
||||
|
||||
for (;;) {
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
schedule_timeout(msecs_to_jiffies(POLLING_INTERVAL));
|
||||
|
||||
/* lock the device pointers */
|
||||
mutex_lock(&dev->dev_mutex);
|
||||
|
||||
/* if the device has disconnected, we are free to exit */
|
||||
if (rtsx_chk_stat(chip, RTSX_STAT_DISCONNECT)) {
|
||||
dev_info(&dev->pci->dev, "-- rtsx-polling exiting\n");
|
||||
mutex_unlock(&dev->dev_mutex);
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&dev->dev_mutex);
|
||||
|
||||
mspro_polling_format_status(chip);
|
||||
|
||||
/* lock the device pointers */
|
||||
mutex_lock(&dev->dev_mutex);
|
||||
|
||||
rtsx_polling_func(chip);
|
||||
|
||||
/* unlock the device pointers */
|
||||
mutex_unlock(&dev->dev_mutex);
|
||||
}
|
||||
|
||||
kthread_complete_and_exit(&dev->polling_exit, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* interrupt handler
|
||||
*/
|
||||
static irqreturn_t rtsx_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct rtsx_dev *dev = dev_id;
|
||||
struct rtsx_chip *chip;
|
||||
int retval;
|
||||
u32 status;
|
||||
|
||||
if (dev)
|
||||
chip = dev->chip;
|
||||
else
|
||||
return IRQ_NONE;
|
||||
|
||||
if (!chip)
|
||||
return IRQ_NONE;
|
||||
|
||||
spin_lock(&dev->reg_lock);
|
||||
|
||||
retval = rtsx_pre_handle_interrupt(chip);
|
||||
if (retval == STATUS_FAIL) {
|
||||
spin_unlock(&dev->reg_lock);
|
||||
if (chip->int_reg == 0xFFFFFFFF)
|
||||
return IRQ_HANDLED;
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
status = chip->int_reg;
|
||||
|
||||
if (dev->check_card_cd) {
|
||||
if (!(dev->check_card_cd & status)) {
|
||||
/* card not exist, return TRANS_RESULT_FAIL */
|
||||
dev->trans_result = TRANS_RESULT_FAIL;
|
||||
if (dev->done)
|
||||
complete(dev->done);
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
if (status & (NEED_COMPLETE_INT | DELINK_INT)) {
|
||||
if (status & (TRANS_FAIL_INT | DELINK_INT)) {
|
||||
if (status & DELINK_INT)
|
||||
RTSX_SET_DELINK(chip);
|
||||
dev->trans_result = TRANS_RESULT_FAIL;
|
||||
if (dev->done)
|
||||
complete(dev->done);
|
||||
} else if (status & TRANS_OK_INT) {
|
||||
dev->trans_result = TRANS_RESULT_OK;
|
||||
if (dev->done)
|
||||
complete(dev->done);
|
||||
} else if (status & DATA_DONE_INT) {
|
||||
dev->trans_result = TRANS_NOT_READY;
|
||||
if (dev->done && dev->trans_state == STATE_TRANS_SG)
|
||||
complete(dev->done);
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
spin_unlock(&dev->reg_lock);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/* Release all our dynamic resources */
|
||||
static void rtsx_release_resources(struct rtsx_dev *dev)
|
||||
{
|
||||
dev_info(&dev->pci->dev, "-- %s\n", __func__);
|
||||
|
||||
/* Tell the control thread to exit. The SCSI host must
|
||||
* already have been removed so it won't try to queue
|
||||
* any more commands.
|
||||
*/
|
||||
dev_info(&dev->pci->dev, "-- sending exit command to thread\n");
|
||||
complete(&dev->cmnd_ready);
|
||||
if (dev->ctl_thread)
|
||||
wait_for_completion(&dev->control_exit);
|
||||
if (dev->polling_thread)
|
||||
wait_for_completion(&dev->polling_exit);
|
||||
|
||||
wait_timeout(200);
|
||||
|
||||
if (dev->rtsx_resv_buf) {
|
||||
dev->chip->host_cmds_ptr = NULL;
|
||||
dev->chip->host_sg_tbl_ptr = NULL;
|
||||
}
|
||||
|
||||
if (dev->irq > 0)
|
||||
free_irq(dev->irq, (void *)dev);
|
||||
if (dev->chip->msi_en)
|
||||
pci_free_irq_vectors(dev->pci);
|
||||
if (dev->remap_addr)
|
||||
iounmap(dev->remap_addr);
|
||||
|
||||
rtsx_release_chip(dev->chip);
|
||||
kfree(dev->chip);
|
||||
}
|
||||
|
||||
/*
|
||||
* First stage of disconnect processing: stop all commands and remove
|
||||
* the host
|
||||
*/
|
||||
static void quiesce_and_remove_host(struct rtsx_dev *dev)
|
||||
{
|
||||
struct Scsi_Host *host = rtsx_to_host(dev);
|
||||
struct rtsx_chip *chip = dev->chip;
|
||||
|
||||
/*
|
||||
* Prevent new transfers, stop the current command, and
|
||||
* interrupt a SCSI-scan or device-reset delay
|
||||
*/
|
||||
mutex_lock(&dev->dev_mutex);
|
||||
spin_lock_irq(host->host_lock);
|
||||
rtsx_set_stat(chip, RTSX_STAT_DISCONNECT);
|
||||
spin_unlock_irq(host->host_lock);
|
||||
mutex_unlock(&dev->dev_mutex);
|
||||
wake_up(&dev->delay_wait);
|
||||
wait_for_completion(&dev->scanning_done);
|
||||
|
||||
/* Wait some time to let other threads exist */
|
||||
wait_timeout(100);
|
||||
|
||||
/*
|
||||
* queuecommand won't accept any new commands and the control
|
||||
* thread won't execute a previously-queued command. If there
|
||||
* is such a command pending, complete it with an error.
|
||||
*/
|
||||
mutex_lock(&dev->dev_mutex);
|
||||
if (chip->srb) {
|
||||
chip->srb->result = DID_NO_CONNECT << 16;
|
||||
spin_lock_irq(host->host_lock);
|
||||
scsi_done(dev->chip->srb);
|
||||
chip->srb = NULL;
|
||||
spin_unlock_irq(host->host_lock);
|
||||
}
|
||||
mutex_unlock(&dev->dev_mutex);
|
||||
|
||||
/* Now we own no commands so it's safe to remove the SCSI host */
|
||||
scsi_remove_host(host);
|
||||
}
|
||||
|
||||
/* Second stage of disconnect processing: deallocate all resources */
|
||||
static void release_everything(struct rtsx_dev *dev)
|
||||
{
|
||||
rtsx_release_resources(dev);
|
||||
|
||||
/*
|
||||
* Drop our reference to the host; the SCSI core will free it
|
||||
* when the refcount becomes 0.
|
||||
*/
|
||||
scsi_host_put(rtsx_to_host(dev));
|
||||
}
|
||||
|
||||
/* Thread to carry out delayed SCSI-device scanning */
|
||||
static int rtsx_scan_thread(void *__dev)
|
||||
{
|
||||
struct rtsx_dev *dev = __dev;
|
||||
struct rtsx_chip *chip = dev->chip;
|
||||
|
||||
/* Wait for the timeout to expire or for a disconnect */
|
||||
if (delay_use > 0) {
|
||||
dev_info(&dev->pci->dev,
|
||||
"%s: waiting for device to settle before scanning\n",
|
||||
CR_DRIVER_NAME);
|
||||
wait_event_interruptible_timeout
|
||||
(dev->delay_wait,
|
||||
rtsx_chk_stat(chip, RTSX_STAT_DISCONNECT),
|
||||
delay_use * HZ);
|
||||
}
|
||||
|
||||
/* If the device is still connected, perform the scanning */
|
||||
if (!rtsx_chk_stat(chip, RTSX_STAT_DISCONNECT)) {
|
||||
scsi_scan_host(rtsx_to_host(dev));
|
||||
dev_info(&dev->pci->dev, "%s: device scan complete\n",
|
||||
CR_DRIVER_NAME);
|
||||
|
||||
/* Should we unbind if no devices were detected? */
|
||||
}
|
||||
|
||||
kthread_complete_and_exit(&dev->scanning_done, 0);
|
||||
}
|
||||
|
||||
static void rtsx_init_options(struct rtsx_chip *chip)
|
||||
{
|
||||
chip->vendor_id = chip->rtsx->pci->vendor;
|
||||
chip->product_id = chip->rtsx->pci->device;
|
||||
chip->adma_mode = 1;
|
||||
chip->lun_mc = 0;
|
||||
chip->driver_first_load = 1;
|
||||
#ifdef HW_AUTO_SWITCH_SD_BUS
|
||||
chip->sdio_in_charge = 0;
|
||||
#endif
|
||||
|
||||
chip->mspro_formatter_enable = 1;
|
||||
chip->ignore_sd = 0;
|
||||
chip->use_hw_setting = 0;
|
||||
chip->lun_mode = DEFAULT_SINGLE;
|
||||
chip->auto_delink_en = auto_delink_en;
|
||||
chip->ss_en = ss_en;
|
||||
chip->ss_idle_period = ss_interval * 1000;
|
||||
chip->remote_wakeup_en = 0;
|
||||
chip->aspm_l0s_l1_en = aspm_l0s_l1_en;
|
||||
chip->dynamic_aspm = 1;
|
||||
chip->fpga_sd_sdr104_clk = CLK_200;
|
||||
chip->fpga_sd_ddr50_clk = CLK_100;
|
||||
chip->fpga_sd_sdr50_clk = CLK_100;
|
||||
chip->fpga_sd_hs_clk = CLK_100;
|
||||
chip->fpga_mmc_52m_clk = CLK_80;
|
||||
chip->fpga_ms_hg_clk = CLK_80;
|
||||
chip->fpga_ms_4bit_clk = CLK_80;
|
||||
chip->fpga_ms_1bit_clk = CLK_40;
|
||||
chip->asic_sd_sdr104_clk = 203;
|
||||
chip->asic_sd_sdr50_clk = 98;
|
||||
chip->asic_sd_ddr50_clk = 98;
|
||||
chip->asic_sd_hs_clk = 98;
|
||||
chip->asic_mmc_52m_clk = 98;
|
||||
chip->asic_ms_hg_clk = 117;
|
||||
chip->asic_ms_4bit_clk = 78;
|
||||
chip->asic_ms_1bit_clk = 39;
|
||||
chip->ssc_depth_sd_sdr104 = SSC_DEPTH_2M;
|
||||
chip->ssc_depth_sd_sdr50 = SSC_DEPTH_2M;
|
||||
chip->ssc_depth_sd_ddr50 = SSC_DEPTH_1M;
|
||||
chip->ssc_depth_sd_hs = SSC_DEPTH_1M;
|
||||
chip->ssc_depth_mmc_52m = SSC_DEPTH_1M;
|
||||
chip->ssc_depth_ms_hg = SSC_DEPTH_1M;
|
||||
chip->ssc_depth_ms_4bit = SSC_DEPTH_512K;
|
||||
chip->ssc_depth_low_speed = SSC_DEPTH_512K;
|
||||
chip->ssc_en = 1;
|
||||
chip->sd_speed_prior = 0x01040203;
|
||||
chip->sd_current_prior = 0x00010203;
|
||||
chip->sd_ctl = SD_PUSH_POINT_AUTO |
|
||||
SD_SAMPLE_POINT_AUTO |
|
||||
SUPPORT_MMC_DDR_MODE;
|
||||
chip->sd_ddr_tx_phase = 0;
|
||||
chip->mmc_ddr_tx_phase = 1;
|
||||
chip->sd_default_tx_phase = 15;
|
||||
chip->sd_default_rx_phase = 15;
|
||||
chip->pmos_pwr_on_interval = 200;
|
||||
chip->sd_voltage_switch_delay = 1000;
|
||||
chip->ms_power_class_en = 3;
|
||||
|
||||
chip->sd_400mA_ocp_thd = 1;
|
||||
chip->sd_800mA_ocp_thd = 5;
|
||||
chip->ms_ocp_thd = 2;
|
||||
|
||||
chip->card_drive_sel = 0x55;
|
||||
chip->sd30_drive_sel_1v8 = 0x03;
|
||||
chip->sd30_drive_sel_3v3 = 0x01;
|
||||
|
||||
chip->do_delink_before_power_down = 1;
|
||||
chip->auto_power_down = 1;
|
||||
chip->polling_config = 0;
|
||||
|
||||
chip->force_clkreq_0 = 1;
|
||||
chip->ft2_fast_mode = 0;
|
||||
|
||||
chip->sdio_retry_cnt = 1;
|
||||
|
||||
chip->xd_timeout = 2000;
|
||||
chip->sd_timeout = 10000;
|
||||
chip->ms_timeout = 2000;
|
||||
chip->mspro_timeout = 15000;
|
||||
|
||||
chip->power_down_in_ss = 1;
|
||||
|
||||
chip->sdr104_en = 1;
|
||||
chip->sdr50_en = 1;
|
||||
chip->ddr50_en = 1;
|
||||
|
||||
chip->delink_stage1_step = 100;
|
||||
chip->delink_stage2_step = 40;
|
||||
chip->delink_stage3_step = 20;
|
||||
|
||||
chip->auto_delink_in_L1 = 1;
|
||||
chip->blink_led = 1;
|
||||
chip->msi_en = msi_en;
|
||||
chip->hp_watch_bios_hotplug = 0;
|
||||
chip->max_payload = 0;
|
||||
chip->phy_voltage = 0;
|
||||
|
||||
chip->support_ms_8bit = 1;
|
||||
chip->s3_pwr_off_delay = 1000;
|
||||
}
|
||||
|
||||
static int rtsx_probe(struct pci_dev *pci,
|
||||
const struct pci_device_id *pci_id)
|
||||
{
|
||||
struct Scsi_Host *host;
|
||||
struct rtsx_dev *dev;
|
||||
int err = 0;
|
||||
struct task_struct *th;
|
||||
|
||||
dev_dbg(&pci->dev, "Realtek PCI-E card reader detected\n");
|
||||
|
||||
err = pcim_enable_device(pci);
|
||||
if (err < 0) {
|
||||
dev_err(&pci->dev, "PCI enable device failed!\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = pci_request_regions(pci, CR_DRIVER_NAME);
|
||||
if (err < 0) {
|
||||
dev_err(&pci->dev, "PCI request regions for %s failed!\n",
|
||||
CR_DRIVER_NAME);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ask the SCSI layer to allocate a host structure, with extra
|
||||
* space at the end for our private rtsx_dev structure.
|
||||
*/
|
||||
host = scsi_host_alloc(&rtsx_host_template, sizeof(*dev));
|
||||
if (!host) {
|
||||
dev_err(&pci->dev, "Unable to allocate the scsi host\n");
|
||||
err = -ENOMEM;
|
||||
goto scsi_host_alloc_fail;
|
||||
}
|
||||
|
||||
dev = host_to_rtsx(host);
|
||||
memset(dev, 0, sizeof(struct rtsx_dev));
|
||||
|
||||
dev->chip = kzalloc(sizeof(*dev->chip), GFP_KERNEL);
|
||||
if (!dev->chip) {
|
||||
err = -ENOMEM;
|
||||
goto chip_alloc_fail;
|
||||
}
|
||||
|
||||
spin_lock_init(&dev->reg_lock);
|
||||
mutex_init(&dev->dev_mutex);
|
||||
init_completion(&dev->cmnd_ready);
|
||||
init_completion(&dev->control_exit);
|
||||
init_completion(&dev->polling_exit);
|
||||
init_completion(&dev->notify);
|
||||
init_completion(&dev->scanning_done);
|
||||
init_waitqueue_head(&dev->delay_wait);
|
||||
|
||||
dev->pci = pci;
|
||||
dev->irq = -1;
|
||||
|
||||
dev_info(&pci->dev, "Resource length: 0x%x\n",
|
||||
(unsigned int)pci_resource_len(pci, 0));
|
||||
dev->addr = pci_resource_start(pci, 0);
|
||||
dev->remap_addr = ioremap(dev->addr, pci_resource_len(pci, 0));
|
||||
if (!dev->remap_addr) {
|
||||
dev_err(&pci->dev, "ioremap error\n");
|
||||
err = -ENXIO;
|
||||
goto ioremap_fail;
|
||||
}
|
||||
|
||||
/*
|
||||
* Using "unsigned long" cast here to eliminate gcc warning in
|
||||
* 64-bit system
|
||||
*/
|
||||
dev_info(&pci->dev, "Original address: 0x%lx, remapped address: 0x%lx\n",
|
||||
(unsigned long)(dev->addr), (unsigned long)(dev->remap_addr));
|
||||
|
||||
dev->rtsx_resv_buf = dmam_alloc_coherent(&pci->dev, RTSX_RESV_BUF_LEN,
|
||||
&dev->rtsx_resv_buf_addr,
|
||||
GFP_KERNEL);
|
||||
if (!dev->rtsx_resv_buf) {
|
||||
dev_err(&pci->dev, "alloc dma buffer fail\n");
|
||||
err = -ENXIO;
|
||||
goto dma_alloc_fail;
|
||||
}
|
||||
dev->chip->host_cmds_ptr = dev->rtsx_resv_buf;
|
||||
dev->chip->host_cmds_addr = dev->rtsx_resv_buf_addr;
|
||||
dev->chip->host_sg_tbl_ptr = dev->rtsx_resv_buf + HOST_CMDS_BUF_LEN;
|
||||
dev->chip->host_sg_tbl_addr = dev->rtsx_resv_buf_addr +
|
||||
HOST_CMDS_BUF_LEN;
|
||||
|
||||
dev->chip->rtsx = dev;
|
||||
|
||||
rtsx_init_options(dev->chip);
|
||||
|
||||
dev_info(&pci->dev, "pci->irq = %d\n", pci->irq);
|
||||
|
||||
if (dev->chip->msi_en) {
|
||||
if (pci_alloc_irq_vectors(pci, 1, 1, PCI_IRQ_MSI) < 0)
|
||||
dev->chip->msi_en = 0;
|
||||
}
|
||||
|
||||
if (rtsx_acquire_irq(dev) < 0) {
|
||||
err = -EBUSY;
|
||||
goto irq_acquire_fail;
|
||||
}
|
||||
|
||||
pci_set_master(pci);
|
||||
synchronize_irq(dev->irq);
|
||||
|
||||
rtsx_init_chip(dev->chip);
|
||||
|
||||
/*
|
||||
* set the supported max_lun and max_id for the scsi host
|
||||
* NOTE: the minimal value of max_id is 1
|
||||
*/
|
||||
host->max_id = 1;
|
||||
host->max_lun = dev->chip->max_lun;
|
||||
|
||||
/* Start up our control thread */
|
||||
th = kthread_run(rtsx_control_thread, dev, CR_DRIVER_NAME);
|
||||
if (IS_ERR(th)) {
|
||||
dev_err(&pci->dev, "Unable to start control thread\n");
|
||||
err = PTR_ERR(th);
|
||||
goto control_thread_fail;
|
||||
}
|
||||
dev->ctl_thread = th;
|
||||
|
||||
err = scsi_add_host(host, &pci->dev);
|
||||
if (err) {
|
||||
dev_err(&pci->dev, "Unable to add the scsi host\n");
|
||||
goto scsi_add_host_fail;
|
||||
}
|
||||
|
||||
/* Start up the thread for delayed SCSI-device scanning */
|
||||
th = kthread_run(rtsx_scan_thread, dev, "rtsx-scan");
|
||||
if (IS_ERR(th)) {
|
||||
dev_err(&pci->dev, "Unable to start the device-scanning thread\n");
|
||||
complete(&dev->scanning_done);
|
||||
err = PTR_ERR(th);
|
||||
goto scan_thread_fail;
|
||||
}
|
||||
|
||||
/* Start up the thread for polling thread */
|
||||
th = kthread_run(rtsx_polling_thread, dev, "rtsx-polling");
|
||||
if (IS_ERR(th)) {
|
||||
dev_err(&pci->dev, "Unable to start the device-polling thread\n");
|
||||
err = PTR_ERR(th);
|
||||
goto scan_thread_fail;
|
||||
}
|
||||
dev->polling_thread = th;
|
||||
|
||||
pci_set_drvdata(pci, dev);
|
||||
|
||||
return 0;
|
||||
|
||||
/* We come here if there are any problems */
|
||||
scan_thread_fail:
|
||||
quiesce_and_remove_host(dev);
|
||||
scsi_add_host_fail:
|
||||
complete(&dev->cmnd_ready);
|
||||
wait_for_completion(&dev->control_exit);
|
||||
control_thread_fail:
|
||||
free_irq(dev->irq, (void *)dev);
|
||||
rtsx_release_chip(dev->chip);
|
||||
irq_acquire_fail:
|
||||
dev->chip->host_cmds_ptr = NULL;
|
||||
dev->chip->host_sg_tbl_ptr = NULL;
|
||||
if (dev->chip->msi_en)
|
||||
pci_free_irq_vectors(dev->pci);
|
||||
dma_alloc_fail:
|
||||
iounmap(dev->remap_addr);
|
||||
ioremap_fail:
|
||||
kfree(dev->chip);
|
||||
chip_alloc_fail:
|
||||
dev_err(&pci->dev, "%s failed\n", __func__);
|
||||
scsi_host_put(host);
|
||||
scsi_host_alloc_fail:
|
||||
pci_release_regions(pci);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void rtsx_remove(struct pci_dev *pci)
|
||||
{
|
||||
struct rtsx_dev *dev = pci_get_drvdata(pci);
|
||||
|
||||
quiesce_and_remove_host(dev);
|
||||
release_everything(dev);
|
||||
pci_release_regions(pci);
|
||||
}
|
||||
|
||||
/* PCI IDs */
|
||||
static const struct pci_device_id rtsx_ids[] = {
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x5208),
|
||||
PCI_CLASS_OTHERS << 16, 0xFF0000 },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x5288),
|
||||
PCI_CLASS_OTHERS << 16, 0xFF0000 },
|
||||
{ 0, },
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(pci, rtsx_ids);
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(rtsx_pm_ops, rtsx_suspend, rtsx_resume);
|
||||
|
||||
/* pci_driver definition */
|
||||
static struct pci_driver rtsx_driver = {
|
||||
.name = CR_DRIVER_NAME,
|
||||
.id_table = rtsx_ids,
|
||||
.probe = rtsx_probe,
|
||||
.remove = rtsx_remove,
|
||||
.driver.pm = &rtsx_pm_ops,
|
||||
.shutdown = rtsx_shutdown,
|
||||
};
|
||||
|
||||
module_pci_driver(rtsx_driver);
|
||||
|
|
@ -1,164 +0,0 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Driver for Realtek PCI-Express card reader
|
||||
*
|
||||
* Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
|
||||
*
|
||||
* Author:
|
||||
* Wei WANG (wei_wang@realsil.com.cn)
|
||||
* Micky Ching (micky_ching@realsil.com.cn)
|
||||
*/
|
||||
|
||||
#ifndef __REALTEK_RTSX_H
|
||||
#define __REALTEK_RTSX_H
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/cdrom.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/time64.h>
|
||||
|
||||
#include <scsi/scsi.h>
|
||||
#include <scsi/scsi_cmnd.h>
|
||||
#include <scsi/scsi_device.h>
|
||||
#include <scsi/scsi_devinfo.h>
|
||||
#include <scsi/scsi_eh.h>
|
||||
#include <scsi/scsi_host.h>
|
||||
|
||||
#define CR_DRIVER_NAME "rts5208"
|
||||
|
||||
/*
|
||||
* macros for easy use
|
||||
*/
|
||||
#define wait_timeout_x(task_state, msecs) \
|
||||
do { \
|
||||
set_current_state((task_state)); \
|
||||
schedule_timeout((msecs) * HZ / 1000); \
|
||||
} while (0)
|
||||
#define wait_timeout(msecs) wait_timeout_x(TASK_INTERRUPTIBLE, (msecs))
|
||||
|
||||
#define STATE_TRANS_NONE 0
|
||||
#define STATE_TRANS_CMD 1
|
||||
#define STATE_TRANS_BUF 2
|
||||
#define STATE_TRANS_SG 3
|
||||
|
||||
#define TRANS_NOT_READY 0
|
||||
#define TRANS_RESULT_OK 1
|
||||
#define TRANS_RESULT_FAIL 2
|
||||
|
||||
#define SCSI_LUN(srb) ((srb)->device->lun)
|
||||
|
||||
struct rtsx_chip;
|
||||
|
||||
struct rtsx_dev {
|
||||
struct pci_dev *pci;
|
||||
|
||||
/* pci resources */
|
||||
unsigned long addr;
|
||||
void __iomem *remap_addr;
|
||||
int irq;
|
||||
|
||||
/* locks */
|
||||
spinlock_t reg_lock;
|
||||
|
||||
struct task_struct *ctl_thread; /* the control thread */
|
||||
struct task_struct *polling_thread; /* the polling thread */
|
||||
|
||||
/* mutual exclusion and synchronization structures */
|
||||
struct completion cmnd_ready; /* to sleep thread on */
|
||||
struct completion control_exit; /* control thread exit */
|
||||
struct completion polling_exit; /* polling thread exit */
|
||||
struct completion notify; /* thread begin/end */
|
||||
struct completion scanning_done; /* wait for scan thread */
|
||||
|
||||
wait_queue_head_t delay_wait; /* wait during scan, reset */
|
||||
struct mutex dev_mutex;
|
||||
|
||||
/* host reserved buffer */
|
||||
void *rtsx_resv_buf;
|
||||
dma_addr_t rtsx_resv_buf_addr;
|
||||
|
||||
char trans_result;
|
||||
char trans_state;
|
||||
|
||||
struct completion *done;
|
||||
/* Whether interrupt handler should care card cd info */
|
||||
u32 check_card_cd;
|
||||
|
||||
struct rtsx_chip *chip;
|
||||
};
|
||||
|
||||
/* Convert between rtsx_dev and the corresponding Scsi_Host */
|
||||
static inline struct Scsi_Host *rtsx_to_host(struct rtsx_dev *dev)
|
||||
{
|
||||
return container_of((void *)dev, struct Scsi_Host, hostdata);
|
||||
}
|
||||
|
||||
static inline struct rtsx_dev *host_to_rtsx(struct Scsi_Host *host)
|
||||
{
|
||||
return (struct rtsx_dev *)host->hostdata;
|
||||
}
|
||||
|
||||
#define lock_state(chip) spin_lock_irq(&((chip)->rtsx->reg_lock))
|
||||
#define unlock_state(chip) spin_unlock_irq(&((chip)->rtsx->reg_lock))
|
||||
|
||||
/* struct scsi_cmnd transfer buffer access utilities */
|
||||
enum xfer_buf_dir {TO_XFER_BUF, FROM_XFER_BUF};
|
||||
|
||||
#include "rtsx_chip.h"
|
||||
#include "rtsx_transport.h"
|
||||
#include "rtsx_scsi.h"
|
||||
#include "rtsx_card.h"
|
||||
#include "rtsx_sys.h"
|
||||
#include "general.h"
|
||||
|
||||
static inline void rtsx_writel(struct rtsx_chip *chip, u32 reg, u32 value)
|
||||
{
|
||||
iowrite32(value, chip->rtsx->remap_addr + reg);
|
||||
}
|
||||
|
||||
static inline u32 rtsx_readl(struct rtsx_chip *chip, u32 reg)
|
||||
{
|
||||
return ioread32(chip->rtsx->remap_addr + reg);
|
||||
}
|
||||
|
||||
static inline void rtsx_writew(struct rtsx_chip *chip, u32 reg, u16 value)
|
||||
{
|
||||
iowrite16(value, chip->rtsx->remap_addr + reg);
|
||||
}
|
||||
|
||||
static inline u16 rtsx_readw(struct rtsx_chip *chip, u32 reg)
|
||||
{
|
||||
return ioread16(chip->rtsx->remap_addr + reg);
|
||||
}
|
||||
|
||||
static inline void rtsx_writeb(struct rtsx_chip *chip, u32 reg, u8 value)
|
||||
{
|
||||
iowrite8(value, chip->rtsx->remap_addr + reg);
|
||||
}
|
||||
|
||||
static inline u8 rtsx_readb(struct rtsx_chip *chip, u32 reg)
|
||||
{
|
||||
return ioread8((chip)->rtsx->remap_addr + reg);
|
||||
}
|
||||
|
||||
static inline int rtsx_read_config_byte(struct rtsx_chip *chip, int where, u8 *val)
|
||||
{
|
||||
return pci_read_config_byte(chip->rtsx->pci, where, val);
|
||||
}
|
||||
|
||||
static inline int rtsx_write_config_byte(struct rtsx_chip *chip, int where, u8 val)
|
||||
{
|
||||
return pci_write_config_byte(chip->rtsx->pci, where, val);
|
||||
}
|
||||
|
||||
#endif /* __REALTEK_RTSX_H */
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -1,987 +0,0 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Driver for Realtek PCI-Express card reader
|
||||
*
|
||||
* Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
|
||||
*
|
||||
* Author:
|
||||
* Wei WANG (wei_wang@realsil.com.cn)
|
||||
* Micky Ching (micky_ching@realsil.com.cn)
|
||||
*/
|
||||
|
||||
#ifndef __REALTEK_RTSX_CHIP_H
|
||||
#define __REALTEK_RTSX_CHIP_H
|
||||
|
||||
#include "rtsx.h"
|
||||
|
||||
#define SUPPORT_CPRM
|
||||
#define SUPPORT_OCP
|
||||
#define SUPPORT_SDIO_ASPM
|
||||
#define SUPPORT_MAGIC_GATE
|
||||
#define SUPPORT_MSXC
|
||||
#define SUPPORT_SD_LOCK
|
||||
/* Hardware switch bus_ctl and cd_ctl automatically */
|
||||
#define HW_AUTO_SWITCH_SD_BUS
|
||||
/* Enable hardware interrupt write clear */
|
||||
#define HW_INT_WRITE_CLR
|
||||
/* #define LED_AUTO_BLINK */
|
||||
/* #define DISABLE_CARD_INT */
|
||||
|
||||
#ifdef SUPPORT_MAGIC_GATE
|
||||
/* Using NORMAL_WRITE instead of AUTO_WRITE to set ICV */
|
||||
#define MG_SET_ICV_SLOW
|
||||
/* HW may miss ERR/CMDNK signal when sampling INT status. */
|
||||
#define MS_SAMPLE_INT_ERR
|
||||
/*
|
||||
* HW DO NOT support Wait_INT function
|
||||
* during READ_BYTES transfer mode
|
||||
*/
|
||||
#define READ_BYTES_WAIT_INT
|
||||
#endif
|
||||
|
||||
#ifdef SUPPORT_MSXC
|
||||
#define XC_POWERCLASS
|
||||
#define SUPPORT_PCGL_1P18
|
||||
#endif
|
||||
|
||||
#ifndef LED_AUTO_BLINK
|
||||
#define REGULAR_BLINK
|
||||
#endif
|
||||
|
||||
#define LED_BLINK_SPEED 5
|
||||
#define LED_TOGGLE_INTERVAL 6
|
||||
#define GPIO_TOGGLE_THRESHOLD 1024
|
||||
#define LED_GPIO 0
|
||||
|
||||
#define POLLING_INTERVAL 30
|
||||
|
||||
#define TRACE_ITEM_CNT 64
|
||||
|
||||
#ifndef STATUS_SUCCESS
|
||||
#define STATUS_SUCCESS 0
|
||||
#endif
|
||||
#ifndef STATUS_FAIL
|
||||
#define STATUS_FAIL 1
|
||||
#endif
|
||||
#ifndef STATUS_TIMEDOUT
|
||||
#define STATUS_TIMEDOUT 2
|
||||
#endif
|
||||
#ifndef STATUS_NOMEM
|
||||
#define STATUS_NOMEM 3
|
||||
#endif
|
||||
#ifndef STATUS_READ_FAIL
|
||||
#define STATUS_READ_FAIL 4
|
||||
#endif
|
||||
#ifndef STATUS_WRITE_FAIL
|
||||
#define STATUS_WRITE_FAIL 5
|
||||
#endif
|
||||
#ifndef STATUS_ERROR
|
||||
#define STATUS_ERROR 10
|
||||
#endif
|
||||
|
||||
#define PM_S1 1
|
||||
#define PM_S3 3
|
||||
|
||||
/*
|
||||
* Transport return codes
|
||||
*/
|
||||
|
||||
#define TRANSPORT_GOOD 0 /* Transport good, command good */
|
||||
#define TRANSPORT_FAILED 1 /* Transport good, command failed */
|
||||
#define TRANSPORT_NO_SENSE 2 /* Command failed, no auto-sense */
|
||||
#define TRANSPORT_ERROR 3 /* Transport bad (i.e. device dead) */
|
||||
|
||||
/*
|
||||
* Start-Stop-Unit
|
||||
*/
|
||||
#define STOP_MEDIUM 0x00 /* access disable */
|
||||
#define MAKE_MEDIUM_READY 0x01 /* access enable */
|
||||
#define UNLOAD_MEDIUM 0x02 /* unload */
|
||||
#define LOAD_MEDIUM 0x03 /* load */
|
||||
|
||||
/*
|
||||
* STANDARD_INQUIRY
|
||||
*/
|
||||
#define QULIFIRE 0x00
|
||||
#define AENC_FNC 0x00
|
||||
#define TRML_IOP 0x00
|
||||
#define REL_ADR 0x00
|
||||
#define WBUS_32 0x00
|
||||
#define WBUS_16 0x00
|
||||
#define SYNC 0x00
|
||||
#define LINKED 0x00
|
||||
#define CMD_QUE 0x00
|
||||
#define SFT_RE 0x00
|
||||
|
||||
#define VEN_ID_LEN 8 /* Vendor ID Length */
|
||||
#define PRDCT_ID_LEN 16 /* Product ID Length */
|
||||
#define PRDCT_REV_LEN 4 /* Product LOT Length */
|
||||
|
||||
/* Dynamic flag definitions: used in set_bit() etc. */
|
||||
/* 0x00040000 transfer is active */
|
||||
#define RTSX_FLIDX_TRANS_ACTIVE 18
|
||||
/* 0x00100000 abort is in progress */
|
||||
#define RTSX_FLIDX_ABORTING 20
|
||||
/* 0x00200000 disconnect in progress */
|
||||
#define RTSX_FLIDX_DISCONNECTING 21
|
||||
|
||||
#define ABORTING_OR_DISCONNECTING ((1UL << US_FLIDX_ABORTING) | \
|
||||
(1UL << US_FLIDX_DISCONNECTING))
|
||||
|
||||
/* 0x00400000 device reset in progress */
|
||||
#define RTSX_FLIDX_RESETTING 22
|
||||
/* 0x00800000 SCSI midlayer timed out */
|
||||
#define RTSX_FLIDX_TIMED_OUT 23
|
||||
#define DRCT_ACCESS_DEV 0x00 /* Direct Access Device */
|
||||
#define RMB_DISC 0x80 /* The Device is Removable */
|
||||
#define ANSI_SCSI2 0x02 /* Based on ANSI-SCSI2 */
|
||||
|
||||
#define SCSI 0x00 /* Interface ID */
|
||||
|
||||
#define WRITE_PROTECTED_MEDIA 0x07
|
||||
|
||||
/*---- sense key ----*/
|
||||
#define ILI 0x20 /* ILI bit is on */
|
||||
|
||||
#define NO_SENSE 0x00 /* not exist sense key */
|
||||
#define RECOVER_ERR 0x01 /* Target/Logical unit is recoverd */
|
||||
#define NOT_READY 0x02 /* Logical unit is not ready */
|
||||
#define MEDIA_ERR 0x03 /* medium/data error */
|
||||
#define HARDWARE_ERR 0x04 /* hardware error */
|
||||
#define ILGAL_REQ 0x05 /* CDB/parameter/identify msg error */
|
||||
#define UNIT_ATTENTION 0x06 /* unit attention condition occur */
|
||||
#define DAT_PRTCT 0x07 /* read/write is desable */
|
||||
#define BLNC_CHK 0x08 /* find blank/DOF in read */
|
||||
/* write to unblank area */
|
||||
#define CPY_ABRT 0x0a /* Copy/Compare/Copy&Verify illegal */
|
||||
#define ABRT_CMD 0x0b /* Target make the command in error */
|
||||
#define EQUAL 0x0c /* Search Data end with Equal */
|
||||
#define VLM_OVRFLW 0x0d /* Some data are left in buffer */
|
||||
#define MISCMP 0x0e /* find inequality */
|
||||
|
||||
#define READ_ERR -1
|
||||
#define WRITE_ERR -2
|
||||
|
||||
#define FIRST_RESET 0x01
|
||||
#define USED_EXIST 0x02
|
||||
|
||||
/*
|
||||
* SENSE_DATA
|
||||
*/
|
||||
/*---- valid ----*/
|
||||
#define SENSE_VALID 0x80 /* Sense data is valid as SCSI2 */
|
||||
#define SENSE_INVALID 0x00 /* Sense data is invalid as SCSI2 */
|
||||
|
||||
/*---- error code ----*/
|
||||
#define CUR_ERR 0x70 /* current error */
|
||||
#define DEF_ERR 0x71 /* specific command error */
|
||||
|
||||
/*---- sense key Information ----*/
|
||||
#define SNSKEYINFO_LEN 3 /* length of sense key information */
|
||||
|
||||
#define SKSV 0x80
|
||||
#define CDB_ILLEGAL 0x40
|
||||
#define DAT_ILLEGAL 0x00
|
||||
#define BPV 0x08
|
||||
#define BIT_ILLEGAL0 0 /* bit0 is illegal */
|
||||
#define BIT_ILLEGAL1 1 /* bit1 is illegal */
|
||||
#define BIT_ILLEGAL2 2 /* bit2 is illegal */
|
||||
#define BIT_ILLEGAL3 3 /* bit3 is illegal */
|
||||
#define BIT_ILLEGAL4 4 /* bit4 is illegal */
|
||||
#define BIT_ILLEGAL5 5 /* bit5 is illegal */
|
||||
#define BIT_ILLEGAL6 6 /* bit6 is illegal */
|
||||
#define BIT_ILLEGAL7 7 /* bit7 is illegal */
|
||||
|
||||
/*---- ASC ----*/
|
||||
#define ASC_NO_INFO 0x00
|
||||
#define ASC_MISCMP 0x1d
|
||||
#define ASC_INVLD_CDB 0x24
|
||||
#define ASC_INVLD_PARA 0x26
|
||||
#define ASC_LU_NOT_READY 0x04
|
||||
#define ASC_WRITE_ERR 0x0c
|
||||
#define ASC_READ_ERR 0x11
|
||||
#define ASC_LOAD_EJCT_ERR 0x53
|
||||
#define ASC_MEDIA_NOT_PRESENT 0x3A
|
||||
#define ASC_MEDIA_CHANGED 0x28
|
||||
#define ASC_MEDIA_IN_PROCESS 0x04
|
||||
#define ASC_WRITE_PROTECT 0x27
|
||||
#define ASC_LUN_NOT_SUPPORTED 0x25
|
||||
|
||||
/*---- ASQC ----*/
|
||||
#define ASCQ_NO_INFO 0x00
|
||||
#define ASCQ_MEDIA_IN_PROCESS 0x01
|
||||
#define ASCQ_MISCMP 0x00
|
||||
#define ASCQ_INVLD_CDB 0x00
|
||||
#define ASCQ_INVLD_PARA 0x02
|
||||
#define ASCQ_LU_NOT_READY 0x02
|
||||
#define ASCQ_WRITE_ERR 0x02
|
||||
#define ASCQ_READ_ERR 0x00
|
||||
#define ASCQ_LOAD_EJCT_ERR 0x00
|
||||
#define ASCQ_WRITE_PROTECT 0x00
|
||||
|
||||
struct sense_data_t {
|
||||
unsigned char err_code; /* error code */
|
||||
/* bit7 : valid */
|
||||
/* (1 : SCSI2) */
|
||||
/* (0 : Vendor * specific) */
|
||||
/* bit6-0 : error * code */
|
||||
/* (0x70 : current * error) */
|
||||
/* (0x71 : specific command error) */
|
||||
unsigned char seg_no; /* segment No. */
|
||||
unsigned char sense_key; /* byte5 : ILI */
|
||||
/* bit3-0 : sense key */
|
||||
unsigned char info[4]; /* information */
|
||||
unsigned char ad_sense_len; /* additional sense data length */
|
||||
unsigned char cmd_info[4]; /* command specific information */
|
||||
unsigned char asc; /* ASC */
|
||||
unsigned char ascq; /* ASCQ */
|
||||
unsigned char rfu; /* FRU */
|
||||
unsigned char sns_key_info[3];/* sense key specific information */
|
||||
};
|
||||
|
||||
/* PCI Operation Register Address */
|
||||
#define RTSX_HCBAR 0x00
|
||||
#define RTSX_HCBCTLR 0x04
|
||||
#define RTSX_HDBAR 0x08
|
||||
#define RTSX_HDBCTLR 0x0C
|
||||
#define RTSX_HAIMR 0x10
|
||||
#define RTSX_BIPR 0x14
|
||||
#define RTSX_BIER 0x18
|
||||
|
||||
/* Host command buffer control register */
|
||||
#define STOP_CMD (0x01 << 28)
|
||||
|
||||
/* Host data buffer control register */
|
||||
#define SDMA_MODE 0x00
|
||||
#define ADMA_MODE (0x02 << 26)
|
||||
#define STOP_DMA (0x01 << 28)
|
||||
#define TRIG_DMA (0x01 << 31)
|
||||
|
||||
/* Bus interrupt pending register */
|
||||
#define CMD_DONE_INT BIT(31)
|
||||
#define DATA_DONE_INT BIT(30)
|
||||
#define TRANS_OK_INT BIT(29)
|
||||
#define TRANS_FAIL_INT BIT(28)
|
||||
#define XD_INT BIT(27)
|
||||
#define MS_INT BIT(26)
|
||||
#define SD_INT BIT(25)
|
||||
#define GPIO0_INT BIT(24)
|
||||
#define OC_INT BIT(23)
|
||||
#define SD_WRITE_PROTECT BIT(19)
|
||||
#define XD_EXIST BIT(18)
|
||||
#define MS_EXIST BIT(17)
|
||||
#define SD_EXIST BIT(16)
|
||||
#define DELINK_INT GPIO0_INT
|
||||
#define MS_OC_INT BIT(23)
|
||||
#define SD_OC_INT BIT(22)
|
||||
|
||||
#define CARD_INT (XD_INT | MS_INT | SD_INT)
|
||||
#define NEED_COMPLETE_INT (DATA_DONE_INT | TRANS_OK_INT | TRANS_FAIL_INT)
|
||||
#define RTSX_INT (CMD_DONE_INT | NEED_COMPLETE_INT | CARD_INT | \
|
||||
GPIO0_INT | OC_INT)
|
||||
|
||||
#define CARD_EXIST (XD_EXIST | MS_EXIST | SD_EXIST)
|
||||
|
||||
/* Bus interrupt enable register */
|
||||
#define CMD_DONE_INT_EN BIT(31)
|
||||
#define DATA_DONE_INT_EN BIT(30)
|
||||
#define TRANS_OK_INT_EN BIT(29)
|
||||
#define TRANS_FAIL_INT_EN BIT(28)
|
||||
#define XD_INT_EN BIT(27)
|
||||
#define MS_INT_EN BIT(26)
|
||||
#define SD_INT_EN BIT(25)
|
||||
#define GPIO0_INT_EN BIT(24)
|
||||
#define OC_INT_EN BIT(23)
|
||||
#define DELINK_INT_EN GPIO0_INT_EN
|
||||
#define MS_OC_INT_EN BIT(23)
|
||||
#define SD_OC_INT_EN BIT(22)
|
||||
|
||||
#define READ_REG_CMD 0
|
||||
#define WRITE_REG_CMD 1
|
||||
#define CHECK_REG_CMD 2
|
||||
|
||||
#define HOST_TO_DEVICE 0
|
||||
#define DEVICE_TO_HOST 1
|
||||
|
||||
#define RTSX_RESV_BUF_LEN 4096
|
||||
#define HOST_CMDS_BUF_LEN 1024
|
||||
#define HOST_SG_TBL_BUF_LEN (RTSX_RESV_BUF_LEN - HOST_CMDS_BUF_LEN)
|
||||
|
||||
#define SD_NR 2
|
||||
#define MS_NR 3
|
||||
#define XD_NR 4
|
||||
#define SPI_NR 7
|
||||
#define SD_CARD BIT(SD_NR)
|
||||
#define MS_CARD BIT(MS_NR)
|
||||
#define XD_CARD BIT(XD_NR)
|
||||
#define SPI_CARD BIT(SPI_NR)
|
||||
|
||||
#define MAX_ALLOWED_LUN_CNT 8
|
||||
|
||||
#define XD_FREE_TABLE_CNT 1200
|
||||
#define MS_FREE_TABLE_CNT 512
|
||||
|
||||
/* Bit Operation */
|
||||
#define SET_BIT(data, idx) ((data) |= 1 << (idx))
|
||||
#define CLR_BIT(data, idx) ((data) &= ~(1 << (idx)))
|
||||
#define CHK_BIT(data, idx) ((data) & (1 << (idx)))
|
||||
|
||||
/* SG descriptor */
|
||||
#define RTSX_SG_INT 0x04
|
||||
#define RTSX_SG_END 0x02
|
||||
#define RTSX_SG_VALID 0x01
|
||||
|
||||
#define RTSX_SG_NO_OP 0x00
|
||||
#define RTSX_SG_TRANS_DATA (0x02 << 4)
|
||||
#define RTSX_SG_LINK_DESC (0x03 << 4)
|
||||
|
||||
struct rtsx_chip;
|
||||
|
||||
typedef int (*card_rw_func)(struct scsi_cmnd *srb, struct rtsx_chip *chip,
|
||||
u32 sec_addr, u16 sec_cnt);
|
||||
|
||||
/* Supported Clock */
|
||||
enum card_clock {CLK_20 = 1, CLK_30, CLK_40, CLK_50, CLK_60,
|
||||
CLK_80, CLK_100, CLK_120, CLK_150, CLK_200};
|
||||
|
||||
enum RTSX_STAT {RTSX_STAT_INIT, RTSX_STAT_IDLE, RTSX_STAT_RUN, RTSX_STAT_SS,
|
||||
RTSX_STAT_DELINK, RTSX_STAT_SUSPEND,
|
||||
RTSX_STAT_ABORT, RTSX_STAT_DISCONNECT};
|
||||
enum IC_VER {IC_VER_AB, IC_VER_C = 2, IC_VER_D = 3};
|
||||
|
||||
#define MAX_RESET_CNT 3
|
||||
|
||||
/* For MS Card */
|
||||
#define MAX_DEFECTIVE_BLOCK 10
|
||||
|
||||
struct zone_entry {
|
||||
u16 *l2p_table;
|
||||
u16 *free_table;
|
||||
u16 defect_list[MAX_DEFECTIVE_BLOCK]; /* For MS card only */
|
||||
int set_index;
|
||||
int get_index;
|
||||
int unused_blk_cnt;
|
||||
int disable_count;
|
||||
/* To indicate whether the L2P table of this zone has been built. */
|
||||
int build_flag;
|
||||
};
|
||||
|
||||
#define TYPE_SD 0x0000
|
||||
#define TYPE_MMC 0x0001
|
||||
|
||||
/* TYPE_SD */
|
||||
#define SD_HS 0x0100
|
||||
#define SD_SDR50 0x0200
|
||||
#define SD_DDR50 0x0400
|
||||
#define SD_SDR104 0x0800
|
||||
#define SD_HCXC 0x1000
|
||||
|
||||
/* TYPE_MMC */
|
||||
#define MMC_26M 0x0100
|
||||
#define MMC_52M 0x0200
|
||||
#define MMC_4BIT 0x0400
|
||||
#define MMC_8BIT 0x0800
|
||||
#define MMC_SECTOR_MODE 0x1000
|
||||
#define MMC_DDR52 0x2000
|
||||
|
||||
/* SD card */
|
||||
#define CHK_SD(sd_card) (((sd_card)->sd_type & 0xFF) == TYPE_SD)
|
||||
#define CHK_SD_HS(sd_card) (CHK_SD(sd_card) && \
|
||||
((sd_card)->sd_type & SD_HS))
|
||||
#define CHK_SD_SDR50(sd_card) (CHK_SD(sd_card) && \
|
||||
((sd_card)->sd_type & SD_SDR50))
|
||||
#define CHK_SD_DDR50(sd_card) (CHK_SD(sd_card) && \
|
||||
((sd_card)->sd_type & SD_DDR50))
|
||||
#define CHK_SD_SDR104(sd_card) (CHK_SD(sd_card) && \
|
||||
((sd_card)->sd_type & SD_SDR104))
|
||||
#define CHK_SD_HCXC(sd_card) (CHK_SD(sd_card) && \
|
||||
((sd_card)->sd_type & SD_HCXC))
|
||||
#define CHK_SD_HC(sd_card) (CHK_SD_HCXC(sd_card) && \
|
||||
((sd_card)->capacity <= 0x4000000))
|
||||
#define CHK_SD_XC(sd_card) (CHK_SD_HCXC(sd_card) && \
|
||||
((sd_card)->capacity > 0x4000000))
|
||||
#define CHK_SD30_SPEED(sd_card) (CHK_SD_SDR50(sd_card) || \
|
||||
CHK_SD_DDR50(sd_card) || \
|
||||
CHK_SD_SDR104(sd_card))
|
||||
|
||||
#define SET_SD(sd_card) ((sd_card)->sd_type = TYPE_SD)
|
||||
#define SET_SD_HS(sd_card) ((sd_card)->sd_type |= SD_HS)
|
||||
#define SET_SD_SDR50(sd_card) ((sd_card)->sd_type |= SD_SDR50)
|
||||
#define SET_SD_DDR50(sd_card) ((sd_card)->sd_type |= SD_DDR50)
|
||||
#define SET_SD_SDR104(sd_card) ((sd_card)->sd_type |= SD_SDR104)
|
||||
#define SET_SD_HCXC(sd_card) ((sd_card)->sd_type |= SD_HCXC)
|
||||
|
||||
#define CLR_SD_HS(sd_card) ((sd_card)->sd_type &= ~SD_HS)
|
||||
#define CLR_SD_SDR50(sd_card) ((sd_card)->sd_type &= ~SD_SDR50)
|
||||
#define CLR_SD_DDR50(sd_card) ((sd_card)->sd_type &= ~SD_DDR50)
|
||||
#define CLR_SD_SDR104(sd_card) ((sd_card)->sd_type &= ~SD_SDR104)
|
||||
#define CLR_SD_HCXC(sd_card) ((sd_card)->sd_type &= ~SD_HCXC)
|
||||
|
||||
/* MMC card */
|
||||
#define CHK_MMC(sd_card) (((sd_card)->sd_type & 0xFF) == \
|
||||
TYPE_MMC)
|
||||
#define CHK_MMC_26M(sd_card) (CHK_MMC(sd_card) && \
|
||||
((sd_card)->sd_type & MMC_26M))
|
||||
#define CHK_MMC_52M(sd_card) (CHK_MMC(sd_card) && \
|
||||
((sd_card)->sd_type & MMC_52M))
|
||||
#define CHK_MMC_4BIT(sd_card) (CHK_MMC(sd_card) && \
|
||||
((sd_card)->sd_type & MMC_4BIT))
|
||||
#define CHK_MMC_8BIT(sd_card) (CHK_MMC(sd_card) && \
|
||||
((sd_card)->sd_type & MMC_8BIT))
|
||||
#define CHK_MMC_SECTOR_MODE(sd_card) (CHK_MMC(sd_card) && \
|
||||
((sd_card)->sd_type & MMC_SECTOR_MODE))
|
||||
#define CHK_MMC_DDR52(sd_card) (CHK_MMC(sd_card) && \
|
||||
((sd_card)->sd_type & MMC_DDR52))
|
||||
|
||||
#define SET_MMC(sd_card) ((sd_card)->sd_type = TYPE_MMC)
|
||||
#define SET_MMC_26M(sd_card) ((sd_card)->sd_type |= MMC_26M)
|
||||
#define SET_MMC_52M(sd_card) ((sd_card)->sd_type |= MMC_52M)
|
||||
#define SET_MMC_4BIT(sd_card) ((sd_card)->sd_type |= MMC_4BIT)
|
||||
#define SET_MMC_8BIT(sd_card) ((sd_card)->sd_type |= MMC_8BIT)
|
||||
#define SET_MMC_SECTOR_MODE(sd_card) ((sd_card)->sd_type |= MMC_SECTOR_MODE)
|
||||
#define SET_MMC_DDR52(sd_card) ((sd_card)->sd_type |= MMC_DDR52)
|
||||
|
||||
#define CLR_MMC_26M(sd_card) ((sd_card)->sd_type &= ~MMC_26M)
|
||||
#define CLR_MMC_52M(sd_card) ((sd_card)->sd_type &= ~MMC_52M)
|
||||
#define CLR_MMC_4BIT(sd_card) ((sd_card)->sd_type &= ~MMC_4BIT)
|
||||
#define CLR_MMC_8BIT(sd_card) ((sd_card)->sd_type &= ~MMC_8BIT)
|
||||
#define CLR_MMC_SECTOR_MODE(sd_card) ((sd_card)->sd_type &= ~MMC_SECTOR_MODE)
|
||||
#define CLR_MMC_DDR52(sd_card) ((sd_card)->sd_type &= ~MMC_DDR52)
|
||||
|
||||
#define CHK_MMC_HS(sd_card) (CHK_MMC_52M(sd_card) && \
|
||||
CHK_MMC_26M(sd_card))
|
||||
#define CLR_MMC_HS(sd_card) \
|
||||
do { \
|
||||
CLR_MMC_DDR52(sd_card); \
|
||||
CLR_MMC_52M(sd_card); \
|
||||
CLR_MMC_26M(sd_card); \
|
||||
} while (0)
|
||||
|
||||
#define SD_SUPPORT_CLASS_TEN 0x01
|
||||
#define SD_SUPPORT_1V8 0x02
|
||||
|
||||
#define SD_SET_CLASS_TEN(sd_card) ((sd_card)->sd_setting |= \
|
||||
SD_SUPPORT_CLASS_TEN)
|
||||
#define SD_CHK_CLASS_TEN(sd_card) ((sd_card)->sd_setting & \
|
||||
SD_SUPPORT_CLASS_TEN)
|
||||
#define SD_CLR_CLASS_TEN(sd_card) ((sd_card)->sd_setting &= \
|
||||
~SD_SUPPORT_CLASS_TEN)
|
||||
#define SD_SET_1V8(sd_card) ((sd_card)->sd_setting |= \
|
||||
SD_SUPPORT_1V8)
|
||||
#define SD_CHK_1V8(sd_card) ((sd_card)->sd_setting & \
|
||||
SD_SUPPORT_1V8)
|
||||
#define SD_CLR_1V8(sd_card) ((sd_card)->sd_setting &= \
|
||||
~SD_SUPPORT_1V8)
|
||||
|
||||
struct sd_info {
|
||||
u16 sd_type;
|
||||
u8 err_code;
|
||||
u8 sd_data_buf_ready;
|
||||
u32 sd_addr;
|
||||
u32 capacity;
|
||||
|
||||
u8 raw_csd[16];
|
||||
u8 raw_scr[8];
|
||||
|
||||
/* Sequential RW */
|
||||
int seq_mode;
|
||||
enum dma_data_direction pre_dir;
|
||||
u32 pre_sec_addr;
|
||||
u16 pre_sec_cnt;
|
||||
|
||||
int cleanup_counter;
|
||||
|
||||
int sd_clock;
|
||||
|
||||
int mmc_dont_switch_bus;
|
||||
|
||||
#ifdef SUPPORT_CPRM
|
||||
int sd_pass_thru_en;
|
||||
int pre_cmd_err;
|
||||
u8 last_rsp_type;
|
||||
u8 rsp[17];
|
||||
#endif
|
||||
|
||||
u8 func_group1_mask;
|
||||
u8 func_group2_mask;
|
||||
u8 func_group3_mask;
|
||||
u8 func_group4_mask;
|
||||
|
||||
u8 sd_switch_fail;
|
||||
u8 sd_read_phase;
|
||||
|
||||
#ifdef SUPPORT_SD_LOCK
|
||||
u8 sd_lock_status;
|
||||
u8 sd_erase_status;
|
||||
u8 sd_lock_notify;
|
||||
#endif
|
||||
int need_retune;
|
||||
};
|
||||
|
||||
struct xd_delay_write_tag {
|
||||
u32 old_phyblock;
|
||||
u32 new_phyblock;
|
||||
u32 logblock;
|
||||
u8 pageoff;
|
||||
u8 delay_write_flag;
|
||||
};
|
||||
|
||||
struct xd_info {
|
||||
u8 maker_code;
|
||||
u8 device_code;
|
||||
u8 block_shift;
|
||||
u8 page_off;
|
||||
u8 addr_cycle;
|
||||
u16 cis_block;
|
||||
u8 multi_flag;
|
||||
u8 err_code;
|
||||
u32 capacity;
|
||||
|
||||
struct zone_entry *zone;
|
||||
int zone_cnt;
|
||||
|
||||
struct xd_delay_write_tag delay_write;
|
||||
int cleanup_counter;
|
||||
|
||||
int xd_clock;
|
||||
};
|
||||
|
||||
#define MODE_512_SEQ 0x01
|
||||
#define MODE_2K_SEQ 0x02
|
||||
|
||||
#define TYPE_MS 0x0000
|
||||
#define TYPE_MSPRO 0x0001
|
||||
|
||||
#define MS_4BIT 0x0100
|
||||
#define MS_8BIT 0x0200
|
||||
#define MS_HG 0x0400
|
||||
#define MS_XC 0x0800
|
||||
|
||||
#define HG8BIT (MS_HG | MS_8BIT)
|
||||
|
||||
#define CHK_MSPRO(ms_card) (((ms_card)->ms_type & 0xFF) == TYPE_MSPRO)
|
||||
#define CHK_HG8BIT(ms_card) (CHK_MSPRO(ms_card) && \
|
||||
(((ms_card)->ms_type & HG8BIT) == HG8BIT))
|
||||
#define CHK_MSXC(ms_card) (CHK_MSPRO(ms_card) && \
|
||||
((ms_card)->ms_type & MS_XC))
|
||||
#define CHK_MSHG(ms_card) (CHK_MSPRO(ms_card) && \
|
||||
((ms_card)->ms_type & MS_HG))
|
||||
|
||||
#define CHK_MS8BIT(ms_card) (((ms_card)->ms_type & MS_8BIT))
|
||||
#define CHK_MS4BIT(ms_card) (((ms_card)->ms_type & MS_4BIT))
|
||||
|
||||
struct ms_delay_write_tag {
|
||||
u16 old_phyblock;
|
||||
u16 new_phyblock;
|
||||
u16 logblock;
|
||||
u8 pageoff;
|
||||
u8 delay_write_flag;
|
||||
};
|
||||
|
||||
struct ms_info {
|
||||
u16 ms_type;
|
||||
u8 block_shift;
|
||||
u8 page_off;
|
||||
u16 total_block;
|
||||
u16 boot_block;
|
||||
u32 capacity;
|
||||
|
||||
u8 check_ms_flow;
|
||||
u8 switch_8bit_fail;
|
||||
u8 err_code;
|
||||
|
||||
struct zone_entry *segment;
|
||||
int segment_cnt;
|
||||
|
||||
int pro_under_formatting;
|
||||
int format_status;
|
||||
u16 progress;
|
||||
u8 raw_sys_info[96];
|
||||
#ifdef SUPPORT_PCGL_1P18
|
||||
u8 raw_model_name[48];
|
||||
#endif
|
||||
|
||||
u8 multi_flag;
|
||||
|
||||
/* Sequential RW */
|
||||
u8 seq_mode;
|
||||
enum dma_data_direction pre_dir;
|
||||
u32 pre_sec_addr;
|
||||
u16 pre_sec_cnt;
|
||||
u32 total_sec_cnt;
|
||||
|
||||
struct ms_delay_write_tag delay_write;
|
||||
|
||||
int cleanup_counter;
|
||||
|
||||
int ms_clock;
|
||||
|
||||
#ifdef SUPPORT_MAGIC_GATE
|
||||
u8 magic_gate_id[16];
|
||||
u8 mg_entry_num;
|
||||
int mg_auth; /* flag to indicate authentication process */
|
||||
#endif
|
||||
};
|
||||
|
||||
struct spi_info {
|
||||
u8 use_clk;
|
||||
u8 write_en;
|
||||
u16 clk_div;
|
||||
u8 err_code;
|
||||
|
||||
int spi_clock;
|
||||
};
|
||||
|
||||
/************/
|
||||
/* LUN mode */
|
||||
/************/
|
||||
/* Single LUN, support xD/SD/MS */
|
||||
#define DEFAULT_SINGLE 0
|
||||
/* 2 LUN mode, support SD/MS */
|
||||
#define SD_MS_2LUN 1
|
||||
/* Single LUN, but only support SD/MS, for Barossa LQFP */
|
||||
#define SD_MS_1LUN 2
|
||||
|
||||
#define LAST_LUN_MODE 2
|
||||
|
||||
/* Barossa package */
|
||||
#define QFN 0
|
||||
#define LQFP 1
|
||||
|
||||
/******************/
|
||||
/* sd_ctl bit map */
|
||||
/******************/
|
||||
/* SD push point control, bit 0, 1 */
|
||||
#define SD_PUSH_POINT_CTL_MASK 0x03
|
||||
#define SD_PUSH_POINT_DELAY 0x01
|
||||
#define SD_PUSH_POINT_AUTO 0x02
|
||||
/* SD sample point control, bit 2, 3 */
|
||||
#define SD_SAMPLE_POINT_CTL_MASK 0x0C
|
||||
#define SD_SAMPLE_POINT_DELAY 0x04
|
||||
#define SD_SAMPLE_POINT_AUTO 0x08
|
||||
/* SD DDR Tx phase set by user, bit 4 */
|
||||
#define SD_DDR_TX_PHASE_SET_BY_USER 0x10
|
||||
/* MMC DDR Tx phase set by user, bit 5 */
|
||||
#define MMC_DDR_TX_PHASE_SET_BY_USER 0x20
|
||||
/* Support MMC DDR mode, bit 6 */
|
||||
#define SUPPORT_MMC_DDR_MODE 0x40
|
||||
/* Reset MMC at first */
|
||||
#define RESET_MMC_FIRST 0x80
|
||||
|
||||
#define SEQ_START_CRITERIA 0x20
|
||||
|
||||
/* MS Power Class En */
|
||||
#define POWER_CLASS_2_EN 0x02
|
||||
#define POWER_CLASS_1_EN 0x01
|
||||
|
||||
#define MAX_SHOW_CNT 10
|
||||
#define MAX_RESET_CNT 3
|
||||
|
||||
#define SDIO_EXIST 0x01
|
||||
#define SDIO_IGNORED 0x02
|
||||
|
||||
#define CHK_SDIO_EXIST(chip) ((chip)->sdio_func_exist & SDIO_EXIST)
|
||||
#define SET_SDIO_EXIST(chip) ((chip)->sdio_func_exist |= SDIO_EXIST)
|
||||
#define CLR_SDIO_EXIST(chip) ((chip)->sdio_func_exist &= ~SDIO_EXIST)
|
||||
|
||||
#define CHK_SDIO_IGNORED(chip) ((chip)->sdio_func_exist & SDIO_IGNORED)
|
||||
#define SET_SDIO_IGNORED(chip) ((chip)->sdio_func_exist |= \
|
||||
SDIO_IGNORED)
|
||||
#define CLR_SDIO_IGNORED(chip) ((chip)->sdio_func_exist &= \
|
||||
~SDIO_IGNORED)
|
||||
|
||||
struct rtsx_chip {
|
||||
struct rtsx_dev *rtsx;
|
||||
|
||||
u32 int_reg; /* Bus interrupt pending register */
|
||||
char max_lun;
|
||||
void *context;
|
||||
|
||||
void *host_cmds_ptr; /* host commands buffer pointer */
|
||||
dma_addr_t host_cmds_addr;
|
||||
int ci; /* Command Index */
|
||||
|
||||
void *host_sg_tbl_ptr; /* SG descriptor table */
|
||||
dma_addr_t host_sg_tbl_addr;
|
||||
int sgi; /* SG entry index */
|
||||
|
||||
struct scsi_cmnd *srb; /* current srb */
|
||||
struct sense_data_t sense_buffer[MAX_ALLOWED_LUN_CNT];
|
||||
|
||||
int cur_clk; /* current card clock */
|
||||
|
||||
/* Current accessed card */
|
||||
int cur_card;
|
||||
|
||||
unsigned long need_release; /* need release bit map */
|
||||
unsigned long need_reset; /* need reset bit map */
|
||||
/*
|
||||
* Flag to indicate that this card is just resumed from SS state,
|
||||
* and need released before being resetted
|
||||
*/
|
||||
unsigned long need_reinit;
|
||||
|
||||
int rw_need_retry;
|
||||
|
||||
#ifdef SUPPORT_OCP
|
||||
u32 ocp_int;
|
||||
u8 ocp_stat;
|
||||
#endif
|
||||
|
||||
u8 card_exist; /* card exist bit map (physical exist) */
|
||||
u8 card_ready; /* card ready bit map (reset successfully) */
|
||||
u8 card_fail; /* card reset fail bit map */
|
||||
u8 card_ejected; /* card ejected bit map */
|
||||
u8 card_wp; /* card write protected bit map */
|
||||
|
||||
u8 lun_mc; /*
|
||||
* flag to indicate whether to answer
|
||||
* MediaChange
|
||||
*/
|
||||
|
||||
#ifndef LED_AUTO_BLINK
|
||||
int led_toggle_counter;
|
||||
#endif
|
||||
|
||||
int sd_reset_counter;
|
||||
int xd_reset_counter;
|
||||
int ms_reset_counter;
|
||||
|
||||
/* card bus width */
|
||||
u8 card_bus_width[MAX_ALLOWED_LUN_CNT];
|
||||
/* card capacity */
|
||||
u32 capacity[MAX_ALLOWED_LUN_CNT];
|
||||
/* read/write card function pointer */
|
||||
card_rw_func rw_card[MAX_ALLOWED_LUN_CNT];
|
||||
/* read/write capacity, used for GPIO Toggle */
|
||||
u32 rw_cap[MAX_ALLOWED_LUN_CNT];
|
||||
/* card to lun mapping table */
|
||||
u8 card2lun[32];
|
||||
/* lun to card mapping table */
|
||||
u8 lun2card[MAX_ALLOWED_LUN_CNT];
|
||||
|
||||
int rw_fail_cnt[MAX_ALLOWED_LUN_CNT];
|
||||
|
||||
int sd_show_cnt;
|
||||
int xd_show_cnt;
|
||||
int ms_show_cnt;
|
||||
|
||||
/* card information */
|
||||
struct sd_info sd_card;
|
||||
struct xd_info xd_card;
|
||||
struct ms_info ms_card;
|
||||
|
||||
struct spi_info spi;
|
||||
|
||||
int auto_delink_cnt;
|
||||
int auto_delink_allowed;
|
||||
|
||||
int aspm_enabled;
|
||||
|
||||
int sdio_aspm;
|
||||
int sdio_idle;
|
||||
int sdio_counter;
|
||||
u8 sdio_raw_data[12];
|
||||
|
||||
u8 sd_io;
|
||||
u8 sd_int;
|
||||
|
||||
u8 rtsx_flag;
|
||||
|
||||
int ss_counter;
|
||||
int idle_counter;
|
||||
enum RTSX_STAT rtsx_stat;
|
||||
|
||||
u16 vendor_id;
|
||||
u16 product_id;
|
||||
u8 ic_version;
|
||||
|
||||
int driver_first_load;
|
||||
|
||||
#ifdef HW_AUTO_SWITCH_SD_BUS
|
||||
int sdio_in_charge;
|
||||
#endif
|
||||
|
||||
u8 aspm_level[2];
|
||||
|
||||
int chip_insert_with_sdio;
|
||||
|
||||
/* Options */
|
||||
|
||||
int adma_mode;
|
||||
|
||||
int auto_delink_en;
|
||||
int ss_en;
|
||||
u8 lun_mode;
|
||||
u8 aspm_l0s_l1_en;
|
||||
|
||||
int power_down_in_ss;
|
||||
|
||||
int sdr104_en;
|
||||
int ddr50_en;
|
||||
int sdr50_en;
|
||||
|
||||
int baro_pkg;
|
||||
|
||||
int asic_code;
|
||||
int phy_debug_mode;
|
||||
int hw_bypass_sd;
|
||||
int sdio_func_exist;
|
||||
int aux_pwr_exist;
|
||||
u8 ms_power_class_en;
|
||||
|
||||
int mspro_formatter_enable;
|
||||
|
||||
int remote_wakeup_en;
|
||||
|
||||
int ignore_sd;
|
||||
int use_hw_setting;
|
||||
|
||||
int ss_idle_period;
|
||||
|
||||
int dynamic_aspm;
|
||||
|
||||
int fpga_sd_sdr104_clk;
|
||||
int fpga_sd_ddr50_clk;
|
||||
int fpga_sd_sdr50_clk;
|
||||
int fpga_sd_hs_clk;
|
||||
int fpga_mmc_52m_clk;
|
||||
int fpga_ms_hg_clk;
|
||||
int fpga_ms_4bit_clk;
|
||||
int fpga_ms_1bit_clk;
|
||||
|
||||
int asic_sd_sdr104_clk;
|
||||
int asic_sd_ddr50_clk;
|
||||
int asic_sd_sdr50_clk;
|
||||
int asic_sd_hs_clk;
|
||||
int asic_mmc_52m_clk;
|
||||
int asic_ms_hg_clk;
|
||||
int asic_ms_4bit_clk;
|
||||
int asic_ms_1bit_clk;
|
||||
|
||||
u8 ssc_depth_sd_sdr104;
|
||||
u8 ssc_depth_sd_ddr50;
|
||||
u8 ssc_depth_sd_sdr50;
|
||||
u8 ssc_depth_sd_hs;
|
||||
u8 ssc_depth_mmc_52m;
|
||||
u8 ssc_depth_ms_hg;
|
||||
u8 ssc_depth_ms_4bit;
|
||||
u8 ssc_depth_low_speed;
|
||||
|
||||
u8 card_drive_sel;
|
||||
u8 sd30_drive_sel_1v8;
|
||||
u8 sd30_drive_sel_3v3;
|
||||
|
||||
u8 sd_400mA_ocp_thd;
|
||||
u8 sd_800mA_ocp_thd;
|
||||
u8 ms_ocp_thd;
|
||||
|
||||
int ssc_en;
|
||||
int msi_en;
|
||||
|
||||
int xd_timeout;
|
||||
int sd_timeout;
|
||||
int ms_timeout;
|
||||
int mspro_timeout;
|
||||
|
||||
int auto_power_down;
|
||||
|
||||
int sd_ddr_tx_phase;
|
||||
int mmc_ddr_tx_phase;
|
||||
int sd_default_tx_phase;
|
||||
int sd_default_rx_phase;
|
||||
|
||||
int pmos_pwr_on_interval;
|
||||
int sd_voltage_switch_delay;
|
||||
int s3_pwr_off_delay;
|
||||
|
||||
int force_clkreq_0;
|
||||
int ft2_fast_mode;
|
||||
|
||||
int do_delink_before_power_down;
|
||||
int polling_config;
|
||||
int sdio_retry_cnt;
|
||||
|
||||
int delink_stage1_step;
|
||||
int delink_stage2_step;
|
||||
int delink_stage3_step;
|
||||
|
||||
int auto_delink_in_L1;
|
||||
int hp_watch_bios_hotplug;
|
||||
int support_ms_8bit;
|
||||
|
||||
u8 blink_led;
|
||||
u8 phy_voltage;
|
||||
u8 max_payload;
|
||||
|
||||
u32 sd_speed_prior;
|
||||
u32 sd_current_prior;
|
||||
u32 sd_ctl;
|
||||
};
|
||||
|
||||
static inline struct device *rtsx_dev(const struct rtsx_chip *chip)
|
||||
{
|
||||
return &chip->rtsx->pci->dev;
|
||||
}
|
||||
|
||||
#define rtsx_set_stat(chip, stat) \
|
||||
do { \
|
||||
if ((stat) != RTSX_STAT_IDLE) { \
|
||||
(chip)->idle_counter = 0; \
|
||||
} \
|
||||
(chip)->rtsx_stat = (enum RTSX_STAT)(stat); \
|
||||
} while (0)
|
||||
#define rtsx_get_stat(chip) ((chip)->rtsx_stat)
|
||||
#define rtsx_chk_stat(chip, stat) ((chip)->rtsx_stat == (stat))
|
||||
|
||||
#define RTSX_SET_DELINK(chip) ((chip)->rtsx_flag |= 0x01)
|
||||
#define RTSX_CLR_DELINK(chip) ((chip)->rtsx_flag &= 0xFE)
|
||||
#define RTSX_TST_DELINK(chip) ((chip)->rtsx_flag & 0x01)
|
||||
|
||||
#define CHECK_PID(chip, pid) ((chip)->product_id == (pid))
|
||||
#define CHECK_BARO_PKG(chip, pkg) ((chip)->baro_pkg == (pkg))
|
||||
#define CHECK_LUN_MODE(chip, mode) ((chip)->lun_mode == (mode))
|
||||
|
||||
/* Power down control */
|
||||
#define SSC_PDCTL 0x01
|
||||
#define OC_PDCTL 0x02
|
||||
|
||||
int rtsx_force_power_on(struct rtsx_chip *chip, u8 ctl);
|
||||
int rtsx_force_power_down(struct rtsx_chip *chip, u8 ctl);
|
||||
|
||||
void rtsx_enable_card_int(struct rtsx_chip *chip);
|
||||
void rtsx_enable_bus_int(struct rtsx_chip *chip);
|
||||
void rtsx_disable_bus_int(struct rtsx_chip *chip);
|
||||
int rtsx_reset_chip(struct rtsx_chip *chip);
|
||||
int rtsx_init_chip(struct rtsx_chip *chip);
|
||||
void rtsx_release_chip(struct rtsx_chip *chip);
|
||||
void rtsx_polling_func(struct rtsx_chip *chip);
|
||||
void rtsx_stop_cmd(struct rtsx_chip *chip, int card);
|
||||
int rtsx_write_register(struct rtsx_chip *chip, u16 addr, u8 mask, u8 data);
|
||||
int rtsx_read_register(struct rtsx_chip *chip, u16 addr, u8 *data);
|
||||
int rtsx_write_cfg_dw(struct rtsx_chip *chip,
|
||||
u8 func_no, u16 addr, u32 mask, u32 val);
|
||||
int rtsx_read_cfg_dw(struct rtsx_chip *chip, u8 func_no, u16 addr, u32 *val);
|
||||
int rtsx_write_cfg_seq(struct rtsx_chip *chip,
|
||||
u8 func, u16 addr, u8 *buf, int len);
|
||||
int rtsx_read_cfg_seq(struct rtsx_chip *chip,
|
||||
u8 func, u16 addr, u8 *buf, int len);
|
||||
int rtsx_write_phy_register(struct rtsx_chip *chip, u8 addr, u16 val);
|
||||
int rtsx_read_phy_register(struct rtsx_chip *chip, u8 addr, u16 *val);
|
||||
int rtsx_read_efuse(struct rtsx_chip *chip, u8 addr, u8 *val);
|
||||
int rtsx_write_efuse(struct rtsx_chip *chip, u8 addr, u8 val);
|
||||
int rtsx_clr_phy_reg_bit(struct rtsx_chip *chip, u8 reg, u8 bit);
|
||||
int rtsx_set_phy_reg_bit(struct rtsx_chip *chip, u8 reg, u8 bit);
|
||||
void rtsx_enter_ss(struct rtsx_chip *chip);
|
||||
void rtsx_exit_ss(struct rtsx_chip *chip);
|
||||
int rtsx_pre_handle_interrupt(struct rtsx_chip *chip);
|
||||
void rtsx_enter_L1(struct rtsx_chip *chip);
|
||||
void rtsx_exit_L1(struct rtsx_chip *chip);
|
||||
void rtsx_do_before_power_down(struct rtsx_chip *chip, int pm_stat);
|
||||
void rtsx_enable_aspm(struct rtsx_chip *chip);
|
||||
void rtsx_disable_aspm(struct rtsx_chip *chip);
|
||||
int rtsx_read_ppbuf(struct rtsx_chip *chip, u8 *buf, int buf_len);
|
||||
int rtsx_write_ppbuf(struct rtsx_chip *chip, u8 *buf, int buf_len);
|
||||
int rtsx_check_chip_exist(struct rtsx_chip *chip);
|
||||
|
||||
#endif /* __REALTEK_RTSX_CHIP_H */
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,131 +0,0 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Driver for Realtek PCI-Express card reader
|
||||
*
|
||||
* Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
|
||||
*
|
||||
* Author:
|
||||
* Wei WANG (wei_wang@realsil.com.cn)
|
||||
* Micky Ching (micky_ching@realsil.com.cn)
|
||||
*/
|
||||
|
||||
#ifndef __REALTEK_RTSX_SCSI_H
|
||||
#define __REALTEK_RTSX_SCSI_H
|
||||
|
||||
#include "rtsx.h"
|
||||
#include "rtsx_chip.h"
|
||||
|
||||
#define MS_SP_CMND 0xFA
|
||||
#define MS_FORMAT 0xA0
|
||||
#define GET_MS_INFORMATION 0xB0
|
||||
|
||||
#define VENDOR_CMND 0xF0
|
||||
|
||||
#define READ_STATUS 0x09
|
||||
|
||||
#define READ_EEPROM 0x04
|
||||
#define WRITE_EEPROM 0x05
|
||||
#define READ_MEM 0x0D
|
||||
#define WRITE_MEM 0x0E
|
||||
#define GET_BUS_WIDTH 0x13
|
||||
#define GET_SD_CSD 0x14
|
||||
#define TOGGLE_GPIO 0x15
|
||||
#define TRACE_MSG 0x18
|
||||
|
||||
#define SCSI_APP_CMD 0x10
|
||||
|
||||
#define PP_READ10 0x1A
|
||||
#define PP_WRITE10 0x0A
|
||||
#define READ_HOST_REG 0x1D
|
||||
#define WRITE_HOST_REG 0x0D
|
||||
#define SET_VAR 0x05
|
||||
#define GET_VAR 0x15
|
||||
#define DMA_READ 0x16
|
||||
#define DMA_WRITE 0x06
|
||||
#define GET_DEV_STATUS 0x10
|
||||
#define SET_CHIP_MODE 0x27
|
||||
#define SUIT_CMD 0xE0
|
||||
#define WRITE_PHY 0x07
|
||||
#define READ_PHY 0x17
|
||||
#define WRITE_EEPROM2 0x03
|
||||
#define READ_EEPROM2 0x13
|
||||
#define ERASE_EEPROM2 0x23
|
||||
#define WRITE_EFUSE 0x04
|
||||
#define READ_EFUSE 0x14
|
||||
#define WRITE_CFG 0x0E
|
||||
#define READ_CFG 0x1E
|
||||
|
||||
#define SPI_VENDOR_COMMAND 0x1C
|
||||
|
||||
#define SCSI_SPI_GETSTATUS 0x00
|
||||
#define SCSI_SPI_SETPARAMETER 0x01
|
||||
#define SCSI_SPI_READFALSHID 0x02
|
||||
#define SCSI_SPI_READFLASH 0x03
|
||||
#define SCSI_SPI_WRITEFLASH 0x04
|
||||
#define SCSI_SPI_WRITEFLASHSTATUS 0x05
|
||||
#define SCSI_SPI_ERASEFLASH 0x06
|
||||
|
||||
#define INIT_BATCHCMD 0x41
|
||||
#define ADD_BATCHCMD 0x42
|
||||
#define SEND_BATCHCMD 0x43
|
||||
#define GET_BATCHRSP 0x44
|
||||
|
||||
#define CHIP_NORMALMODE 0x00
|
||||
#define CHIP_DEBUGMODE 0x01
|
||||
|
||||
/* SD Pass Through Command Extension */
|
||||
#define SD_PASS_THRU_MODE 0xD0
|
||||
#define SD_EXECUTE_NO_DATA 0xD1
|
||||
#define SD_EXECUTE_READ 0xD2
|
||||
#define SD_EXECUTE_WRITE 0xD3
|
||||
#define SD_GET_RSP 0xD4
|
||||
#define SD_HW_RST 0xD6
|
||||
|
||||
#ifdef SUPPORT_MAGIC_GATE
|
||||
#define CMD_MSPRO_MG_RKEY 0xA4 /* Report Key Command */
|
||||
#define CMD_MSPRO_MG_SKEY 0xA3 /* Send Key Command */
|
||||
|
||||
/* CBWCB field: key class */
|
||||
#define KC_MG_R_PRO 0xBE /* MG-R PRO*/
|
||||
|
||||
/* CBWCB field: key format */
|
||||
#define KF_SET_LEAF_ID 0x31 /* Set Leaf ID */
|
||||
#define KF_GET_LOC_EKB 0x32 /* Get Local EKB */
|
||||
#define KF_CHG_HOST 0x33 /* Challenge (host) */
|
||||
#define KF_RSP_CHG 0x34 /* Response and Challenge (device) */
|
||||
#define KF_RSP_HOST 0x35 /* Response (host) */
|
||||
#define KF_GET_ICV 0x36 /* Get ICV */
|
||||
#define KF_SET_ICV 0x37 /* SSet ICV */
|
||||
#endif
|
||||
|
||||
/* Sense type */
|
||||
#define SENSE_TYPE_NO_SENSE 0
|
||||
#define SENSE_TYPE_MEDIA_CHANGE 1
|
||||
#define SENSE_TYPE_MEDIA_NOT_PRESENT 2
|
||||
#define SENSE_TYPE_MEDIA_LBA_OVER_RANGE 3
|
||||
#define SENSE_TYPE_MEDIA_LUN_NOT_SUPPORT 4
|
||||
#define SENSE_TYPE_MEDIA_WRITE_PROTECT 5
|
||||
#define SENSE_TYPE_MEDIA_INVALID_CMD_FIELD 6
|
||||
#define SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR 7
|
||||
#define SENSE_TYPE_MEDIA_WRITE_ERR 8
|
||||
#define SENSE_TYPE_FORMAT_IN_PROGRESS 9
|
||||
#define SENSE_TYPE_FORMAT_CMD_FAILED 10
|
||||
#ifdef SUPPORT_MAGIC_GATE
|
||||
#define SENSE_TYPE_MG_KEY_FAIL_NOT_ESTAB 0x0b
|
||||
#define SENSE_TYPE_MG_KEY_FAIL_NOT_AUTHEN 0x0c
|
||||
#define SENSE_TYPE_MG_INCOMPATIBLE_MEDIUM 0x0d
|
||||
#define SENSE_TYPE_MG_WRITE_ERR 0x0e
|
||||
#endif
|
||||
#ifdef SUPPORT_SD_LOCK
|
||||
/* FOR Locked SD card*/
|
||||
#define SENSE_TYPE_MEDIA_READ_FORBIDDEN 0x10
|
||||
#endif
|
||||
|
||||
void scsi_show_command(struct rtsx_chip *chip);
|
||||
void set_sense_type(struct rtsx_chip *chip, unsigned int lun, int sense_type);
|
||||
void set_sense_data(struct rtsx_chip *chip, unsigned int lun, u8 err_code,
|
||||
u8 sense_key, u32 info, u8 asc, u8 ascq,
|
||||
u8 sns_key_info0, u16 sns_key_info1);
|
||||
int rtsx_scsi_handler(struct scsi_cmnd *srb, struct rtsx_chip *chip);
|
||||
|
||||
#endif /* __REALTEK_RTSX_SCSI_H */
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Driver for Realtek PCI-Express card reader
|
||||
*
|
||||
* Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
|
||||
*
|
||||
* Author:
|
||||
* Wei WANG (wei_wang@realsil.com.cn)
|
||||
* Micky Ching (micky_ching@realsil.com.cn)
|
||||
*/
|
||||
|
||||
#ifndef __RTSX_SYS_H
|
||||
#define __RTSX_SYS_H
|
||||
|
||||
#include "rtsx.h"
|
||||
#include "rtsx_chip.h"
|
||||
#include "rtsx_card.h"
|
||||
|
||||
static inline void rtsx_exclusive_enter_ss(struct rtsx_chip *chip)
|
||||
{
|
||||
struct rtsx_dev *dev = chip->rtsx;
|
||||
|
||||
spin_lock(&dev->reg_lock);
|
||||
rtsx_enter_ss(chip);
|
||||
spin_unlock(&dev->reg_lock);
|
||||
}
|
||||
|
||||
static inline void rtsx_reset_detected_cards(struct rtsx_chip *chip, int flag)
|
||||
{
|
||||
rtsx_reset_cards(chip);
|
||||
}
|
||||
|
||||
#define RTSX_MSG_IN_INT(x)
|
||||
|
||||
#endif /* __RTSX_SYS_H */
|
||||
|
||||
|
|
@ -1,768 +0,0 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Driver for Realtek PCI-Express card reader
|
||||
*
|
||||
* Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
|
||||
*
|
||||
* Author:
|
||||
* Wei WANG (wei_wang@realsil.com.cn)
|
||||
* Micky Ching (micky_ching@realsil.com.cn)
|
||||
*/
|
||||
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
#include "rtsx.h"
|
||||
|
||||
/***********************************************************************
|
||||
* Scatter-gather transfer buffer access routines
|
||||
***********************************************************************/
|
||||
|
||||
/*
|
||||
* Copy a buffer of length buflen to/from the srb's transfer buffer.
|
||||
* (Note: for scatter-gather transfers (srb->use_sg > 0), srb->request_buffer
|
||||
* points to a list of s-g entries and we ignore srb->request_bufflen.
|
||||
* For non-scatter-gather transfers, srb->request_buffer points to the
|
||||
* transfer buffer itself and srb->request_bufflen is the buffer's length.)
|
||||
* Update the *index and *offset variables so that the next copy will
|
||||
* pick up from where this one left off.
|
||||
*/
|
||||
|
||||
unsigned int rtsx_stor_access_xfer_buf(unsigned char *buffer,
|
||||
unsigned int buflen,
|
||||
struct scsi_cmnd *srb,
|
||||
unsigned int *index,
|
||||
unsigned int *offset,
|
||||
enum xfer_buf_dir dir)
|
||||
{
|
||||
unsigned int cnt;
|
||||
|
||||
/* If not using scatter-gather, just transfer the data directly. */
|
||||
if (scsi_sg_count(srb) == 0) {
|
||||
unsigned char *sgbuffer;
|
||||
|
||||
if (*offset >= scsi_bufflen(srb))
|
||||
return 0;
|
||||
cnt = min(buflen, scsi_bufflen(srb) - *offset);
|
||||
|
||||
sgbuffer = (unsigned char *)scsi_sglist(srb) + *offset;
|
||||
|
||||
if (dir == TO_XFER_BUF)
|
||||
memcpy(sgbuffer, buffer, cnt);
|
||||
else
|
||||
memcpy(buffer, sgbuffer, cnt);
|
||||
*offset += cnt;
|
||||
|
||||
/*
|
||||
* Using scatter-gather. We have to go through the list one entry
|
||||
* at a time. Each s-g entry contains some number of pages which
|
||||
* have to be copied one at a time.
|
||||
*/
|
||||
} else {
|
||||
struct scatterlist *sg =
|
||||
(struct scatterlist *)scsi_sglist(srb)
|
||||
+ *index;
|
||||
|
||||
/*
|
||||
* This loop handles a single s-g list entry, which may
|
||||
* include multiple pages. Find the initial page structure
|
||||
* and the starting offset within the page, and update
|
||||
* the *offset and *index values for the next loop.
|
||||
*/
|
||||
cnt = 0;
|
||||
while (cnt < buflen && *index < scsi_sg_count(srb)) {
|
||||
struct page *page = sg_page(sg) +
|
||||
((sg->offset + *offset) >> PAGE_SHIFT);
|
||||
unsigned int poff = (sg->offset + *offset) &
|
||||
(PAGE_SIZE - 1);
|
||||
unsigned int sglen = sg->length - *offset;
|
||||
|
||||
if (sglen > buflen - cnt) {
|
||||
/* Transfer ends within this s-g entry */
|
||||
sglen = buflen - cnt;
|
||||
*offset += sglen;
|
||||
} else {
|
||||
/* Transfer continues to next s-g entry */
|
||||
*offset = 0;
|
||||
++*index;
|
||||
++sg;
|
||||
}
|
||||
|
||||
while (sglen > 0) {
|
||||
unsigned int plen = min(sglen, (unsigned int)
|
||||
PAGE_SIZE - poff);
|
||||
|
||||
if (dir == TO_XFER_BUF)
|
||||
memcpy_to_page(page, poff, buffer + cnt, plen);
|
||||
else
|
||||
memcpy_from_page(buffer + cnt, page, poff, plen);
|
||||
|
||||
/* Start at the beginning of the next page */
|
||||
poff = 0;
|
||||
++page;
|
||||
cnt += plen;
|
||||
sglen -= plen;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the amount actually transferred */
|
||||
return cnt;
|
||||
}
|
||||
|
||||
/*
|
||||
* Store the contents of buffer into srb's transfer buffer and set the
|
||||
* SCSI residue.
|
||||
*/
|
||||
void rtsx_stor_set_xfer_buf(unsigned char *buffer,
|
||||
unsigned int buflen, struct scsi_cmnd *srb)
|
||||
{
|
||||
unsigned int index = 0, offset = 0;
|
||||
|
||||
rtsx_stor_access_xfer_buf(buffer, buflen, srb, &index, &offset,
|
||||
TO_XFER_BUF);
|
||||
if (buflen < scsi_bufflen(srb))
|
||||
scsi_set_resid(srb, scsi_bufflen(srb) - buflen);
|
||||
}
|
||||
|
||||
void rtsx_stor_get_xfer_buf(unsigned char *buffer,
|
||||
unsigned int buflen, struct scsi_cmnd *srb)
|
||||
{
|
||||
unsigned int index = 0, offset = 0;
|
||||
|
||||
rtsx_stor_access_xfer_buf(buffer, buflen, srb, &index, &offset,
|
||||
FROM_XFER_BUF);
|
||||
if (buflen < scsi_bufflen(srb))
|
||||
scsi_set_resid(srb, scsi_bufflen(srb) - buflen);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* Transport routines
|
||||
***********************************************************************/
|
||||
|
||||
/*
|
||||
* Invoke the transport and basic error-handling/recovery methods
|
||||
*
|
||||
* This is used to send the message to the device and receive the response.
|
||||
*/
|
||||
void rtsx_invoke_transport(struct scsi_cmnd *srb, struct rtsx_chip *chip)
|
||||
{
|
||||
int result;
|
||||
|
||||
result = rtsx_scsi_handler(srb, chip);
|
||||
|
||||
/*
|
||||
* if the command gets aborted by the higher layers, we need to
|
||||
* short-circuit all other processing.
|
||||
*/
|
||||
if (rtsx_chk_stat(chip, RTSX_STAT_ABORT)) {
|
||||
dev_dbg(rtsx_dev(chip), "-- command was aborted\n");
|
||||
srb->result = DID_ABORT << 16;
|
||||
goto handle_errors;
|
||||
}
|
||||
|
||||
/* if there is a transport error, reset and don't auto-sense */
|
||||
if (result == TRANSPORT_ERROR) {
|
||||
dev_dbg(rtsx_dev(chip), "-- transport indicates error, resetting\n");
|
||||
srb->result = DID_ERROR << 16;
|
||||
goto handle_errors;
|
||||
}
|
||||
|
||||
srb->result = SAM_STAT_GOOD;
|
||||
|
||||
/*
|
||||
* If we have a failure, we're going to do a REQUEST_SENSE
|
||||
* automatically. Note that we differentiate between a command
|
||||
* "failure" and an "error" in the transport mechanism.
|
||||
*/
|
||||
if (result == TRANSPORT_FAILED) {
|
||||
/* set the result so the higher layers expect this data */
|
||||
srb->result = SAM_STAT_CHECK_CONDITION;
|
||||
memcpy(srb->sense_buffer,
|
||||
(unsigned char *)&chip->sense_buffer[SCSI_LUN(srb)],
|
||||
sizeof(struct sense_data_t));
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
handle_errors:
|
||||
return;
|
||||
}
|
||||
|
||||
void rtsx_add_cmd(struct rtsx_chip *chip,
|
||||
u8 cmd_type, u16 reg_addr, u8 mask, u8 data)
|
||||
{
|
||||
__le32 *cb = (__le32 *)(chip->host_cmds_ptr);
|
||||
u32 val = 0;
|
||||
|
||||
val |= (u32)(cmd_type & 0x03) << 30;
|
||||
val |= (u32)(reg_addr & 0x3FFF) << 16;
|
||||
val |= (u32)mask << 8;
|
||||
val |= (u32)data;
|
||||
|
||||
spin_lock_irq(&chip->rtsx->reg_lock);
|
||||
if (chip->ci < (HOST_CMDS_BUF_LEN / 4))
|
||||
cb[(chip->ci)++] = cpu_to_le32(val);
|
||||
|
||||
spin_unlock_irq(&chip->rtsx->reg_lock);
|
||||
}
|
||||
|
||||
void rtsx_send_cmd_no_wait(struct rtsx_chip *chip)
|
||||
{
|
||||
u32 val = BIT(31);
|
||||
|
||||
rtsx_writel(chip, RTSX_HCBAR, chip->host_cmds_addr);
|
||||
|
||||
val |= (u32)(chip->ci * 4) & 0x00FFFFFF;
|
||||
/* Hardware Auto Response */
|
||||
val |= 0x40000000;
|
||||
rtsx_writel(chip, RTSX_HCBCTLR, val);
|
||||
}
|
||||
|
||||
int rtsx_send_cmd(struct rtsx_chip *chip, u8 card, int timeout)
|
||||
{
|
||||
struct rtsx_dev *rtsx = chip->rtsx;
|
||||
struct completion trans_done;
|
||||
u32 val = BIT(31);
|
||||
long timeleft;
|
||||
int err = 0;
|
||||
|
||||
if (card == SD_CARD)
|
||||
rtsx->check_card_cd = SD_EXIST;
|
||||
else if (card == MS_CARD)
|
||||
rtsx->check_card_cd = MS_EXIST;
|
||||
else if (card == XD_CARD)
|
||||
rtsx->check_card_cd = XD_EXIST;
|
||||
else
|
||||
rtsx->check_card_cd = 0;
|
||||
|
||||
spin_lock_irq(&rtsx->reg_lock);
|
||||
|
||||
/* set up data structures for the wakeup system */
|
||||
rtsx->done = &trans_done;
|
||||
rtsx->trans_result = TRANS_NOT_READY;
|
||||
init_completion(&trans_done);
|
||||
rtsx->trans_state = STATE_TRANS_CMD;
|
||||
|
||||
rtsx_writel(chip, RTSX_HCBAR, chip->host_cmds_addr);
|
||||
|
||||
val |= (u32)(chip->ci * 4) & 0x00FFFFFF;
|
||||
/* Hardware Auto Response */
|
||||
val |= 0x40000000;
|
||||
rtsx_writel(chip, RTSX_HCBCTLR, val);
|
||||
|
||||
spin_unlock_irq(&rtsx->reg_lock);
|
||||
|
||||
/* Wait for TRANS_OK_INT */
|
||||
timeleft = wait_for_completion_interruptible_timeout(&trans_done,
|
||||
msecs_to_jiffies(timeout));
|
||||
if (timeleft <= 0) {
|
||||
dev_dbg(rtsx_dev(chip), "chip->int_reg = 0x%x\n",
|
||||
chip->int_reg);
|
||||
err = -ETIMEDOUT;
|
||||
goto finish_send_cmd;
|
||||
}
|
||||
|
||||
spin_lock_irq(&rtsx->reg_lock);
|
||||
if (rtsx->trans_result == TRANS_RESULT_FAIL)
|
||||
err = -EIO;
|
||||
else if (rtsx->trans_result == TRANS_RESULT_OK)
|
||||
err = 0;
|
||||
|
||||
spin_unlock_irq(&rtsx->reg_lock);
|
||||
|
||||
finish_send_cmd:
|
||||
rtsx->done = NULL;
|
||||
rtsx->trans_state = STATE_TRANS_NONE;
|
||||
|
||||
if (err < 0)
|
||||
rtsx_stop_cmd(chip, card);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static inline void rtsx_add_sg_tbl(struct rtsx_chip *chip,
|
||||
u32 addr, u32 len, u8 option)
|
||||
{
|
||||
__le64 *sgb = (__le64 *)(chip->host_sg_tbl_ptr);
|
||||
u64 val = 0;
|
||||
u32 temp_len = 0;
|
||||
u8 temp_opt = 0;
|
||||
|
||||
do {
|
||||
if (len > 0x80000) {
|
||||
temp_len = 0x80000;
|
||||
temp_opt = option & (~RTSX_SG_END);
|
||||
} else {
|
||||
temp_len = len;
|
||||
temp_opt = option;
|
||||
}
|
||||
val = ((u64)addr << 32) | ((u64)temp_len << 12) | temp_opt;
|
||||
|
||||
if (chip->sgi < (HOST_SG_TBL_BUF_LEN / 8))
|
||||
sgb[(chip->sgi)++] = cpu_to_le64(val);
|
||||
|
||||
len -= temp_len;
|
||||
addr += temp_len;
|
||||
} while (len);
|
||||
}
|
||||
|
||||
static int rtsx_transfer_sglist_adma_partial(struct rtsx_chip *chip, u8 card,
|
||||
struct scatterlist *sg, int num_sg,
|
||||
unsigned int *index,
|
||||
unsigned int *offset, int size,
|
||||
enum dma_data_direction dma_dir,
|
||||
int timeout)
|
||||
{
|
||||
struct rtsx_dev *rtsx = chip->rtsx;
|
||||
struct completion trans_done;
|
||||
u8 dir;
|
||||
int sg_cnt, i, resid;
|
||||
int err = 0;
|
||||
long timeleft;
|
||||
struct scatterlist *sg_ptr;
|
||||
u32 val = TRIG_DMA;
|
||||
|
||||
if (!sg || num_sg <= 0 || !offset || !index)
|
||||
return -EIO;
|
||||
|
||||
if (dma_dir == DMA_TO_DEVICE)
|
||||
dir = HOST_TO_DEVICE;
|
||||
else if (dma_dir == DMA_FROM_DEVICE)
|
||||
dir = DEVICE_TO_HOST;
|
||||
else
|
||||
return -ENXIO;
|
||||
|
||||
if (card == SD_CARD)
|
||||
rtsx->check_card_cd = SD_EXIST;
|
||||
else if (card == MS_CARD)
|
||||
rtsx->check_card_cd = MS_EXIST;
|
||||
else if (card == XD_CARD)
|
||||
rtsx->check_card_cd = XD_EXIST;
|
||||
else
|
||||
rtsx->check_card_cd = 0;
|
||||
|
||||
spin_lock_irq(&rtsx->reg_lock);
|
||||
|
||||
/* set up data structures for the wakeup system */
|
||||
rtsx->done = &trans_done;
|
||||
|
||||
rtsx->trans_state = STATE_TRANS_SG;
|
||||
rtsx->trans_result = TRANS_NOT_READY;
|
||||
|
||||
spin_unlock_irq(&rtsx->reg_lock);
|
||||
|
||||
sg_cnt = dma_map_sg(&rtsx->pci->dev, sg, num_sg, dma_dir);
|
||||
|
||||
resid = size;
|
||||
sg_ptr = sg;
|
||||
chip->sgi = 0;
|
||||
/*
|
||||
* Usually the next entry will be @sg@ + 1, but if this sg element
|
||||
* is part of a chained scatterlist, it could jump to the start of
|
||||
* a new scatterlist array. So here we use sg_next to move to
|
||||
* the proper sg.
|
||||
*/
|
||||
for (i = 0; i < *index; i++)
|
||||
sg_ptr = sg_next(sg_ptr);
|
||||
for (i = *index; i < sg_cnt; i++) {
|
||||
dma_addr_t addr;
|
||||
unsigned int len;
|
||||
u8 option;
|
||||
|
||||
addr = sg_dma_address(sg_ptr);
|
||||
len = sg_dma_len(sg_ptr);
|
||||
|
||||
dev_dbg(rtsx_dev(chip), "DMA addr: 0x%x, Len: 0x%x\n",
|
||||
(unsigned int)addr, len);
|
||||
dev_dbg(rtsx_dev(chip), "*index = %d, *offset = %d\n",
|
||||
*index, *offset);
|
||||
|
||||
addr += *offset;
|
||||
|
||||
if ((len - *offset) > resid) {
|
||||
*offset += resid;
|
||||
len = resid;
|
||||
resid = 0;
|
||||
} else {
|
||||
resid -= (len - *offset);
|
||||
len -= *offset;
|
||||
*offset = 0;
|
||||
*index = *index + 1;
|
||||
}
|
||||
option = RTSX_SG_VALID | RTSX_SG_TRANS_DATA;
|
||||
if ((i == sg_cnt - 1) || !resid)
|
||||
option |= RTSX_SG_END;
|
||||
|
||||
rtsx_add_sg_tbl(chip, (u32)addr, (u32)len, option);
|
||||
|
||||
if (!resid)
|
||||
break;
|
||||
|
||||
sg_ptr = sg_next(sg_ptr);
|
||||
}
|
||||
|
||||
dev_dbg(rtsx_dev(chip), "SG table count = %d\n", chip->sgi);
|
||||
|
||||
val |= (u32)(dir & 0x01) << 29;
|
||||
val |= ADMA_MODE;
|
||||
|
||||
spin_lock_irq(&rtsx->reg_lock);
|
||||
|
||||
init_completion(&trans_done);
|
||||
|
||||
rtsx_writel(chip, RTSX_HDBAR, chip->host_sg_tbl_addr);
|
||||
rtsx_writel(chip, RTSX_HDBCTLR, val);
|
||||
|
||||
spin_unlock_irq(&rtsx->reg_lock);
|
||||
|
||||
timeleft = wait_for_completion_interruptible_timeout(&trans_done,
|
||||
msecs_to_jiffies(timeout));
|
||||
if (timeleft <= 0) {
|
||||
dev_dbg(rtsx_dev(chip), "Timeout (%s %d)\n",
|
||||
__func__, __LINE__);
|
||||
dev_dbg(rtsx_dev(chip), "chip->int_reg = 0x%x\n",
|
||||
chip->int_reg);
|
||||
err = -ETIMEDOUT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
spin_lock_irq(&rtsx->reg_lock);
|
||||
if (rtsx->trans_result == TRANS_RESULT_FAIL) {
|
||||
err = -EIO;
|
||||
spin_unlock_irq(&rtsx->reg_lock);
|
||||
goto out;
|
||||
}
|
||||
spin_unlock_irq(&rtsx->reg_lock);
|
||||
|
||||
/* Wait for TRANS_OK_INT */
|
||||
spin_lock_irq(&rtsx->reg_lock);
|
||||
if (rtsx->trans_result == TRANS_NOT_READY) {
|
||||
init_completion(&trans_done);
|
||||
spin_unlock_irq(&rtsx->reg_lock);
|
||||
timeleft = wait_for_completion_interruptible_timeout(&trans_done,
|
||||
msecs_to_jiffies(timeout));
|
||||
if (timeleft <= 0) {
|
||||
dev_dbg(rtsx_dev(chip), "Timeout (%s %d)\n",
|
||||
__func__, __LINE__);
|
||||
dev_dbg(rtsx_dev(chip), "chip->int_reg = 0x%x\n",
|
||||
chip->int_reg);
|
||||
err = -ETIMEDOUT;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
spin_unlock_irq(&rtsx->reg_lock);
|
||||
}
|
||||
|
||||
spin_lock_irq(&rtsx->reg_lock);
|
||||
if (rtsx->trans_result == TRANS_RESULT_FAIL)
|
||||
err = -EIO;
|
||||
else if (rtsx->trans_result == TRANS_RESULT_OK)
|
||||
err = 0;
|
||||
|
||||
spin_unlock_irq(&rtsx->reg_lock);
|
||||
|
||||
out:
|
||||
rtsx->done = NULL;
|
||||
rtsx->trans_state = STATE_TRANS_NONE;
|
||||
dma_unmap_sg(&rtsx->pci->dev, sg, num_sg, dma_dir);
|
||||
|
||||
if (err < 0)
|
||||
rtsx_stop_cmd(chip, card);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int rtsx_transfer_sglist_adma(struct rtsx_chip *chip, u8 card,
|
||||
struct scatterlist *sg, int num_sg,
|
||||
enum dma_data_direction dma_dir,
|
||||
int timeout)
|
||||
{
|
||||
struct rtsx_dev *rtsx = chip->rtsx;
|
||||
struct completion trans_done;
|
||||
u8 dir;
|
||||
int buf_cnt, i;
|
||||
int err = 0;
|
||||
long timeleft;
|
||||
struct scatterlist *sg_ptr;
|
||||
|
||||
if (!sg || num_sg <= 0)
|
||||
return -EIO;
|
||||
|
||||
if (dma_dir == DMA_TO_DEVICE)
|
||||
dir = HOST_TO_DEVICE;
|
||||
else if (dma_dir == DMA_FROM_DEVICE)
|
||||
dir = DEVICE_TO_HOST;
|
||||
else
|
||||
return -ENXIO;
|
||||
|
||||
if (card == SD_CARD)
|
||||
rtsx->check_card_cd = SD_EXIST;
|
||||
else if (card == MS_CARD)
|
||||
rtsx->check_card_cd = MS_EXIST;
|
||||
else if (card == XD_CARD)
|
||||
rtsx->check_card_cd = XD_EXIST;
|
||||
else
|
||||
rtsx->check_card_cd = 0;
|
||||
|
||||
spin_lock_irq(&rtsx->reg_lock);
|
||||
|
||||
/* set up data structures for the wakeup system */
|
||||
rtsx->done = &trans_done;
|
||||
|
||||
rtsx->trans_state = STATE_TRANS_SG;
|
||||
rtsx->trans_result = TRANS_NOT_READY;
|
||||
|
||||
spin_unlock_irq(&rtsx->reg_lock);
|
||||
|
||||
buf_cnt = dma_map_sg(&rtsx->pci->dev, sg, num_sg, dma_dir);
|
||||
|
||||
sg_ptr = sg;
|
||||
|
||||
for (i = 0; i <= buf_cnt / (HOST_SG_TBL_BUF_LEN / 8); i++) {
|
||||
u32 val = TRIG_DMA;
|
||||
int sg_cnt, j;
|
||||
|
||||
if (i == buf_cnt / (HOST_SG_TBL_BUF_LEN / 8))
|
||||
sg_cnt = buf_cnt % (HOST_SG_TBL_BUF_LEN / 8);
|
||||
else
|
||||
sg_cnt = HOST_SG_TBL_BUF_LEN / 8;
|
||||
|
||||
chip->sgi = 0;
|
||||
for (j = 0; j < sg_cnt; j++) {
|
||||
dma_addr_t addr = sg_dma_address(sg_ptr);
|
||||
unsigned int len = sg_dma_len(sg_ptr);
|
||||
u8 option;
|
||||
|
||||
dev_dbg(rtsx_dev(chip), "DMA addr: 0x%x, Len: 0x%x\n",
|
||||
(unsigned int)addr, len);
|
||||
|
||||
option = RTSX_SG_VALID | RTSX_SG_TRANS_DATA;
|
||||
if (j == (sg_cnt - 1))
|
||||
option |= RTSX_SG_END;
|
||||
|
||||
rtsx_add_sg_tbl(chip, (u32)addr, (u32)len, option);
|
||||
|
||||
sg_ptr = sg_next(sg_ptr);
|
||||
}
|
||||
|
||||
dev_dbg(rtsx_dev(chip), "SG table count = %d\n", chip->sgi);
|
||||
|
||||
val |= (u32)(dir & 0x01) << 29;
|
||||
val |= ADMA_MODE;
|
||||
|
||||
spin_lock_irq(&rtsx->reg_lock);
|
||||
|
||||
init_completion(&trans_done);
|
||||
|
||||
rtsx_writel(chip, RTSX_HDBAR, chip->host_sg_tbl_addr);
|
||||
rtsx_writel(chip, RTSX_HDBCTLR, val);
|
||||
|
||||
spin_unlock_irq(&rtsx->reg_lock);
|
||||
|
||||
timeleft = wait_for_completion_interruptible_timeout(&trans_done,
|
||||
msecs_to_jiffies(timeout));
|
||||
if (timeleft <= 0) {
|
||||
dev_dbg(rtsx_dev(chip), "Timeout (%s %d)\n",
|
||||
__func__, __LINE__);
|
||||
dev_dbg(rtsx_dev(chip), "chip->int_reg = 0x%x\n",
|
||||
chip->int_reg);
|
||||
err = -ETIMEDOUT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
spin_lock_irq(&rtsx->reg_lock);
|
||||
if (rtsx->trans_result == TRANS_RESULT_FAIL) {
|
||||
err = -EIO;
|
||||
spin_unlock_irq(&rtsx->reg_lock);
|
||||
goto out;
|
||||
}
|
||||
spin_unlock_irq(&rtsx->reg_lock);
|
||||
|
||||
sg_ptr += sg_cnt;
|
||||
}
|
||||
|
||||
/* Wait for TRANS_OK_INT */
|
||||
spin_lock_irq(&rtsx->reg_lock);
|
||||
if (rtsx->trans_result == TRANS_NOT_READY) {
|
||||
init_completion(&trans_done);
|
||||
spin_unlock_irq(&rtsx->reg_lock);
|
||||
timeleft = wait_for_completion_interruptible_timeout(&trans_done,
|
||||
msecs_to_jiffies(timeout));
|
||||
if (timeleft <= 0) {
|
||||
dev_dbg(rtsx_dev(chip), "Timeout (%s %d)\n",
|
||||
__func__, __LINE__);
|
||||
dev_dbg(rtsx_dev(chip), "chip->int_reg = 0x%x\n",
|
||||
chip->int_reg);
|
||||
err = -ETIMEDOUT;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
spin_unlock_irq(&rtsx->reg_lock);
|
||||
}
|
||||
|
||||
spin_lock_irq(&rtsx->reg_lock);
|
||||
if (rtsx->trans_result == TRANS_RESULT_FAIL)
|
||||
err = -EIO;
|
||||
else if (rtsx->trans_result == TRANS_RESULT_OK)
|
||||
err = 0;
|
||||
|
||||
spin_unlock_irq(&rtsx->reg_lock);
|
||||
|
||||
out:
|
||||
rtsx->done = NULL;
|
||||
rtsx->trans_state = STATE_TRANS_NONE;
|
||||
dma_unmap_sg(&rtsx->pci->dev, sg, num_sg, dma_dir);
|
||||
|
||||
if (err < 0)
|
||||
rtsx_stop_cmd(chip, card);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int rtsx_transfer_buf(struct rtsx_chip *chip, u8 card, void *buf,
|
||||
size_t len, enum dma_data_direction dma_dir,
|
||||
int timeout)
|
||||
{
|
||||
struct rtsx_dev *rtsx = chip->rtsx;
|
||||
struct completion trans_done;
|
||||
dma_addr_t addr;
|
||||
u8 dir;
|
||||
int err = 0;
|
||||
u32 val = BIT(31);
|
||||
long timeleft;
|
||||
|
||||
if (!buf || len <= 0)
|
||||
return -EIO;
|
||||
|
||||
if (dma_dir == DMA_TO_DEVICE)
|
||||
dir = HOST_TO_DEVICE;
|
||||
else if (dma_dir == DMA_FROM_DEVICE)
|
||||
dir = DEVICE_TO_HOST;
|
||||
else
|
||||
return -ENXIO;
|
||||
|
||||
addr = dma_map_single(&rtsx->pci->dev, buf, len, dma_dir);
|
||||
if (dma_mapping_error(&rtsx->pci->dev, addr))
|
||||
return -ENOMEM;
|
||||
|
||||
if (card == SD_CARD)
|
||||
rtsx->check_card_cd = SD_EXIST;
|
||||
else if (card == MS_CARD)
|
||||
rtsx->check_card_cd = MS_EXIST;
|
||||
else if (card == XD_CARD)
|
||||
rtsx->check_card_cd = XD_EXIST;
|
||||
else
|
||||
rtsx->check_card_cd = 0;
|
||||
|
||||
val |= (u32)(dir & 0x01) << 29;
|
||||
val |= (u32)(len & 0x00FFFFFF);
|
||||
|
||||
spin_lock_irq(&rtsx->reg_lock);
|
||||
|
||||
/* set up data structures for the wakeup system */
|
||||
rtsx->done = &trans_done;
|
||||
|
||||
init_completion(&trans_done);
|
||||
|
||||
rtsx->trans_state = STATE_TRANS_BUF;
|
||||
rtsx->trans_result = TRANS_NOT_READY;
|
||||
|
||||
rtsx_writel(chip, RTSX_HDBAR, addr);
|
||||
rtsx_writel(chip, RTSX_HDBCTLR, val);
|
||||
|
||||
spin_unlock_irq(&rtsx->reg_lock);
|
||||
|
||||
/* Wait for TRANS_OK_INT */
|
||||
timeleft = wait_for_completion_interruptible_timeout(&trans_done,
|
||||
msecs_to_jiffies(timeout));
|
||||
if (timeleft <= 0) {
|
||||
dev_dbg(rtsx_dev(chip), "Timeout (%s %d)\n",
|
||||
__func__, __LINE__);
|
||||
dev_dbg(rtsx_dev(chip), "chip->int_reg = 0x%x\n",
|
||||
chip->int_reg);
|
||||
err = -ETIMEDOUT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
spin_lock_irq(&rtsx->reg_lock);
|
||||
if (rtsx->trans_result == TRANS_RESULT_FAIL)
|
||||
err = -EIO;
|
||||
else if (rtsx->trans_result == TRANS_RESULT_OK)
|
||||
err = 0;
|
||||
|
||||
spin_unlock_irq(&rtsx->reg_lock);
|
||||
|
||||
out:
|
||||
rtsx->done = NULL;
|
||||
rtsx->trans_state = STATE_TRANS_NONE;
|
||||
dma_unmap_single(&rtsx->pci->dev, addr, len, dma_dir);
|
||||
|
||||
if (err < 0)
|
||||
rtsx_stop_cmd(chip, card);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int rtsx_transfer_data_partial(struct rtsx_chip *chip, u8 card,
|
||||
void *buf, size_t len, int use_sg,
|
||||
unsigned int *index, unsigned int *offset,
|
||||
enum dma_data_direction dma_dir, int timeout)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
/* don't transfer data during abort processing */
|
||||
if (rtsx_chk_stat(chip, RTSX_STAT_ABORT))
|
||||
return -EIO;
|
||||
|
||||
if (use_sg) {
|
||||
struct scatterlist *sg = buf;
|
||||
|
||||
err = rtsx_transfer_sglist_adma_partial(chip, card, sg, use_sg,
|
||||
index, offset, (int)len,
|
||||
dma_dir, timeout);
|
||||
} else {
|
||||
err = rtsx_transfer_buf(chip, card,
|
||||
buf, len, dma_dir, timeout);
|
||||
}
|
||||
if (err < 0) {
|
||||
if (RTSX_TST_DELINK(chip)) {
|
||||
RTSX_CLR_DELINK(chip);
|
||||
chip->need_reinit = SD_CARD | MS_CARD | XD_CARD;
|
||||
rtsx_reinit_cards(chip, 1);
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int rtsx_transfer_data(struct rtsx_chip *chip, u8 card, void *buf, size_t len,
|
||||
int use_sg, enum dma_data_direction dma_dir, int timeout)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
dev_dbg(rtsx_dev(chip), "use_sg = %d\n", use_sg);
|
||||
|
||||
/* don't transfer data during abort processing */
|
||||
if (rtsx_chk_stat(chip, RTSX_STAT_ABORT))
|
||||
return -EIO;
|
||||
|
||||
if (use_sg) {
|
||||
err = rtsx_transfer_sglist_adma(chip, card, buf,
|
||||
use_sg, dma_dir, timeout);
|
||||
} else {
|
||||
err = rtsx_transfer_buf(chip, card, buf, len, dma_dir, timeout);
|
||||
}
|
||||
|
||||
if (err < 0) {
|
||||
if (RTSX_TST_DELINK(chip)) {
|
||||
RTSX_CLR_DELINK(chip);
|
||||
chip->need_reinit = SD_CARD | MS_CARD | XD_CARD;
|
||||
rtsx_reinit_cards(chip, 1);
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Driver for Realtek PCI-Express card reader
|
||||
*
|
||||
* Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
|
||||
*
|
||||
* Author:
|
||||
* Wei WANG (wei_wang@realsil.com.cn)
|
||||
* Micky Ching (micky_ching@realsil.com.cn)
|
||||
*/
|
||||
|
||||
#ifndef __REALTEK_RTSX_TRANSPORT_H
|
||||
#define __REALTEK_RTSX_TRANSPORT_H
|
||||
|
||||
#include "rtsx.h"
|
||||
#include "rtsx_chip.h"
|
||||
|
||||
#define WAIT_TIME 2000
|
||||
|
||||
unsigned int rtsx_stor_access_xfer_buf(unsigned char *buffer,
|
||||
unsigned int buflen,
|
||||
struct scsi_cmnd *srb,
|
||||
unsigned int *index,
|
||||
unsigned int *offset,
|
||||
enum xfer_buf_dir dir);
|
||||
void rtsx_stor_set_xfer_buf(unsigned char *buffer, unsigned int buflen,
|
||||
struct scsi_cmnd *srb);
|
||||
void rtsx_stor_get_xfer_buf(unsigned char *buffer, unsigned int buflen,
|
||||
struct scsi_cmnd *srb);
|
||||
void rtsx_invoke_transport(struct scsi_cmnd *srb, struct rtsx_chip *chip);
|
||||
|
||||
#define rtsx_init_cmd(chip) ((chip)->ci = 0)
|
||||
|
||||
void rtsx_add_cmd(struct rtsx_chip *chip, u8 cmd_type, u16 reg_addr, u8 mask,
|
||||
u8 data);
|
||||
void rtsx_send_cmd_no_wait(struct rtsx_chip *chip);
|
||||
int rtsx_send_cmd(struct rtsx_chip *chip, u8 card, int timeout);
|
||||
|
||||
static inline u8 *rtsx_get_cmd_data(struct rtsx_chip *chip)
|
||||
{
|
||||
#ifdef CMD_USING_SG
|
||||
return (u8 *)(chip->host_sg_tbl_ptr);
|
||||
#else
|
||||
return (u8 *)(chip->host_cmds_ptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
int rtsx_transfer_data(struct rtsx_chip *chip, u8 card, void *buf, size_t len,
|
||||
int use_sg, enum dma_data_direction dma_dir,
|
||||
int timeout);
|
||||
|
||||
int rtsx_transfer_data_partial(struct rtsx_chip *chip, u8 card, void *buf,
|
||||
size_t len, int use_sg, unsigned int *index,
|
||||
unsigned int *offset,
|
||||
enum dma_data_direction dma_dir, int timeout);
|
||||
|
||||
#endif /* __REALTEK_RTSX_TRANSPORT_H */
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,289 +0,0 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Driver for Realtek PCI-Express card reader
|
||||
*
|
||||
* Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
|
||||
*
|
||||
* Author:
|
||||
* Wei WANG (wei_wang@realsil.com.cn)
|
||||
* Micky Ching (micky_ching@realsil.com.cn)
|
||||
*/
|
||||
|
||||
#ifndef __REALTEK_RTSX_SD_H
|
||||
#define __REALTEK_RTSX_SD_H
|
||||
|
||||
#include "rtsx_chip.h"
|
||||
|
||||
#define SUPPORT_VOLTAGE 0x003C0000
|
||||
|
||||
/* Error Code */
|
||||
#define SD_NO_ERROR 0x0
|
||||
#define SD_CRC_ERR 0x80
|
||||
#define SD_TO_ERR 0x40
|
||||
#define SD_NO_CARD 0x20
|
||||
#define SD_BUSY 0x10
|
||||
#define SD_STS_ERR 0x08
|
||||
#define SD_RSP_TIMEOUT 0x04
|
||||
#define SD_IO_ERR 0x02
|
||||
|
||||
/* Return code for MMC switch bus */
|
||||
#define SWITCH_SUCCESS 0
|
||||
#define SWITCH_ERR 1
|
||||
#define SWITCH_FAIL 2
|
||||
|
||||
/* MMC/SD Command Index */
|
||||
/* Basic command (class 0) */
|
||||
#define GO_IDLE_STATE 0
|
||||
#define SEND_OP_COND 1
|
||||
#define ALL_SEND_CID 2
|
||||
#define SET_RELATIVE_ADDR 3
|
||||
#define SEND_RELATIVE_ADDR 3
|
||||
#define SET_DSR 4
|
||||
#define IO_SEND_OP_COND 5
|
||||
#define SWITCH 6
|
||||
#define SELECT_CARD 7
|
||||
#define DESELECT_CARD 7
|
||||
/* CMD8 is "SEND_EXT_CSD" for MMC4.x Spec
|
||||
* while is "SEND_IF_COND" for SD 2.0
|
||||
*/
|
||||
#define SEND_EXT_CSD 8
|
||||
#define SEND_IF_COND 8
|
||||
|
||||
#define SEND_CSD 9
|
||||
#define SEND_CID 10
|
||||
#define VOLTAGE_SWITCH 11
|
||||
#define READ_DAT_UTIL_STOP 11
|
||||
#define STOP_TRANSMISSION 12
|
||||
#define SEND_STATUS 13
|
||||
#define GO_INACTIVE_STATE 15
|
||||
|
||||
#define SET_BLOCKLEN 16
|
||||
#define READ_SINGLE_BLOCK 17
|
||||
#define READ_MULTIPLE_BLOCK 18
|
||||
#define SEND_TUNING_PATTERN 19
|
||||
|
||||
#define BUSTEST_R 14
|
||||
#define BUSTEST_W 19
|
||||
|
||||
#define WRITE_BLOCK 24
|
||||
#define WRITE_MULTIPLE_BLOCK 25
|
||||
#define PROGRAM_CSD 27
|
||||
|
||||
#define ERASE_WR_BLK_START 32
|
||||
#define ERASE_WR_BLK_END 33
|
||||
#define ERASE_CMD 38
|
||||
|
||||
#define LOCK_UNLOCK 42
|
||||
#define IO_RW_DIRECT 52
|
||||
|
||||
#define APP_CMD 55
|
||||
#define GEN_CMD 56
|
||||
|
||||
#define SET_BUS_WIDTH 6
|
||||
#define SD_STATUS 13
|
||||
#define SEND_NUM_WR_BLOCKS 22
|
||||
#define SET_WR_BLK_ERASE_COUNT 23
|
||||
#define SD_APP_OP_COND 41
|
||||
#define SET_CLR_CARD_DETECT 42
|
||||
#define SEND_SCR 51
|
||||
|
||||
#define SD_READ_COMPLETE 0x00
|
||||
#define SD_READ_TO 0x01
|
||||
#define SD_READ_ADVENCE 0x02
|
||||
|
||||
#define SD_CHECK_MODE 0x00
|
||||
#define SD_SWITCH_MODE 0x80
|
||||
#define SD_FUNC_GROUP_1 0x01
|
||||
#define SD_FUNC_GROUP_2 0x02
|
||||
#define SD_FUNC_GROUP_3 0x03
|
||||
#define SD_FUNC_GROUP_4 0x04
|
||||
#define SD_CHECK_SPEC_V1_1 0xFF
|
||||
|
||||
#define NO_ARGUMENT 0x00
|
||||
#define CHECK_PATTERN 0x000000AA
|
||||
#define VOLTAGE_SUPPLY_RANGE 0x00000100
|
||||
#define SUPPORT_HIGH_AND_EXTENDED_CAPACITY 0x40000000
|
||||
#define SUPPORT_MAX_POWER_PERMANCE 0x10000000
|
||||
#define SUPPORT_1V8 0x01000000
|
||||
|
||||
#define SWITCH_NO_ERR 0x00
|
||||
#define CARD_NOT_EXIST 0x01
|
||||
#define SPEC_NOT_SUPPORT 0x02
|
||||
#define CHECK_MODE_ERR 0x03
|
||||
#define CHECK_NOT_READY 0x04
|
||||
#define SWITCH_CRC_ERR 0x05
|
||||
#define SWITCH_MODE_ERR 0x06
|
||||
#define SWITCH_PASS 0x07
|
||||
|
||||
#ifdef SUPPORT_SD_LOCK
|
||||
#define SD_ERASE 0x08
|
||||
#define SD_LOCK 0x04
|
||||
#define SD_UNLOCK 0x00
|
||||
#define SD_CLR_PWD 0x02
|
||||
#define SD_SET_PWD 0x01
|
||||
|
||||
#define SD_PWD_LEN 0x10
|
||||
|
||||
#define SD_LOCKED 0x80
|
||||
#define SD_LOCK_1BIT_MODE 0x40
|
||||
#define SD_PWD_EXIST 0x20
|
||||
#define SD_UNLOCK_POW_ON 0x01
|
||||
#define SD_SDR_RST 0x02
|
||||
|
||||
#define SD_NOT_ERASE 0x00
|
||||
#define SD_UNDER_ERASING 0x01
|
||||
#define SD_COMPLETE_ERASE 0x02
|
||||
|
||||
#define SD_RW_FORBIDDEN 0x0F
|
||||
|
||||
#endif
|
||||
|
||||
#define HS_SUPPORT 0x01
|
||||
#define SDR50_SUPPORT 0x02
|
||||
#define SDR104_SUPPORT 0x03
|
||||
#define DDR50_SUPPORT 0x04
|
||||
|
||||
#define HS_SUPPORT_MASK 0x02
|
||||
#define SDR50_SUPPORT_MASK 0x04
|
||||
#define SDR104_SUPPORT_MASK 0x08
|
||||
#define DDR50_SUPPORT_MASK 0x10
|
||||
|
||||
#define HS_QUERY_SWITCH_OK 0x01
|
||||
#define SDR50_QUERY_SWITCH_OK 0x02
|
||||
#define SDR104_QUERY_SWITCH_OK 0x03
|
||||
#define DDR50_QUERY_SWITCH_OK 0x04
|
||||
|
||||
#define HS_SWITCH_BUSY 0x02
|
||||
#define SDR50_SWITCH_BUSY 0x04
|
||||
#define SDR104_SWITCH_BUSY 0x08
|
||||
#define DDR50_SWITCH_BUSY 0x10
|
||||
|
||||
#define FUNCTION_GROUP1_SUPPORT_OFFSET 0x0D
|
||||
#define FUNCTION_GROUP1_QUERY_SWITCH_OFFSET 0x10
|
||||
#define FUNCTION_GROUP1_CHECK_BUSY_OFFSET 0x1D
|
||||
|
||||
#define DRIVING_TYPE_A 0x01
|
||||
#define DRIVING_TYPE_B 0x00
|
||||
#define DRIVING_TYPE_C 0x02
|
||||
#define DRIVING_TYPE_D 0x03
|
||||
|
||||
#define DRIVING_TYPE_A_MASK 0x02
|
||||
#define DRIVING_TYPE_B_MASK 0x01
|
||||
#define DRIVING_TYPE_C_MASK 0x04
|
||||
#define DRIVING_TYPE_D_MASK 0x08
|
||||
|
||||
#define TYPE_A_QUERY_SWITCH_OK 0x01
|
||||
#define TYPE_B_QUERY_SWITCH_OK 0x00
|
||||
#define TYPE_C_QUERY_SWITCH_OK 0x02
|
||||
#define TYPE_D_QUERY_SWITCH_OK 0x03
|
||||
|
||||
#define TYPE_A_SWITCH_BUSY 0x02
|
||||
#define TYPE_B_SWITCH_BUSY 0x01
|
||||
#define TYPE_C_SWITCH_BUSY 0x04
|
||||
#define TYPE_D_SWITCH_BUSY 0x08
|
||||
|
||||
#define FUNCTION_GROUP3_SUPPORT_OFFSET 0x09
|
||||
#define FUNCTION_GROUP3_QUERY_SWITCH_OFFSET 0x0F
|
||||
#define FUNCTION_GROUP3_CHECK_BUSY_OFFSET 0x19
|
||||
|
||||
#define CURRENT_LIMIT_200 0x00
|
||||
#define CURRENT_LIMIT_400 0x01
|
||||
#define CURRENT_LIMIT_600 0x02
|
||||
#define CURRENT_LIMIT_800 0x03
|
||||
|
||||
#define CURRENT_LIMIT_200_MASK 0x01
|
||||
#define CURRENT_LIMIT_400_MASK 0x02
|
||||
#define CURRENT_LIMIT_600_MASK 0x04
|
||||
#define CURRENT_LIMIT_800_MASK 0x08
|
||||
|
||||
#define CURRENT_LIMIT_200_QUERY_SWITCH_OK 0x00
|
||||
#define CURRENT_LIMIT_400_QUERY_SWITCH_OK 0x01
|
||||
#define CURRENT_LIMIT_600_QUERY_SWITCH_OK 0x02
|
||||
#define CURRENT_LIMIT_800_QUERY_SWITCH_OK 0x03
|
||||
|
||||
#define CURRENT_LIMIT_200_SWITCH_BUSY 0x01
|
||||
#define CURRENT_LIMIT_400_SWITCH_BUSY 0x02
|
||||
#define CURRENT_LIMIT_600_SWITCH_BUSY 0x04
|
||||
#define CURRENT_LIMIT_800_SWITCH_BUSY 0x08
|
||||
|
||||
#define FUNCTION_GROUP4_SUPPORT_OFFSET 0x07
|
||||
#define FUNCTION_GROUP4_QUERY_SWITCH_OFFSET 0x0F
|
||||
#define FUNCTION_GROUP4_CHECK_BUSY_OFFSET 0x17
|
||||
|
||||
#define DATA_STRUCTURE_VER_OFFSET 0x11
|
||||
|
||||
#define MAX_PHASE 31
|
||||
|
||||
#define MMC_8BIT_BUS 0x0010
|
||||
#define MMC_4BIT_BUS 0x0020
|
||||
|
||||
#define MMC_SWITCH_ERR 0x80
|
||||
|
||||
#define SD_IO_3V3 0
|
||||
#define SD_IO_1V8 1
|
||||
|
||||
#define TUNE_TX 0x00
|
||||
#define TUNE_RX 0x01
|
||||
|
||||
#define CHANGE_TX 0x00
|
||||
#define CHANGE_RX 0x01
|
||||
|
||||
#define DCM_HIGH_FREQUENCY_MODE 0x00
|
||||
#define DCM_LOW_FREQUENCY_MODE 0x01
|
||||
|
||||
#define DCM_HIGH_FREQUENCY_MODE_SET 0x0C
|
||||
#define DCM_LOW_FREQUENCY_MODE_SET 0x00
|
||||
|
||||
#define MULTIPLY_BY_1 0x00
|
||||
#define MULTIPLY_BY_2 0x01
|
||||
#define MULTIPLY_BY_3 0x02
|
||||
#define MULTIPLY_BY_4 0x03
|
||||
#define MULTIPLY_BY_5 0x04
|
||||
#define MULTIPLY_BY_6 0x05
|
||||
#define MULTIPLY_BY_7 0x06
|
||||
#define MULTIPLY_BY_8 0x07
|
||||
#define MULTIPLY_BY_9 0x08
|
||||
#define MULTIPLY_BY_10 0x09
|
||||
|
||||
#define DIVIDE_BY_2 0x01
|
||||
#define DIVIDE_BY_3 0x02
|
||||
#define DIVIDE_BY_4 0x03
|
||||
#define DIVIDE_BY_5 0x04
|
||||
#define DIVIDE_BY_6 0x05
|
||||
#define DIVIDE_BY_7 0x06
|
||||
#define DIVIDE_BY_8 0x07
|
||||
#define DIVIDE_BY_9 0x08
|
||||
#define DIVIDE_BY_10 0x09
|
||||
|
||||
struct timing_phase_path {
|
||||
int start;
|
||||
int end;
|
||||
int mid;
|
||||
int len;
|
||||
};
|
||||
|
||||
int sd_select_card(struct rtsx_chip *chip, int select);
|
||||
int sd_pull_ctl_enable(struct rtsx_chip *chip);
|
||||
int reset_sd_card(struct rtsx_chip *chip);
|
||||
int sd_switch_clock(struct rtsx_chip *chip);
|
||||
void sd_stop_seq_mode(struct rtsx_chip *chip);
|
||||
int sd_rw(struct scsi_cmnd *srb, struct rtsx_chip *chip,
|
||||
u32 start_sector, u16 sector_cnt);
|
||||
void sd_cleanup_work(struct rtsx_chip *chip);
|
||||
int sd_power_off_card3v3(struct rtsx_chip *chip);
|
||||
int release_sd_card(struct rtsx_chip *chip);
|
||||
#ifdef SUPPORT_CPRM
|
||||
int ext_sd_send_cmd_get_rsp(struct rtsx_chip *chip, u8 cmd_idx,
|
||||
u32 arg, u8 rsp_type, u8 *rsp, int rsp_len,
|
||||
bool special_check);
|
||||
int ext_sd_get_rsp(struct rtsx_chip *chip, int len, u8 *rsp, u8 rsp_type);
|
||||
|
||||
int sd_pass_thru_mode(struct scsi_cmnd *srb, struct rtsx_chip *chip);
|
||||
int sd_execute_no_data(struct scsi_cmnd *srb, struct rtsx_chip *chip);
|
||||
int sd_execute_read_data(struct scsi_cmnd *srb, struct rtsx_chip *chip);
|
||||
int sd_execute_write_data(struct scsi_cmnd *srb, struct rtsx_chip *chip);
|
||||
int sd_get_cmd_rsp(struct scsi_cmnd *srb, struct rtsx_chip *chip);
|
||||
int sd_hw_rst(struct scsi_cmnd *srb, struct rtsx_chip *chip);
|
||||
#endif
|
||||
|
||||
#endif /* __REALTEK_RTSX_SD_H */
|
||||
|
|
@ -1,906 +0,0 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Driver for Realtek PCI-Express card reader
|
||||
*
|
||||
* Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
|
||||
*
|
||||
* Author:
|
||||
* Wei WANG (wei_wang@realsil.com.cn)
|
||||
* Micky Ching (micky_ching@realsil.com.cn)
|
||||
*/
|
||||
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
#include "rtsx.h"
|
||||
#include "spi.h"
|
||||
|
||||
static inline void spi_set_err_code(struct rtsx_chip *chip, u8 err_code)
|
||||
{
|
||||
struct spi_info *spi = &chip->spi;
|
||||
|
||||
spi->err_code = err_code;
|
||||
}
|
||||
|
||||
static int spi_init(struct rtsx_chip *chip)
|
||||
{
|
||||
int retval;
|
||||
|
||||
retval = rtsx_write_register(chip, SPI_CONTROL, 0xFF,
|
||||
CS_POLARITY_LOW | DTO_MSB_FIRST
|
||||
| SPI_MASTER | SPI_MODE0 | SPI_AUTO);
|
||||
if (retval)
|
||||
return retval;
|
||||
retval = rtsx_write_register(chip, SPI_TCTL, EDO_TIMING_MASK,
|
||||
SAMPLE_DELAY_HALF);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static int spi_set_init_para(struct rtsx_chip *chip)
|
||||
{
|
||||
struct spi_info *spi = &chip->spi;
|
||||
int retval;
|
||||
|
||||
retval = rtsx_write_register(chip, SPI_CLK_DIVIDER1, 0xFF,
|
||||
(u8)(spi->clk_div >> 8));
|
||||
if (retval)
|
||||
return retval;
|
||||
retval = rtsx_write_register(chip, SPI_CLK_DIVIDER0, 0xFF,
|
||||
(u8)(spi->clk_div));
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
retval = switch_clock(chip, spi->spi_clock);
|
||||
if (retval != STATUS_SUCCESS)
|
||||
return STATUS_FAIL;
|
||||
|
||||
retval = select_card(chip, SPI_CARD);
|
||||
if (retval != STATUS_SUCCESS)
|
||||
return STATUS_FAIL;
|
||||
|
||||
retval = rtsx_write_register(chip, CARD_CLK_EN, SPI_CLK_EN,
|
||||
SPI_CLK_EN);
|
||||
if (retval)
|
||||
return retval;
|
||||
retval = rtsx_write_register(chip, CARD_OE, SPI_OUTPUT_EN,
|
||||
SPI_OUTPUT_EN);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
wait_timeout(10);
|
||||
|
||||
retval = spi_init(chip);
|
||||
if (retval != STATUS_SUCCESS)
|
||||
return STATUS_FAIL;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static int sf_polling_status(struct rtsx_chip *chip, int msec)
|
||||
{
|
||||
int retval;
|
||||
|
||||
rtsx_init_cmd(chip);
|
||||
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_COMMAND, 0xFF, SPI_RDSR);
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_TRANSFER0, 0xFF,
|
||||
SPI_TRANSFER0_START | SPI_POLLING_MODE0);
|
||||
rtsx_add_cmd(chip, CHECK_REG_CMD, SPI_TRANSFER0, SPI_TRANSFER0_END,
|
||||
SPI_TRANSFER0_END);
|
||||
|
||||
retval = rtsx_send_cmd(chip, 0, msec);
|
||||
if (retval < 0) {
|
||||
rtsx_clear_spi_error(chip);
|
||||
spi_set_err_code(chip, SPI_BUSY_ERR);
|
||||
return STATUS_FAIL;
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static int sf_enable_write(struct rtsx_chip *chip, u8 ins)
|
||||
{
|
||||
struct spi_info *spi = &chip->spi;
|
||||
int retval;
|
||||
|
||||
if (!spi->write_en)
|
||||
return STATUS_SUCCESS;
|
||||
|
||||
rtsx_init_cmd(chip);
|
||||
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_COMMAND, 0xFF, ins);
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_CA_NUMBER, 0xFF,
|
||||
SPI_COMMAND_BIT_8 | SPI_ADDRESS_BIT_24);
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_TRANSFER0, 0xFF,
|
||||
SPI_TRANSFER0_START | SPI_C_MODE0);
|
||||
rtsx_add_cmd(chip, CHECK_REG_CMD, SPI_TRANSFER0, SPI_TRANSFER0_END,
|
||||
SPI_TRANSFER0_END);
|
||||
|
||||
retval = rtsx_send_cmd(chip, 0, 100);
|
||||
if (retval < 0) {
|
||||
rtsx_clear_spi_error(chip);
|
||||
spi_set_err_code(chip, SPI_HW_ERR);
|
||||
return STATUS_FAIL;
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static int sf_disable_write(struct rtsx_chip *chip, u8 ins)
|
||||
{
|
||||
struct spi_info *spi = &chip->spi;
|
||||
int retval;
|
||||
|
||||
if (!spi->write_en)
|
||||
return STATUS_SUCCESS;
|
||||
|
||||
rtsx_init_cmd(chip);
|
||||
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_COMMAND, 0xFF, ins);
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_CA_NUMBER, 0xFF,
|
||||
SPI_COMMAND_BIT_8 | SPI_ADDRESS_BIT_24);
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_TRANSFER0, 0xFF,
|
||||
SPI_TRANSFER0_START | SPI_C_MODE0);
|
||||
rtsx_add_cmd(chip, CHECK_REG_CMD, SPI_TRANSFER0, SPI_TRANSFER0_END,
|
||||
SPI_TRANSFER0_END);
|
||||
|
||||
retval = rtsx_send_cmd(chip, 0, 100);
|
||||
if (retval < 0) {
|
||||
rtsx_clear_spi_error(chip);
|
||||
spi_set_err_code(chip, SPI_HW_ERR);
|
||||
return STATUS_FAIL;
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static void sf_program(struct rtsx_chip *chip, u8 ins, u8 addr_mode, u32 addr,
|
||||
u16 len)
|
||||
{
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_COMMAND, 0xFF, ins);
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_CA_NUMBER, 0xFF,
|
||||
SPI_COMMAND_BIT_8 | SPI_ADDRESS_BIT_24);
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_LENGTH0, 0xFF, (u8)len);
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_LENGTH1, 0xFF, (u8)(len >> 8));
|
||||
if (addr_mode) {
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR0, 0xFF, (u8)addr);
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR1, 0xFF,
|
||||
(u8)(addr >> 8));
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR2, 0xFF,
|
||||
(u8)(addr >> 16));
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_TRANSFER0, 0xFF,
|
||||
SPI_TRANSFER0_START | SPI_CADO_MODE0);
|
||||
} else {
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_TRANSFER0, 0xFF,
|
||||
SPI_TRANSFER0_START | SPI_CDO_MODE0);
|
||||
}
|
||||
rtsx_add_cmd(chip, CHECK_REG_CMD, SPI_TRANSFER0, SPI_TRANSFER0_END,
|
||||
SPI_TRANSFER0_END);
|
||||
}
|
||||
|
||||
static int sf_erase(struct rtsx_chip *chip, u8 ins, u8 addr_mode, u32 addr)
|
||||
{
|
||||
int retval;
|
||||
|
||||
rtsx_init_cmd(chip);
|
||||
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_COMMAND, 0xFF, ins);
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_CA_NUMBER, 0xFF,
|
||||
SPI_COMMAND_BIT_8 | SPI_ADDRESS_BIT_24);
|
||||
if (addr_mode) {
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR0, 0xFF, (u8)addr);
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR1, 0xFF,
|
||||
(u8)(addr >> 8));
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR2, 0xFF,
|
||||
(u8)(addr >> 16));
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_TRANSFER0, 0xFF,
|
||||
SPI_TRANSFER0_START | SPI_CA_MODE0);
|
||||
} else {
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_TRANSFER0, 0xFF,
|
||||
SPI_TRANSFER0_START | SPI_C_MODE0);
|
||||
}
|
||||
rtsx_add_cmd(chip, CHECK_REG_CMD, SPI_TRANSFER0, SPI_TRANSFER0_END,
|
||||
SPI_TRANSFER0_END);
|
||||
|
||||
retval = rtsx_send_cmd(chip, 0, 100);
|
||||
if (retval < 0) {
|
||||
rtsx_clear_spi_error(chip);
|
||||
spi_set_err_code(chip, SPI_HW_ERR);
|
||||
return STATUS_FAIL;
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static int spi_init_eeprom(struct rtsx_chip *chip)
|
||||
{
|
||||
int retval;
|
||||
int clk;
|
||||
|
||||
if (chip->asic_code)
|
||||
clk = 30;
|
||||
else
|
||||
clk = CLK_30;
|
||||
|
||||
retval = rtsx_write_register(chip, SPI_CLK_DIVIDER1, 0xFF, 0x00);
|
||||
if (retval)
|
||||
return retval;
|
||||
retval = rtsx_write_register(chip, SPI_CLK_DIVIDER0, 0xFF, 0x27);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
retval = switch_clock(chip, clk);
|
||||
if (retval != STATUS_SUCCESS)
|
||||
return STATUS_FAIL;
|
||||
|
||||
retval = select_card(chip, SPI_CARD);
|
||||
if (retval != STATUS_SUCCESS)
|
||||
return STATUS_FAIL;
|
||||
|
||||
retval = rtsx_write_register(chip, CARD_CLK_EN, SPI_CLK_EN,
|
||||
SPI_CLK_EN);
|
||||
if (retval)
|
||||
return retval;
|
||||
retval = rtsx_write_register(chip, CARD_OE, SPI_OUTPUT_EN,
|
||||
SPI_OUTPUT_EN);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
wait_timeout(10);
|
||||
|
||||
retval = rtsx_write_register(chip, SPI_CONTROL, 0xFF,
|
||||
CS_POLARITY_HIGH | SPI_EEPROM_AUTO);
|
||||
if (retval)
|
||||
return retval;
|
||||
retval = rtsx_write_register(chip, SPI_TCTL, EDO_TIMING_MASK,
|
||||
SAMPLE_DELAY_HALF);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static int spi_eeprom_program_enable(struct rtsx_chip *chip)
|
||||
{
|
||||
int retval;
|
||||
|
||||
rtsx_init_cmd(chip);
|
||||
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_CA_NUMBER, 0xFF, 0x86);
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_COMMAND, 0xFF, 0x13);
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_TRANSFER0, 0xFF,
|
||||
SPI_TRANSFER0_START | SPI_CA_MODE0);
|
||||
rtsx_add_cmd(chip, CHECK_REG_CMD, SPI_TRANSFER0, SPI_TRANSFER0_END,
|
||||
SPI_TRANSFER0_END);
|
||||
|
||||
retval = rtsx_send_cmd(chip, 0, 100);
|
||||
if (retval < 0)
|
||||
return STATUS_FAIL;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
int spi_erase_eeprom_chip(struct rtsx_chip *chip)
|
||||
{
|
||||
int retval;
|
||||
|
||||
retval = spi_init_eeprom(chip);
|
||||
if (retval != STATUS_SUCCESS)
|
||||
return STATUS_FAIL;
|
||||
|
||||
retval = spi_eeprom_program_enable(chip);
|
||||
if (retval != STATUS_SUCCESS)
|
||||
return STATUS_FAIL;
|
||||
|
||||
rtsx_init_cmd(chip);
|
||||
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_GPIO_DIR, 0x01, 0);
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, 0x01, RING_BUFFER);
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_COMMAND, 0xFF, 0x12);
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_CA_NUMBER, 0xFF, 0x84);
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_TRANSFER0, 0xFF,
|
||||
SPI_TRANSFER0_START | SPI_CA_MODE0);
|
||||
rtsx_add_cmd(chip, CHECK_REG_CMD, SPI_TRANSFER0, SPI_TRANSFER0_END,
|
||||
SPI_TRANSFER0_END);
|
||||
|
||||
retval = rtsx_send_cmd(chip, 0, 100);
|
||||
if (retval < 0)
|
||||
return STATUS_FAIL;
|
||||
|
||||
retval = rtsx_write_register(chip, CARD_GPIO_DIR, 0x01, 0x01);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
int spi_erase_eeprom_byte(struct rtsx_chip *chip, u16 addr)
|
||||
{
|
||||
int retval;
|
||||
|
||||
retval = spi_init_eeprom(chip);
|
||||
if (retval != STATUS_SUCCESS)
|
||||
return STATUS_FAIL;
|
||||
|
||||
retval = spi_eeprom_program_enable(chip);
|
||||
if (retval != STATUS_SUCCESS)
|
||||
return STATUS_FAIL;
|
||||
|
||||
rtsx_init_cmd(chip);
|
||||
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_GPIO_DIR, 0x01, 0);
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, 0x01, RING_BUFFER);
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_COMMAND, 0xFF, 0x07);
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR0, 0xFF, (u8)addr);
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR1, 0xFF, (u8)(addr >> 8));
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_CA_NUMBER, 0xFF, 0x46);
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_TRANSFER0, 0xFF,
|
||||
SPI_TRANSFER0_START | SPI_CA_MODE0);
|
||||
rtsx_add_cmd(chip, CHECK_REG_CMD, SPI_TRANSFER0, SPI_TRANSFER0_END,
|
||||
SPI_TRANSFER0_END);
|
||||
|
||||
retval = rtsx_send_cmd(chip, 0, 100);
|
||||
if (retval < 0)
|
||||
return STATUS_FAIL;
|
||||
|
||||
retval = rtsx_write_register(chip, CARD_GPIO_DIR, 0x01, 0x01);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
int spi_read_eeprom(struct rtsx_chip *chip, u16 addr, u8 *val)
|
||||
{
|
||||
int retval;
|
||||
u8 data;
|
||||
|
||||
retval = spi_init_eeprom(chip);
|
||||
if (retval != STATUS_SUCCESS)
|
||||
return STATUS_FAIL;
|
||||
|
||||
rtsx_init_cmd(chip);
|
||||
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_GPIO_DIR, 0x01, 0);
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, 0x01, RING_BUFFER);
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_COMMAND, 0xFF, 0x06);
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR0, 0xFF, (u8)addr);
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR1, 0xFF, (u8)(addr >> 8));
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_CA_NUMBER, 0xFF, 0x46);
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_LENGTH0, 0xFF, 1);
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_TRANSFER0, 0xFF,
|
||||
SPI_TRANSFER0_START | SPI_CADI_MODE0);
|
||||
rtsx_add_cmd(chip, CHECK_REG_CMD, SPI_TRANSFER0, SPI_TRANSFER0_END,
|
||||
SPI_TRANSFER0_END);
|
||||
|
||||
retval = rtsx_send_cmd(chip, 0, 100);
|
||||
if (retval < 0)
|
||||
return STATUS_FAIL;
|
||||
|
||||
wait_timeout(5);
|
||||
retval = rtsx_read_register(chip, SPI_DATA, &data);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
if (val)
|
||||
*val = data;
|
||||
|
||||
retval = rtsx_write_register(chip, CARD_GPIO_DIR, 0x01, 0x01);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
int spi_write_eeprom(struct rtsx_chip *chip, u16 addr, u8 val)
|
||||
{
|
||||
int retval;
|
||||
|
||||
retval = spi_init_eeprom(chip);
|
||||
if (retval != STATUS_SUCCESS)
|
||||
return STATUS_FAIL;
|
||||
|
||||
retval = spi_eeprom_program_enable(chip);
|
||||
if (retval != STATUS_SUCCESS)
|
||||
return STATUS_FAIL;
|
||||
|
||||
rtsx_init_cmd(chip);
|
||||
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_GPIO_DIR, 0x01, 0);
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, 0x01, RING_BUFFER);
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_COMMAND, 0xFF, 0x05);
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR0, 0xFF, val);
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR1, 0xFF, (u8)addr);
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR2, 0xFF, (u8)(addr >> 8));
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_CA_NUMBER, 0xFF, 0x4E);
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_TRANSFER0, 0xFF,
|
||||
SPI_TRANSFER0_START | SPI_CA_MODE0);
|
||||
rtsx_add_cmd(chip, CHECK_REG_CMD, SPI_TRANSFER0, SPI_TRANSFER0_END,
|
||||
SPI_TRANSFER0_END);
|
||||
|
||||
retval = rtsx_send_cmd(chip, 0, 100);
|
||||
if (retval < 0)
|
||||
return STATUS_FAIL;
|
||||
|
||||
retval = rtsx_write_register(chip, CARD_GPIO_DIR, 0x01, 0x01);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
int spi_get_status(struct scsi_cmnd *srb, struct rtsx_chip *chip)
|
||||
{
|
||||
struct spi_info *spi = &chip->spi;
|
||||
|
||||
dev_dbg(rtsx_dev(chip), "%s: err_code = 0x%x\n", __func__,
|
||||
spi->err_code);
|
||||
rtsx_stor_set_xfer_buf(&spi->err_code,
|
||||
min_t(int, scsi_bufflen(srb), 1), srb);
|
||||
scsi_set_resid(srb, scsi_bufflen(srb) - 1);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
int spi_set_parameter(struct scsi_cmnd *srb, struct rtsx_chip *chip)
|
||||
{
|
||||
struct spi_info *spi = &chip->spi;
|
||||
|
||||
spi_set_err_code(chip, SPI_NO_ERR);
|
||||
|
||||
if (chip->asic_code)
|
||||
spi->spi_clock = ((u16)(srb->cmnd[8]) << 8) | srb->cmnd[9];
|
||||
else
|
||||
spi->spi_clock = srb->cmnd[3];
|
||||
|
||||
spi->clk_div = ((u16)(srb->cmnd[4]) << 8) | srb->cmnd[5];
|
||||
spi->write_en = srb->cmnd[6];
|
||||
|
||||
dev_dbg(rtsx_dev(chip), "spi_clock = %d, clk_div = %d, write_en = %d\n",
|
||||
spi->spi_clock, spi->clk_div, spi->write_en);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
int spi_read_flash_id(struct scsi_cmnd *srb, struct rtsx_chip *chip)
|
||||
{
|
||||
int retval;
|
||||
u16 len;
|
||||
u8 *buf;
|
||||
|
||||
spi_set_err_code(chip, SPI_NO_ERR);
|
||||
|
||||
len = ((u16)(srb->cmnd[7]) << 8) | srb->cmnd[8];
|
||||
if (len > 512) {
|
||||
spi_set_err_code(chip, SPI_INVALID_COMMAND);
|
||||
return STATUS_FAIL;
|
||||
}
|
||||
|
||||
retval = spi_set_init_para(chip);
|
||||
if (retval != STATUS_SUCCESS) {
|
||||
spi_set_err_code(chip, SPI_HW_ERR);
|
||||
return STATUS_FAIL;
|
||||
}
|
||||
|
||||
rtsx_init_cmd(chip);
|
||||
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, 0x01,
|
||||
PINGPONG_BUFFER);
|
||||
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_COMMAND, 0xFF, srb->cmnd[3]);
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR2, 0xFF, srb->cmnd[4]);
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR1, 0xFF, srb->cmnd[5]);
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR0, 0xFF, srb->cmnd[6]);
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_CA_NUMBER, 0xFF,
|
||||
SPI_COMMAND_BIT_8 | SPI_ADDRESS_BIT_24);
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_LENGTH1, 0xFF, srb->cmnd[7]);
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_LENGTH0, 0xFF, srb->cmnd[8]);
|
||||
|
||||
if (len == 0) {
|
||||
if (srb->cmnd[9]) {
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_TRANSFER0,
|
||||
0xFF, SPI_TRANSFER0_START | SPI_CA_MODE0);
|
||||
} else {
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_TRANSFER0,
|
||||
0xFF, SPI_TRANSFER0_START | SPI_C_MODE0);
|
||||
}
|
||||
} else {
|
||||
if (srb->cmnd[9]) {
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_TRANSFER0, 0xFF,
|
||||
SPI_TRANSFER0_START | SPI_CADI_MODE0);
|
||||
} else {
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_TRANSFER0, 0xFF,
|
||||
SPI_TRANSFER0_START | SPI_CDI_MODE0);
|
||||
}
|
||||
}
|
||||
|
||||
rtsx_add_cmd(chip, CHECK_REG_CMD, SPI_TRANSFER0, SPI_TRANSFER0_END,
|
||||
SPI_TRANSFER0_END);
|
||||
|
||||
retval = rtsx_send_cmd(chip, 0, 100);
|
||||
if (retval < 0) {
|
||||
rtsx_clear_spi_error(chip);
|
||||
spi_set_err_code(chip, SPI_HW_ERR);
|
||||
return STATUS_FAIL;
|
||||
}
|
||||
|
||||
if (len) {
|
||||
buf = kmalloc(len, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return STATUS_ERROR;
|
||||
|
||||
retval = rtsx_read_ppbuf(chip, buf, len);
|
||||
if (retval != STATUS_SUCCESS) {
|
||||
spi_set_err_code(chip, SPI_READ_ERR);
|
||||
kfree(buf);
|
||||
return STATUS_FAIL;
|
||||
}
|
||||
|
||||
rtsx_stor_set_xfer_buf(buf, scsi_bufflen(srb), srb);
|
||||
scsi_set_resid(srb, 0);
|
||||
|
||||
kfree(buf);
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
int spi_read_flash(struct scsi_cmnd *srb, struct rtsx_chip *chip)
|
||||
{
|
||||
int retval;
|
||||
unsigned int index = 0, offset = 0;
|
||||
u8 ins, slow_read;
|
||||
u32 addr;
|
||||
u16 len;
|
||||
u8 *buf;
|
||||
|
||||
spi_set_err_code(chip, SPI_NO_ERR);
|
||||
|
||||
ins = srb->cmnd[3];
|
||||
addr = ((u32)(srb->cmnd[4]) << 16) | ((u32)(srb->cmnd[5])
|
||||
<< 8) | srb->cmnd[6];
|
||||
len = ((u16)(srb->cmnd[7]) << 8) | srb->cmnd[8];
|
||||
slow_read = srb->cmnd[9];
|
||||
|
||||
retval = spi_set_init_para(chip);
|
||||
if (retval != STATUS_SUCCESS) {
|
||||
spi_set_err_code(chip, SPI_HW_ERR);
|
||||
return STATUS_FAIL;
|
||||
}
|
||||
|
||||
buf = kmalloc(SF_PAGE_LEN, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return STATUS_ERROR;
|
||||
|
||||
while (len) {
|
||||
u16 pagelen = SF_PAGE_LEN - (u8)addr;
|
||||
|
||||
if (pagelen > len)
|
||||
pagelen = len;
|
||||
|
||||
rtsx_init_cmd(chip);
|
||||
|
||||
trans_dma_enable(DMA_FROM_DEVICE, chip, 256, DMA_256);
|
||||
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_COMMAND, 0xFF, ins);
|
||||
|
||||
if (slow_read) {
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR0, 0xFF,
|
||||
(u8)addr);
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR1, 0xFF,
|
||||
(u8)(addr >> 8));
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR2, 0xFF,
|
||||
(u8)(addr >> 16));
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_CA_NUMBER, 0xFF,
|
||||
SPI_COMMAND_BIT_8 | SPI_ADDRESS_BIT_24);
|
||||
} else {
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR1, 0xFF,
|
||||
(u8)addr);
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR2, 0xFF,
|
||||
(u8)(addr >> 8));
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR3, 0xFF,
|
||||
(u8)(addr >> 16));
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_CA_NUMBER, 0xFF,
|
||||
SPI_COMMAND_BIT_8 | SPI_ADDRESS_BIT_32);
|
||||
}
|
||||
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_LENGTH1, 0xFF,
|
||||
(u8)(pagelen >> 8));
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_LENGTH0, 0xFF,
|
||||
(u8)pagelen);
|
||||
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_TRANSFER0, 0xFF,
|
||||
SPI_TRANSFER0_START | SPI_CADI_MODE0);
|
||||
rtsx_add_cmd(chip, CHECK_REG_CMD, SPI_TRANSFER0,
|
||||
SPI_TRANSFER0_END, SPI_TRANSFER0_END);
|
||||
|
||||
rtsx_send_cmd_no_wait(chip);
|
||||
|
||||
retval = rtsx_transfer_data(chip, 0, buf, pagelen, 0,
|
||||
DMA_FROM_DEVICE, 10000);
|
||||
if (retval < 0) {
|
||||
kfree(buf);
|
||||
rtsx_clear_spi_error(chip);
|
||||
spi_set_err_code(chip, SPI_HW_ERR);
|
||||
return STATUS_FAIL;
|
||||
}
|
||||
|
||||
rtsx_stor_access_xfer_buf(buf, pagelen, srb, &index, &offset,
|
||||
TO_XFER_BUF);
|
||||
|
||||
addr += pagelen;
|
||||
len -= pagelen;
|
||||
}
|
||||
|
||||
scsi_set_resid(srb, 0);
|
||||
kfree(buf);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
int spi_write_flash(struct scsi_cmnd *srb, struct rtsx_chip *chip)
|
||||
{
|
||||
int retval;
|
||||
u8 ins, program_mode;
|
||||
u32 addr;
|
||||
u16 len;
|
||||
u8 *buf;
|
||||
unsigned int index = 0, offset = 0;
|
||||
|
||||
spi_set_err_code(chip, SPI_NO_ERR);
|
||||
|
||||
ins = srb->cmnd[3];
|
||||
addr = ((u32)(srb->cmnd[4]) << 16) | ((u32)(srb->cmnd[5])
|
||||
<< 8) | srb->cmnd[6];
|
||||
len = ((u16)(srb->cmnd[7]) << 8) | srb->cmnd[8];
|
||||
program_mode = srb->cmnd[9];
|
||||
|
||||
retval = spi_set_init_para(chip);
|
||||
if (retval != STATUS_SUCCESS) {
|
||||
spi_set_err_code(chip, SPI_HW_ERR);
|
||||
return STATUS_FAIL;
|
||||
}
|
||||
|
||||
if (program_mode == BYTE_PROGRAM) {
|
||||
buf = kmalloc(4, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return STATUS_ERROR;
|
||||
|
||||
while (len) {
|
||||
retval = sf_enable_write(chip, SPI_WREN);
|
||||
if (retval != STATUS_SUCCESS) {
|
||||
kfree(buf);
|
||||
return STATUS_FAIL;
|
||||
}
|
||||
|
||||
rtsx_stor_access_xfer_buf(buf, 1, srb, &index, &offset,
|
||||
FROM_XFER_BUF);
|
||||
|
||||
rtsx_init_cmd(chip);
|
||||
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE,
|
||||
0x01, PINGPONG_BUFFER);
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, PPBUF_BASE2, 0xFF,
|
||||
buf[0]);
|
||||
sf_program(chip, ins, 1, addr, 1);
|
||||
|
||||
retval = rtsx_send_cmd(chip, 0, 100);
|
||||
if (retval < 0) {
|
||||
kfree(buf);
|
||||
rtsx_clear_spi_error(chip);
|
||||
spi_set_err_code(chip, SPI_HW_ERR);
|
||||
return STATUS_FAIL;
|
||||
}
|
||||
|
||||
retval = sf_polling_status(chip, 100);
|
||||
if (retval != STATUS_SUCCESS) {
|
||||
kfree(buf);
|
||||
return STATUS_FAIL;
|
||||
}
|
||||
|
||||
addr++;
|
||||
len--;
|
||||
}
|
||||
|
||||
kfree(buf);
|
||||
|
||||
} else if (program_mode == AAI_PROGRAM) {
|
||||
int first_byte = 1;
|
||||
|
||||
retval = sf_enable_write(chip, SPI_WREN);
|
||||
if (retval != STATUS_SUCCESS)
|
||||
return STATUS_FAIL;
|
||||
|
||||
buf = kmalloc(4, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return STATUS_ERROR;
|
||||
|
||||
while (len) {
|
||||
rtsx_stor_access_xfer_buf(buf, 1, srb, &index, &offset,
|
||||
FROM_XFER_BUF);
|
||||
|
||||
rtsx_init_cmd(chip);
|
||||
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE,
|
||||
0x01, PINGPONG_BUFFER);
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, PPBUF_BASE2, 0xFF,
|
||||
buf[0]);
|
||||
if (first_byte) {
|
||||
sf_program(chip, ins, 1, addr, 1);
|
||||
first_byte = 0;
|
||||
} else {
|
||||
sf_program(chip, ins, 0, 0, 1);
|
||||
}
|
||||
|
||||
retval = rtsx_send_cmd(chip, 0, 100);
|
||||
if (retval < 0) {
|
||||
kfree(buf);
|
||||
rtsx_clear_spi_error(chip);
|
||||
spi_set_err_code(chip, SPI_HW_ERR);
|
||||
return STATUS_FAIL;
|
||||
}
|
||||
|
||||
retval = sf_polling_status(chip, 100);
|
||||
if (retval != STATUS_SUCCESS) {
|
||||
kfree(buf);
|
||||
return STATUS_FAIL;
|
||||
}
|
||||
|
||||
len--;
|
||||
}
|
||||
|
||||
kfree(buf);
|
||||
|
||||
retval = sf_disable_write(chip, SPI_WRDI);
|
||||
if (retval != STATUS_SUCCESS)
|
||||
return STATUS_FAIL;
|
||||
|
||||
retval = sf_polling_status(chip, 100);
|
||||
if (retval != STATUS_SUCCESS)
|
||||
return STATUS_FAIL;
|
||||
} else if (program_mode == PAGE_PROGRAM) {
|
||||
buf = kmalloc(SF_PAGE_LEN, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return STATUS_NOMEM;
|
||||
|
||||
while (len) {
|
||||
u16 pagelen = SF_PAGE_LEN - (u8)addr;
|
||||
|
||||
if (pagelen > len)
|
||||
pagelen = len;
|
||||
|
||||
retval = sf_enable_write(chip, SPI_WREN);
|
||||
if (retval != STATUS_SUCCESS) {
|
||||
kfree(buf);
|
||||
return STATUS_FAIL;
|
||||
}
|
||||
|
||||
rtsx_init_cmd(chip);
|
||||
|
||||
trans_dma_enable(DMA_TO_DEVICE, chip, 256, DMA_256);
|
||||
sf_program(chip, ins, 1, addr, pagelen);
|
||||
|
||||
rtsx_send_cmd_no_wait(chip);
|
||||
|
||||
rtsx_stor_access_xfer_buf(buf, pagelen, srb, &index,
|
||||
&offset, FROM_XFER_BUF);
|
||||
|
||||
retval = rtsx_transfer_data(chip, 0, buf, pagelen, 0,
|
||||
DMA_TO_DEVICE, 100);
|
||||
if (retval < 0) {
|
||||
kfree(buf);
|
||||
rtsx_clear_spi_error(chip);
|
||||
spi_set_err_code(chip, SPI_HW_ERR);
|
||||
return STATUS_FAIL;
|
||||
}
|
||||
|
||||
retval = sf_polling_status(chip, 100);
|
||||
if (retval != STATUS_SUCCESS) {
|
||||
kfree(buf);
|
||||
return STATUS_FAIL;
|
||||
}
|
||||
|
||||
addr += pagelen;
|
||||
len -= pagelen;
|
||||
}
|
||||
|
||||
kfree(buf);
|
||||
} else {
|
||||
spi_set_err_code(chip, SPI_INVALID_COMMAND);
|
||||
return STATUS_FAIL;
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
int spi_erase_flash(struct scsi_cmnd *srb, struct rtsx_chip *chip)
|
||||
{
|
||||
int retval;
|
||||
u8 ins, erase_mode;
|
||||
u32 addr;
|
||||
|
||||
spi_set_err_code(chip, SPI_NO_ERR);
|
||||
|
||||
ins = srb->cmnd[3];
|
||||
addr = ((u32)(srb->cmnd[4]) << 16) | ((u32)(srb->cmnd[5])
|
||||
<< 8) | srb->cmnd[6];
|
||||
erase_mode = srb->cmnd[9];
|
||||
|
||||
retval = spi_set_init_para(chip);
|
||||
if (retval != STATUS_SUCCESS) {
|
||||
spi_set_err_code(chip, SPI_HW_ERR);
|
||||
return STATUS_FAIL;
|
||||
}
|
||||
|
||||
if (erase_mode == PAGE_ERASE) {
|
||||
retval = sf_enable_write(chip, SPI_WREN);
|
||||
if (retval != STATUS_SUCCESS)
|
||||
return STATUS_FAIL;
|
||||
|
||||
retval = sf_erase(chip, ins, 1, addr);
|
||||
if (retval != STATUS_SUCCESS)
|
||||
return STATUS_FAIL;
|
||||
} else if (erase_mode == CHIP_ERASE) {
|
||||
retval = sf_enable_write(chip, SPI_WREN);
|
||||
if (retval != STATUS_SUCCESS)
|
||||
return STATUS_FAIL;
|
||||
|
||||
retval = sf_erase(chip, ins, 0, 0);
|
||||
if (retval != STATUS_SUCCESS)
|
||||
return STATUS_FAIL;
|
||||
} else {
|
||||
spi_set_err_code(chip, SPI_INVALID_COMMAND);
|
||||
return STATUS_FAIL;
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
int spi_write_flash_status(struct scsi_cmnd *srb, struct rtsx_chip *chip)
|
||||
{
|
||||
int retval;
|
||||
u8 ins, status, ewsr;
|
||||
|
||||
ins = srb->cmnd[3];
|
||||
status = srb->cmnd[4];
|
||||
ewsr = srb->cmnd[5];
|
||||
|
||||
retval = spi_set_init_para(chip);
|
||||
if (retval != STATUS_SUCCESS) {
|
||||
spi_set_err_code(chip, SPI_HW_ERR);
|
||||
return STATUS_FAIL;
|
||||
}
|
||||
|
||||
retval = sf_enable_write(chip, ewsr);
|
||||
if (retval != STATUS_SUCCESS)
|
||||
return STATUS_FAIL;
|
||||
|
||||
rtsx_init_cmd(chip);
|
||||
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, 0x01,
|
||||
PINGPONG_BUFFER);
|
||||
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_COMMAND, 0xFF, ins);
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_CA_NUMBER, 0xFF,
|
||||
SPI_COMMAND_BIT_8 | SPI_ADDRESS_BIT_24);
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_LENGTH1, 0xFF, 0);
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_LENGTH0, 0xFF, 1);
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, PPBUF_BASE2, 0xFF, status);
|
||||
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_TRANSFER0, 0xFF,
|
||||
SPI_TRANSFER0_START | SPI_CDO_MODE0);
|
||||
rtsx_add_cmd(chip, CHECK_REG_CMD, SPI_TRANSFER0, SPI_TRANSFER0_END,
|
||||
SPI_TRANSFER0_END);
|
||||
|
||||
retval = rtsx_send_cmd(chip, 0, 100);
|
||||
if (retval != STATUS_SUCCESS) {
|
||||
rtsx_clear_spi_error(chip);
|
||||
spi_set_err_code(chip, SPI_HW_ERR);
|
||||
return STATUS_FAIL;
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
|
@ -1,52 +0,0 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Driver for Realtek PCI-Express card reader
|
||||
*
|
||||
* Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
|
||||
*
|
||||
* Author:
|
||||
* Wei WANG (wei_wang@realsil.com.cn)
|
||||
* Micky Ching (micky_ching@realsil.com.cn)
|
||||
*/
|
||||
|
||||
#ifndef __REALTEK_RTSX_SPI_H
|
||||
#define __REALTEK_RTSX_SPI_H
|
||||
|
||||
/* SPI operation error */
|
||||
#define SPI_NO_ERR 0x00
|
||||
#define SPI_HW_ERR 0x01
|
||||
#define SPI_INVALID_COMMAND 0x02
|
||||
#define SPI_READ_ERR 0x03
|
||||
#define SPI_WRITE_ERR 0x04
|
||||
#define SPI_ERASE_ERR 0x05
|
||||
#define SPI_BUSY_ERR 0x06
|
||||
|
||||
/* Serial flash instruction */
|
||||
#define SPI_READ 0x03
|
||||
#define SPI_FAST_READ 0x0B
|
||||
#define SPI_WREN 0x06
|
||||
#define SPI_WRDI 0x04
|
||||
#define SPI_RDSR 0x05
|
||||
|
||||
#define SF_PAGE_LEN 256
|
||||
|
||||
#define BYTE_PROGRAM 0
|
||||
#define AAI_PROGRAM 1
|
||||
#define PAGE_PROGRAM 2
|
||||
|
||||
#define PAGE_ERASE 0
|
||||
#define CHIP_ERASE 1
|
||||
|
||||
int spi_erase_eeprom_chip(struct rtsx_chip *chip);
|
||||
int spi_erase_eeprom_byte(struct rtsx_chip *chip, u16 addr);
|
||||
int spi_read_eeprom(struct rtsx_chip *chip, u16 addr, u8 *val);
|
||||
int spi_write_eeprom(struct rtsx_chip *chip, u16 addr, u8 val);
|
||||
int spi_get_status(struct scsi_cmnd *srb, struct rtsx_chip *chip);
|
||||
int spi_set_parameter(struct scsi_cmnd *srb, struct rtsx_chip *chip);
|
||||
int spi_read_flash_id(struct scsi_cmnd *srb, struct rtsx_chip *chip);
|
||||
int spi_read_flash(struct scsi_cmnd *srb, struct rtsx_chip *chip);
|
||||
int spi_write_flash(struct scsi_cmnd *srb, struct rtsx_chip *chip);
|
||||
int spi_erase_flash(struct scsi_cmnd *srb, struct rtsx_chip *chip);
|
||||
int spi_write_flash_status(struct scsi_cmnd *srb, struct rtsx_chip *chip);
|
||||
|
||||
#endif /* __REALTEK_RTSX_SPI_H */
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,176 +0,0 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Driver for Realtek PCI-Express card reader
|
||||
*
|
||||
* Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
|
||||
*
|
||||
* Author:
|
||||
* Wei WANG (wei_wang@realsil.com.cn)
|
||||
* Micky Ching (micky_ching@realsil.com.cn)
|
||||
*/
|
||||
|
||||
#ifndef __REALTEK_RTSX_XD_H
|
||||
#define __REALTEK_RTSX_XD_H
|
||||
|
||||
#define XD_DELAY_WRITE
|
||||
|
||||
/* Error Codes */
|
||||
#define XD_NO_ERROR 0x00
|
||||
#define XD_NO_MEMORY 0x80
|
||||
#define XD_PRG_ERROR 0x40
|
||||
#define XD_NO_CARD 0x20
|
||||
#define XD_READ_FAIL 0x10
|
||||
#define XD_ERASE_FAIL 0x08
|
||||
#define XD_WRITE_FAIL 0x04
|
||||
#define XD_ECC_ERROR 0x02
|
||||
#define XD_TO_ERROR 0x01
|
||||
|
||||
/* XD Commands */
|
||||
#define READ1_1 0x00
|
||||
#define READ1_2 0x01
|
||||
#define READ2 0x50
|
||||
#define READ_ID 0x90
|
||||
#define RESET 0xff
|
||||
#define PAGE_PRG_1 0x80
|
||||
#define PAGE_PRG_2 0x10
|
||||
#define BLK_ERASE_1 0x60
|
||||
#define BLK_ERASE_2 0xD0
|
||||
#define READ_STS 0x70
|
||||
#define READ_XD_ID 0x9A
|
||||
#define COPY_BACK_512 0x8A
|
||||
#define COPY_BACK_2K 0x85
|
||||
#define READ1_1_2 0x30
|
||||
#define READ1_1_3 0x35
|
||||
#define CHG_DAT_OUT_1 0x05
|
||||
#define RDM_DAT_OUT_1 0x05
|
||||
#define CHG_DAT_OUT_2 0xE0
|
||||
#define RDM_DAT_OUT_2 0xE0
|
||||
#define CHG_DAT_OUT_2 0xE0
|
||||
#define CHG_DAT_IN_1 0x85
|
||||
#define CACHE_PRG 0x15
|
||||
|
||||
/* Redundant Area Related */
|
||||
#define XD_EXTRA_SIZE 0x10
|
||||
#define XD_2K_EXTRA_SIZE 0x40
|
||||
|
||||
#define NOT_WRITE_PROTECTED 0x80
|
||||
#define READY_STATE 0x40
|
||||
#define PROGRAM_ERROR 0x01
|
||||
#define PROGRAM_ERROR_N_1 0x02
|
||||
#define INTERNAL_READY 0x20
|
||||
#define READY_FLAG 0x5F
|
||||
|
||||
#define XD_8M_X8_512 0xE6
|
||||
#define XD_16M_X8_512 0x73
|
||||
#define XD_32M_X8_512 0x75
|
||||
#define XD_64M_X8_512 0x76
|
||||
#define XD_128M_X8_512 0x79
|
||||
#define XD_256M_X8_512 0x71
|
||||
#define XD_128M_X8_2048 0xF1
|
||||
#define XD_256M_X8_2048 0xDA
|
||||
#define XD_512M_X8 0xDC
|
||||
#define XD_128M_X16_2048 0xC1
|
||||
#define XD_4M_X8_512_1 0xE3
|
||||
#define XD_4M_X8_512_2 0xE5
|
||||
#define XD_1G_X8_512 0xD3
|
||||
#define XD_2G_X8_512 0xD5
|
||||
|
||||
#define XD_ID_CODE 0xB5
|
||||
|
||||
#define VENDOR_BLOCK 0xEFFF
|
||||
#define CIS_BLOCK 0xDFFF
|
||||
|
||||
#define BLK_NOT_FOUND 0xFFFFFFFF
|
||||
|
||||
#define NO_NEW_BLK 0xFFFFFFFF
|
||||
|
||||
#define PAGE_CORRECTABLE 0x0
|
||||
#define PAGE_NOTCORRECTABLE 0x1
|
||||
|
||||
#define NO_OFFSET 0x0
|
||||
#define WITH_OFFSET 0x1
|
||||
|
||||
#define SECT_PER_PAGE 4
|
||||
#define XD_ADDR_MODE_2C XD_ADDR_MODE_2A
|
||||
|
||||
#define ZONE0_BAD_BLOCK 23
|
||||
#define NOT_ZONE0_BAD_BLOCK 24
|
||||
|
||||
#define XD_RW_ADDR 0x01
|
||||
#define XD_ERASE_ADDR 0x02
|
||||
|
||||
#define XD_PAGE_512(xd_card) \
|
||||
do { \
|
||||
(xd_card)->block_shift = 5; \
|
||||
(xd_card)->page_off = 0x1F; \
|
||||
} while (0)
|
||||
|
||||
#define XD_SET_BAD_NEWBLK(xd_card) ((xd_card)->multi_flag |= 0x01)
|
||||
#define XD_CLR_BAD_NEWBLK(xd_card) ((xd_card)->multi_flag &= ~0x01)
|
||||
#define XD_CHK_BAD_NEWBLK(xd_card) ((xd_card)->multi_flag & 0x01)
|
||||
|
||||
#define XD_SET_BAD_OLDBLK(xd_card) ((xd_card)->multi_flag |= 0x02)
|
||||
#define XD_CLR_BAD_OLDBLK(xd_card) ((xd_card)->multi_flag &= ~0x02)
|
||||
#define XD_CHK_BAD_OLDBLK(xd_card) ((xd_card)->multi_flag & 0x02)
|
||||
|
||||
#define XD_SET_MBR_FAIL(xd_card) ((xd_card)->multi_flag |= 0x04)
|
||||
#define XD_CLR_MBR_FAIL(xd_card) ((xd_card)->multi_flag &= ~0x04)
|
||||
#define XD_CHK_MBR_FAIL(xd_card) ((xd_card)->multi_flag & 0x04)
|
||||
|
||||
#define XD_SET_ECC_FLD_ERR(xd_card) ((xd_card)->multi_flag |= 0x08)
|
||||
#define XD_CLR_ECC_FLD_ERR(xd_card) ((xd_card)->multi_flag &= ~0x08)
|
||||
#define XD_CHK_ECC_FLD_ERR(xd_card) ((xd_card)->multi_flag & 0x08)
|
||||
|
||||
#define XD_SET_4MB(xd_card) ((xd_card)->multi_flag |= 0x10)
|
||||
#define XD_CLR_4MB(xd_card) ((xd_card)->multi_flag &= ~0x10)
|
||||
#define XD_CHK_4MB(xd_card) ((xd_card)->multi_flag & 0x10)
|
||||
|
||||
#define XD_SET_ECC_ERR(xd_card) ((xd_card)->multi_flag |= 0x40)
|
||||
#define XD_CLR_ECC_ERR(xd_card) ((xd_card)->multi_flag &= ~0x40)
|
||||
#define XD_CHK_ECC_ERR(xd_card) ((xd_card)->multi_flag & 0x40)
|
||||
|
||||
#define PAGE_STATUS 0
|
||||
#define BLOCK_STATUS 1
|
||||
#define BLOCK_ADDR1_L 2
|
||||
#define BLOCK_ADDR1_H 3
|
||||
#define BLOCK_ADDR2_L 4
|
||||
#define BLOCK_ADDR2_H 5
|
||||
#define RESERVED0 6
|
||||
#define RESERVED1 7
|
||||
#define RESERVED2 8
|
||||
#define RESERVED3 9
|
||||
#define PARITY 10
|
||||
|
||||
#define CIS0_0 0
|
||||
#define CIS0_1 1
|
||||
#define CIS0_2 2
|
||||
#define CIS0_3 3
|
||||
#define CIS0_4 4
|
||||
#define CIS0_5 5
|
||||
#define CIS0_6 6
|
||||
#define CIS0_7 7
|
||||
#define CIS0_8 8
|
||||
#define CIS0_9 9
|
||||
#define CIS1_0 256
|
||||
#define CIS1_1 (256 + 1)
|
||||
#define CIS1_2 (256 + 2)
|
||||
#define CIS1_3 (256 + 3)
|
||||
#define CIS1_4 (256 + 4)
|
||||
#define CIS1_5 (256 + 5)
|
||||
#define CIS1_6 (256 + 6)
|
||||
#define CIS1_7 (256 + 7)
|
||||
#define CIS1_8 (256 + 8)
|
||||
#define CIS1_9 (256 + 9)
|
||||
|
||||
int reset_xd_card(struct rtsx_chip *chip);
|
||||
#ifdef XD_DELAY_WRITE
|
||||
int xd_delay_write(struct rtsx_chip *chip);
|
||||
#endif
|
||||
int xd_rw(struct scsi_cmnd *srb, struct rtsx_chip *chip,
|
||||
u32 start_sector, u16 sector_cnt);
|
||||
void xd_free_l2p_tbl(struct rtsx_chip *chip);
|
||||
void xd_cleanup_work(struct rtsx_chip *chip);
|
||||
int xd_power_off_card3v3(struct rtsx_chip *chip);
|
||||
int release_xd_card(struct rtsx_chip *chip);
|
||||
|
||||
#endif /* __REALTEK_RTSX_XD_H */
|
||||
Loading…
Reference in New Issue
Block a user