/* Driver for Realtek PCI-Express card reader
*
* Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, see <http://www.gnu.org/licenses/>.
*
* Author:
* wwang (wei_wang@realsil.com.cn)
* No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
*/
#include <linux/blkdev.h>
#include <linux/kthread.h>
#include <linux/sched.h>
#include <linux/workqueue.h>
#include <linux/vmalloc.h>
#include "rtsx.h"
#include "rtsx_transport.h"
#include "rtsx_scsi.h"
#include "rtsx_card.h"
#include "rtsx_chip.h"
#include "rtsx_sys.h"
#include "general.h"
#include "sd.h"
#include "xd.h"
#include "ms.h"
static void rtsx_calibration(struct rtsx_chip *chip)
{
rtsx_write_phy_register(chip, 0x1B, 0x135E);
wait_timeout(10);
rtsx_write_phy_register(chip, 0x00, 0x0280);
rtsx_write_phy_register(chip, 0x01, 0x7112);
rtsx_write_phy_register(chip, 0x01, 0x7110);
rtsx_write_phy_register(chip, 0x01, 0x7112);
rtsx_write_phy_register(chip, 0x01, 0x7113);
rtsx_write_phy_register(chip, 0x00, 0x0288);
}
void rtsx_disable_card_int(struct rtsx_chip *chip)
{
u32 reg = rtsx_readl(chip, RTSX_BIER);
reg &= ~(XD_INT_EN | SD_INT_EN | MS_INT_EN);
rtsx_writel(chip, RTSX_BIER, reg);
}
void rtsx_enable_card_int(struct rtsx_chip *chip)
{
u32 reg = rtsx_readl(chip, RTSX_BIER);
int i;
for (i = 0; i <= chip->max_lun; i++) {
if (chip->lun2card[i] & XD_CARD)
reg |= XD_INT_EN;
if (chip->lun2card[i] & SD_CARD)
reg |= SD_INT_EN;
if (chip->lun2card[i] & MS_CARD)
reg |= MS_INT_EN;
}
if (chip->hw_bypass_sd)
reg &= ~((u32)SD_INT_EN);
rtsx_writel(chip, RTSX_BIER, reg);
}
void rtsx_enable_bus_int(struct rtsx_chip *chip)
{
u32 reg = 0;
#ifndef DISABLE_CARD_INT
int i;
#endif
reg = TRANS_OK_INT_EN | TRANS_FAIL_INT_EN;
#ifndef DISABLE_CARD_INT
for (i = 0; i <= chip->max_lun; i++) {
RTSX_DEBUGP("lun2card[%d] = 0x%02x\n", i, chip->lun2card[i]);
if (chip->lun2card[i] & XD_CARD)
reg |= XD_INT_EN;
if (chip->lun2card[i] & SD_CARD)
reg |= SD_INT_EN;
if (chip->lun2card[i] & MS_CARD)
reg |= MS_INT_EN;
}
if (chip->hw_bypass_sd)
reg &= ~((u32)SD_INT_EN);
#endif
if (chip->ic_version >= IC_VER_C)
reg |= DELINK_INT_EN;
#ifdef SUPPORT_OCP
if (CHECK_PID(chip, 0x5209)) {
if (CHECK_LUN_MODE(chip, SD_MS_2LUN))
reg |= MS_OC_INT_EN | SD_OC_INT_EN;
else
reg |= SD_OC_INT_EN;
} else {
reg |= OC_INT_EN;
}
#endif
if (!chip->adma_mode)
reg |= DATA_DONE_INT_EN;
/* Enable Bus Interrupt */
rtsx_writel(chip, RTSX_BIER, reg);
RTSX_DEBUGP("RTSX_BIER: 0x%08x\n", reg);
}
void rtsx_disable_bus_int(struct rtsx_chip *chip)
{
rtsx_writel(chip, RTSX_BIER, 0);
}
static int rtsx_pre_handle_sdio_old(struct rtsx_chip *chip)
{
if (chip->ignore_sd && CHK_SDIO_EXIST(chip)) {
if (chip->asic_code) {
RTSX_WRITE_REG(chip, CARD_PULL_CTL5, 0xFF,
MS_INS_PU | SD_WP_PU | SD_CD_PU | SD_CMD_PU);
} else {
RTSX_WRITE_REG(chip, FPGA_PULL_CTL, 0xFF, FPGA_SD_PULL_CTL_EN);
}
RTSX_WRITE_REG(chip, CARD_SHARE_MODE, 0xFF, CARD_SHARE_48_SD);
/* Enable SDIO internal clock */
RTSX_WRITE_REG(chip, 0xFF2C, 0x01, 0x01);
RTSX_WRITE_REG(chip, SDIO_CTRL, 0xFF, SDIO_BUS_CTRL | SDIO_CD_CTRL);
chip->sd_int = 1;
chip->sd_io = 1;
} else {
chip->need_reset |= SD_CARD;
}
return STATUS_SUCCESS;
}
#ifdef HW_AUTO_SWITCH_SD_BUS
static int rtsx_pre_handle_sdio_new(struct rtsx_chip *chip)
{
u8 tmp;
int sw_bypass_sd = 0;
int retval;
if (chip->driver_first_load) {
if (CHECK_PID(chip, 0x5288)) {
RTSX_READ_REG(chip, 0xFE5A, &tmp);
if (tmp & 0x08)
sw_bypass_sd = 1;
} else if (CHECK_PID(chip, 0x5208)) {
RTSX_READ_REG(chip, 0xFE70, &tmp);
if (tmp & 0x80)
sw_bypass_sd = 1;
} else if (CHECK_PID(chip, 0x5209)) {
RTSX_READ_REG(chip, SDIO_CFG, &tmp);
if (tmp & SDIO_BUS_AUTO_SWITCH)
sw_bypass_sd = 1;
}
} else {
if (chip->sdio_in_charge)
sw_bypass_sd = 1;
}
RTSX_DEBUGP("chip->sdio_in_charge = %d\n", chip->sdio_in_charge);
RTSX_DEBUGP("chip->driver_first_load = %d\n", chip->driver_first_load);
RTSX_DEBUGP("sw_bypass_sd = %d\n", sw_bypass_sd);
if (sw_bypass_sd) {
u8 cd_toggle_mask = 0;
RTSX_READ_REG(chip, TLPTISTAT, &tmp);
if (CHECK_PID(chip, 0x5209))
cd_toggle_mask = 0x10;
else
cd_toggle_mask = 0x08;
if (tmp & cd_toggle_mask) {
/* Disable sdio_bus_auto_switch */
if (CHECK_PID(chip, 0x5288))
RTSX_WRITE_REG(chip, 0xFE5A, 0x08, 0x00);
else if (CHECK_PID(chip, 0x5208))
RTSX_WRITE_REG(chip, 0xFE70, 0x80, 0x00);
else
RTSX_WRITE_REG(chip, SDIO_CFG, SDIO_BUS_AUTO_SWITCH, 0);
RTSX_WRITE_REG(chip, TLPTISTAT, 0xFF, tmp);
chip->need_reset |= SD_CARD;
} else {
RTSX_DEBUGP("Chip inserted with SDIO!\n");
if (chip->asic_code) {
retval = sd_pull_ctl_enable(chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
} else {
RTSX_WRITE_REG(chip, FPGA_PULL_CTL, FPGA_SD_PULL_CTL_BIT | 0x20, 0);
}
retval = card_share_mode(chip, SD_CARD);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
/* Enable sdio_bus_auto_switch */
if (CHECK_PID(chip, 0x5288)) {
RTSX_WRITE_REG(chip, 0xFE5A, 0x08, 0x08);
} else if (CHECK_PID(chip, 0x5208)) {
RTSX_WRITE_REG(chip, 0xFE70, 0x80, 0x80);
} else {
RTSX_WRITE_REG(chip, SDIO_CFG,
SDIO_BUS_AUTO_SWITCH, SDIO_BUS_AUTO_SWITCH);
}
chip->chip_insert_with_sdio = 1;
chip->sd_io = 1;
}
} else {
if (CHECK_PID(chip, 0x5209))
RTSX_WRITE_REG(chip, TLPTISTAT, 0x10, 0x10);
else
RTSX_WRITE_REG(chip, TLPTISTAT, 0x08, 0x08);
chip->need_reset |= SD_CARD;
}
return STATUS_SUCCESS;
}
#endif
int rtsx_reset_chip(struct rtsx_chip *chip)
{
int retval;
rtsx_writel(chip, RTSX_HCBAR, chip->host_cmds_addr);
rtsx_disable_aspm(chip);
if (CHECK_PID(chip, 0x5209) && chip->asic_code) {
u16 val;
/* optimize PHY */
retval = rtsx_write_phy_register(chip, 0x00, 0xB966);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
retval = rtsx_write_phy_register(chip, 0x01, 0x713F);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
retval = rtsx_write_phy_register(chip, 0x03, 0xA549);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
retval = rtsx_write_phy_register(chip, 0x06, 0xB235);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
retval = rtsx_write_phy_register(chip, 0x07, 0xEF40);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
retval = rtsx_write_phy_register(chip, 0x1E, 0xF8EB);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
retval = rtsx_write_phy_register(chip, 0x19, 0xFE6C);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
wait_timeout(1);
retval = rtsx_write_phy_register(chip, 0x0A, 0x05C0);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
retval = rtsx_write_cfg_dw(chip, 1, 0x110, 0xFFFF, 0xFFFF);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
retval = rtsx_read_phy_register(chip, 0x08, &val);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
RTSX_DEBUGP("Read from phy 0x08: 0x%04x\n", val);
if (chip->phy_voltage) {
chip->phy_voltage &= 0x3F;
RTSX_DEBUGP("chip->phy_voltage = 0x%x\n", chip->phy_voltage);
val &= ~0x3F;
val |= chip->phy_voltage;
RTSX_DEBUGP("Write to phy 0x08: 0x%04x\n", val);
retval = rtsx_write_phy_register(chip, 0x08, val);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
} else {
chip->phy_voltage = (u8)(val & 0x3F);
RTSX_DEBUGP("Default, chip->phy_voltage = 0x%x\n", chip->phy_voltage);
}
}
RTSX_WRITE_REG(chip, HOST_SLEEP_STATE, 0x03, 0x00);
/* Disable card clock */
RTSX_WRITE_REG(chip, CARD_CLK_EN, 0x1E, 0);
#ifdef SUPPORT_OCP
/* SSC power on, OCD power on */
if (CHECK_LUN_MODE(chip, SD_MS_2LUN))
RTSX_WRITE_REG(chip, FPDCTL, OC_POWER_DOWN, 0);
else
RTSX_WRITE_REG(chip, FPDCTL, OC_POWER_DOWN, MS_OC_POWER_DOWN);
if (CHECK_PID(chip, 0x5209)) {
RTSX_WRITE_REG(chip, OCPPARA1, SD_OCP_TIME_MASK | MS_OCP_TIME_MASK,
SD_OCP_TIME_800 | MS_OCP_TIME_800);
RTSX_WRITE_REG(chip, OCPPARA2, SD_OCP_THD_MASK | MS_OCP_THD_MASK,
chip->sd_400mA_ocp_thd | (chip->ms_ocp_thd << 4));
if (CHECK_LUN_MODE(chip, SD_MS_2LUN)) {
RTSX_WRITE_REG(chip, OCPGLITCH, SD_OCP_GLITCH_MASK | MS_OCP_GLITCH_MASK,
SD_OCP_GLITCH_10000 | MS_OCP_GLITCH_10000);
} else {
RTSX_WRITE_REG(chip, OCPGLITCH, SD_OCP_GLITCH_MASK, SD_OCP_GLITCH_10000);
}
RTSX_WRITE_REG(chip, OCPCTL, 0xFF,
SD_OCP_INT_EN | SD_DETECT_EN | MS_OCP_INT_EN | MS_DETECT_EN);
} else {
RTSX_WRITE_REG(chip, OCPPARA1, OCP_TIME_MASK, OCP_TIME_800);
RTSX_WRITE_REG(chip, OCPPARA2, OCP_THD_MASK, OCP_THD_244_946);
RTSX_WRITE_REG(chip, OCPCTL, 0xFF, CARD_OC_INT_EN | CARD_DETECT_EN);
}
#else
/* OC power down */
RTSX_WRITE_REG(chip, FPDCTL, OC_POWER_DOWN, OC_POWER_DOWN);
#endif
if (!CHECK_PID(chip, 0x5288))
RTSX_WRITE_REG(chip, CARD_GPIO_DIR, 0xFF, 0x03);
/* Turn off LED */
RTSX_WRITE_REG(chip, CARD_GPIO, 0xFF, 0x03);
/* Reset delink mode */
RTSX_WRITE_REG(chip, CHANGE_LINK_STATE, 0x0A, 0);
/* Card driving select */
RTSX_WRITE_REG(chip, CARD_DRIVE_SEL, 0xFF, chip->card_drive_sel);
if (CHECK_PID(chip, 0x5209))
RTSX_WRITE_REG(chip, SD30_DRIVE_SEL, 0x07, chip->sd30_drive_sel_3v3);
|