summaryrefslogtreecommitdiff
path: root/drivers/ata
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/ata')
-rw-r--r--drivers/ata/Kconfig7
-rw-r--r--drivers/ata/ahci_imx.c195
-rw-r--r--drivers/ata/ahci_xgene.c6
-rw-r--r--drivers/ata/libata-core.c61
-rw-r--r--drivers/ata/libata.h1
-rw-r--r--drivers/ata/sata_mv.c2
6 files changed, 242 insertions, 30 deletions
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 2c8be74f401d..38318aaf29d3 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -80,6 +80,8 @@ config SATA_PMP
This option adds support for SATA Port Multipliers
(the SATA version of an ethernet hub, or SAS expander).
+if HAS_DMA
+
comment "Controllers with non-SFF native interface"
config SATA_AHCI
@@ -232,6 +234,8 @@ config SATA_SIL24
If unsure, say N.
+endif # HAS_DMA
+
config ATA_SFF
bool "ATA SFF support (for legacy IDE and PATA)"
default y
@@ -289,6 +293,7 @@ config SATA_SX4
config ATA_BMDMA
bool "ATA BMDMA support"
+ depends on HAS_DMA
default y
help
This option adds support for SFF ATA controllers with BMDMA
@@ -344,6 +349,7 @@ config SATA_DWC_VDEBUG
config SATA_HIGHBANK
tristate "Calxeda Highbank SATA support"
+ depends on HAS_DMA
depends on ARCH_HIGHBANK || COMPILE_TEST
help
This option enables support for the Calxeda Highbank SoC's
@@ -353,6 +359,7 @@ config SATA_HIGHBANK
config SATA_MV
tristate "Marvell SATA support"
+ depends on HAS_DMA
depends on PCI || ARCH_DOVE || ARCH_MV78XX0 || \
ARCH_MVEBU || ARCH_ORION5X || COMPILE_TEST
select GENERIC_PHY
diff --git a/drivers/ata/ahci_imx.c b/drivers/ata/ahci_imx.c
index 3f3a7db208ae..420f065978dc 100644
--- a/drivers/ata/ahci_imx.c
+++ b/drivers/ata/ahci_imx.c
@@ -26,6 +26,9 @@
#include <linux/mfd/syscon.h>
#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
#include <linux/libata.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/thermal.h>
#include "ahci.h"
#define DRV_NAME "ahci-imx"
@@ -214,6 +217,180 @@ static int imx_sata_phy_reset(struct ahci_host_priv *hpriv)
return timeout ? 0 : -ETIMEDOUT;
}
+enum {
+ /* SATA PHY Register */
+ SATA_PHY_CR_CLOCK_CRCMP_LT_LIMIT = 0x0001,
+ SATA_PHY_CR_CLOCK_DAC_CTL = 0x0008,
+ SATA_PHY_CR_CLOCK_RTUNE_CTL = 0x0009,
+ SATA_PHY_CR_CLOCK_ADC_OUT = 0x000A,
+ SATA_PHY_CR_CLOCK_MPLL_TST = 0x0017,
+};
+
+static int read_adc_sum(void *dev, u16 rtune_ctl_reg, void __iomem * mmio)
+{
+ u16 adc_out_reg, read_sum;
+ u32 index, read_attempt;
+ const u32 attempt_limit = 100;
+
+ imx_phy_reg_addressing(SATA_PHY_CR_CLOCK_RTUNE_CTL, mmio);
+ imx_phy_reg_write(rtune_ctl_reg, mmio);
+
+ /* two dummy read */
+ index = 0;
+ read_attempt = 0;
+ adc_out_reg = 0;
+ imx_phy_reg_addressing(SATA_PHY_CR_CLOCK_ADC_OUT, mmio);
+ while (index < 2) {
+ imx_phy_reg_read(&adc_out_reg, mmio);
+ /* check if valid */
+ if (adc_out_reg & 0x400)
+ index++;
+
+ read_attempt++;
+ if (read_attempt > attempt_limit) {
+ dev_err(dev, "Read REG more than %d times!\n",
+ attempt_limit);
+ break;
+ }
+ }
+
+ index = 0;
+ read_attempt = 0;
+ read_sum = 0;
+ while (index < 80) {
+ imx_phy_reg_read(&adc_out_reg, mmio);
+ if (adc_out_reg & 0x400) {
+ read_sum = read_sum + (adc_out_reg & 0x3FF);
+ index++;
+ }
+ read_attempt++;
+ if (read_attempt > attempt_limit) {
+ dev_err(dev, "Read REG more than %d times!\n",
+ attempt_limit);
+ break;
+ }
+ }
+
+ /* Use the U32 to make 1000 precision */
+ return (read_sum * 1000) / 80;
+}
+
+/* SATA AHCI temperature monitor */
+static int sata_ahci_read_temperature(void *dev, int *temp)
+{
+ u16 mpll_test_reg, rtune_ctl_reg, dac_ctl_reg, read_sum;
+ u32 str1, str2, str3, str4;
+ int m1, m2, a;
+ struct ahci_host_priv *hpriv = dev_get_drvdata(dev);
+ void __iomem *mmio = hpriv->mmio;
+
+ /* check rd-wr to reg */
+ read_sum = 0;
+ imx_phy_reg_addressing(SATA_PHY_CR_CLOCK_CRCMP_LT_LIMIT, mmio);
+ imx_phy_reg_write(read_sum, mmio);
+ imx_phy_reg_read(&read_sum, mmio);
+ if ((read_sum & 0xffff) != 0)
+ dev_err(dev, "Read/Write REG error, 0x%x!\n", read_sum);
+
+ imx_phy_reg_write(0x5A5A, mmio);
+ imx_phy_reg_read(&read_sum, mmio);
+ if ((read_sum & 0xffff) != 0x5A5A)
+ dev_err(dev, "Read/Write REG error, 0x%x!\n", read_sum);
+
+ imx_phy_reg_write(0x1234, mmio);
+ imx_phy_reg_read(&read_sum, mmio);
+ if ((read_sum & 0xffff) != 0x1234)
+ dev_err(dev, "Read/Write REG error, 0x%x!\n", read_sum);
+
+ /* start temperature test */
+ imx_phy_reg_addressing(SATA_PHY_CR_CLOCK_MPLL_TST, mmio);
+ imx_phy_reg_read(&mpll_test_reg, mmio);
+ imx_phy_reg_addressing(SATA_PHY_CR_CLOCK_RTUNE_CTL, mmio);
+ imx_phy_reg_read(&rtune_ctl_reg, mmio);
+ imx_phy_reg_addressing(SATA_PHY_CR_CLOCK_DAC_CTL, mmio);
+ imx_phy_reg_read(&dac_ctl_reg, mmio);
+
+ /* mpll_tst.meas_iv ([12:2]) */
+ str1 = (mpll_test_reg >> 2) & 0x7FF;
+ /* rtune_ctl.mode ([1:0]) */
+ str2 = (rtune_ctl_reg) & 0x3;
+ /* dac_ctl.dac_mode ([14:12]) */
+ str3 = (dac_ctl_reg >> 12) & 0x7;
+ /* rtune_ctl.sel_atbp ([4]) */
+ str4 = (rtune_ctl_reg >> 4);
+
+ /* Calculate the m1 */
+ /* mpll_tst.meas_iv */
+ mpll_test_reg = (mpll_test_reg & 0xE03) | (512) << 2;
+ /* rtune_ctl.mode */
+ rtune_ctl_reg = (rtune_ctl_reg & 0xFFC) | (1);
+ /* dac_ctl.dac_mode */
+ dac_ctl_reg = (dac_ctl_reg & 0x8FF) | (4) << 12;
+ /* rtune_ctl.sel_atbp */
+ rtune_ctl_reg = (rtune_ctl_reg & 0xFEF) | (0) << 4;
+ imx_phy_reg_addressing(SATA_PHY_CR_CLOCK_MPLL_TST, mmio);
+ imx_phy_reg_write(mpll_test_reg, mmio);
+ imx_phy_reg_addressing(SATA_PHY_CR_CLOCK_DAC_CTL, mmio);
+ imx_phy_reg_write(dac_ctl_reg, mmio);
+ m1 = read_adc_sum(dev, rtune_ctl_reg, mmio);
+
+ /* Calculate the m2 */
+ /* rtune_ctl.sel_atbp */
+ rtune_ctl_reg = (rtune_ctl_reg & 0xFEF) | (1) << 4;
+ m2 = read_adc_sum(dev, rtune_ctl_reg, mmio);
+
+ /* restore the status */
+ /* mpll_tst.meas_iv */
+ mpll_test_reg = (mpll_test_reg & 0xE03) | (str1) << 2;
+ /* rtune_ctl.mode */
+ rtune_ctl_reg = (rtune_ctl_reg & 0xFFC) | (str2);
+ /* dac_ctl.dac_mode */
+ dac_ctl_reg = (dac_ctl_reg & 0x8FF) | (str3) << 12;
+ /* rtune_ctl.sel_atbp */
+ rtune_ctl_reg = (rtune_ctl_reg & 0xFEF) | (str4) << 4;
+
+ imx_phy_reg_addressing(SATA_PHY_CR_CLOCK_MPLL_TST, mmio);
+ imx_phy_reg_write(mpll_test_reg, mmio);
+ imx_phy_reg_addressing(SATA_PHY_CR_CLOCK_DAC_CTL, mmio);
+ imx_phy_reg_write(dac_ctl_reg, mmio);
+ imx_phy_reg_addressing(SATA_PHY_CR_CLOCK_RTUNE_CTL, mmio);
+ imx_phy_reg_write(rtune_ctl_reg, mmio);
+
+ /* Compute temperature */
+ if (!(m2 / 1000))
+ m2 = 1000;
+ a = (m2 - m1) / (m2/1000);
+ *temp = ((-559) * a * a) / 1000 + (1379) * a + (-458000);
+
+ return 0;
+}
+
+static ssize_t sata_ahci_show_temp(struct device *dev,
+ struct device_attribute *da,
+ char *buf)
+{
+ unsigned int temp = 0;
+ int err;
+
+ err = sata_ahci_read_temperature(dev, &temp);
+ if (err < 0)
+ return err;
+
+ return sprintf(buf, "%u\n", temp);
+}
+
+static const struct thermal_zone_of_device_ops fsl_sata_ahci_of_thermal_ops = {
+ .get_temp = sata_ahci_read_temperature,
+};
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, sata_ahci_show_temp, NULL, 0);
+
+static struct attribute *fsl_sata_ahci_attrs[] = {
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ NULL
+};
+ATTRIBUTE_GROUPS(fsl_sata_ahci);
+
static int imx_sata_enable(struct ahci_host_priv *hpriv)
{
struct imx_ahci_priv *imxpriv = hpriv->plat_data;
@@ -597,6 +774,24 @@ static int imx_ahci_probe(struct platform_device *pdev)
if (ret)
return ret;
+ if (imxpriv->type == AHCI_IMX53) {
+ /* Add the temperature monitor */
+ struct device *hwmon_dev;
+
+ hwmon_dev =
+ devm_hwmon_device_register_with_groups(dev,
+ "sata_ahci",
+ hpriv,
+ fsl_sata_ahci_groups);
+ if (IS_ERR(hwmon_dev)) {
+ ret = PTR_ERR(hwmon_dev);
+ goto disable_clk;
+ }
+ devm_thermal_zone_of_sensor_register(hwmon_dev, 0, hwmon_dev,
+ &fsl_sata_ahci_of_thermal_ops);
+ dev_info(dev, "%s: sensor 'sata_ahci'\n", dev_name(hwmon_dev));
+ }
+
ret = imx_sata_enable(hpriv);
if (ret)
goto disable_clk;
diff --git a/drivers/ata/ahci_xgene.c b/drivers/ata/ahci_xgene.c
index 73b19b277138..c2b5941d9184 100644
--- a/drivers/ata/ahci_xgene.c
+++ b/drivers/ata/ahci_xgene.c
@@ -821,8 +821,10 @@ static int xgene_ahci_probe(struct platform_device *pdev)
dev_warn(&pdev->dev, "%s: Error reading device info. Assume version1\n",
__func__);
version = XGENE_AHCI_V1;
- } else if (info->valid & ACPI_VALID_CID) {
- version = XGENE_AHCI_V2;
+ } else {
+ if (info->valid & ACPI_VALID_CID)
+ version = XGENE_AHCI_V2;
+ kfree(info);
}
}
}
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index c2d3785ec227..ca75823697dd 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -4816,32 +4816,6 @@ static unsigned int ata_dev_init_params(struct ata_device *dev,
}
/**
- * ata_sg_clean - Unmap DMA memory associated with command
- * @qc: Command containing DMA memory to be released
- *
- * Unmap all mapped DMA memory associated with this command.
- *
- * LOCKING:
- * spin_lock_irqsave(host lock)
- */
-void ata_sg_clean(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- struct scatterlist *sg = qc->sg;
- int dir = qc->dma_dir;
-
- WARN_ON_ONCE(sg == NULL);
-
- VPRINTK("unmapping %u sg elements\n", qc->n_elem);
-
- if (qc->n_elem)
- dma_unmap_sg(ap->dev, sg, qc->orig_n_elem, dir);
-
- qc->flags &= ~ATA_QCFLAG_DMAMAP;
- qc->sg = NULL;
-}
-
-/**
* atapi_check_dma - Check whether ATAPI DMA can be supported
* @qc: Metadata associated with taskfile to check
*
@@ -4925,6 +4899,34 @@ void ata_sg_init(struct ata_queued_cmd *qc, struct scatterlist *sg,
qc->cursg = qc->sg;
}
+#ifdef CONFIG_HAS_DMA
+
+/**
+ * ata_sg_clean - Unmap DMA memory associated with command
+ * @qc: Command containing DMA memory to be released
+ *
+ * Unmap all mapped DMA memory associated with this command.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+void ata_sg_clean(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct scatterlist *sg = qc->sg;
+ int dir = qc->dma_dir;
+
+ WARN_ON_ONCE(sg == NULL);
+
+ VPRINTK("unmapping %u sg elements\n", qc->n_elem);
+
+ if (qc->n_elem)
+ dma_unmap_sg(ap->dev, sg, qc->orig_n_elem, dir);
+
+ qc->flags &= ~ATA_QCFLAG_DMAMAP;
+ qc->sg = NULL;
+}
+
/**
* ata_sg_setup - DMA-map the scatter-gather table associated with a command.
* @qc: Command with scatter-gather table to be mapped.
@@ -4957,6 +4959,13 @@ static int ata_sg_setup(struct ata_queued_cmd *qc)
return 0;
}
+#else /* !CONFIG_HAS_DMA */
+
+static inline void ata_sg_clean(struct ata_queued_cmd *qc) {}
+static inline int ata_sg_setup(struct ata_queued_cmd *qc) { return -1; }
+
+#endif /* !CONFIG_HAS_DMA */
+
/**
* swap_buf_le16 - swap halves of 16-bit words in place
* @buf: Buffer to swap
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index 8f3a5596dd67..1133e9439f9c 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -89,7 +89,6 @@ extern int sata_down_spd_limit(struct ata_link *link, u32 spd_limit);
extern int ata_down_xfermask_limit(struct ata_device *dev, unsigned int sel);
extern unsigned int ata_dev_set_feature(struct ata_device *dev,
u8 enable, u8 feature);
-extern void ata_sg_clean(struct ata_queued_cmd *qc);
extern void ata_qc_free(struct ata_queued_cmd *qc);
extern void ata_qc_issue(struct ata_queued_cmd *qc);
extern void __ata_qc_complete(struct ata_queued_cmd *qc);
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
index 2f32782cea6d..6eed4a72d328 100644
--- a/drivers/ata/sata_mv.c
+++ b/drivers/ata/sata_mv.c
@@ -4529,7 +4529,7 @@ static void __exit mv_exit(void)
MODULE_AUTHOR("Brett Russ");
MODULE_DESCRIPTION("SCSI low-level driver for Marvell SATA controllers");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
MODULE_DEVICE_TABLE(pci, mv_pci_tbl);
MODULE_VERSION(DRV_VERSION);
MODULE_ALIAS("platform:" DRV_NAME);