From: Linus Torvalds Date: Mon, 29 Jan 2018 18:59:24 +0000 (-0800) Subject: Merge tag 'mfd-next-4.16' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd X-Git-Tag: microblaze-4.16-rc6~227 X-Git-Url: http://git.monstr.eu/?a=commitdiff_plain;h=bc4e118355caf83f472a5d31b850e73adddcf0ab;p=linux-2.6-microblaze.git Merge tag 'mfd-next-4.16' of git://git./linux/kernel/git/lee/mfd Pull MFD updates from Lee Jones: "New Drivers: - Add support for RAVE Supervisory Processor Moved drivers: - Move Realtek Card Reader Driver to Misc New Device Support: - Add support for Pinctrl to axp20x New Functionality: - Add resume support to atmel-flexcom Fix-ups: - Split MFD (mfd) and userspace handlers (platform) in cros_ec - Fix trivial (whitespace, spelling) issue(s) in pcf50633-core - Clean-up error handling in ab8500-debugfs - General tidying up in tmio_core - Kconfig fix-ups for qcom-pm8xxx - Licensing changes (SPDX) to stm32-lptimer, stm32-timers - Device Tree fixups in mc13xxx - Simplify/remove unused code in cros_ec_spi, axp20x, ti_am335x_tscadc, kempld-core, intel_soc_pmic_core.c, ab8500-debugfs" * tag 'mfd-next-4.16' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd: (32 commits) mfd: lpc_ich: Do not touch SPI-NOR write protection bit on Apollo Lake mfd: axp20x: Mark axp288 CHRG_BAK_CTRL register volatile mfd: ab8500: Introduce DEFINE_SHOW_ATTRIBUTE() macro atmel_flexcom: Support resuming after a chip reset mfd: Remove duplicate includes dt-bindings: mfd: mc13xxx: Add the unit address to sysled mfd: stm32: Adopt SPDX identifier mfd: axp20x: Add pinctrl cell for AXP813 mfd: pm8xxx: Make elegible for COMPILE_TEST mfd: kempld-core: Use resource_size function on resource object mfd: tmio: Move register macros to tmio_core.c mfd: cros ec: spi: Simplify delay handling between SPI messages mfd: palmas: Assign the right powerhold mask for tps65917 mfd: ab8500-debugfs: Use common error handling code in ab8500_print_modem_registers() mfd: ti_am335x_tscadc: Remove redundant assignment to node mfd: pcf50633: Fix spelling mistake: 'Falied' -> 'Failed' dt-bindings: watchdog: Add bindings for RAVE SP watchdog driver watchdog: Add RAVE SP watchdog driver mfd: Add driver for RAVE Supervisory Processor serdev: Introduce devm_serdev_device_open() ... --- bc4e118355caf83f472a5d31b850e73adddcf0ab diff --cc drivers/mfd/cros_ec_spi.c index 59c82cdcf48d,54cb760342f5..1b52b8557034 --- a/drivers/mfd/cros_ec_spi.c +++ b/drivers/mfd/cros_ec_spi.c @@@ -377,8 -376,8 +376,9 @@@ static int cros_ec_pkt_xfer_spi(struct u8 *ptr; u8 *rx_buf; u8 sum; + u8 rx_byte; int ret = 0, final_ret; + unsigned long delay; len = cros_ec_prepare_tx(ec_dev, ec_msg); dev_dbg(ec_dev->dev, "prepared, len=%d\n", len); @@@ -506,9 -504,9 +502,10 @@@ static int cros_ec_cmd_xfer_spi(struct int i, len; u8 *ptr; u8 *rx_buf; + u8 rx_byte; int sum; int ret = 0, final_ret; + unsigned long delay; len = cros_ec_prepare_tx(ec_dev, ec_msg); dev_dbg(ec_dev->dev, "prepared, len=%d\n", len); diff --cc drivers/misc/cardreader/rtsx_pcr.c index 000000000000,5345170fc57b..fd09b0960097 mode 000000,100644..100644 --- a/drivers/misc/cardreader/rtsx_pcr.c +++ b/drivers/misc/cardreader/rtsx_pcr.c @@@ -1,0 -1,1690 +1,1693 @@@ + /* Driver for Realtek PCI-Express card reader + * + * Copyright(c) 2009-2013 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 . + * + * Author: + * Wei WANG + */ + + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + + #include "rtsx_pcr.h" + + static bool msi_en = true; + module_param(msi_en, bool, S_IRUGO | S_IWUSR); + MODULE_PARM_DESC(msi_en, "Enable MSI"); + + static DEFINE_IDR(rtsx_pci_idr); + static DEFINE_SPINLOCK(rtsx_pci_lock); + + static struct mfd_cell rtsx_pcr_cells[] = { + [RTSX_SD_CARD] = { + .name = DRV_NAME_RTSX_PCI_SDMMC, + }, + [RTSX_MS_CARD] = { + .name = DRV_NAME_RTSX_PCI_MS, + }, + }; + + static const struct pci_device_id rtsx_pci_ids[] = { + { PCI_DEVICE(0x10EC, 0x5209), PCI_CLASS_OTHERS << 16, 0xFF0000 }, + { PCI_DEVICE(0x10EC, 0x5229), PCI_CLASS_OTHERS << 16, 0xFF0000 }, + { PCI_DEVICE(0x10EC, 0x5289), PCI_CLASS_OTHERS << 16, 0xFF0000 }, + { PCI_DEVICE(0x10EC, 0x5227), PCI_CLASS_OTHERS << 16, 0xFF0000 }, + { PCI_DEVICE(0x10EC, 0x522A), PCI_CLASS_OTHERS << 16, 0xFF0000 }, + { PCI_DEVICE(0x10EC, 0x5249), PCI_CLASS_OTHERS << 16, 0xFF0000 }, + { PCI_DEVICE(0x10EC, 0x5287), PCI_CLASS_OTHERS << 16, 0xFF0000 }, + { PCI_DEVICE(0x10EC, 0x5286), PCI_CLASS_OTHERS << 16, 0xFF0000 }, + { PCI_DEVICE(0x10EC, 0x524A), PCI_CLASS_OTHERS << 16, 0xFF0000 }, + { PCI_DEVICE(0x10EC, 0x525A), PCI_CLASS_OTHERS << 16, 0xFF0000 }, + { PCI_DEVICE(0x10EC, 0x5260), PCI_CLASS_OTHERS << 16, 0xFF0000 }, + { 0, } + }; + + MODULE_DEVICE_TABLE(pci, rtsx_pci_ids); + + static inline void rtsx_pci_enable_aspm(struct rtsx_pcr *pcr) + { + rtsx_pci_update_cfg_byte(pcr, pcr->pcie_cap + PCI_EXP_LNKCTL, + 0xFC, pcr->aspm_en); + } + + static inline void rtsx_pci_disable_aspm(struct rtsx_pcr *pcr) + { + rtsx_pci_update_cfg_byte(pcr, pcr->pcie_cap + PCI_EXP_LNKCTL, + 0xFC, 0); + } + + int rtsx_comm_set_ltr_latency(struct rtsx_pcr *pcr, u32 latency) + { + rtsx_pci_write_register(pcr, MSGTXDATA0, + MASK_8_BIT_DEF, (u8) (latency & 0xFF)); + rtsx_pci_write_register(pcr, MSGTXDATA1, + MASK_8_BIT_DEF, (u8)((latency >> 8) & 0xFF)); + rtsx_pci_write_register(pcr, MSGTXDATA2, + MASK_8_BIT_DEF, (u8)((latency >> 16) & 0xFF)); + rtsx_pci_write_register(pcr, MSGTXDATA3, + MASK_8_BIT_DEF, (u8)((latency >> 24) & 0xFF)); + rtsx_pci_write_register(pcr, LTR_CTL, LTR_TX_EN_MASK | + LTR_LATENCY_MODE_MASK, LTR_TX_EN_1 | LTR_LATENCY_MODE_SW); + + return 0; + } + + int rtsx_set_ltr_latency(struct rtsx_pcr *pcr, u32 latency) + { + if (pcr->ops->set_ltr_latency) + return pcr->ops->set_ltr_latency(pcr, latency); + else + return rtsx_comm_set_ltr_latency(pcr, latency); + } + + static void rtsx_comm_set_aspm(struct rtsx_pcr *pcr, bool enable) + { + struct rtsx_cr_option *option = &pcr->option; + + if (pcr->aspm_enabled == enable) + return; + + if (option->dev_aspm_mode == DEV_ASPM_DYNAMIC) { + if (enable) + rtsx_pci_enable_aspm(pcr); + else + rtsx_pci_disable_aspm(pcr); + } else if (option->dev_aspm_mode == DEV_ASPM_BACKDOOR) { + u8 mask = FORCE_ASPM_VAL_MASK; + u8 val = 0; + + if (enable) + val = pcr->aspm_en; + rtsx_pci_write_register(pcr, ASPM_FORCE_CTL, mask, val); + } + + pcr->aspm_enabled = enable; + } + + static void rtsx_disable_aspm(struct rtsx_pcr *pcr) + { + if (pcr->ops->set_aspm) + pcr->ops->set_aspm(pcr, false); + else + rtsx_comm_set_aspm(pcr, false); + } + + int rtsx_set_l1off_sub(struct rtsx_pcr *pcr, u8 val) + { + rtsx_pci_write_register(pcr, L1SUB_CONFIG3, 0xFF, val); + + return 0; + } + + void rtsx_set_l1off_sub_cfg_d0(struct rtsx_pcr *pcr, int active) + { + if (pcr->ops->set_l1off_cfg_sub_d0) + pcr->ops->set_l1off_cfg_sub_d0(pcr, active); + } + + static void rtsx_comm_pm_full_on(struct rtsx_pcr *pcr) + { + struct rtsx_cr_option *option = &pcr->option; + + rtsx_disable_aspm(pcr); + + if (option->ltr_enabled) + rtsx_set_ltr_latency(pcr, option->ltr_active_latency); + + if (rtsx_check_dev_flag(pcr, LTR_L1SS_PWR_GATE_EN)) + rtsx_set_l1off_sub_cfg_d0(pcr, 1); + } + + void rtsx_pm_full_on(struct rtsx_pcr *pcr) + { + if (pcr->ops->full_on) + pcr->ops->full_on(pcr); + else + rtsx_comm_pm_full_on(pcr); + } + + void rtsx_pci_start_run(struct rtsx_pcr *pcr) + { + /* If pci device removed, don't queue idle work any more */ + if (pcr->remove_pci) + return; + + if (pcr->state != PDEV_STAT_RUN) { + pcr->state = PDEV_STAT_RUN; + if (pcr->ops->enable_auto_blink) + pcr->ops->enable_auto_blink(pcr); + rtsx_pm_full_on(pcr); + } + + mod_delayed_work(system_wq, &pcr->idle_work, msecs_to_jiffies(200)); + } + EXPORT_SYMBOL_GPL(rtsx_pci_start_run); + + int rtsx_pci_write_register(struct rtsx_pcr *pcr, u16 addr, u8 mask, u8 data) + { + int i; + u32 val = HAIMR_WRITE_START; + + val |= (u32)(addr & 0x3FFF) << 16; + val |= (u32)mask << 8; + val |= (u32)data; + + rtsx_pci_writel(pcr, RTSX_HAIMR, val); + + for (i = 0; i < MAX_RW_REG_CNT; i++) { + val = rtsx_pci_readl(pcr, RTSX_HAIMR); + if ((val & HAIMR_TRANS_END) == 0) { + if (data != (u8)val) + return -EIO; + return 0; + } + } + + return -ETIMEDOUT; + } + EXPORT_SYMBOL_GPL(rtsx_pci_write_register); + + int rtsx_pci_read_register(struct rtsx_pcr *pcr, u16 addr, u8 *data) + { + u32 val = HAIMR_READ_START; + int i; + + val |= (u32)(addr & 0x3FFF) << 16; + rtsx_pci_writel(pcr, RTSX_HAIMR, val); + + for (i = 0; i < MAX_RW_REG_CNT; i++) { + val = rtsx_pci_readl(pcr, RTSX_HAIMR); + if ((val & HAIMR_TRANS_END) == 0) + break; + } + + if (i >= MAX_RW_REG_CNT) + return -ETIMEDOUT; + + if (data) + *data = (u8)(val & 0xFF); + + return 0; + } + EXPORT_SYMBOL_GPL(rtsx_pci_read_register); + + int __rtsx_pci_write_phy_register(struct rtsx_pcr *pcr, u8 addr, u16 val) + { + int err, i, finished = 0; + u8 tmp; + + rtsx_pci_init_cmd(pcr); + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PHYDATA0, 0xFF, (u8)val); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PHYDATA1, 0xFF, (u8)(val >> 8)); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PHYADDR, 0xFF, addr); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PHYRWCTL, 0xFF, 0x81); + + err = rtsx_pci_send_cmd(pcr, 100); + if (err < 0) + return err; + + for (i = 0; i < 100000; i++) { + err = rtsx_pci_read_register(pcr, PHYRWCTL, &tmp); + if (err < 0) + return err; + + if (!(tmp & 0x80)) { + finished = 1; + break; + } + } + + if (!finished) + return -ETIMEDOUT; + + return 0; + } + + int rtsx_pci_write_phy_register(struct rtsx_pcr *pcr, u8 addr, u16 val) + { + if (pcr->ops->write_phy) + return pcr->ops->write_phy(pcr, addr, val); + + return __rtsx_pci_write_phy_register(pcr, addr, val); + } + EXPORT_SYMBOL_GPL(rtsx_pci_write_phy_register); + + int __rtsx_pci_read_phy_register(struct rtsx_pcr *pcr, u8 addr, u16 *val) + { + int err, i, finished = 0; + u16 data; + u8 *ptr, tmp; + + rtsx_pci_init_cmd(pcr); + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PHYADDR, 0xFF, addr); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PHYRWCTL, 0xFF, 0x80); + + err = rtsx_pci_send_cmd(pcr, 100); + if (err < 0) + return err; + + for (i = 0; i < 100000; i++) { + err = rtsx_pci_read_register(pcr, PHYRWCTL, &tmp); + if (err < 0) + return err; + + if (!(tmp & 0x80)) { + finished = 1; + break; + } + } + + if (!finished) + return -ETIMEDOUT; + + rtsx_pci_init_cmd(pcr); + + rtsx_pci_add_cmd(pcr, READ_REG_CMD, PHYDATA0, 0, 0); + rtsx_pci_add_cmd(pcr, READ_REG_CMD, PHYDATA1, 0, 0); + + err = rtsx_pci_send_cmd(pcr, 100); + if (err < 0) + return err; + + ptr = rtsx_pci_get_cmd_data(pcr); + data = ((u16)ptr[1] << 8) | ptr[0]; + + if (val) + *val = data; + + return 0; + } + + int rtsx_pci_read_phy_register(struct rtsx_pcr *pcr, u8 addr, u16 *val) + { + if (pcr->ops->read_phy) + return pcr->ops->read_phy(pcr, addr, val); + + return __rtsx_pci_read_phy_register(pcr, addr, val); + } + EXPORT_SYMBOL_GPL(rtsx_pci_read_phy_register); + + void rtsx_pci_stop_cmd(struct rtsx_pcr *pcr) + { + if (pcr->ops->stop_cmd) + return pcr->ops->stop_cmd(pcr); + + rtsx_pci_writel(pcr, RTSX_HCBCTLR, STOP_CMD); + rtsx_pci_writel(pcr, RTSX_HDBCTLR, STOP_DMA); + + rtsx_pci_write_register(pcr, DMACTL, 0x80, 0x80); + rtsx_pci_write_register(pcr, RBCTL, 0x80, 0x80); + } + EXPORT_SYMBOL_GPL(rtsx_pci_stop_cmd); + + void rtsx_pci_add_cmd(struct rtsx_pcr *pcr, + u8 cmd_type, u16 reg_addr, u8 mask, u8 data) + { + unsigned long flags; + u32 val = 0; + u32 *ptr = (u32 *)(pcr->host_cmds_ptr); + + val |= (u32)(cmd_type & 0x03) << 30; + val |= (u32)(reg_addr & 0x3FFF) << 16; + val |= (u32)mask << 8; + val |= (u32)data; + + spin_lock_irqsave(&pcr->lock, flags); + ptr += pcr->ci; + if (pcr->ci < (HOST_CMDS_BUF_LEN / 4)) { + put_unaligned_le32(val, ptr); + ptr++; + pcr->ci++; + } + spin_unlock_irqrestore(&pcr->lock, flags); + } + EXPORT_SYMBOL_GPL(rtsx_pci_add_cmd); + + void rtsx_pci_send_cmd_no_wait(struct rtsx_pcr *pcr) + { + u32 val = 1 << 31; + + rtsx_pci_writel(pcr, RTSX_HCBAR, pcr->host_cmds_addr); + + val |= (u32)(pcr->ci * 4) & 0x00FFFFFF; + /* Hardware Auto Response */ + val |= 0x40000000; + rtsx_pci_writel(pcr, RTSX_HCBCTLR, val); + } + EXPORT_SYMBOL_GPL(rtsx_pci_send_cmd_no_wait); + + int rtsx_pci_send_cmd(struct rtsx_pcr *pcr, int timeout) + { + struct completion trans_done; + u32 val = 1 << 31; + long timeleft; + unsigned long flags; + int err = 0; + + spin_lock_irqsave(&pcr->lock, flags); + + /* set up data structures for the wakeup system */ + pcr->done = &trans_done; + pcr->trans_result = TRANS_NOT_READY; + init_completion(&trans_done); + + rtsx_pci_writel(pcr, RTSX_HCBAR, pcr->host_cmds_addr); + + val |= (u32)(pcr->ci * 4) & 0x00FFFFFF; + /* Hardware Auto Response */ + val |= 0x40000000; + rtsx_pci_writel(pcr, RTSX_HCBCTLR, val); + + spin_unlock_irqrestore(&pcr->lock, flags); + + /* Wait for TRANS_OK_INT */ + timeleft = wait_for_completion_interruptible_timeout( + &trans_done, msecs_to_jiffies(timeout)); + if (timeleft <= 0) { + pcr_dbg(pcr, "Timeout (%s %d)\n", __func__, __LINE__); + err = -ETIMEDOUT; + goto finish_send_cmd; + } + + spin_lock_irqsave(&pcr->lock, flags); + if (pcr->trans_result == TRANS_RESULT_FAIL) + err = -EINVAL; + else if (pcr->trans_result == TRANS_RESULT_OK) + err = 0; + else if (pcr->trans_result == TRANS_NO_DEVICE) + err = -ENODEV; + spin_unlock_irqrestore(&pcr->lock, flags); + + finish_send_cmd: + spin_lock_irqsave(&pcr->lock, flags); + pcr->done = NULL; + spin_unlock_irqrestore(&pcr->lock, flags); + + if ((err < 0) && (err != -ENODEV)) + rtsx_pci_stop_cmd(pcr); + + if (pcr->finish_me) + complete(pcr->finish_me); + + return err; + } + EXPORT_SYMBOL_GPL(rtsx_pci_send_cmd); + + static void rtsx_pci_add_sg_tbl(struct rtsx_pcr *pcr, + dma_addr_t addr, unsigned int len, int end) + { + u64 *ptr = (u64 *)(pcr->host_sg_tbl_ptr) + pcr->sgi; + u64 val; + u8 option = SG_VALID | SG_TRANS_DATA; + + pcr_dbg(pcr, "DMA addr: 0x%x, Len: 0x%x\n", (unsigned int)addr, len); + + if (end) + option |= SG_END; + val = ((u64)addr << 32) | ((u64)len << 12) | option; + + put_unaligned_le64(val, ptr); + pcr->sgi++; + } + + int rtsx_pci_transfer_data(struct rtsx_pcr *pcr, struct scatterlist *sglist, + int num_sg, bool read, int timeout) + { + int err = 0, count; + + pcr_dbg(pcr, "--> %s: num_sg = %d\n", __func__, num_sg); + count = rtsx_pci_dma_map_sg(pcr, sglist, num_sg, read); + if (count < 1) + return -EINVAL; + pcr_dbg(pcr, "DMA mapping count: %d\n", count); + + err = rtsx_pci_dma_transfer(pcr, sglist, count, read, timeout); + + rtsx_pci_dma_unmap_sg(pcr, sglist, num_sg, read); + + return err; + } + EXPORT_SYMBOL_GPL(rtsx_pci_transfer_data); + + int rtsx_pci_dma_map_sg(struct rtsx_pcr *pcr, struct scatterlist *sglist, + int num_sg, bool read) + { + enum dma_data_direction dir = read ? DMA_FROM_DEVICE : DMA_TO_DEVICE; + + if (pcr->remove_pci) + return -EINVAL; + + if ((sglist == NULL) || (num_sg <= 0)) + return -EINVAL; + + return dma_map_sg(&(pcr->pci->dev), sglist, num_sg, dir); + } + EXPORT_SYMBOL_GPL(rtsx_pci_dma_map_sg); + + void rtsx_pci_dma_unmap_sg(struct rtsx_pcr *pcr, struct scatterlist *sglist, + int num_sg, bool read) + { + enum dma_data_direction dir = read ? DMA_FROM_DEVICE : DMA_TO_DEVICE; + + dma_unmap_sg(&(pcr->pci->dev), sglist, num_sg, dir); + } + EXPORT_SYMBOL_GPL(rtsx_pci_dma_unmap_sg); + + int rtsx_pci_dma_transfer(struct rtsx_pcr *pcr, struct scatterlist *sglist, + int count, bool read, int timeout) + { + struct completion trans_done; + struct scatterlist *sg; + dma_addr_t addr; + long timeleft; + unsigned long flags; + unsigned int len; + int i, err = 0; + u32 val; + u8 dir = read ? DEVICE_TO_HOST : HOST_TO_DEVICE; + + if (pcr->remove_pci) + return -ENODEV; + + if ((sglist == NULL) || (count < 1)) + return -EINVAL; + + val = ((u32)(dir & 0x01) << 29) | TRIG_DMA | ADMA_MODE; + pcr->sgi = 0; + for_each_sg(sglist, sg, count, i) { + addr = sg_dma_address(sg); + len = sg_dma_len(sg); + rtsx_pci_add_sg_tbl(pcr, addr, len, i == count - 1); + } + + spin_lock_irqsave(&pcr->lock, flags); + + pcr->done = &trans_done; + pcr->trans_result = TRANS_NOT_READY; + init_completion(&trans_done); + rtsx_pci_writel(pcr, RTSX_HDBAR, pcr->host_sg_tbl_addr); + rtsx_pci_writel(pcr, RTSX_HDBCTLR, val); + + spin_unlock_irqrestore(&pcr->lock, flags); + + timeleft = wait_for_completion_interruptible_timeout( + &trans_done, msecs_to_jiffies(timeout)); + if (timeleft <= 0) { + pcr_dbg(pcr, "Timeout (%s %d)\n", __func__, __LINE__); + err = -ETIMEDOUT; + goto out; + } + + spin_lock_irqsave(&pcr->lock, flags); + if (pcr->trans_result == TRANS_RESULT_FAIL) { + err = -EILSEQ; + if (pcr->dma_error_count < RTS_MAX_TIMES_FREQ_REDUCTION) + pcr->dma_error_count++; + } + + else if (pcr->trans_result == TRANS_NO_DEVICE) + err = -ENODEV; + spin_unlock_irqrestore(&pcr->lock, flags); + + out: + spin_lock_irqsave(&pcr->lock, flags); + pcr->done = NULL; + spin_unlock_irqrestore(&pcr->lock, flags); + + if ((err < 0) && (err != -ENODEV)) + rtsx_pci_stop_cmd(pcr); + + if (pcr->finish_me) + complete(pcr->finish_me); + + return err; + } + EXPORT_SYMBOL_GPL(rtsx_pci_dma_transfer); + + int rtsx_pci_read_ppbuf(struct rtsx_pcr *pcr, u8 *buf, int buf_len) + { + int err; + int i, j; + u16 reg; + u8 *ptr; + + if (buf_len > 512) + buf_len = 512; + + ptr = buf; + reg = PPBUF_BASE2; + for (i = 0; i < buf_len / 256; i++) { + rtsx_pci_init_cmd(pcr); + + for (j = 0; j < 256; j++) + rtsx_pci_add_cmd(pcr, READ_REG_CMD, reg++, 0, 0); + + err = rtsx_pci_send_cmd(pcr, 250); + if (err < 0) + return err; + + memcpy(ptr, rtsx_pci_get_cmd_data(pcr), 256); + ptr += 256; + } + + if (buf_len % 256) { + rtsx_pci_init_cmd(pcr); + + for (j = 0; j < buf_len % 256; j++) + rtsx_pci_add_cmd(pcr, READ_REG_CMD, reg++, 0, 0); + + err = rtsx_pci_send_cmd(pcr, 250); + if (err < 0) + return err; + } + + memcpy(ptr, rtsx_pci_get_cmd_data(pcr), buf_len % 256); + + return 0; + } + EXPORT_SYMBOL_GPL(rtsx_pci_read_ppbuf); + + int rtsx_pci_write_ppbuf(struct rtsx_pcr *pcr, u8 *buf, int buf_len) + { + int err; + int i, j; + u16 reg; + u8 *ptr; + + if (buf_len > 512) + buf_len = 512; + + ptr = buf; + reg = PPBUF_BASE2; + for (i = 0; i < buf_len / 256; i++) { + rtsx_pci_init_cmd(pcr); + + for (j = 0; j < 256; j++) { + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, + reg++, 0xFF, *ptr); + ptr++; + } + + err = rtsx_pci_send_cmd(pcr, 250); + if (err < 0) + return err; + } + + if (buf_len % 256) { + rtsx_pci_init_cmd(pcr); + + for (j = 0; j < buf_len % 256; j++) { + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, + reg++, 0xFF, *ptr); + ptr++; + } + + err = rtsx_pci_send_cmd(pcr, 250); + if (err < 0) + return err; + } + + return 0; + } + EXPORT_SYMBOL_GPL(rtsx_pci_write_ppbuf); + + static int rtsx_pci_set_pull_ctl(struct rtsx_pcr *pcr, const u32 *tbl) + { + rtsx_pci_init_cmd(pcr); + + while (*tbl & 0xFFFF0000) { + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, + (u16)(*tbl >> 16), 0xFF, (u8)(*tbl)); + tbl++; + } + + return rtsx_pci_send_cmd(pcr, 100); + } + + int rtsx_pci_card_pull_ctl_enable(struct rtsx_pcr *pcr, int card) + { + const u32 *tbl; + + if (card == RTSX_SD_CARD) + tbl = pcr->sd_pull_ctl_enable_tbl; + else if (card == RTSX_MS_CARD) + tbl = pcr->ms_pull_ctl_enable_tbl; + else + return -EINVAL; + + return rtsx_pci_set_pull_ctl(pcr, tbl); + } + EXPORT_SYMBOL_GPL(rtsx_pci_card_pull_ctl_enable); + + int rtsx_pci_card_pull_ctl_disable(struct rtsx_pcr *pcr, int card) + { + const u32 *tbl; + + if (card == RTSX_SD_CARD) + tbl = pcr->sd_pull_ctl_disable_tbl; + else if (card == RTSX_MS_CARD) + tbl = pcr->ms_pull_ctl_disable_tbl; + else + return -EINVAL; + + + return rtsx_pci_set_pull_ctl(pcr, tbl); + } + EXPORT_SYMBOL_GPL(rtsx_pci_card_pull_ctl_disable); + + static void rtsx_pci_enable_bus_int(struct rtsx_pcr *pcr) + { + pcr->bier = TRANS_OK_INT_EN | TRANS_FAIL_INT_EN | SD_INT_EN; + + if (pcr->num_slots > 1) + pcr->bier |= MS_INT_EN; + + /* Enable Bus Interrupt */ + rtsx_pci_writel(pcr, RTSX_BIER, pcr->bier); + + pcr_dbg(pcr, "RTSX_BIER: 0x%08x\n", pcr->bier); + } + + static inline u8 double_ssc_depth(u8 depth) + { + return ((depth > 1) ? (depth - 1) : depth); + } + + static u8 revise_ssc_depth(u8 ssc_depth, u8 div) + { + if (div > CLK_DIV_1) { + if (ssc_depth > (div - 1)) + ssc_depth -= (div - 1); + else + ssc_depth = SSC_DEPTH_4M; + } + + return ssc_depth; + } + + int rtsx_pci_switch_clock(struct rtsx_pcr *pcr, unsigned int card_clock, + u8 ssc_depth, bool initial_mode, bool double_clk, bool vpclk) + { + int err, clk; + u8 n, clk_divider, mcu_cnt, div; + static const u8 depth[] = { + [RTSX_SSC_DEPTH_4M] = SSC_DEPTH_4M, + [RTSX_SSC_DEPTH_2M] = SSC_DEPTH_2M, + [RTSX_SSC_DEPTH_1M] = SSC_DEPTH_1M, + [RTSX_SSC_DEPTH_500K] = SSC_DEPTH_500K, + [RTSX_SSC_DEPTH_250K] = SSC_DEPTH_250K, + }; + + if (initial_mode) { + /* We use 250k(around) here, in initial stage */ + clk_divider = SD_CLK_DIVIDE_128; + card_clock = 30000000; + } else { + clk_divider = SD_CLK_DIVIDE_0; + } + err = rtsx_pci_write_register(pcr, SD_CFG1, + SD_CLK_DIVIDE_MASK, clk_divider); + if (err < 0) + return err; + + /* Reduce card clock by 20MHz each time a DMA transfer error occurs */ + if (card_clock == UHS_SDR104_MAX_DTR && + pcr->dma_error_count && + PCI_PID(pcr) == RTS5227_DEVICE_ID) + card_clock = UHS_SDR104_MAX_DTR - + (pcr->dma_error_count * 20000000); + + card_clock /= 1000000; + pcr_dbg(pcr, "Switch card clock to %dMHz\n", card_clock); + + clk = card_clock; + if (!initial_mode && double_clk) + clk = card_clock * 2; + pcr_dbg(pcr, "Internal SSC clock: %dMHz (cur_clock = %d)\n", + clk, pcr->cur_clock); + + if (clk == pcr->cur_clock) + return 0; + + if (pcr->ops->conv_clk_and_div_n) + n = (u8)pcr->ops->conv_clk_and_div_n(clk, CLK_TO_DIV_N); + else + n = (u8)(clk - 2); + if ((clk <= 2) || (n > MAX_DIV_N_PCR)) + return -EINVAL; + + mcu_cnt = (u8)(125/clk + 3); + if (mcu_cnt > 15) + mcu_cnt = 15; + + /* Make sure that the SSC clock div_n is not less than MIN_DIV_N_PCR */ + div = CLK_DIV_1; + while ((n < MIN_DIV_N_PCR) && (div < CLK_DIV_8)) { + if (pcr->ops->conv_clk_and_div_n) { + int dbl_clk = pcr->ops->conv_clk_and_div_n(n, + DIV_N_TO_CLK) * 2; + n = (u8)pcr->ops->conv_clk_and_div_n(dbl_clk, + CLK_TO_DIV_N); + } else { + n = (n + 2) * 2 - 2; + } + div++; + } + pcr_dbg(pcr, "n = %d, div = %d\n", n, div); + + ssc_depth = depth[ssc_depth]; + if (double_clk) + ssc_depth = double_ssc_depth(ssc_depth); + + ssc_depth = revise_ssc_depth(ssc_depth, div); + pcr_dbg(pcr, "ssc_depth = %d\n", ssc_depth); + + rtsx_pci_init_cmd(pcr); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, + CLK_LOW_FREQ, CLK_LOW_FREQ); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_DIV, + 0xFF, (div << 4) | mcu_cnt); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL1, SSC_RSTB, 0); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL2, + SSC_DEPTH_MASK, ssc_depth); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_DIV_N_0, 0xFF, n); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL1, SSC_RSTB, SSC_RSTB); + if (vpclk) { + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_VPCLK0_CTL, + PHASE_NOT_RESET, 0); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_VPCLK0_CTL, + PHASE_NOT_RESET, PHASE_NOT_RESET); + } + + err = rtsx_pci_send_cmd(pcr, 2000); + if (err < 0) + return err; + + /* Wait SSC clock stable */ + udelay(SSC_CLOCK_STABLE_WAIT); + err = rtsx_pci_write_register(pcr, CLK_CTL, CLK_LOW_FREQ, 0); + if (err < 0) + return err; + + pcr->cur_clock = clk; + return 0; + } + EXPORT_SYMBOL_GPL(rtsx_pci_switch_clock); + + int rtsx_pci_card_power_on(struct rtsx_pcr *pcr, int card) + { + if (pcr->ops->card_power_on) + return pcr->ops->card_power_on(pcr, card); + + return 0; + } + EXPORT_SYMBOL_GPL(rtsx_pci_card_power_on); + + int rtsx_pci_card_power_off(struct rtsx_pcr *pcr, int card) + { + if (pcr->ops->card_power_off) + return pcr->ops->card_power_off(pcr, card); + + return 0; + } + EXPORT_SYMBOL_GPL(rtsx_pci_card_power_off); + + int rtsx_pci_card_exclusive_check(struct rtsx_pcr *pcr, int card) + { + static const unsigned int cd_mask[] = { + [RTSX_SD_CARD] = SD_EXIST, + [RTSX_MS_CARD] = MS_EXIST + }; + + if (!(pcr->flags & PCR_MS_PMOS)) { + /* When using single PMOS, accessing card is not permitted + * if the existing card is not the designated one. + */ + if (pcr->card_exist & (~cd_mask[card])) + return -EIO; + } + + return 0; + } + EXPORT_SYMBOL_GPL(rtsx_pci_card_exclusive_check); + + int rtsx_pci_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage) + { + if (pcr->ops->switch_output_voltage) + return pcr->ops->switch_output_voltage(pcr, voltage); + + return 0; + } + EXPORT_SYMBOL_GPL(rtsx_pci_switch_output_voltage); + + unsigned int rtsx_pci_card_exist(struct rtsx_pcr *pcr) + { + unsigned int val; + + val = rtsx_pci_readl(pcr, RTSX_BIPR); + if (pcr->ops->cd_deglitch) + val = pcr->ops->cd_deglitch(pcr); + + return val; + } + EXPORT_SYMBOL_GPL(rtsx_pci_card_exist); + + void rtsx_pci_complete_unfinished_transfer(struct rtsx_pcr *pcr) + { + struct completion finish; + + pcr->finish_me = &finish; + init_completion(&finish); + + if (pcr->done) + complete(pcr->done); + + if (!pcr->remove_pci) + rtsx_pci_stop_cmd(pcr); + + wait_for_completion_interruptible_timeout(&finish, + msecs_to_jiffies(2)); + pcr->finish_me = NULL; + } + EXPORT_SYMBOL_GPL(rtsx_pci_complete_unfinished_transfer); + + static void rtsx_pci_card_detect(struct work_struct *work) + { + struct delayed_work *dwork; + struct rtsx_pcr *pcr; + unsigned long flags; + unsigned int card_detect = 0, card_inserted, card_removed; + u32 irq_status; + + dwork = to_delayed_work(work); + pcr = container_of(dwork, struct rtsx_pcr, carddet_work); + + pcr_dbg(pcr, "--> %s\n", __func__); + + mutex_lock(&pcr->pcr_mutex); + spin_lock_irqsave(&pcr->lock, flags); + + irq_status = rtsx_pci_readl(pcr, RTSX_BIPR); + pcr_dbg(pcr, "irq_status: 0x%08x\n", irq_status); + + irq_status &= CARD_EXIST; + card_inserted = pcr->card_inserted & irq_status; + card_removed = pcr->card_removed; + pcr->card_inserted = 0; + pcr->card_removed = 0; + + spin_unlock_irqrestore(&pcr->lock, flags); + + if (card_inserted || card_removed) { + pcr_dbg(pcr, "card_inserted: 0x%x, card_removed: 0x%x\n", + card_inserted, card_removed); + + if (pcr->ops->cd_deglitch) + card_inserted = pcr->ops->cd_deglitch(pcr); + + card_detect = card_inserted | card_removed; + + pcr->card_exist |= card_inserted; + pcr->card_exist &= ~card_removed; + } + + mutex_unlock(&pcr->pcr_mutex); + + if ((card_detect & SD_EXIST) && pcr->slots[RTSX_SD_CARD].card_event) + pcr->slots[RTSX_SD_CARD].card_event( + pcr->slots[RTSX_SD_CARD].p_dev); + if ((card_detect & MS_EXIST) && pcr->slots[RTSX_MS_CARD].card_event) + pcr->slots[RTSX_MS_CARD].card_event( + pcr->slots[RTSX_MS_CARD].p_dev); + } + + void rtsx_pci_process_ocp(struct rtsx_pcr *pcr) + { + if (pcr->ops->process_ocp) + pcr->ops->process_ocp(pcr); + } + + int rtsx_pci_process_ocp_interrupt(struct rtsx_pcr *pcr) + { + if (pcr->option.ocp_en) + rtsx_pci_process_ocp(pcr); + + return 0; + } + + static irqreturn_t rtsx_pci_isr(int irq, void *dev_id) + { + struct rtsx_pcr *pcr = dev_id; + u32 int_reg; + + if (!pcr) + return IRQ_NONE; + + spin_lock(&pcr->lock); + + int_reg = rtsx_pci_readl(pcr, RTSX_BIPR); + /* Clear interrupt flag */ + rtsx_pci_writel(pcr, RTSX_BIPR, int_reg); + if ((int_reg & pcr->bier) == 0) { + spin_unlock(&pcr->lock); + return IRQ_NONE; + } + if (int_reg == 0xFFFFFFFF) { + spin_unlock(&pcr->lock); + return IRQ_HANDLED; + } + + int_reg &= (pcr->bier | 0x7FFFFF); + + if (int_reg & SD_OC_INT) + rtsx_pci_process_ocp_interrupt(pcr); + + if (int_reg & SD_INT) { + if (int_reg & SD_EXIST) { + pcr->card_inserted |= SD_EXIST; + } else { + pcr->card_removed |= SD_EXIST; + pcr->card_inserted &= ~SD_EXIST; + } + pcr->dma_error_count = 0; + } + + if (int_reg & MS_INT) { + if (int_reg & MS_EXIST) { + pcr->card_inserted |= MS_EXIST; + } else { + pcr->card_removed |= MS_EXIST; + pcr->card_inserted &= ~MS_EXIST; + } + } + + if (int_reg & (NEED_COMPLETE_INT | DELINK_INT)) { + if (int_reg & (TRANS_FAIL_INT | DELINK_INT)) { + pcr->trans_result = TRANS_RESULT_FAIL; + if (pcr->done) + complete(pcr->done); + } else if (int_reg & TRANS_OK_INT) { + pcr->trans_result = TRANS_RESULT_OK; + if (pcr->done) + complete(pcr->done); + } + } + + if (pcr->card_inserted || pcr->card_removed) + schedule_delayed_work(&pcr->carddet_work, + msecs_to_jiffies(200)); + + spin_unlock(&pcr->lock); + return IRQ_HANDLED; + } + + static int rtsx_pci_acquire_irq(struct rtsx_pcr *pcr) + { + pcr_dbg(pcr, "%s: pcr->msi_en = %d, pci->irq = %d\n", + __func__, pcr->msi_en, pcr->pci->irq); + + if (request_irq(pcr->pci->irq, rtsx_pci_isr, + pcr->msi_en ? 0 : IRQF_SHARED, + DRV_NAME_RTSX_PCI, pcr)) { + dev_err(&(pcr->pci->dev), + "rtsx_sdmmc: unable to grab IRQ %d, disabling device\n", + pcr->pci->irq); + return -1; + } + + pcr->irq = pcr->pci->irq; + pci_intx(pcr->pci, !pcr->msi_en); + + return 0; + } + + static void rtsx_enable_aspm(struct rtsx_pcr *pcr) + { + if (pcr->ops->set_aspm) + pcr->ops->set_aspm(pcr, true); + else + rtsx_comm_set_aspm(pcr, true); + } + + static void rtsx_comm_pm_power_saving(struct rtsx_pcr *pcr) + { + struct rtsx_cr_option *option = &pcr->option; + + if (option->ltr_enabled) { + u32 latency = option->ltr_l1off_latency; + + if (rtsx_check_dev_flag(pcr, L1_SNOOZE_TEST_EN)) + mdelay(option->l1_snooze_delay); + + rtsx_set_ltr_latency(pcr, latency); + } + + if (rtsx_check_dev_flag(pcr, LTR_L1SS_PWR_GATE_EN)) + rtsx_set_l1off_sub_cfg_d0(pcr, 0); + + rtsx_enable_aspm(pcr); + } + + void rtsx_pm_power_saving(struct rtsx_pcr *pcr) + { + if (pcr->ops->power_saving) + pcr->ops->power_saving(pcr); + else + rtsx_comm_pm_power_saving(pcr); + } + + static void rtsx_pci_idle_work(struct work_struct *work) + { + struct delayed_work *dwork = to_delayed_work(work); + struct rtsx_pcr *pcr = container_of(dwork, struct rtsx_pcr, idle_work); + + pcr_dbg(pcr, "--> %s\n", __func__); + + mutex_lock(&pcr->pcr_mutex); + + pcr->state = PDEV_STAT_IDLE; + + if (pcr->ops->disable_auto_blink) + pcr->ops->disable_auto_blink(pcr); + if (pcr->ops->turn_off_led) + pcr->ops->turn_off_led(pcr); + + rtsx_pm_power_saving(pcr); + + mutex_unlock(&pcr->pcr_mutex); + } + + #ifdef CONFIG_PM + static void rtsx_pci_power_off(struct rtsx_pcr *pcr, u8 pm_state) + { + if (pcr->ops->turn_off_led) + pcr->ops->turn_off_led(pcr); + + rtsx_pci_writel(pcr, RTSX_BIER, 0); + pcr->bier = 0; + + rtsx_pci_write_register(pcr, PETXCFG, 0x08, 0x08); + rtsx_pci_write_register(pcr, HOST_SLEEP_STATE, 0x03, pm_state); + + if (pcr->ops->force_power_down) + pcr->ops->force_power_down(pcr, pm_state); + } + #endif + + void rtsx_pci_enable_ocp(struct rtsx_pcr *pcr) + { + u8 val = SD_OCP_INT_EN | SD_DETECT_EN; + + if (pcr->ops->enable_ocp) + pcr->ops->enable_ocp(pcr); + else + rtsx_pci_write_register(pcr, REG_OCPCTL, 0xFF, val); + + } + + void rtsx_pci_disable_ocp(struct rtsx_pcr *pcr) + { + u8 mask = SD_OCP_INT_EN | SD_DETECT_EN; + + if (pcr->ops->disable_ocp) + pcr->ops->disable_ocp(pcr); + else + rtsx_pci_write_register(pcr, REG_OCPCTL, mask, 0); + } + + void rtsx_pci_init_ocp(struct rtsx_pcr *pcr) + { + if (pcr->ops->init_ocp) { + pcr->ops->init_ocp(pcr); + } else { + struct rtsx_cr_option *option = &(pcr->option); + + if (option->ocp_en) { + u8 val = option->sd_400mA_ocp_thd; + + rtsx_pci_write_register(pcr, FPDCTL, OC_POWER_DOWN, 0); + rtsx_pci_write_register(pcr, REG_OCPPARA1, + SD_OCP_TIME_MASK, SD_OCP_TIME_800); + rtsx_pci_write_register(pcr, REG_OCPPARA2, + SD_OCP_THD_MASK, val); + rtsx_pci_write_register(pcr, REG_OCPGLITCH, + SD_OCP_GLITCH_MASK, pcr->hw_param.ocp_glitch); + rtsx_pci_enable_ocp(pcr); + } else { + /* OC power down */ + rtsx_pci_write_register(pcr, FPDCTL, OC_POWER_DOWN, + OC_POWER_DOWN); + } + } + } + + int rtsx_pci_get_ocpstat(struct rtsx_pcr *pcr, u8 *val) + { + if (pcr->ops->get_ocpstat) + return pcr->ops->get_ocpstat(pcr, val); + else + return rtsx_pci_read_register(pcr, REG_OCPSTAT, val); + } + + void rtsx_pci_clear_ocpstat(struct rtsx_pcr *pcr) + { + if (pcr->ops->clear_ocpstat) { + pcr->ops->clear_ocpstat(pcr); + } else { + u8 mask = SD_OCP_INT_CLR | SD_OC_CLR; + u8 val = SD_OCP_INT_CLR | SD_OC_CLR; + + rtsx_pci_write_register(pcr, REG_OCPCTL, mask, val); + rtsx_pci_write_register(pcr, REG_OCPCTL, mask, 0); + } + } + + int rtsx_sd_power_off_card3v3(struct rtsx_pcr *pcr) + { + rtsx_pci_write_register(pcr, CARD_CLK_EN, SD_CLK_EN | + MS_CLK_EN | SD40_CLK_EN, 0); + rtsx_pci_write_register(pcr, CARD_OE, SD_OUTPUT_EN, 0); + + rtsx_pci_card_power_off(pcr, RTSX_SD_CARD); + + msleep(50); + + rtsx_pci_card_pull_ctl_disable(pcr, RTSX_SD_CARD); + + return 0; + } + + int rtsx_ms_power_off_card3v3(struct rtsx_pcr *pcr) + { + rtsx_pci_write_register(pcr, CARD_CLK_EN, SD_CLK_EN | + MS_CLK_EN | SD40_CLK_EN, 0); + + rtsx_pci_card_pull_ctl_disable(pcr, RTSX_MS_CARD); + + rtsx_pci_write_register(pcr, CARD_OE, MS_OUTPUT_EN, 0); + rtsx_pci_card_power_off(pcr, RTSX_MS_CARD); + + return 0; + } + + static int rtsx_pci_init_hw(struct rtsx_pcr *pcr) + { + int err; + + pcr->pcie_cap = pci_find_capability(pcr->pci, PCI_CAP_ID_EXP); + rtsx_pci_writel(pcr, RTSX_HCBAR, pcr->host_cmds_addr); + + rtsx_pci_enable_bus_int(pcr); + + /* Power on SSC */ + err = rtsx_pci_write_register(pcr, FPDCTL, SSC_POWER_DOWN, 0); + if (err < 0) + return err; + + /* Wait SSC power stable */ + udelay(200); + + rtsx_pci_disable_aspm(pcr); + if (pcr->ops->optimize_phy) { + err = pcr->ops->optimize_phy(pcr); + if (err < 0) + return err; + } + + rtsx_pci_init_cmd(pcr); + + /* Set mcu_cnt to 7 to ensure data can be sampled properly */ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_DIV, 0x07, 0x07); + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, HOST_SLEEP_STATE, 0x03, 0x00); + /* Disable card clock */ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_CLK_EN, 0x1E, 0); + /* Reset delink mode */ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CHANGE_LINK_STATE, 0x0A, 0); + /* Card driving select */ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_DRIVE_SEL, + 0xFF, pcr->card_drive_sel); + /* Enable SSC Clock */ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL1, + 0xFF, SSC_8X_EN | SSC_SEL_4M); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL2, 0xFF, 0x12); + /* Disable cd_pwr_save */ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CHANGE_LINK_STATE, 0x16, 0x10); + /* Clear Link Ready Interrupt */ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, IRQSTAT0, + LINK_RDY_INT, LINK_RDY_INT); + /* Enlarge the estimation window of PERST# glitch + * to reduce the chance of invalid card interrupt + */ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PERST_GLITCH_WIDTH, 0xFF, 0x80); + /* Update RC oscillator to 400k + * bit[0] F_HIGH: for RC oscillator, Rst_value is 1'b1 + * 1: 2M 0: 400k + */ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, RCCTL, 0x01, 0x00); + /* Set interrupt write clear + * bit 1: U_elbi_if_rd_clr_en + * 1: Enable ELBI interrupt[31:22] & [7:0] flag read clear + * 0: ELBI interrupt flag[31:22] & [7:0] only can be write clear + */ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, NFTS_TX_CTRL, 0x02, 0); + + err = rtsx_pci_send_cmd(pcr, 100); + if (err < 0) + return err; + + switch (PCI_PID(pcr)) { + case PID_5250: + case PID_524A: + case PID_525A: + case PID_5260: + rtsx_pci_write_register(pcr, PM_CLK_FORCE_CTL, 1, 1); + break; + default: + break; + } + + /* Enable clk_request_n to enable clock power management */ + rtsx_pci_write_config_byte(pcr, pcr->pcie_cap + PCI_EXP_LNKCTL + 1, 1); + /* Enter L1 when host tx idle */ + rtsx_pci_write_config_byte(pcr, 0x70F, 0x5B); + + if (pcr->ops->extra_init_hw) { + err = pcr->ops->extra_init_hw(pcr); + if (err < 0) + return err; + } + + /* No CD interrupt if probing driver with card inserted. + * So we need to initialize pcr->card_exist here. + */ + if (pcr->ops->cd_deglitch) + pcr->card_exist = pcr->ops->cd_deglitch(pcr); + else + pcr->card_exist = rtsx_pci_readl(pcr, RTSX_BIPR) & CARD_EXIST; + + return 0; + } + + static int rtsx_pci_init_chip(struct rtsx_pcr *pcr) + { + int err; + + spin_lock_init(&pcr->lock); + mutex_init(&pcr->pcr_mutex); + + switch (PCI_PID(pcr)) { + default: + case 0x5209: + rts5209_init_params(pcr); + break; + + case 0x5229: + rts5229_init_params(pcr); + break; + + case 0x5289: + rtl8411_init_params(pcr); + break; + + case 0x5227: + rts5227_init_params(pcr); + break; + + case 0x522A: + rts522a_init_params(pcr); + break; + + case 0x5249: + rts5249_init_params(pcr); + break; + + case 0x524A: + rts524a_init_params(pcr); + break; + + case 0x525A: + rts525a_init_params(pcr); + break; + + case 0x5287: + rtl8411b_init_params(pcr); + break; + + case 0x5286: + rtl8402_init_params(pcr); + break; + case 0x5260: + rts5260_init_params(pcr); + break; + } + + pcr_dbg(pcr, "PID: 0x%04x, IC version: 0x%02x\n", + PCI_PID(pcr), pcr->ic_version); + + pcr->slots = kcalloc(pcr->num_slots, sizeof(struct rtsx_slot), + GFP_KERNEL); + if (!pcr->slots) + return -ENOMEM; + + if (pcr->ops->fetch_vendor_settings) + pcr->ops->fetch_vendor_settings(pcr); + + pcr_dbg(pcr, "pcr->aspm_en = 0x%x\n", pcr->aspm_en); + pcr_dbg(pcr, "pcr->sd30_drive_sel_1v8 = 0x%x\n", + pcr->sd30_drive_sel_1v8); + pcr_dbg(pcr, "pcr->sd30_drive_sel_3v3 = 0x%x\n", + pcr->sd30_drive_sel_3v3); + pcr_dbg(pcr, "pcr->card_drive_sel = 0x%x\n", + pcr->card_drive_sel); + pcr_dbg(pcr, "pcr->flags = 0x%x\n", pcr->flags); + + pcr->state = PDEV_STAT_IDLE; + err = rtsx_pci_init_hw(pcr); + if (err < 0) { + kfree(pcr->slots); + return err; + } + + return 0; + } + + static int rtsx_pci_probe(struct pci_dev *pcidev, + const struct pci_device_id *id) + { + struct rtsx_pcr *pcr; + struct pcr_handle *handle; + u32 base, len; + int ret, i, bar = 0; + + dev_dbg(&(pcidev->dev), + ": Realtek PCI-E Card Reader found at %s [%04x:%04x] (rev %x)\n", + pci_name(pcidev), (int)pcidev->vendor, (int)pcidev->device, + (int)pcidev->revision); + + ret = pci_set_dma_mask(pcidev, DMA_BIT_MASK(32)); + if (ret < 0) + return ret; + + ret = pci_enable_device(pcidev); + if (ret) + return ret; + + ret = pci_request_regions(pcidev, DRV_NAME_RTSX_PCI); + if (ret) + goto disable; + + pcr = kzalloc(sizeof(*pcr), GFP_KERNEL); + if (!pcr) { + ret = -ENOMEM; + goto release_pci; + } + + handle = kzalloc(sizeof(*handle), GFP_KERNEL); + if (!handle) { + ret = -ENOMEM; + goto free_pcr; + } + handle->pcr = pcr; + + idr_preload(GFP_KERNEL); + spin_lock(&rtsx_pci_lock); + ret = idr_alloc(&rtsx_pci_idr, pcr, 0, 0, GFP_NOWAIT); + if (ret >= 0) + pcr->id = ret; + spin_unlock(&rtsx_pci_lock); + idr_preload_end(); + if (ret < 0) + goto free_handle; + + pcr->pci = pcidev; + dev_set_drvdata(&pcidev->dev, handle); + + if (CHK_PCI_PID(pcr, 0x525A)) + bar = 1; + len = pci_resource_len(pcidev, bar); + base = pci_resource_start(pcidev, bar); + pcr->remap_addr = ioremap_nocache(base, len); + if (!pcr->remap_addr) { + ret = -ENOMEM; + goto free_handle; + } + + pcr->rtsx_resv_buf = dma_alloc_coherent(&(pcidev->dev), + RTSX_RESV_BUF_LEN, &(pcr->rtsx_resv_buf_addr), + GFP_KERNEL); + if (pcr->rtsx_resv_buf == NULL) { + ret = -ENXIO; + goto unmap; + } + pcr->host_cmds_ptr = pcr->rtsx_resv_buf; + pcr->host_cmds_addr = pcr->rtsx_resv_buf_addr; + pcr->host_sg_tbl_ptr = pcr->rtsx_resv_buf + HOST_CMDS_BUF_LEN; + pcr->host_sg_tbl_addr = pcr->rtsx_resv_buf_addr + HOST_CMDS_BUF_LEN; + + pcr->card_inserted = 0; + pcr->card_removed = 0; + INIT_DELAYED_WORK(&pcr->carddet_work, rtsx_pci_card_detect); + INIT_DELAYED_WORK(&pcr->idle_work, rtsx_pci_idle_work); + + pcr->msi_en = msi_en; + if (pcr->msi_en) { + ret = pci_enable_msi(pcidev); + if (ret) + pcr->msi_en = false; + } + + ret = rtsx_pci_acquire_irq(pcr); + if (ret < 0) + goto disable_msi; + + pci_set_master(pcidev); + synchronize_irq(pcr->irq); + + ret = rtsx_pci_init_chip(pcr); + if (ret < 0) + goto disable_irq; + + for (i = 0; i < ARRAY_SIZE(rtsx_pcr_cells); i++) { + rtsx_pcr_cells[i].platform_data = handle; + rtsx_pcr_cells[i].pdata_size = sizeof(*handle); + } + ret = mfd_add_devices(&pcidev->dev, pcr->id, rtsx_pcr_cells, + ARRAY_SIZE(rtsx_pcr_cells), NULL, 0, NULL); + if (ret < 0) + goto disable_irq; + + schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200)); + + return 0; + + disable_irq: + free_irq(pcr->irq, (void *)pcr); + disable_msi: + if (pcr->msi_en) + pci_disable_msi(pcr->pci); + dma_free_coherent(&(pcr->pci->dev), RTSX_RESV_BUF_LEN, + pcr->rtsx_resv_buf, pcr->rtsx_resv_buf_addr); + unmap: + iounmap(pcr->remap_addr); + free_handle: + kfree(handle); + free_pcr: + kfree(pcr); + release_pci: + pci_release_regions(pcidev); + disable: + pci_disable_device(pcidev); + + return ret; + } + + static void rtsx_pci_remove(struct pci_dev *pcidev) + { + struct pcr_handle *handle = pci_get_drvdata(pcidev); + struct rtsx_pcr *pcr = handle->pcr; + + pcr->remove_pci = true; + + /* Disable interrupts at the pcr level */ + spin_lock_irq(&pcr->lock); + rtsx_pci_writel(pcr, RTSX_BIER, 0); + pcr->bier = 0; + spin_unlock_irq(&pcr->lock); + + cancel_delayed_work_sync(&pcr->carddet_work); + cancel_delayed_work_sync(&pcr->idle_work); + + mfd_remove_devices(&pcidev->dev); + + dma_free_coherent(&(pcr->pci->dev), RTSX_RESV_BUF_LEN, + pcr->rtsx_resv_buf, pcr->rtsx_resv_buf_addr); + free_irq(pcr->irq, (void *)pcr); + if (pcr->msi_en) + pci_disable_msi(pcr->pci); + iounmap(pcr->remap_addr); + + pci_release_regions(pcidev); + pci_disable_device(pcidev); + + spin_lock(&rtsx_pci_lock); + idr_remove(&rtsx_pci_idr, pcr->id); + spin_unlock(&rtsx_pci_lock); + + kfree(pcr->slots); + kfree(pcr); + kfree(handle); + + dev_dbg(&(pcidev->dev), + ": Realtek PCI-E Card Reader at %s [%04x:%04x] has been removed\n", + pci_name(pcidev), (int)pcidev->vendor, (int)pcidev->device); + } + + #ifdef CONFIG_PM + + static int rtsx_pci_suspend(struct pci_dev *pcidev, pm_message_t state) + { + struct pcr_handle *handle; + struct rtsx_pcr *pcr; + + dev_dbg(&(pcidev->dev), "--> %s\n", __func__); + + handle = pci_get_drvdata(pcidev); + pcr = handle->pcr; + + cancel_delayed_work(&pcr->carddet_work); + cancel_delayed_work(&pcr->idle_work); + + mutex_lock(&pcr->pcr_mutex); + + rtsx_pci_power_off(pcr, HOST_ENTER_S3); + + pci_save_state(pcidev); + pci_enable_wake(pcidev, pci_choose_state(pcidev, state), 0); + pci_disable_device(pcidev); + pci_set_power_state(pcidev, pci_choose_state(pcidev, state)); + + mutex_unlock(&pcr->pcr_mutex); + return 0; + } + + static int rtsx_pci_resume(struct pci_dev *pcidev) + { + struct pcr_handle *handle; + struct rtsx_pcr *pcr; + int ret = 0; + + dev_dbg(&(pcidev->dev), "--> %s\n", __func__); + + handle = pci_get_drvdata(pcidev); + pcr = handle->pcr; + + mutex_lock(&pcr->pcr_mutex); + + pci_set_power_state(pcidev, PCI_D0); + pci_restore_state(pcidev); + ret = pci_enable_device(pcidev); + if (ret) + goto out; + pci_set_master(pcidev); + + ret = rtsx_pci_write_register(pcr, HOST_SLEEP_STATE, 0x03, 0x00); + if (ret) + goto out; + + ret = rtsx_pci_init_hw(pcr); + if (ret) + goto out; + + schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200)); + + out: + mutex_unlock(&pcr->pcr_mutex); + return ret; + } + + static void rtsx_pci_shutdown(struct pci_dev *pcidev) + { + struct pcr_handle *handle; + struct rtsx_pcr *pcr; + + dev_dbg(&(pcidev->dev), "--> %s\n", __func__); + + handle = pci_get_drvdata(pcidev); + pcr = handle->pcr; + rtsx_pci_power_off(pcr, HOST_ENTER_S1); + + pci_disable_device(pcidev); ++ free_irq(pcr->irq, (void *)pcr); ++ if (pcr->msi_en) ++ pci_disable_msi(pcr->pci); + } + + #else /* CONFIG_PM */ + + #define rtsx_pci_suspend NULL + #define rtsx_pci_resume NULL + #define rtsx_pci_shutdown NULL + + #endif /* CONFIG_PM */ + + static struct pci_driver rtsx_pci_driver = { + .name = DRV_NAME_RTSX_PCI, + .id_table = rtsx_pci_ids, + .probe = rtsx_pci_probe, + .remove = rtsx_pci_remove, + .suspend = rtsx_pci_suspend, + .resume = rtsx_pci_resume, + .shutdown = rtsx_pci_shutdown, + }; + module_pci_driver(rtsx_pci_driver); + + MODULE_LICENSE("GPL"); + MODULE_AUTHOR("Wei WANG "); + MODULE_DESCRIPTION("Realtek PCI-E Card Reader Driver"); diff --cc include/linux/rtsx_pci.h index 000000000000,a44670e1c537..478acf6efac6 mode 000000,100644..100644 --- a/include/linux/rtsx_pci.h +++ b/include/linux/rtsx_pci.h @@@ -1,0 -1,1367 +1,1367 @@@ + /* Driver for Realtek PCI-Express card reader + * + * Copyright(c) 2009-2013 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 . + * + * Author: + * Wei WANG + */ + + #ifndef __RTSX_PCI_H + #define __RTSX_PCI_H + + #include + #include + #include + + #define MAX_RW_REG_CNT 1024 + + #define RTSX_HCBAR 0x00 + #define RTSX_HCBCTLR 0x04 + #define STOP_CMD (0x01 << 28) + #define READ_REG_CMD 0 + #define WRITE_REG_CMD 1 + #define CHECK_REG_CMD 2 + + #define RTSX_HDBAR 0x08 + #define SG_INT 0x04 + #define SG_END 0x02 + #define SG_VALID 0x01 + #define SG_NO_OP 0x00 + #define SG_TRANS_DATA (0x02 << 4) + #define SG_LINK_DESC (0x03 << 4) + #define RTSX_HDBCTLR 0x0C + #define SDMA_MODE 0x00 + #define ADMA_MODE (0x02 << 26) + #define STOP_DMA (0x01 << 28) + #define TRIG_DMA (0x01 << 31) + + #define RTSX_HAIMR 0x10 + #define HAIMR_TRANS_START (0x01 << 31) + #define HAIMR_READ 0x00 + #define HAIMR_WRITE (0x01 << 30) + #define HAIMR_READ_START (HAIMR_TRANS_START | HAIMR_READ) + #define HAIMR_WRITE_START (HAIMR_TRANS_START | HAIMR_WRITE) + #define HAIMR_TRANS_END (HAIMR_TRANS_START) + + #define RTSX_BIPR 0x14 + #define CMD_DONE_INT (1 << 31) + #define DATA_DONE_INT (1 << 30) + #define TRANS_OK_INT (1 << 29) + #define TRANS_FAIL_INT (1 << 28) + #define XD_INT (1 << 27) + #define MS_INT (1 << 26) + #define SD_INT (1 << 25) + #define GPIO0_INT (1 << 24) + #define OC_INT (1 << 23) + #define SD_WRITE_PROTECT (1 << 19) + #define XD_EXIST (1 << 18) + #define MS_EXIST (1 << 17) + #define SD_EXIST (1 << 16) + #define DELINK_INT GPIO0_INT + #define MS_OC_INT (1 << 23) + #define SD_OC_INT (1 << 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) + + #define RTSX_BIER 0x18 + #define CMD_DONE_INT_EN (1 << 31) + #define DATA_DONE_INT_EN (1 << 30) + #define TRANS_OK_INT_EN (1 << 29) + #define TRANS_FAIL_INT_EN (1 << 28) + #define XD_INT_EN (1 << 27) + #define MS_INT_EN (1 << 26) + #define SD_INT_EN (1 << 25) + #define GPIO0_INT_EN (1 << 24) + #define OC_INT_EN (1 << 23) + #define DELINK_INT_EN GPIO0_INT_EN + #define MS_OC_INT_EN (1 << 23) + #define SD_OC_INT_EN (1 << 22) + + + /* + * macros for easy use + */ + #define rtsx_pci_writel(pcr, reg, value) \ + iowrite32(value, (pcr)->remap_addr + reg) + #define rtsx_pci_readl(pcr, reg) \ + ioread32((pcr)->remap_addr + reg) + #define rtsx_pci_writew(pcr, reg, value) \ + iowrite16(value, (pcr)->remap_addr + reg) + #define rtsx_pci_readw(pcr, reg) \ + ioread16((pcr)->remap_addr + reg) + #define rtsx_pci_writeb(pcr, reg, value) \ + iowrite8(value, (pcr)->remap_addr + reg) + #define rtsx_pci_readb(pcr, reg) \ + ioread8((pcr)->remap_addr + reg) + + #define rtsx_pci_read_config_byte(pcr, where, val) \ + pci_read_config_byte((pcr)->pci, where, val) + + #define rtsx_pci_write_config_byte(pcr, where, val) \ + pci_write_config_byte((pcr)->pci, where, val) + + #define rtsx_pci_read_config_dword(pcr, where, val) \ + pci_read_config_dword((pcr)->pci, where, val) + + #define rtsx_pci_write_config_dword(pcr, where, val) \ + pci_write_config_dword((pcr)->pci, where, val) + + #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 TRANS_NO_DEVICE 3 + + #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 HOST_SG_TBL_ITEMS (HOST_SG_TBL_BUF_LEN / 8) + #define MAX_SG_ITEM_LEN 0x80000 + #define HOST_TO_DEVICE 0 + #define DEVICE_TO_HOST 1 + + #define OUTPUT_3V3 0 + #define OUTPUT_1V8 1 + + #define RTSX_PHASE_MAX 32 + #define RX_TUNING_CNT 3 + + #define MS_CFG 0xFD40 + #define SAMPLE_TIME_RISING 0x00 + #define SAMPLE_TIME_FALLING 0x80 + #define PUSH_TIME_DEFAULT 0x00 + #define PUSH_TIME_ODD 0x40 + #define NO_EXTEND_TOGGLE 0x00 + #define EXTEND_TOGGLE_CHK 0x20 + #define MS_BUS_WIDTH_1 0x00 + #define MS_BUS_WIDTH_4 0x10 + #define MS_BUS_WIDTH_8 0x18 + #define MS_2K_SECTOR_MODE 0x04 + #define MS_512_SECTOR_MODE 0x00 + #define MS_TOGGLE_TIMEOUT_EN 0x00 + #define MS_TOGGLE_TIMEOUT_DISEN 0x01 + #define MS_NO_CHECK_INT 0x02 + #define MS_TPC 0xFD41 + #define MS_TRANS_CFG 0xFD42 + #define WAIT_INT 0x80 + #define NO_WAIT_INT 0x00 + #define NO_AUTO_READ_INT_REG 0x00 + #define AUTO_READ_INT_REG 0x40 + #define MS_CRC16_ERR 0x20 + #define MS_RDY_TIMEOUT 0x10 + #define MS_INT_CMDNK 0x08 + #define MS_INT_BREQ 0x04 + #define MS_INT_ERR 0x02 + #define MS_INT_CED 0x01 + #define MS_TRANSFER 0xFD43 + #define MS_TRANSFER_START 0x80 + #define MS_TRANSFER_END 0x40 + #define MS_TRANSFER_ERR 0x20 + #define MS_BS_STATE 0x10 + #define MS_TM_READ_BYTES 0x00 + #define MS_TM_NORMAL_READ 0x01 + #define MS_TM_WRITE_BYTES 0x04 + #define MS_TM_NORMAL_WRITE 0x05 + #define MS_TM_AUTO_READ 0x08 + #define MS_TM_AUTO_WRITE 0x0C + #define MS_INT_REG 0xFD44 + #define MS_BYTE_CNT 0xFD45 + #define MS_SECTOR_CNT_L 0xFD46 + #define MS_SECTOR_CNT_H 0xFD47 + #define MS_DBUS_H 0xFD48 + + #define SD_CFG1 0xFDA0 + #define SD_CLK_DIVIDE_0 0x00 + #define SD_CLK_DIVIDE_256 0xC0 + #define SD_CLK_DIVIDE_128 0x80 + #define SD_BUS_WIDTH_1BIT 0x00 + #define SD_BUS_WIDTH_4BIT 0x01 + #define SD_BUS_WIDTH_8BIT 0x02 + #define SD_ASYNC_FIFO_NOT_RST 0x10 + #define SD_20_MODE 0x00 + #define SD_DDR_MODE 0x04 + #define SD_30_MODE 0x08 + #define SD_CLK_DIVIDE_MASK 0xC0 + #define SD_MODE_SELECT_MASK 0x0C + #define SD_CFG2 0xFDA1 + #define SD_CALCULATE_CRC7 0x00 + #define SD_NO_CALCULATE_CRC7 0x80 + #define SD_CHECK_CRC16 0x00 + #define SD_NO_CHECK_CRC16 0x40 + #define SD_NO_CHECK_WAIT_CRC_TO 0x20 + #define SD_WAIT_BUSY_END 0x08 + #define SD_NO_WAIT_BUSY_END 0x00 + #define SD_CHECK_CRC7 0x00 + #define SD_NO_CHECK_CRC7 0x04 + #define SD_RSP_LEN_0 0x00 + #define SD_RSP_LEN_6 0x01 + #define SD_RSP_LEN_17 0x02 + #define SD_RSP_TYPE_R0 0x04 + #define SD_RSP_TYPE_R1 0x01 + #define SD_RSP_TYPE_R1b 0x09 + #define SD_RSP_TYPE_R2 0x02 + #define SD_RSP_TYPE_R3 0x05 + #define SD_RSP_TYPE_R4 0x05 + #define SD_RSP_TYPE_R5 0x01 + #define SD_RSP_TYPE_R6 0x01 + #define SD_RSP_TYPE_R7 0x01 + #define SD_CFG3 0xFDA2 + #define SD30_CLK_END_EN 0x10 + #define SD_RSP_80CLK_TIMEOUT_EN 0x01 + + #define SD_STAT1 0xFDA3 + #define SD_CRC7_ERR 0x80 + #define SD_CRC16_ERR 0x40 + #define SD_CRC_WRITE_ERR 0x20 + #define SD_CRC_WRITE_ERR_MASK 0x1C + #define GET_CRC_TIME_OUT 0x02 + #define SD_TUNING_COMPARE_ERR 0x01 + #define SD_STAT2 0xFDA4 + #define SD_RSP_80CLK_TIMEOUT 0x01 + + #define SD_BUS_STAT 0xFDA5 + #define SD_CLK_TOGGLE_EN 0x80 + #define SD_CLK_FORCE_STOP 0x40 + #define SD_DAT3_STATUS 0x10 + #define SD_DAT2_STATUS 0x08 + #define SD_DAT1_STATUS 0x04 + #define SD_DAT0_STATUS 0x02 + #define SD_CMD_STATUS 0x01 + #define SD_PAD_CTL 0xFDA6 + #define SD_IO_USING_1V8 0x80 + #define SD_IO_USING_3V3 0x7F + #define TYPE_A_DRIVING 0x00 + #define TYPE_B_DRIVING 0x01 + #define TYPE_C_DRIVING 0x02 + #define TYPE_D_DRIVING 0x03 + #define SD_SAMPLE_POINT_CTL 0xFDA7 + #define DDR_FIX_RX_DAT 0x00 + #define DDR_VAR_RX_DAT 0x80 + #define DDR_FIX_RX_DAT_EDGE 0x00 + #define DDR_FIX_RX_DAT_14_DELAY 0x40 + #define DDR_FIX_RX_CMD 0x00 + #define DDR_VAR_RX_CMD 0x20 + #define DDR_FIX_RX_CMD_POS_EDGE 0x00 + #define DDR_FIX_RX_CMD_14_DELAY 0x10 + #define SD20_RX_POS_EDGE 0x00 + #define SD20_RX_14_DELAY 0x08 + #define SD20_RX_SEL_MASK 0x08 + #define SD_PUSH_POINT_CTL 0xFDA8 + #define DDR_FIX_TX_CMD_DAT 0x00 + #define DDR_VAR_TX_CMD_DAT 0x80 + #define DDR_FIX_TX_DAT_14_TSU 0x00 + #define DDR_FIX_TX_DAT_12_TSU 0x40 + #define DDR_FIX_TX_CMD_NEG_EDGE 0x00 + #define DDR_FIX_TX_CMD_14_AHEAD 0x20 + #define SD20_TX_NEG_EDGE 0x00 + #define SD20_TX_14_AHEAD 0x10 + #define SD20_TX_SEL_MASK 0x10 + #define DDR_VAR_SDCLK_POL_SWAP 0x01 + #define SD_CMD0 0xFDA9 + #define SD_CMD_START 0x40 + #define SD_CMD1 0xFDAA + #define SD_CMD2 0xFDAB + #define SD_CMD3 0xFDAC + #define SD_CMD4 0xFDAD + #define SD_CMD5 0xFDAE + #define SD_BYTE_CNT_L 0xFDAF + #define SD_BYTE_CNT_H 0xFDB0 + #define SD_BLOCK_CNT_L 0xFDB1 + #define SD_BLOCK_CNT_H 0xFDB2 + #define SD_TRANSFER 0xFDB3 + #define SD_TRANSFER_START 0x80 + #define SD_TRANSFER_END 0x40 + #define SD_STAT_IDLE 0x20 + #define SD_TRANSFER_ERR 0x10 + #define SD_TM_NORMAL_WRITE 0x00 + #define SD_TM_AUTO_WRITE_3 0x01 + #define SD_TM_AUTO_WRITE_4 0x02 + #define SD_TM_AUTO_READ_3 0x05 + #define SD_TM_AUTO_READ_4 0x06 + #define SD_TM_CMD_RSP 0x08 + #define SD_TM_AUTO_WRITE_1 0x09 + #define SD_TM_AUTO_WRITE_2 0x0A + #define SD_TM_NORMAL_READ 0x0C + #define SD_TM_AUTO_READ_1 0x0D + #define SD_TM_AUTO_READ_2 0x0E + #define SD_TM_AUTO_TUNING 0x0F + #define SD_CMD_STATE 0xFDB5 + #define SD_CMD_IDLE 0x80 + + #define SD_DATA_STATE 0xFDB6 + #define SD_DATA_IDLE 0x80 + #define REG_SD_STOP_SDCLK_CFG 0xFDB8 + #define SD30_CLK_STOP_CFG_EN 0x04 + #define SD30_CLK_STOP_CFG1 0x02 + #define SD30_CLK_STOP_CFG0 0x01 + #define REG_PRE_RW_MODE 0xFD70 + #define EN_INFINITE_MODE 0x01 + + #define SRCTL 0xFC13 + + #define DCM_DRP_CTL 0xFC23 + #define DCM_RESET 0x08 + #define DCM_LOCKED 0x04 + #define DCM_208M 0x00 + #define DCM_TX 0x01 + #define DCM_RX 0x02 + #define DCM_DRP_TRIG 0xFC24 + #define DRP_START 0x80 + #define DRP_DONE 0x40 + #define DCM_DRP_CFG 0xFC25 + #define DRP_WRITE 0x80 + #define DRP_READ 0x00 + #define DCM_WRITE_ADDRESS_50 0x50 + #define DCM_WRITE_ADDRESS_51 0x51 + #define DCM_READ_ADDRESS_00 0x00 + #define DCM_READ_ADDRESS_51 0x51 + #define DCM_DRP_WR_DATA_L 0xFC26 + #define DCM_DRP_WR_DATA_H 0xFC27 + #define DCM_DRP_RD_DATA_L 0xFC28 + #define DCM_DRP_RD_DATA_H 0xFC29 + #define SD_VPCLK0_CTL 0xFC2A + #define SD_VPCLK1_CTL 0xFC2B + #define PHASE_SELECT_MASK 0x1F + #define SD_DCMPS0_CTL 0xFC2C + #define SD_DCMPS1_CTL 0xFC2D + #define SD_VPTX_CTL SD_VPCLK0_CTL + #define SD_VPRX_CTL SD_VPCLK1_CTL + #define PHASE_CHANGE 0x80 + #define PHASE_NOT_RESET 0x40 + #define SD_DCMPS_TX_CTL SD_DCMPS0_CTL + #define SD_DCMPS_RX_CTL SD_DCMPS1_CTL + #define DCMPS_CHANGE 0x80 + #define DCMPS_CHANGE_DONE 0x40 + #define DCMPS_ERROR 0x20 + #define DCMPS_CURRENT_PHASE 0x1F + #define CARD_CLK_SOURCE 0xFC2E + #define CRC_FIX_CLK (0x00 << 0) + #define CRC_VAR_CLK0 (0x01 << 0) + #define CRC_VAR_CLK1 (0x02 << 0) + #define SD30_FIX_CLK (0x00 << 2) + #define SD30_VAR_CLK0 (0x01 << 2) + #define SD30_VAR_CLK1 (0x02 << 2) + #define SAMPLE_FIX_CLK (0x00 << 4) + #define SAMPLE_VAR_CLK0 (0x01 << 4) + #define SAMPLE_VAR_CLK1 (0x02 << 4) + #define CARD_PWR_CTL 0xFD50 + #define PMOS_STRG_MASK 0x10 + #define PMOS_STRG_800mA 0x10 + #define PMOS_STRG_400mA 0x00 + #define SD_POWER_OFF 0x03 + #define SD_PARTIAL_POWER_ON 0x01 + #define SD_POWER_ON 0x00 + #define SD_POWER_MASK 0x03 + #define MS_POWER_OFF 0x0C + #define MS_PARTIAL_POWER_ON 0x04 + #define MS_POWER_ON 0x00 + #define MS_POWER_MASK 0x0C + #define BPP_POWER_OFF 0x0F + #define BPP_POWER_5_PERCENT_ON 0x0E + #define BPP_POWER_10_PERCENT_ON 0x0C + #define BPP_POWER_15_PERCENT_ON 0x08 + #define BPP_POWER_ON 0x00 + #define BPP_POWER_MASK 0x0F + #define SD_VCC_PARTIAL_POWER_ON 0x02 + #define SD_VCC_POWER_ON 0x00 + #define CARD_CLK_SWITCH 0xFD51 + #define RTL8411B_PACKAGE_MODE 0xFD51 + #define CARD_SHARE_MODE 0xFD52 + #define CARD_SHARE_MASK 0x0F + #define CARD_SHARE_MULTI_LUN 0x00 + #define CARD_SHARE_NORMAL 0x00 + #define CARD_SHARE_48_SD 0x04 + #define CARD_SHARE_48_MS 0x08 + #define CARD_SHARE_BAROSSA_SD 0x01 + #define CARD_SHARE_BAROSSA_MS 0x02 + #define CARD_DRIVE_SEL 0xFD53 + #define MS_DRIVE_8mA (0x01 << 6) + #define MMC_DRIVE_8mA (0x01 << 4) + #define XD_DRIVE_8mA (0x01 << 2) + #define GPIO_DRIVE_8mA 0x01 + #define RTS5209_CARD_DRIVE_DEFAULT (MS_DRIVE_8mA | MMC_DRIVE_8mA |\ + XD_DRIVE_8mA | GPIO_DRIVE_8mA) + #define RTL8411_CARD_DRIVE_DEFAULT (MS_DRIVE_8mA | MMC_DRIVE_8mA |\ + XD_DRIVE_8mA) + #define RTSX_CARD_DRIVE_DEFAULT (MS_DRIVE_8mA | GPIO_DRIVE_8mA) + + #define CARD_STOP 0xFD54 + #define SPI_STOP 0x01 + #define XD_STOP 0x02 + #define SD_STOP 0x04 + #define MS_STOP 0x08 + #define SPI_CLR_ERR 0x10 + #define XD_CLR_ERR 0x20 + #define SD_CLR_ERR 0x40 + #define MS_CLR_ERR 0x80 + #define CARD_OE 0xFD55 + #define SD_OUTPUT_EN 0x04 + #define MS_OUTPUT_EN 0x08 + #define CARD_AUTO_BLINK 0xFD56 + #define CARD_GPIO_DIR 0xFD57 + #define CARD_GPIO 0xFD58 + #define CARD_DATA_SOURCE 0xFD5B + #define PINGPONG_BUFFER 0x01 + #define RING_BUFFER 0x00 + #define SD30_CLK_DRIVE_SEL 0xFD5A + #define DRIVER_TYPE_A 0x05 + #define DRIVER_TYPE_B 0x03 + #define DRIVER_TYPE_C 0x02 + #define DRIVER_TYPE_D 0x01 + #define CARD_SELECT 0xFD5C + #define SD_MOD_SEL 2 + #define MS_MOD_SEL 3 + #define SD30_DRIVE_SEL 0xFD5E + #define CFG_DRIVER_TYPE_A 0x02 + #define CFG_DRIVER_TYPE_B 0x03 + #define CFG_DRIVER_TYPE_C 0x01 + #define CFG_DRIVER_TYPE_D 0x00 + #define SD30_CMD_DRIVE_SEL 0xFD5E + #define SD30_DAT_DRIVE_SEL 0xFD5F + #define CARD_CLK_EN 0xFD69 + #define SD_CLK_EN 0x04 + #define MS_CLK_EN 0x08 + #define SD40_CLK_EN 0x10 + #define SDIO_CTRL 0xFD6B + #define CD_PAD_CTL 0xFD73 + #define CD_DISABLE_MASK 0x07 + #define MS_CD_DISABLE 0x04 + #define SD_CD_DISABLE 0x02 + #define XD_CD_DISABLE 0x01 + #define CD_DISABLE 0x07 + #define CD_ENABLE 0x00 + #define MS_CD_EN_ONLY 0x03 + #define SD_CD_EN_ONLY 0x05 + #define XD_CD_EN_ONLY 0x06 + #define FORCE_CD_LOW_MASK 0x38 + #define FORCE_CD_XD_LOW 0x08 + #define FORCE_CD_SD_LOW 0x10 + #define FORCE_CD_MS_LOW 0x20 + #define CD_AUTO_DISABLE 0x40 + #define FPDCTL 0xFC00 + #define SSC_POWER_DOWN 0x01 + #define SD_OC_POWER_DOWN 0x02 + #define ALL_POWER_DOWN 0x03 + #define OC_POWER_DOWN 0x02 + #define PDINFO 0xFC01 + + #define CLK_CTL 0xFC02 + #define CHANGE_CLK 0x01 + #define CLK_LOW_FREQ 0x01 + + #define CLK_DIV 0xFC03 + #define CLK_DIV_1 0x01 + #define CLK_DIV_2 0x02 + #define CLK_DIV_4 0x03 + #define CLK_DIV_8 0x04 + #define CLK_SEL 0xFC04 + + #define SSC_DIV_N_0 0xFC0F + #define SSC_DIV_N_1 0xFC10 + #define SSC_CTL1 0xFC11 + #define SSC_RSTB 0x80 + #define SSC_8X_EN 0x40 + #define SSC_FIX_FRAC 0x20 + #define SSC_SEL_1M 0x00 + #define SSC_SEL_2M 0x08 + #define SSC_SEL_4M 0x10 + #define SSC_SEL_8M 0x18 + #define SSC_CTL2 0xFC12 + #define SSC_DEPTH_MASK 0x07 + #define SSC_DEPTH_DISALBE 0x00 + #define SSC_DEPTH_4M 0x01 + #define SSC_DEPTH_2M 0x02 + #define SSC_DEPTH_1M 0x03 + #define SSC_DEPTH_500K 0x04 + #define SSC_DEPTH_250K 0x05 + #define RCCTL 0xFC14 + + #define FPGA_PULL_CTL 0xFC1D + #define OLT_LED_CTL 0xFC1E + #define LED_SHINE_MASK 0x08 + #define LED_SHINE_EN 0x08 + #define LED_SHINE_DISABLE 0x00 + #define GPIO_CTL 0xFC1F + + #define LDO_CTL 0xFC1E + #define BPP_ASIC_1V7 0x00 + #define BPP_ASIC_1V8 0x01 + #define BPP_ASIC_1V9 0x02 + #define BPP_ASIC_2V0 0x03 + #define BPP_ASIC_2V7 0x04 + #define BPP_ASIC_2V8 0x05 + #define BPP_ASIC_3V2 0x06 + #define BPP_ASIC_3V3 0x07 + #define BPP_REG_TUNED18 0x07 + #define BPP_TUNED18_SHIFT_8402 5 + #define BPP_TUNED18_SHIFT_8411 4 + #define BPP_PAD_MASK 0x04 + #define BPP_PAD_3V3 0x04 + #define BPP_PAD_1V8 0x00 + #define BPP_LDO_POWB 0x03 + #define BPP_LDO_ON 0x00 + #define BPP_LDO_SUSPEND 0x02 + #define BPP_LDO_OFF 0x03 + #define EFUSE_CTL 0xFC30 + #define EFUSE_ADD 0xFC31 + #define SYS_VER 0xFC32 + #define EFUSE_DATAL 0xFC34 + #define EFUSE_DATAH 0xFC35 + + #define CARD_PULL_CTL1 0xFD60 + #define CARD_PULL_CTL2 0xFD61 + #define CARD_PULL_CTL3 0xFD62 + #define CARD_PULL_CTL4 0xFD63 + #define CARD_PULL_CTL5 0xFD64 + #define CARD_PULL_CTL6 0xFD65 + + /* PCI Express Related Registers */ + #define IRQEN0 0xFE20 + #define IRQSTAT0 0xFE21 + #define DMA_DONE_INT 0x80 + #define SUSPEND_INT 0x40 + #define LINK_RDY_INT 0x20 + #define LINK_DOWN_INT 0x10 + #define IRQEN1 0xFE22 + #define IRQSTAT1 0xFE23 + #define TLPRIEN 0xFE24 + #define TLPRISTAT 0xFE25 + #define TLPTIEN 0xFE26 + #define TLPTISTAT 0xFE27 + #define DMATC0 0xFE28 + #define DMATC1 0xFE29 + #define DMATC2 0xFE2A + #define DMATC3 0xFE2B + #define DMACTL 0xFE2C + #define DMA_RST 0x80 + #define DMA_BUSY 0x04 + #define DMA_DIR_TO_CARD 0x00 + #define DMA_DIR_FROM_CARD 0x02 + #define DMA_EN 0x01 + #define DMA_128 (0 << 4) + #define DMA_256 (1 << 4) + #define DMA_512 (2 << 4) + #define DMA_1024 (3 << 4) + #define DMA_PACK_SIZE_MASK 0x30 + #define BCTL 0xFE2D + #define RBBC0 0xFE2E + #define RBBC1 0xFE2F + #define RBDAT 0xFE30 + #define RBCTL 0xFE34 + #define U_AUTO_DMA_EN_MASK 0x20 + #define U_AUTO_DMA_DISABLE 0x00 + #define RB_FLUSH 0x80 + #define CFGADDR0 0xFE35 + #define CFGADDR1 0xFE36 + #define CFGDATA0 0xFE37 + #define CFGDATA1 0xFE38 + #define CFGDATA2 0xFE39 + #define CFGDATA3 0xFE3A + #define CFGRWCTL 0xFE3B + #define PHYRWCTL 0xFE3C + #define PHYDATA0 0xFE3D + #define PHYDATA1 0xFE3E + #define PHYADDR 0xFE3F + #define MSGRXDATA0 0xFE40 + #define MSGRXDATA1 0xFE41 + #define MSGRXDATA2 0xFE42 + #define MSGRXDATA3 0xFE43 + #define MSGTXDATA0 0xFE44 + #define MSGTXDATA1 0xFE45 + #define MSGTXDATA2 0xFE46 + #define MSGTXDATA3 0xFE47 + #define MSGTXCTL 0xFE48 + #define LTR_CTL 0xFE4A + #define LTR_TX_EN_MASK BIT(7) + #define LTR_TX_EN_1 BIT(7) + #define LTR_TX_EN_0 0 + #define LTR_LATENCY_MODE_MASK BIT(6) + #define LTR_LATENCY_MODE_HW 0 + #define LTR_LATENCY_MODE_SW BIT(6) + #define OBFF_CFG 0xFE4C + #define OBFF_EN_MASK 0x03 + #define OBFF_DISABLE 0x00 + + #define CDRESUMECTL 0xFE52 + #define WAKE_SEL_CTL 0xFE54 + #define PCLK_CTL 0xFE55 + #define PCLK_MODE_SEL 0x20 + #define PME_FORCE_CTL 0xFE56 + + #define ASPM_FORCE_CTL 0xFE57 + #define FORCE_ASPM_CTL0 0x10 + #define FORCE_ASPM_VAL_MASK 0x03 + #define FORCE_ASPM_L1_EN 0x02 + #define FORCE_ASPM_L0_EN 0x01 + #define FORCE_ASPM_NO_ASPM 0x00 + #define PM_CLK_FORCE_CTL 0xFE58 + #define CLK_PM_EN 0x01 + #define FUNC_FORCE_CTL 0xFE59 + #define FUNC_FORCE_UPME_XMT_DBG 0x02 + #define PERST_GLITCH_WIDTH 0xFE5C + #define CHANGE_LINK_STATE 0xFE5B + #define RESET_LOAD_REG 0xFE5E + #define EFUSE_CONTENT 0xFE5F + #define HOST_SLEEP_STATE 0xFE60 + #define HOST_ENTER_S1 1 + #define HOST_ENTER_S3 2 + + #define SDIO_CFG 0xFE70 + #define PM_EVENT_DEBUG 0xFE71 + #define PME_DEBUG_0 0x08 + #define NFTS_TX_CTRL 0xFE72 + + #define PWR_GATE_CTRL 0xFE75 + #define PWR_GATE_EN 0x01 + #define LDO3318_PWR_MASK 0x06 + #define LDO_ON 0x00 + #define LDO_SUSPEND 0x04 + #define LDO_OFF 0x06 + #define PWD_SUSPEND_EN 0xFE76 + #define LDO_PWR_SEL 0xFE78 + + #define L1SUB_CONFIG1 0xFE8D + #define AUX_CLK_ACTIVE_SEL_MASK 0x01 + #define MAC_CKSW_DONE 0x00 + #define L1SUB_CONFIG2 0xFE8E + #define L1SUB_AUTO_CFG 0x02 + #define L1SUB_CONFIG3 0xFE8F + #define L1OFF_MBIAS2_EN_5250 BIT(7) + + #define DUMMY_REG_RESET_0 0xFE90 + #define IC_VERSION_MASK 0x0F + + #define REG_VREF 0xFE97 + #define PWD_SUSPND_EN 0x10 + #define RTS5260_DMA_RST_CTL_0 0xFEBF + #define RTS5260_DMA_RST 0x80 + #define RTS5260_ADMA3_RST 0x40 + #define AUTOLOAD_CFG_BASE 0xFF00 + #define RELINK_TIME_MASK 0x01 + #define PETXCFG 0xFF03 + #define FORCE_CLKREQ_DELINK_MASK BIT(7) + #define FORCE_CLKREQ_LOW 0x80 + #define FORCE_CLKREQ_HIGH 0x00 + + #define PM_CTRL1 0xFF44 + #define CD_RESUME_EN_MASK 0xF0 + + #define PM_CTRL2 0xFF45 + #define PM_CTRL3 0xFF46 + #define SDIO_SEND_PME_EN 0x80 + #define FORCE_RC_MODE_ON 0x40 + #define FORCE_RX50_LINK_ON 0x20 + #define D3_DELINK_MODE_EN 0x10 + #define USE_PESRTB_CTL_DELINK 0x08 + #define DELAY_PIN_WAKE 0x04 + #define RESET_PIN_WAKE 0x02 + #define PM_WAKE_EN 0x01 + #define PM_CTRL4 0xFF47 + + /* Memory mapping */ + #define SRAM_BASE 0xE600 + #define RBUF_BASE 0xF400 + #define PPBUF_BASE1 0xF800 + #define PPBUF_BASE2 0xFA00 + #define IMAGE_FLAG_ADDR0 0xCE80 + #define IMAGE_FLAG_ADDR1 0xCE81 + + #define RREF_CFG 0xFF6C + #define RREF_VBGSEL_MASK 0x38 + #define RREF_VBGSEL_1V25 0x28 + + #define OOBS_CONFIG 0xFF6E + #define OOBS_AUTOK_DIS 0x80 + #define OOBS_VAL_MASK 0x1F + + #define LDO_DV18_CFG 0xFF70 + #define LDO_DV18_SR_MASK 0xC0 + #define LDO_DV18_SR_DF 0x40 + #define DV331812_MASK 0x70 + #define DV331812_33 0x70 + #define DV331812_17 0x30 + + #define LDO_CONFIG2 0xFF71 + #define LDO_D3318_MASK 0x07 + #define LDO_D3318_33V 0x07 + #define LDO_D3318_18V 0x02 + #define DV331812_VDD1 0x04 + #define DV331812_POWERON 0x08 + #define DV331812_POWEROFF 0x00 + + #define LDO_VCC_CFG0 0xFF72 + #define LDO_VCC_LMTVTH_MASK 0x30 + #define LDO_VCC_LMTVTH_2A 0x10 + /*RTS5260*/ + #define RTS5260_DVCC_TUNE_MASK 0x70 + #define RTS5260_DVCC_33 0x70 + + #define LDO_VCC_CFG1 0xFF73 + #define LDO_VCC_REF_TUNE_MASK 0x30 + #define LDO_VCC_REF_1V2 0x20 + #define LDO_VCC_TUNE_MASK 0x07 + #define LDO_VCC_1V8 0x04 + #define LDO_VCC_3V3 0x07 + #define LDO_VCC_LMT_EN 0x08 + /*RTS5260*/ + #define LDO_POW_SDVDD1_MASK 0x08 + #define LDO_POW_SDVDD1_ON 0x08 + #define LDO_POW_SDVDD1_OFF 0x00 + + #define LDO_VIO_CFG 0xFF75 + #define LDO_VIO_SR_MASK 0xC0 + #define LDO_VIO_SR_DF 0x40 + #define LDO_VIO_REF_TUNE_MASK 0x30 + #define LDO_VIO_REF_1V2 0x20 + #define LDO_VIO_TUNE_MASK 0x07 + #define LDO_VIO_1V7 0x03 + #define LDO_VIO_1V8 0x04 + #define LDO_VIO_3V3 0x07 + + #define LDO_DV12S_CFG 0xFF76 + #define LDO_REF12_TUNE_MASK 0x18 + #define LDO_REF12_TUNE_DF 0x10 + #define LDO_D12_TUNE_MASK 0x07 + #define LDO_D12_TUNE_DF 0x04 + + #define LDO_AV12S_CFG 0xFF77 + #define LDO_AV12S_TUNE_MASK 0x07 + #define LDO_AV12S_TUNE_DF 0x04 + + #define SD40_LDO_CTL1 0xFE7D + #define SD40_VIO_TUNE_MASK 0x70 + #define SD40_VIO_TUNE_1V7 0x30 + #define SD_VIO_LDO_1V8 0x40 + #define SD_VIO_LDO_3V3 0x70 + + #define RTS5260_AUTOLOAD_CFG4 0xFF7F + #define RTS5260_MIMO_DISABLE 0x8A + + #define RTS5260_REG_GPIO_CTL0 0xFC1A + #define RTS5260_REG_GPIO_MASK 0x01 + #define RTS5260_REG_GPIO_ON 0x01 + #define RTS5260_REG_GPIO_OFF 0x00 + + #define PWR_GLOBAL_CTRL 0xF200 + #define PCIE_L1_2_EN 0x0C + #define PCIE_L1_1_EN 0x0A + #define PCIE_L1_0_EN 0x09 + #define PWR_FE_CTL 0xF201 + #define PCIE_L1_2_PD_FE_EN 0x0C + #define PCIE_L1_1_PD_FE_EN 0x0A + #define PCIE_L1_0_PD_FE_EN 0x09 + #define CFG_PCIE_APHY_OFF_0 0xF204 + #define CFG_PCIE_APHY_OFF_0_DEFAULT 0xBF + #define CFG_PCIE_APHY_OFF_1 0xF205 + #define CFG_PCIE_APHY_OFF_1_DEFAULT 0xFF + #define CFG_PCIE_APHY_OFF_2 0xF206 + #define CFG_PCIE_APHY_OFF_2_DEFAULT 0x01 + #define CFG_PCIE_APHY_OFF_3 0xF207 + #define CFG_PCIE_APHY_OFF_3_DEFAULT 0x00 + #define CFG_L1_0_PCIE_MAC_RET_VALUE 0xF20C + #define CFG_L1_0_PCIE_DPHY_RET_VALUE 0xF20E + #define CFG_L1_0_SYS_RET_VALUE 0xF210 + #define CFG_L1_0_CRC_MISC_RET_VALUE 0xF212 + #define CFG_L1_0_CRC_SD30_RET_VALUE 0xF214 + #define CFG_L1_0_CRC_SD40_RET_VALUE 0xF216 + #define CFG_LP_FPWM_VALUE 0xF219 + #define CFG_LP_FPWM_VALUE_DEFAULT 0x18 + #define PWC_CDR 0xF253 + #define PWC_CDR_DEFAULT 0x03 + #define CFG_L1_0_RET_VALUE_DEFAULT 0x1B + #define CFG_L1_0_CRC_MISC_RET_VALUE_DEFAULT 0x0C + + /* OCPCTL */ + #define SD_DETECT_EN 0x08 + #define SD_OCP_INT_EN 0x04 + #define SD_OCP_INT_CLR 0x02 + #define SD_OC_CLR 0x01 + + #define SDVIO_DETECT_EN (1 << 7) + #define SDVIO_OCP_INT_EN (1 << 6) + #define SDVIO_OCP_INT_CLR (1 << 5) + #define SDVIO_OC_CLR (1 << 4) + + /* OCPSTAT */ + #define SD_OCP_DETECT 0x08 + #define SD_OC_NOW 0x04 + #define SD_OC_EVER 0x02 + + #define SDVIO_OC_NOW (1 << 6) + #define SDVIO_OC_EVER (1 << 5) + + #define REG_OCPCTL 0xFD6A + #define REG_OCPSTAT 0xFD6E + #define REG_OCPGLITCH 0xFD6C + #define REG_OCPPARA1 0xFD6B + #define REG_OCPPARA2 0xFD6D + + /* rts5260 DV3318 OCP-related registers */ + #define REG_DV3318_OCPCTL 0xFD89 + #define DV3318_OCP_TIME_MASK 0xF0 + #define DV3318_DETECT_EN 0x08 + #define DV3318_OCP_INT_EN 0x04 + #define DV3318_OCP_INT_CLR 0x02 + #define DV3318_OCP_CLR 0x01 + + #define REG_DV3318_OCPSTAT 0xFD8A + #define DV3318_OCP_GlITCH_TIME_MASK 0xF0 + #define DV3318_OCP_DETECT 0x08 + #define DV3318_OCP_NOW 0x04 + #define DV3318_OCP_EVER 0x02 + + #define SD_OCP_GLITCH_MASK 0x0F + + /* OCPPARA1 */ + #define SDVIO_OCP_TIME_60 0x00 + #define SDVIO_OCP_TIME_100 0x10 + #define SDVIO_OCP_TIME_200 0x20 + #define SDVIO_OCP_TIME_400 0x30 + #define SDVIO_OCP_TIME_600 0x40 + #define SDVIO_OCP_TIME_800 0x50 + #define SDVIO_OCP_TIME_1100 0x60 + #define SDVIO_OCP_TIME_MASK 0x70 + + #define SD_OCP_TIME_60 0x00 + #define SD_OCP_TIME_100 0x01 + #define SD_OCP_TIME_200 0x02 + #define SD_OCP_TIME_400 0x03 + #define SD_OCP_TIME_600 0x04 + #define SD_OCP_TIME_800 0x05 + #define SD_OCP_TIME_1100 0x06 + #define SD_OCP_TIME_MASK 0x07 + + /* OCPPARA2 */ + #define SDVIO_OCP_THD_190 0x00 + #define SDVIO_OCP_THD_250 0x10 + #define SDVIO_OCP_THD_320 0x20 + #define SDVIO_OCP_THD_380 0x30 + #define SDVIO_OCP_THD_440 0x40 + #define SDVIO_OCP_THD_500 0x50 + #define SDVIO_OCP_THD_570 0x60 + #define SDVIO_OCP_THD_630 0x70 + #define SDVIO_OCP_THD_MASK 0x70 + + #define SD_OCP_THD_450 0x00 + #define SD_OCP_THD_550 0x01 + #define SD_OCP_THD_650 0x02 + #define SD_OCP_THD_750 0x03 + #define SD_OCP_THD_850 0x04 + #define SD_OCP_THD_950 0x05 + #define SD_OCP_THD_1050 0x06 + #define SD_OCP_THD_1150 0x07 + #define SD_OCP_THD_MASK 0x07 + + #define SDVIO_OCP_GLITCH_MASK 0xF0 + #define SDVIO_OCP_GLITCH_NONE 0x00 + #define SDVIO_OCP_GLITCH_50U 0x10 + #define SDVIO_OCP_GLITCH_100U 0x20 + #define SDVIO_OCP_GLITCH_200U 0x30 + #define SDVIO_OCP_GLITCH_600U 0x40 + #define SDVIO_OCP_GLITCH_800U 0x50 + #define SDVIO_OCP_GLITCH_1M 0x60 + #define SDVIO_OCP_GLITCH_2M 0x70 + #define SDVIO_OCP_GLITCH_3M 0x80 + #define SDVIO_OCP_GLITCH_4M 0x90 + #define SDVIO_OCP_GLIVCH_5M 0xA0 + #define SDVIO_OCP_GLITCH_6M 0xB0 + #define SDVIO_OCP_GLITCH_7M 0xC0 + #define SDVIO_OCP_GLITCH_8M 0xD0 + #define SDVIO_OCP_GLITCH_9M 0xE0 + #define SDVIO_OCP_GLITCH_10M 0xF0 + + #define SD_OCP_GLITCH_MASK 0x0F + #define SD_OCP_GLITCH_NONE 0x00 + #define SD_OCP_GLITCH_50U 0x01 + #define SD_OCP_GLITCH_100U 0x02 + #define SD_OCP_GLITCH_200U 0x03 + #define SD_OCP_GLITCH_600U 0x04 + #define SD_OCP_GLITCH_800U 0x05 + #define SD_OCP_GLITCH_1M 0x06 + #define SD_OCP_GLITCH_2M 0x07 + #define SD_OCP_GLITCH_3M 0x08 + #define SD_OCP_GLITCH_4M 0x09 + #define SD_OCP_GLIVCH_5M 0x0A + #define SD_OCP_GLITCH_6M 0x0B + #define SD_OCP_GLITCH_7M 0x0C + #define SD_OCP_GLITCH_8M 0x0D + #define SD_OCP_GLITCH_9M 0x0E + #define SD_OCP_GLITCH_10M 0x0F + + /* Phy register */ + #define PHY_PCR 0x00 + #define PHY_PCR_FORCE_CODE 0xB000 + #define PHY_PCR_OOBS_CALI_50 0x0800 + #define PHY_PCR_OOBS_VCM_08 0x0200 + #define PHY_PCR_OOBS_SEN_90 0x0040 + #define PHY_PCR_RSSI_EN 0x0002 + #define PHY_PCR_RX10K 0x0001 + + #define PHY_RCR0 0x01 + #define PHY_RCR1 0x02 + #define PHY_RCR1_ADP_TIME_4 0x0400 + #define PHY_RCR1_VCO_COARSE 0x001F + #define PHY_RCR1_INIT_27S 0x0A1F + #define PHY_SSCCR2 0x02 + #define PHY_SSCCR2_PLL_NCODE 0x0A00 + #define PHY_SSCCR2_TIME0 0x001C + #define PHY_SSCCR2_TIME2_WIDTH 0x0003 + + #define PHY_RCR2 0x03 + #define PHY_RCR2_EMPHASE_EN 0x8000 + #define PHY_RCR2_NADJR 0x4000 + #define PHY_RCR2_CDR_SR_2 0x0100 + #define PHY_RCR2_FREQSEL_12 0x0040 + #define PHY_RCR2_CDR_SC_12P 0x0010 + #define PHY_RCR2_CALIB_LATE 0x0002 + #define PHY_RCR2_INIT_27S 0xC152 + #define PHY_SSCCR3 0x03 + #define PHY_SSCCR3_STEP_IN 0x2740 + #define PHY_SSCCR3_CHECK_DELAY 0x0008 + #define _PHY_ANA03 0x03 + #define _PHY_ANA03_TIMER_MAX 0x2700 + #define _PHY_ANA03_OOBS_DEB_EN 0x0040 + #define _PHY_CMU_DEBUG_EN 0x0008 + + #define PHY_RTCR 0x04 + #define PHY_RDR 0x05 + #define PHY_RDR_RXDSEL_1_9 0x4000 + #define PHY_SSC_AUTO_PWD 0x0600 + #define PHY_TCR0 0x06 + #define PHY_TCR1 0x07 + #define PHY_TUNE 0x08 + #define PHY_TUNE_TUNEREF_1_0 0x4000 + #define PHY_TUNE_VBGSEL_1252 0x0C00 + #define PHY_TUNE_SDBUS_33 0x0200 + #define PHY_TUNE_TUNED18 0x01C0 + #define PHY_TUNE_TUNED12 0X0020 + #define PHY_TUNE_TUNEA12 0x0004 + #define PHY_TUNE_VOLTAGE_MASK 0xFC3F + #define PHY_TUNE_VOLTAGE_3V3 0x03C0 + #define PHY_TUNE_D18_1V8 0x0100 + #define PHY_TUNE_D18_1V7 0x0080 + #define PHY_ANA08 0x08 + #define PHY_ANA08_RX_EQ_DCGAIN 0x5000 + #define PHY_ANA08_SEL_RX_EN 0x0400 + #define PHY_ANA08_RX_EQ_VAL 0x03C0 + #define PHY_ANA08_SCP 0x0020 + #define PHY_ANA08_SEL_IPI 0x0004 + + #define PHY_IMR 0x09 + #define PHY_BPCR 0x0A + #define PHY_BPCR_IBRXSEL 0x0400 + #define PHY_BPCR_IBTXSEL 0x0100 + #define PHY_BPCR_IB_FILTER 0x0080 + #define PHY_BPCR_CMIRROR_EN 0x0040 + + #define PHY_BIST 0x0B + #define PHY_RAW_L 0x0C + #define PHY_RAW_H 0x0D + #define PHY_RAW_DATA 0x0E + #define PHY_HOST_CLK_CTRL 0x0F + #define PHY_DMR 0x10 + #define PHY_BACR 0x11 + #define PHY_BACR_BASIC_MASK 0xFFF3 + #define PHY_IER 0x12 + #define PHY_BCSR 0x13 + #define PHY_BPR 0x14 + #define PHY_BPNR2 0x15 + #define PHY_BPNR 0x16 + #define PHY_BRNR2 0x17 + #define PHY_BENR 0x18 + #define PHY_REV 0x19 + #define PHY_REV_RESV 0xE000 + #define PHY_REV_RXIDLE_LATCHED 0x1000 + #define PHY_REV_P1_EN 0x0800 + #define PHY_REV_RXIDLE_EN 0x0400 + #define PHY_REV_CLKREQ_TX_EN 0x0200 + #define PHY_REV_CLKREQ_RX_EN 0x0100 + #define PHY_REV_CLKREQ_DT_1_0 0x0040 + #define PHY_REV_STOP_CLKRD 0x0020 + #define PHY_REV_RX_PWST 0x0008 + #define PHY_REV_STOP_CLKWR 0x0004 + #define _PHY_REV0 0x19 + #define _PHY_REV0_FILTER_OUT 0x3800 + #define _PHY_REV0_CDR_BYPASS_PFD 0x0100 + #define _PHY_REV0_CDR_RX_IDLE_BYPASS 0x0002 + + #define PHY_FLD0 0x1A + #define PHY_ANA1A 0x1A + #define PHY_ANA1A_TXR_LOOPBACK 0x2000 + #define PHY_ANA1A_RXT_BIST 0x0500 + #define PHY_ANA1A_TXR_BIST 0x0040 + #define PHY_ANA1A_REV 0x0006 + #define PHY_FLD0_INIT_27S 0x2546 + #define PHY_FLD1 0x1B + #define PHY_FLD2 0x1C + #define PHY_FLD3 0x1D + #define PHY_FLD3_TIMER_4 0x0800 + #define PHY_FLD3_TIMER_6 0x0020 + #define PHY_FLD3_RXDELINK 0x0004 + #define PHY_FLD3_INIT_27S 0x0004 + #define PHY_ANA1D 0x1D + #define PHY_ANA1D_DEBUG_ADDR 0x0004 + #define _PHY_FLD0 0x1D + #define _PHY_FLD0_CLK_REQ_20C 0x8000 + #define _PHY_FLD0_RX_IDLE_EN 0x1000 + #define _PHY_FLD0_BIT_ERR_RSTN 0x0800 + #define _PHY_FLD0_BER_COUNT 0x01E0 + #define _PHY_FLD0_BER_TIMER 0x001E + #define _PHY_FLD0_CHECK_EN 0x0001 + + #define PHY_FLD4 0x1E + #define PHY_FLD4_FLDEN_SEL 0x4000 + #define PHY_FLD4_REQ_REF 0x2000 + #define PHY_FLD4_RXAMP_OFF 0x1000 + #define PHY_FLD4_REQ_ADDA 0x0800 + #define PHY_FLD4_BER_COUNT 0x00E0 + #define PHY_FLD4_BER_TIMER 0x000A + #define PHY_FLD4_BER_CHK_EN 0x0001 + #define PHY_FLD4_INIT_27S 0x5C7F + #define PHY_DIG1E 0x1E + #define PHY_DIG1E_REV 0x4000 + #define PHY_DIG1E_D0_X_D1 0x1000 + #define PHY_DIG1E_RX_ON_HOST 0x0800 + #define PHY_DIG1E_RCLK_REF_HOST 0x0400 + #define PHY_DIG1E_RCLK_TX_EN_KEEP 0x0040 + #define PHY_DIG1E_RCLK_TX_TERM_KEEP 0x0020 + #define PHY_DIG1E_RCLK_RX_EIDLE_ON 0x0010 + #define PHY_DIG1E_TX_TERM_KEEP 0x0008 + #define PHY_DIG1E_RX_TERM_KEEP 0x0004 + #define PHY_DIG1E_TX_EN_KEEP 0x0002 + #define PHY_DIG1E_RX_EN_KEEP 0x0001 + #define PHY_DUM_REG 0x1F + + #define PCR_ASPM_SETTING_REG1 0x160 + #define PCR_ASPM_SETTING_REG2 0x168 + #define PCR_ASPM_SETTING_5260 0x178 + + #define PCR_SETTING_REG1 0x724 + #define PCR_SETTING_REG2 0x814 + #define PCR_SETTING_REG3 0x747 + + #define rtsx_pci_init_cmd(pcr) ((pcr)->ci = 0) + + #define RTS5227_DEVICE_ID 0x5227 + #define RTS_MAX_TIMES_FREQ_REDUCTION 8 + + struct rtsx_pcr; + + struct pcr_handle { + struct rtsx_pcr *pcr; + }; + + struct pcr_ops { + int (*write_phy)(struct rtsx_pcr *pcr, u8 addr, u16 val); + int (*read_phy)(struct rtsx_pcr *pcr, u8 addr, u16 *val); + int (*extra_init_hw)(struct rtsx_pcr *pcr); + int (*optimize_phy)(struct rtsx_pcr *pcr); + int (*turn_on_led)(struct rtsx_pcr *pcr); + int (*turn_off_led)(struct rtsx_pcr *pcr); + int (*enable_auto_blink)(struct rtsx_pcr *pcr); + int (*disable_auto_blink)(struct rtsx_pcr *pcr); + int (*card_power_on)(struct rtsx_pcr *pcr, int card); + int (*card_power_off)(struct rtsx_pcr *pcr, int card); + int (*switch_output_voltage)(struct rtsx_pcr *pcr, + u8 voltage); + unsigned int (*cd_deglitch)(struct rtsx_pcr *pcr); + int (*conv_clk_and_div_n)(int clk, int dir); + void (*fetch_vendor_settings)(struct rtsx_pcr *pcr); + void (*force_power_down)(struct rtsx_pcr *pcr, u8 pm_state); + void (*stop_cmd)(struct rtsx_pcr *pcr); + + void (*set_aspm)(struct rtsx_pcr *pcr, bool enable); + int (*set_ltr_latency)(struct rtsx_pcr *pcr, u32 latency); + int (*set_l1off_sub)(struct rtsx_pcr *pcr, u8 val); + void (*set_l1off_cfg_sub_d0)(struct rtsx_pcr *pcr, int active); + void (*full_on)(struct rtsx_pcr *pcr); + void (*power_saving)(struct rtsx_pcr *pcr); + void (*enable_ocp)(struct rtsx_pcr *pcr); + void (*disable_ocp)(struct rtsx_pcr *pcr); + void (*init_ocp)(struct rtsx_pcr *pcr); + void (*process_ocp)(struct rtsx_pcr *pcr); + int (*get_ocpstat)(struct rtsx_pcr *pcr, u8 *val); + void (*clear_ocpstat)(struct rtsx_pcr *pcr); + }; + + enum PDEV_STAT {PDEV_STAT_IDLE, PDEV_STAT_RUN}; + + #define ASPM_L1_1_EN_MASK BIT(3) + #define ASPM_L1_2_EN_MASK BIT(2) + #define PM_L1_1_EN_MASK BIT(1) + #define PM_L1_2_EN_MASK BIT(0) + + #define ASPM_L1_1_EN BIT(0) + #define ASPM_L1_2_EN BIT(1) + #define PM_L1_1_EN BIT(2) + #define PM_L1_2_EN BIT(3) + #define LTR_L1SS_PWR_GATE_EN BIT(4) + #define L1_SNOOZE_TEST_EN BIT(5) + #define LTR_L1SS_PWR_GATE_CHECK_CARD_EN BIT(6) + + enum dev_aspm_mode { - DEV_ASPM_DISABLE = 0, + DEV_ASPM_DYNAMIC, + DEV_ASPM_BACKDOOR, + DEV_ASPM_STATIC, ++ DEV_ASPM_DISABLE, + }; + + /* + * struct rtsx_cr_option - card reader option + * @dev_flags: device flags + * @force_clkreq_0: force clock request + * @ltr_en: enable ltr mode flag + * @ltr_enabled: ltr mode in configure space flag + * @ltr_active: ltr mode status + * @ltr_active_latency: ltr mode active latency + * @ltr_idle_latency: ltr mode idle latency + * @ltr_l1off_latency: ltr mode l1off latency + * @dev_aspm_mode: device aspm mode + * @l1_snooze_delay: l1 snooze delay + * @ltr_l1off_sspwrgate: ltr l1off sspwrgate + * @ltr_l1off_snooze_sspwrgate: ltr l1off snooze sspwrgate + * @ocp_en: enable ocp flag + * @sd_400mA_ocp_thd: 400mA ocp thd + * @sd_800mA_ocp_thd: 800mA ocp thd + */ + struct rtsx_cr_option { + u32 dev_flags; + bool force_clkreq_0; + bool ltr_en; + bool ltr_enabled; + bool ltr_active; + u32 ltr_active_latency; + u32 ltr_idle_latency; + u32 ltr_l1off_latency; + enum dev_aspm_mode dev_aspm_mode; + u32 l1_snooze_delay; + u8 ltr_l1off_sspwrgate; + u8 ltr_l1off_snooze_sspwrgate; + bool ocp_en; + u8 sd_400mA_ocp_thd; + u8 sd_800mA_ocp_thd; + }; + + /* + * struct rtsx_hw_param - card reader hardware param + * @interrupt_en: indicate which interrutp enable + * @ocp_glitch: ocp glitch time + */ + struct rtsx_hw_param { + u32 interrupt_en; + u8 ocp_glitch; + }; + + #define rtsx_set_dev_flag(cr, flag) \ + ((cr)->option.dev_flags |= (flag)) + #define rtsx_clear_dev_flag(cr, flag) \ + ((cr)->option.dev_flags &= ~(flag)) + #define rtsx_check_dev_flag(cr, flag) \ + ((cr)->option.dev_flags & (flag)) + + struct rtsx_pcr { + struct pci_dev *pci; + unsigned int id; + int pcie_cap; + struct rtsx_cr_option option; + struct rtsx_hw_param hw_param; + + /* pci resources */ + unsigned long addr; + void __iomem *remap_addr; + int irq; + + /* host reserved buffer */ + void *rtsx_resv_buf; + dma_addr_t rtsx_resv_buf_addr; + + void *host_cmds_ptr; + dma_addr_t host_cmds_addr; + int ci; + + void *host_sg_tbl_ptr; + dma_addr_t host_sg_tbl_addr; + int sgi; + + u32 bier; + char trans_result; + + unsigned int card_inserted; + unsigned int card_removed; + unsigned int card_exist; + + struct delayed_work carddet_work; + struct delayed_work idle_work; + + spinlock_t lock; + struct mutex pcr_mutex; + struct completion *done; + struct completion *finish_me; + + unsigned int cur_clock; + bool remove_pci; + bool msi_en; + + #define EXTRA_CAPS_SD_SDR50 (1 << 0) + #define EXTRA_CAPS_SD_SDR104 (1 << 1) + #define EXTRA_CAPS_SD_DDR50 (1 << 2) + #define EXTRA_CAPS_MMC_HSDDR (1 << 3) + #define EXTRA_CAPS_MMC_HS200 (1 << 4) + #define EXTRA_CAPS_MMC_8BIT (1 << 5) + u32 extra_caps; + + #define IC_VER_A 0 + #define IC_VER_B 1 + #define IC_VER_C 2 + #define IC_VER_D 3 + u8 ic_version; + + u8 sd30_drive_sel_1v8; + u8 sd30_drive_sel_3v3; + u8 card_drive_sel; + #define ASPM_L1_EN 0x02 + u8 aspm_en; + bool aspm_enabled; + + #define PCR_MS_PMOS (1 << 0) + #define PCR_REVERSE_SOCKET (1 << 1) + u32 flags; + + u32 tx_initial_phase; + u32 rx_initial_phase; + + const u32 *sd_pull_ctl_enable_tbl; + const u32 *sd_pull_ctl_disable_tbl; + const u32 *ms_pull_ctl_enable_tbl; + const u32 *ms_pull_ctl_disable_tbl; + + const struct pcr_ops *ops; + enum PDEV_STAT state; + + u16 reg_pm_ctrl3; + + int num_slots; + struct rtsx_slot *slots; + + u8 dma_error_count; + u8 ocp_stat; + u8 ocp_stat2; + }; + + #define PID_524A 0x524A + #define PID_5249 0x5249 + #define PID_5250 0x5250 + #define PID_525A 0x525A + #define PID_5260 0x5260 + + #define CHK_PCI_PID(pcr, pid) ((pcr)->pci->device == (pid)) + #define PCI_VID(pcr) ((pcr)->pci->vendor) + #define PCI_PID(pcr) ((pcr)->pci->device) + #define is_version(pcr, pid, ver) \ + (CHK_PCI_PID(pcr, pid) && (pcr)->ic_version == (ver)) + #define pcr_dbg(pcr, fmt, arg...) \ + dev_dbg(&(pcr)->pci->dev, fmt, ##arg) + + #define SDR104_PHASE(val) ((val) & 0xFF) + #define SDR50_PHASE(val) (((val) >> 8) & 0xFF) + #define DDR50_PHASE(val) (((val) >> 16) & 0xFF) + #define SDR104_TX_PHASE(pcr) SDR104_PHASE((pcr)->tx_initial_phase) + #define SDR50_TX_PHASE(pcr) SDR50_PHASE((pcr)->tx_initial_phase) + #define DDR50_TX_PHASE(pcr) DDR50_PHASE((pcr)->tx_initial_phase) + #define SDR104_RX_PHASE(pcr) SDR104_PHASE((pcr)->rx_initial_phase) + #define SDR50_RX_PHASE(pcr) SDR50_PHASE((pcr)->rx_initial_phase) + #define DDR50_RX_PHASE(pcr) DDR50_PHASE((pcr)->rx_initial_phase) + #define SET_CLOCK_PHASE(sdr104, sdr50, ddr50) \ + (((ddr50) << 16) | ((sdr50) << 8) | (sdr104)) + + void rtsx_pci_start_run(struct rtsx_pcr *pcr); + int rtsx_pci_write_register(struct rtsx_pcr *pcr, u16 addr, u8 mask, u8 data); + int rtsx_pci_read_register(struct rtsx_pcr *pcr, u16 addr, u8 *data); + int rtsx_pci_write_phy_register(struct rtsx_pcr *pcr, u8 addr, u16 val); + int rtsx_pci_read_phy_register(struct rtsx_pcr *pcr, u8 addr, u16 *val); + void rtsx_pci_stop_cmd(struct rtsx_pcr *pcr); + void rtsx_pci_add_cmd(struct rtsx_pcr *pcr, + u8 cmd_type, u16 reg_addr, u8 mask, u8 data); + void rtsx_pci_send_cmd_no_wait(struct rtsx_pcr *pcr); + int rtsx_pci_send_cmd(struct rtsx_pcr *pcr, int timeout); + int rtsx_pci_transfer_data(struct rtsx_pcr *pcr, struct scatterlist *sglist, + int num_sg, bool read, int timeout); + int rtsx_pci_dma_map_sg(struct rtsx_pcr *pcr, struct scatterlist *sglist, + int num_sg, bool read); + void rtsx_pci_dma_unmap_sg(struct rtsx_pcr *pcr, struct scatterlist *sglist, + int num_sg, bool read); + int rtsx_pci_dma_transfer(struct rtsx_pcr *pcr, struct scatterlist *sglist, + int count, bool read, int timeout); + int rtsx_pci_read_ppbuf(struct rtsx_pcr *pcr, u8 *buf, int buf_len); + int rtsx_pci_write_ppbuf(struct rtsx_pcr *pcr, u8 *buf, int buf_len); + int rtsx_pci_card_pull_ctl_enable(struct rtsx_pcr *pcr, int card); + int rtsx_pci_card_pull_ctl_disable(struct rtsx_pcr *pcr, int card); + int rtsx_pci_switch_clock(struct rtsx_pcr *pcr, unsigned int card_clock, + u8 ssc_depth, bool initial_mode, bool double_clk, bool vpclk); + int rtsx_pci_card_power_on(struct rtsx_pcr *pcr, int card); + int rtsx_pci_card_power_off(struct rtsx_pcr *pcr, int card); + int rtsx_pci_card_exclusive_check(struct rtsx_pcr *pcr, int card); + int rtsx_pci_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage); + unsigned int rtsx_pci_card_exist(struct rtsx_pcr *pcr); + void rtsx_pci_complete_unfinished_transfer(struct rtsx_pcr *pcr); + + static inline u8 *rtsx_pci_get_cmd_data(struct rtsx_pcr *pcr) + { + return (u8 *)(pcr->host_cmds_ptr); + } + + static inline int rtsx_pci_update_cfg_byte(struct rtsx_pcr *pcr, int addr, + u8 mask, u8 append) + { + int err; + u8 val; + + err = pci_read_config_byte(pcr->pci, addr, &val); + if (err < 0) + return err; + return pci_write_config_byte(pcr->pci, addr, (val & mask) | append); + } + + static inline void rtsx_pci_write_be32(struct rtsx_pcr *pcr, u16 reg, u32 val) + { + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, reg, 0xFF, val >> 24); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, reg + 1, 0xFF, val >> 16); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, reg + 2, 0xFF, val >> 8); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, reg + 3, 0xFF, val); + } + + static inline int rtsx_pci_update_phy(struct rtsx_pcr *pcr, u8 addr, + u16 mask, u16 append) + { + int err; + u16 val; + + err = rtsx_pci_read_phy_register(pcr, addr, &val); + if (err < 0) + return err; + + return rtsx_pci_write_phy_register(pcr, addr, (val & mask) | append); + } + + #endif