summaryrefslogtreecommitdiffstats
path: root/drivers/ata
diff options
context:
space:
mode:
authorJiri Kosina <jkosina@suse.cz>2014-02-20 14:54:28 +0100
committerJiri Kosina <jkosina@suse.cz>2014-02-20 14:54:28 +0100
commitd4263348f796f29546f90802177865dd4379dd0a (patch)
treeadcbdaebae584eee2f32fab95e826e8e49eef385 /drivers/ata
parentbe873ac782f5ff5ee6675f83929f4fe6737eead2 (diff)
parent6d0abeca3242a88cab8232e4acd7e2bf088f3bc2 (diff)
downloadop-kernel-dev-d4263348f796f29546f90802177865dd4379dd0a.zip
op-kernel-dev-d4263348f796f29546f90802177865dd4379dd0a.tar.gz
Merge branch 'master' into for-next
Diffstat (limited to 'drivers/ata')
-rw-r--r--drivers/ata/ahci.c137
-rw-r--r--drivers/ata/ahci_imx.c241
-rw-r--r--drivers/ata/ata_generic.c7
-rw-r--r--drivers/ata/libahci.c4
-rw-r--r--drivers/ata/libata-acpi.c28
-rw-r--r--drivers/ata/libata-core.c46
-rw-r--r--drivers/ata/libata-eh.c5
-rw-r--r--drivers/ata/libata-scsi.c39
-rw-r--r--drivers/ata/pata_acpi.c5
-rw-r--r--drivers/ata/pata_samsung_cf.c43
-rw-r--r--drivers/ata/sata_highbank.c1
-rw-r--r--drivers/ata/sata_mv.c54
-rw-r--r--drivers/ata/sata_rcar.c118
-rw-r--r--drivers/ata/sata_sis.c4
14 files changed, 541 insertions, 191 deletions
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 14f1e95..dc2756f 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -83,6 +83,8 @@ enum board_ids {
static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline);
+static void ahci_mcp89_apple_enable(struct pci_dev *pdev);
+static bool is_mcp89_apple(struct pci_dev *pdev);
static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline);
#ifdef CONFIG_PM
@@ -427,6 +429,9 @@ static const struct pci_device_id ahci_pci_tbl[] = {
.driver_data = board_ahci_yes_fbs }, /* 88se9128 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9125),
.driver_data = board_ahci_yes_fbs }, /* 88se9125 */
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_MARVELL_EXT, 0x9178,
+ PCI_VENDOR_ID_MARVELL_EXT, 0x9170),
+ .driver_data = board_ahci_yes_fbs }, /* 88se9170 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x917a),
.driver_data = board_ahci_yes_fbs }, /* 88se9172 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9172),
@@ -661,6 +666,10 @@ static int ahci_pci_device_resume(struct pci_dev *pdev)
if (rc)
return rc;
+ /* Apple BIOS helpfully mangles the registers on resume */
+ if (is_mcp89_apple(pdev))
+ ahci_mcp89_apple_enable(pdev);
+
if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
rc = ahci_pci_reset_controller(host);
if (rc)
@@ -777,6 +786,48 @@ static void ahci_p5wdh_workaround(struct ata_host *host)
}
}
+/*
+ * Macbook7,1 firmware forcibly disables MCP89 AHCI and changes PCI ID when
+ * booting in BIOS compatibility mode. We restore the registers but not ID.
+ */
+static void ahci_mcp89_apple_enable(struct pci_dev *pdev)
+{
+ u32 val;
+
+ printk(KERN_INFO "ahci: enabling MCP89 AHCI mode\n");
+
+ pci_read_config_dword(pdev, 0xf8, &val);
+ val |= 1 << 0x1b;
+ /* the following changes the device ID, but appears not to affect function */
+ /* val = (val & ~0xf0000000) | 0x80000000; */
+ pci_write_config_dword(pdev, 0xf8, val);
+
+ pci_read_config_dword(pdev, 0x54c, &val);
+ val |= 1 << 0xc;
+ pci_write_config_dword(pdev, 0x54c, val);
+
+ pci_read_config_dword(pdev, 0x4a4, &val);
+ val &= 0xff;
+ val |= 0x01060100;
+ pci_write_config_dword(pdev, 0x4a4, val);
+
+ pci_read_config_dword(pdev, 0x54c, &val);
+ val &= ~(1 << 0xc);
+ pci_write_config_dword(pdev, 0x54c, val);
+
+ pci_read_config_dword(pdev, 0xf8, &val);
+ val &= ~(1 << 0x1b);
+ pci_write_config_dword(pdev, 0xf8, val);
+}
+
+static bool is_mcp89_apple(struct pci_dev *pdev)
+{
+ return pdev->vendor == PCI_VENDOR_ID_NVIDIA &&
+ pdev->device == PCI_DEVICE_ID_NVIDIA_NFORCE_MCP89_SATA &&
+ pdev->subsystem_vendor == PCI_VENDOR_ID_APPLE &&
+ pdev->subsystem_device == 0xcb89;
+}
+
/* only some SB600 ahci controllers can do 64bit DMA */
static bool ahci_sb600_enable_64bit(struct pci_dev *pdev)
{
@@ -1097,26 +1148,40 @@ static inline void ahci_gtf_filter_workaround(struct ata_host *host)
{}
#endif
-int ahci_init_interrupts(struct pci_dev *pdev, struct ahci_host_priv *hpriv)
+static int ahci_init_interrupts(struct pci_dev *pdev, unsigned int n_ports,
+ struct ahci_host_priv *hpriv)
{
- int rc;
- unsigned int maxvec;
+ int rc, nvec;
- if (!(hpriv->flags & AHCI_HFLAG_NO_MSI)) {
- rc = pci_enable_msi_block_auto(pdev, &maxvec);
- if (rc > 0) {
- if ((rc == maxvec) || (rc == 1))
- return rc;
- /*
- * Assume that advantage of multipe MSIs is negated,
- * so fallback to single MSI mode to save resources
- */
- pci_disable_msi(pdev);
- if (!pci_enable_msi(pdev))
- return 1;
- }
- }
+ if (hpriv->flags & AHCI_HFLAG_NO_MSI)
+ goto intx;
+
+ rc = pci_msi_vec_count(pdev);
+ if (rc < 0)
+ goto intx;
+
+ /*
+ * If number of MSIs is less than number of ports then Sharing Last
+ * Message mode could be enforced. In this case assume that advantage
+ * of multipe MSIs is negated and use single MSI mode instead.
+ */
+ if (rc < n_ports)
+ goto single_msi;
+
+ nvec = rc;
+ rc = pci_enable_msi_block(pdev, nvec);
+ if (rc)
+ goto intx;
+
+ return nvec;
+
+single_msi:
+ rc = pci_enable_msi(pdev);
+ if (rc)
+ goto intx;
+ return 1;
+intx:
pci_intx(pdev, 1);
return 0;
}
@@ -1209,15 +1274,9 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (pdev->vendor == PCI_VENDOR_ID_MARVELL && !marvell_enable)
return -ENODEV;
- /*
- * For some reason, MCP89 on MacBook 7,1 doesn't work with
- * ahci, use ata_generic instead.
- */
- if (pdev->vendor == PCI_VENDOR_ID_NVIDIA &&
- pdev->device == PCI_DEVICE_ID_NVIDIA_NFORCE_MCP89_SATA &&
- pdev->subsystem_vendor == PCI_VENDOR_ID_APPLE &&
- pdev->subsystem_device == 0xcb89)
- return -ENODEV;
+ /* Apple BIOS on MCP89 prevents us using AHCI */
+ if (is_mcp89_apple(pdev))
+ ahci_mcp89_apple_enable(pdev);
/* Promise's PDC42819 is a SAS/SATA controller that has an AHCI mode.
* At the moment, we can only use the AHCI mode. Let the users know
@@ -1238,15 +1297,6 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (rc)
return rc;
- /* AHCI controllers often implement SFF compatible interface.
- * Grab all PCI BARs just in case.
- */
- rc = pcim_iomap_regions_request_all(pdev, 1 << ahci_pci_bar, DRV_NAME);
- if (rc == -EBUSY)
- pcim_pin_device(pdev);
- if (rc)
- return rc;
-
if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
(pdev->device == 0x2652 || pdev->device == 0x2653)) {
u8 map;
@@ -1263,6 +1313,15 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
}
}
+ /* AHCI controllers often implement SFF compatible interface.
+ * Grab all PCI BARs just in case.
+ */
+ rc = pcim_iomap_regions_request_all(pdev, 1 << ahci_pci_bar, DRV_NAME);
+ if (rc == -EBUSY)
+ pcim_pin_device(pdev);
+ if (rc)
+ return rc;
+
hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
if (!hpriv)
return -ENOMEM;
@@ -1283,10 +1342,6 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
hpriv->mmio = pcim_iomap_table(pdev)[ahci_pci_bar];
- n_msis = ahci_init_interrupts(pdev, hpriv);
- if (n_msis > 1)
- hpriv->flags |= AHCI_HFLAG_MULTI_MSI;
-
/* save initial config */
ahci_pci_save_initial_config(pdev, hpriv);
@@ -1341,6 +1396,10 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
*/
n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map));
+ n_msis = ahci_init_interrupts(pdev, n_ports, hpriv);
+ if (n_msis > 1)
+ hpriv->flags |= AHCI_HFLAG_MULTI_MSI;
+
host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
if (!host)
return -ENOMEM;
diff --git a/drivers/ata/ahci_imx.c b/drivers/ata/ahci_imx.c
index ae2d73f..dd4d6f7 100644
--- a/drivers/ata/ahci_imx.c
+++ b/drivers/ata/ahci_imx.c
@@ -34,10 +34,21 @@ enum {
HOST_TIMER1MS = 0xe0, /* Timer 1-ms */
};
+enum ahci_imx_type {
+ AHCI_IMX53,
+ AHCI_IMX6Q,
+};
+
struct imx_ahci_priv {
struct platform_device *ahci_pdev;
+ enum ahci_imx_type type;
+
+ /* i.MX53 clock */
+ struct clk *sata_gate_clk;
+ /* Common clock */
struct clk *sata_ref_clk;
struct clk *ahb_clk;
+
struct regmap *gpr;
bool no_device;
bool first_time;
@@ -47,6 +58,59 @@ static int ahci_imx_hotplug;
module_param_named(hotplug, ahci_imx_hotplug, int, 0644);
MODULE_PARM_DESC(hotplug, "AHCI IMX hot-plug support (0=Don't support, 1=support)");
+static int imx_sata_clock_enable(struct device *dev)
+{
+ struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent);
+ int ret;
+
+ if (imxpriv->type == AHCI_IMX53) {
+ ret = clk_prepare_enable(imxpriv->sata_gate_clk);
+ if (ret < 0) {
+ dev_err(dev, "prepare-enable sata_gate clock err:%d\n",
+ ret);
+ return ret;
+ }
+ }
+
+ ret = clk_prepare_enable(imxpriv->sata_ref_clk);
+ if (ret < 0) {
+ dev_err(dev, "prepare-enable sata_ref clock err:%d\n",
+ ret);
+ goto clk_err;
+ }
+
+ if (imxpriv->type == AHCI_IMX6Q) {
+ regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13,
+ IMX6Q_GPR13_SATA_MPLL_CLK_EN,
+ IMX6Q_GPR13_SATA_MPLL_CLK_EN);
+ }
+
+ usleep_range(1000, 2000);
+
+ return 0;
+
+clk_err:
+ if (imxpriv->type == AHCI_IMX53)
+ clk_disable_unprepare(imxpriv->sata_gate_clk);
+ return ret;
+}
+
+static void imx_sata_clock_disable(struct device *dev)
+{
+ struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent);
+
+ if (imxpriv->type == AHCI_IMX6Q) {
+ regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13,
+ IMX6Q_GPR13_SATA_MPLL_CLK_EN,
+ !IMX6Q_GPR13_SATA_MPLL_CLK_EN);
+ }
+
+ clk_disable_unprepare(imxpriv->sata_ref_clk);
+
+ if (imxpriv->type == AHCI_IMX53)
+ clk_disable_unprepare(imxpriv->sata_gate_clk);
+}
+
static void ahci_imx_error_handler(struct ata_port *ap)
{
u32 reg_val;
@@ -72,16 +136,29 @@ static void ahci_imx_error_handler(struct ata_port *ap)
*/
reg_val = readl(mmio + PORT_PHY_CTL);
writel(reg_val | PORT_PHY_CTL_PDDQ_LOC, mmio + PORT_PHY_CTL);
- regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13,
- IMX6Q_GPR13_SATA_MPLL_CLK_EN,
- !IMX6Q_GPR13_SATA_MPLL_CLK_EN);
- clk_disable_unprepare(imxpriv->sata_ref_clk);
+ imx_sata_clock_disable(ap->dev);
imxpriv->no_device = true;
}
+static int ahci_imx_softreset(struct ata_link *link, unsigned int *class,
+ unsigned long deadline)
+{
+ struct ata_port *ap = link->ap;
+ struct imx_ahci_priv *imxpriv = dev_get_drvdata(ap->dev->parent);
+ int ret = -EIO;
+
+ if (imxpriv->type == AHCI_IMX53)
+ ret = ahci_pmp_retry_srst_ops.softreset(link, class, deadline);
+ else if (imxpriv->type == AHCI_IMX6Q)
+ ret = ahci_ops.softreset(link, class, deadline);
+
+ return ret;
+}
+
static struct ata_port_operations ahci_imx_ops = {
.inherits = &ahci_platform_ops,
.error_handler = ahci_imx_error_handler,
+ .softreset = ahci_imx_softreset,
};
static const struct ata_port_info ahci_imx_port_info = {
@@ -91,51 +168,15 @@ static const struct ata_port_info ahci_imx_port_info = {
.port_ops = &ahci_imx_ops,
};
-static int imx6q_sata_init(struct device *dev, void __iomem *mmio)
+static int imx_sata_init(struct device *dev, void __iomem *mmio)
{
int ret = 0;
unsigned int reg_val;
struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent);
- imxpriv->gpr =
- syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr");
- if (IS_ERR(imxpriv->gpr)) {
- dev_err(dev, "failed to find fsl,imx6q-iomux-gpr regmap\n");
- return PTR_ERR(imxpriv->gpr);
- }
-
- ret = clk_prepare_enable(imxpriv->sata_ref_clk);
- if (ret < 0) {
- dev_err(dev, "prepare-enable sata_ref clock err:%d\n", ret);
+ ret = imx_sata_clock_enable(dev);
+ if (ret < 0)
return ret;
- }
-
- /*
- * set PHY Paremeters, two steps to configure the GPR13,
- * one write for rest of parameters, mask of first write
- * is 0x07fffffd, and the other one write for setting
- * the mpll_clk_en.
- */
- regmap_update_bits(imxpriv->gpr, 0x34, IMX6Q_GPR13_SATA_RX_EQ_VAL_MASK
- | IMX6Q_GPR13_SATA_RX_LOS_LVL_MASK
- | IMX6Q_GPR13_SATA_RX_DPLL_MODE_MASK
- | IMX6Q_GPR13_SATA_SPD_MODE_MASK
- | IMX6Q_GPR13_SATA_MPLL_SS_EN
- | IMX6Q_GPR13_SATA_TX_ATTEN_MASK
- | IMX6Q_GPR13_SATA_TX_BOOST_MASK
- | IMX6Q_GPR13_SATA_TX_LVL_MASK
- | IMX6Q_GPR13_SATA_TX_EDGE_RATE
- , IMX6Q_GPR13_SATA_RX_EQ_VAL_3_0_DB
- | IMX6Q_GPR13_SATA_RX_LOS_LVL_SATA2M
- | IMX6Q_GPR13_SATA_RX_DPLL_MODE_2P_4F
- | IMX6Q_GPR13_SATA_SPD_MODE_3P0G
- | IMX6Q_GPR13_SATA_MPLL_SS_EN
- | IMX6Q_GPR13_SATA_TX_ATTEN_9_16
- | IMX6Q_GPR13_SATA_TX_BOOST_3_33_DB
- | IMX6Q_GPR13_SATA_TX_LVL_1_025_V);
- regmap_update_bits(imxpriv->gpr, 0x34, IMX6Q_GPR13_SATA_MPLL_CLK_EN,
- IMX6Q_GPR13_SATA_MPLL_CLK_EN);
- usleep_range(100, 200);
/*
* Configure the HWINIT bits of the HOST_CAP and HOST_PORTS_IMPL,
@@ -161,13 +202,9 @@ static int imx6q_sata_init(struct device *dev, void __iomem *mmio)
return 0;
}
-static void imx6q_sata_exit(struct device *dev)
+static void imx_sata_exit(struct device *dev)
{
- struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent);
-
- regmap_update_bits(imxpriv->gpr, 0x34, IMX6Q_GPR13_SATA_MPLL_CLK_EN,
- !IMX6Q_GPR13_SATA_MPLL_CLK_EN);
- clk_disable_unprepare(imxpriv->sata_ref_clk);
+ imx_sata_clock_disable(dev);
}
static int imx_ahci_suspend(struct device *dev)
@@ -178,12 +215,8 @@ static int imx_ahci_suspend(struct device *dev)
* If no_device is set, The CLKs had been gated off in the
* initialization so don't do it again here.
*/
- if (!imxpriv->no_device) {
- regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13,
- IMX6Q_GPR13_SATA_MPLL_CLK_EN,
- !IMX6Q_GPR13_SATA_MPLL_CLK_EN);
- clk_disable_unprepare(imxpriv->sata_ref_clk);
- }
+ if (!imxpriv->no_device)
+ imx_sata_clock_disable(dev);
return 0;
}
@@ -191,34 +224,26 @@ static int imx_ahci_suspend(struct device *dev)
static int imx_ahci_resume(struct device *dev)
{
struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent);
- int ret;
-
- if (!imxpriv->no_device) {
- ret = clk_prepare_enable(imxpriv->sata_ref_clk);
- if (ret < 0) {
- dev_err(dev, "pre-enable sata_ref clock err:%d\n", ret);
- return ret;
- }
+ int ret = 0;
- regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13,
- IMX6Q_GPR13_SATA_MPLL_CLK_EN,
- IMX6Q_GPR13_SATA_MPLL_CLK_EN);
- usleep_range(1000, 2000);
- }
+ if (!imxpriv->no_device)
+ ret = imx_sata_clock_enable(dev);
- return 0;
+ return ret;
}
-static struct ahci_platform_data imx6q_sata_pdata = {
- .init = imx6q_sata_init,
- .exit = imx6q_sata_exit,
- .ata_port_info = &ahci_imx_port_info,
- .suspend = imx_ahci_suspend,
- .resume = imx_ahci_resume,
+static struct ahci_platform_data imx_sata_pdata = {
+ .init = imx_sata_init,
+ .exit = imx_sata_exit,
+ .ata_port_info = &ahci_imx_port_info,
+ .suspend = imx_ahci_suspend,
+ .resume = imx_ahci_resume,
+
};
static const struct of_device_id imx_ahci_of_match[] = {
- { .compatible = "fsl,imx6q-ahci", .data = &imx6q_sata_pdata},
+ { .compatible = "fsl,imx53-ahci", .data = (void *)AHCI_IMX53 },
+ { .compatible = "fsl,imx6q-ahci", .data = (void *)AHCI_IMX6Q },
{},
};
MODULE_DEVICE_TABLE(of, imx_ahci_of_match);
@@ -228,12 +253,20 @@ static int imx_ahci_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct resource *mem, *irq, res[2];
const struct of_device_id *of_id;
+ enum ahci_imx_type type;
const struct ahci_platform_data *pdata = NULL;
struct imx_ahci_priv *imxpriv;
struct device *ahci_dev;
struct platform_device *ahci_pdev;
int ret;
+ of_id = of_match_device(imx_ahci_of_match, dev);
+ if (!of_id)
+ return -EINVAL;
+
+ type = (enum ahci_imx_type)of_id->data;
+ pdata = &imx_sata_pdata;
+
imxpriv = devm_kzalloc(dev, sizeof(*imxpriv), GFP_KERNEL);
if (!imxpriv) {
dev_err(dev, "can't alloc ahci_host_priv\n");
@@ -249,6 +282,8 @@ static int imx_ahci_probe(struct platform_device *pdev)
imxpriv->no_device = false;
imxpriv->first_time = true;
+ imxpriv->type = type;
+
imxpriv->ahb_clk = devm_clk_get(dev, "ahb");
if (IS_ERR(imxpriv->ahb_clk)) {
dev_err(dev, "can't get ahb clock.\n");
@@ -256,6 +291,15 @@ static int imx_ahci_probe(struct platform_device *pdev)
goto err_out;
}
+ if (type == AHCI_IMX53) {
+ imxpriv->sata_gate_clk = devm_clk_get(dev, "sata_gate");
+ if (IS_ERR(imxpriv->sata_gate_clk)) {
+ dev_err(dev, "can't get sata_gate clock.\n");
+ ret = PTR_ERR(imxpriv->sata_gate_clk);
+ goto err_out;
+ }
+ }
+
imxpriv->sata_ref_clk = devm_clk_get(dev, "sata_ref");
if (IS_ERR(imxpriv->sata_ref_clk)) {
dev_err(dev, "can't get sata_ref clock.\n");
@@ -266,14 +310,6 @@ static int imx_ahci_probe(struct platform_device *pdev)
imxpriv->ahci_pdev = ahci_pdev;
platform_set_drvdata(pdev, imxpriv);
- of_id = of_match_device(imx_ahci_of_match, dev);
- if (of_id) {
- pdata = of_id->data;
- } else {
- ret = -EINVAL;
- goto err_out;
- }
-
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!mem || !irq) {
@@ -289,6 +325,43 @@ static int imx_ahci_probe(struct platform_device *pdev)
ahci_dev->dma_mask = &ahci_dev->coherent_dma_mask;
ahci_dev->of_node = dev->of_node;
+ if (type == AHCI_IMX6Q) {
+ imxpriv->gpr = syscon_regmap_lookup_by_compatible(
+ "fsl,imx6q-iomuxc-gpr");
+ if (IS_ERR(imxpriv->gpr)) {
+ dev_err(dev,
+ "failed to find fsl,imx6q-iomux-gpr regmap\n");
+ ret = PTR_ERR(imxpriv->gpr);
+ goto err_out;
+ }
+
+ /*
+ * Set PHY Paremeters, two steps to configure the GPR13,
+ * one write for rest of parameters, mask of first write
+ * is 0x07fffffe, and the other one write for setting
+ * the mpll_clk_en happens in imx_sata_clock_enable().
+ */
+ regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13,
+ IMX6Q_GPR13_SATA_RX_EQ_VAL_MASK |
+ IMX6Q_GPR13_SATA_RX_LOS_LVL_MASK |
+ IMX6Q_GPR13_SATA_RX_DPLL_MODE_MASK |
+ IMX6Q_GPR13_SATA_SPD_MODE_MASK |
+ IMX6Q_GPR13_SATA_MPLL_SS_EN |
+ IMX6Q_GPR13_SATA_TX_ATTEN_MASK |
+ IMX6Q_GPR13_SATA_TX_BOOST_MASK |
+ IMX6Q_GPR13_SATA_TX_LVL_MASK |
+ IMX6Q_GPR13_SATA_MPLL_CLK_EN |
+ IMX6Q_GPR13_SATA_TX_EDGE_RATE,
+ IMX6Q_GPR13_SATA_RX_EQ_VAL_3_0_DB |
+ IMX6Q_GPR13_SATA_RX_LOS_LVL_SATA2M |
+ IMX6Q_GPR13_SATA_RX_DPLL_MODE_2P_4F |
+ IMX6Q_GPR13_SATA_SPD_MODE_3P0G |
+ IMX6Q_GPR13_SATA_MPLL_SS_EN |
+ IMX6Q_GPR13_SATA_TX_ATTEN_9_16 |
+ IMX6Q_GPR13_SATA_TX_BOOST_3_33_DB |
+ IMX6Q_GPR13_SATA_TX_LVL_1_025_V);
+ }
+
ret = platform_device_add_resources(ahci_pdev, res, 2);
if (ret)
goto err_out;
diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c
index f8f38a0..7d19665 100644
--- a/drivers/ata/ata_generic.c
+++ b/drivers/ata/ata_generic.c
@@ -221,13 +221,6 @@ static struct pci_device_id ata_generic[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C558), },
{ PCI_DEVICE(PCI_VENDOR_ID_CENATEK,PCI_DEVICE_ID_CENATEK_IDE),
.driver_data = ATA_GEN_FORCE_DMA },
- /*
- * For some reason, MCP89 on MacBook 7,1 doesn't work with
- * ahci, use ata_generic instead.
- */
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP89_SATA,
- PCI_VENDOR_ID_APPLE, 0xcb89,
- .driver_data = ATA_GEN_FORCE_DMA },
#if !defined(CONFIG_PATA_TOSHIBA) && !defined(CONFIG_PATA_TOSHIBA_MODULE)
{ PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_1), },
{ PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_2), },
diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c
index c482f8c..36605ab 100644
--- a/drivers/ata/libahci.c
+++ b/drivers/ata/libahci.c
@@ -1764,7 +1764,7 @@ static void ahci_handle_port_interrupt(struct ata_port *ap,
}
}
-void ahci_port_intr(struct ata_port *ap)
+static void ahci_port_intr(struct ata_port *ap)
{
void __iomem *port_mmio = ahci_port_base(ap);
u32 status;
@@ -1797,7 +1797,7 @@ irqreturn_t ahci_thread_fn(int irq, void *dev_instance)
}
EXPORT_SYMBOL_GPL(ahci_thread_fn);
-void ahci_hw_port_interrupt(struct ata_port *ap)
+static void ahci_hw_port_interrupt(struct ata_port *ap)
{
void __iomem *port_mmio = ahci_port_base(ap);
struct ahci_port_priv *pp = ap->private_data;
diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c
index 4372cfa..9e69a53 100644
--- a/drivers/ata/libata-acpi.c
+++ b/drivers/ata/libata-acpi.c
@@ -20,8 +20,6 @@
#include <scsi/scsi_device.h>
#include "libata.h"
-#include <acpi/acpi_bus.h>
-
unsigned int ata_acpi_gtf_filter = ATA_ACPI_FILTER_DEFAULT;
module_param_named(acpi_gtf_filter, ata_acpi_gtf_filter, int, 0644);
MODULE_PARM_DESC(acpi_gtf_filter, "filter mask for ACPI _GTF commands, set to filter out (0x1=set xfermode, 0x2=lock/freeze lock, 0x4=DIPM, 0x8=FPDMA non-zero offset, 0x10=FPDMA DMA Setup FIS auto-activate)");
@@ -180,12 +178,12 @@ static const struct acpi_dock_ops ata_acpi_ap_dock_ops = {
/* bind acpi handle to pata port */
void ata_acpi_bind_port(struct ata_port *ap)
{
- acpi_handle host_handle = ACPI_HANDLE(ap->host->dev);
+ struct acpi_device *host_companion = ACPI_COMPANION(ap->host->dev);
- if (libata_noacpi || ap->flags & ATA_FLAG_ACPI_SATA || !host_handle)
+ if (libata_noacpi || ap->flags & ATA_FLAG_ACPI_SATA || !host_companion)
return;
- acpi_preset_companion(&ap->tdev, host_handle, ap->port_no);
+ acpi_preset_companion(&ap->tdev, host_companion, ap->port_no);
if (ata_acpi_gtm(ap, &ap->__acpi_init_gtm) == 0)
ap->pflags |= ATA_PFLAG_INIT_GTM_VALID;
@@ -198,17 +196,17 @@ void ata_acpi_bind_port(struct ata_port *ap)
void ata_acpi_bind_dev(struct ata_device *dev)
{
struct ata_port *ap = dev->link->ap;
- acpi_handle port_handle = ACPI_HANDLE(&ap->tdev);
- acpi_handle host_handle = ACPI_HANDLE(ap->host->dev);
- acpi_handle parent_handle;
+ struct acpi_device *port_companion = ACPI_COMPANION(&ap->tdev);
+ struct acpi_device *host_companion = ACPI_COMPANION(ap->host->dev);
+ struct acpi_device *parent;
u64 adr;
/*
- * For both sata/pata devices, host handle is required.
- * For pata device, port handle is also required.
+ * For both sata/pata devices, host companion device is required.
+ * For pata device, port companion device is also required.
*/
- if (libata_noacpi || !host_handle ||
- (!(ap->flags & ATA_FLAG_ACPI_SATA) && !port_handle))
+ if (libata_noacpi || !host_companion ||
+ (!(ap->flags & ATA_FLAG_ACPI_SATA) && !port_companion))
return;
if (ap->flags & ATA_FLAG_ACPI_SATA) {
@@ -216,13 +214,13 @@ void ata_acpi_bind_dev(struct ata_device *dev)
adr = SATA_ADR(ap->port_no, NO_PORT_MULT);
else
adr = SATA_ADR(ap->port_no, dev->link->pmp);
- parent_handle = host_handle;
+ parent = host_companion;
} else {
adr = dev->devno;
- parent_handle = port_handle;
+ parent = port_companion;
}
- acpi_preset_companion(&dev->tdev, parent_handle, adr);
+ acpi_preset_companion(&dev->tdev, parent, adr);
register_hotplug_dock_device(ata_dev_acpi_handle(dev),
&ata_acpi_dev_dock_ops, dev, NULL, NULL);
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 1274720..a440958 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -2149,9 +2149,16 @@ static int ata_dev_config_ncq(struct ata_device *dev,
"failed to get NCQ Send/Recv Log Emask 0x%x\n",
err_mask);
} else {
+ u8 *cmds = dev->ncq_send_recv_cmds;
+
dev->flags |= ATA_DFLAG_NCQ_SEND_RECV;
- memcpy(dev->ncq_send_recv_cmds, ap->sector_buf,
- ATA_LOG_NCQ_SEND_RECV_SIZE);
+ memcpy(cmds, ap->sector_buf, ATA_LOG_NCQ_SEND_RECV_SIZE);
+
+ if (dev->horkage & ATA_HORKAGE_NO_NCQ_TRIM) {
+ ata_dev_dbg(dev, "disabling queued TRIM support\n");
+ cmds[ATA_LOG_NCQ_SEND_RECV_DSM_OFFSET] &=
+ ~ATA_LOG_NCQ_SEND_RECV_DSM_TRIM;
+ }
}
}
@@ -2215,6 +2222,16 @@ int ata_dev_configure(struct ata_device *dev)
if (rc)
return rc;
+ /* some WD SATA-1 drives have issues with LPM, turn on NOLPM for them */
+ if ((dev->horkage & ATA_HORKAGE_WD_BROKEN_LPM) &&
+ (id[ATA_ID_SATA_CAPABILITY] & 0xe) == 0x2)
+ dev->horkage |= ATA_HORKAGE_NOLPM;
+
+ if (dev->horkage & ATA_HORKAGE_NOLPM) {
+ ata_dev_warn(dev, "LPM support broken, forcing max_power\n");
+ dev->link->ap->target_lpm_policy = ATA_LPM_MAX_POWER;
+ }
+
/* let ACPI work its magic */
rc = ata_acpi_on_devcfg(dev);
if (rc)
@@ -4156,6 +4173,9 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
{ "ST3320[68]13AS", "SD1[5-9]", ATA_HORKAGE_NONCQ |
ATA_HORKAGE_FIRMWARE_WARN },
+ /* Seagate Momentus SpinPoint M8 seem to have FPMDA_AA issues */
+ { "ST1000LM024 HN-M101MBB", "2AR10001", ATA_HORKAGE_BROKEN_FPDMA_AA },
+
/* Blacklist entries taken from Silicon Image 3124/3132
Windows driver .inf file - also several Linux problem reports */
{ "HTS541060G9SA00", "MB3OC60D", ATA_HORKAGE_NONCQ, },
@@ -4202,6 +4222,27 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
{ "PIONEER DVD-RW DVR-212D", NULL, ATA_HORKAGE_NOSETXFER },
{ "PIONEER DVD-RW DVR-216D", NULL, ATA_HORKAGE_NOSETXFER },
+ /* devices that don't properly handle queued TRIM commands */
+ { "Micron_M500*", NULL, ATA_HORKAGE_NO_NCQ_TRIM, },
+ { "Crucial_CT???M500SSD1", NULL, ATA_HORKAGE_NO_NCQ_TRIM, },
+
+ /*
+ * Some WD SATA-I drives spin up and down erratically when the link
+ * is put into the slumber mode. We don't have full list of the
+ * affected devices. Disable LPM if the device matches one of the
+ * known prefixes and is SATA-1. As a side effect LPM partial is
+ * lost too.
+ *
+ * https://bugzilla.kernel.org/show_bug.cgi?id=57211
+ */
+ { "WDC WD800JD-*", NULL, ATA_HORKAGE_WD_BROKEN_LPM },
+ { "WDC WD1200JD-*", NULL, ATA_HORKAGE_WD_BROKEN_LPM },
+ { "WDC WD1600JD-*", NULL, ATA_HORKAGE_WD_BROKEN_LPM },
+ { "WDC WD2000JD-*", NULL, ATA_HORKAGE_WD_BROKEN_LPM },
+ { "WDC WD2500JD-*", NULL, ATA_HORKAGE_WD_BROKEN_LPM },
+ { "WDC WD3000JD-*", NULL, ATA_HORKAGE_WD_BROKEN_LPM },
+ { "WDC WD3200JD-*", NULL, ATA_HORKAGE_WD_BROKEN_LPM },
+
/* End Marker */
{ }
};
@@ -6519,6 +6560,7 @@ static int __init ata_parse_force_one(char **cur,
{ "norst", .lflags = ATA_LFLAG_NO_HRST | ATA_LFLAG_NO_SRST },
{ "rstonce", .lflags = ATA_LFLAG_RST_ONCE },
{ "atapi_dmadir", .horkage_on = ATA_HORKAGE_ATAPI_DMADIR },
+ { "disable", .horkage_on = ATA_HORKAGE_DISABLE },
};
char *start = *cur, *p = *cur;
char *id, *val, *endp;
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 92d7797..6d87570 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -2402,7 +2402,7 @@ static void ata_eh_link_report(struct ata_link *link)
struct ata_port *ap = link->ap;
struct ata_eh_context *ehc = &link->eh_context;
const char *frozen, *desc;
- char tries_buf[6];
+ char tries_buf[6] = "";
int tag, nr_failed = 0;
if (ehc->i.flags & ATA_EHI_QUIET)
@@ -2433,9 +2433,8 @@ static void ata_eh_link_report(struct ata_link *link)
if (ap->pflags & ATA_PFLAG_FROZEN)
frozen = " frozen";
- memset(tries_buf, 0, sizeof(tries_buf));
if (ap->eh_tries < ATA_EH_MAX_TRIES)
- snprintf(tries_buf, sizeof(tries_buf) - 1, " t%d",
+ snprintf(tries_buf, sizeof(tries_buf), " t%d",
ap->eh_tries);
if (ehc->i.dev) {
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index ab58556..ef8567d 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -111,12 +111,14 @@ static const char *ata_lpm_policy_names[] = {
[ATA_LPM_MIN_POWER] = "min_power",
};
-static ssize_t ata_scsi_lpm_store(struct device *dev,
+static ssize_t ata_scsi_lpm_store(struct device *device,
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct Scsi_Host *shost = class_to_shost(dev);
+ struct Scsi_Host *shost = class_to_shost(device);
struct ata_port *ap = ata_shost_to_port(shost);
+ struct ata_link *link;
+ struct ata_device *dev;
enum ata_lpm_policy policy;
unsigned long flags;
@@ -132,10 +134,20 @@ static ssize_t ata_scsi_lpm_store(struct device *dev,
return -EINVAL;
spin_lock_irqsave(ap->lock, flags);
+
+ ata_for_each_link(link, ap, EDGE) {
+ ata_for_each_dev(dev, &ap->link, ENABLED) {
+ if (dev->horkage & ATA_HORKAGE_NOLPM) {
+ count = -EOPNOTSUPP;
+ goto out_unlock;
+ }
+ }
+ }
+
ap->target_lpm_policy = policy;
ata_port_schedule_eh(ap);
+out_unlock:
spin_unlock_irqrestore(ap->lock, flags);
-
return count;
}
@@ -3872,6 +3884,27 @@ void ata_scsi_hotplug(struct work_struct *work)
return;
}
+ /*
+ * XXX - UGLY HACK
+ *
+ * The block layer suspend/resume path is fundamentally broken due
+ * to freezable kthreads and workqueue and may deadlock if a block
+ * device gets removed while resume is in progress. I don't know
+ * what the solution is short of removing freezable kthreads and
+ * workqueues altogether.
+ *
+ * The following is an ugly hack to avoid kicking off device
+ * removal while freezer is active. This is a joke but does avoid
+ * this particular deadlock scenario.
+ *
+ * https://bugzilla.kernel.org/show_bug.cgi?id=62801
+ * http://marc.info/?l=linux-kernel&m=138695698516487
+ */
+#ifdef CONFIG_FREEZER
+ while (pm_freezing)
+ msleep(10);
+#endif
+
DPRINTK("ENTER\n");
mutex_lock(&ap->scsi_scan_mutex);
diff --git a/drivers/ata/pata_acpi.c b/drivers/ata/pata_acpi.c
index 73212c9..62c9ac8 100644
--- a/drivers/ata/pata_acpi.c
+++ b/drivers/ata/pata_acpi.c
@@ -12,11 +12,10 @@
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/gfp.h>
-#include <scsi/scsi_host.h>
-#include <acpi/acpi_bus.h>
-
+#include <linux/acpi.h>
#include <linux/libata.h>
#include <linux/ata.h>
+#include <scsi/scsi_host.h>
#define DRV_NAME "pata_acpi"
#define DRV_VERSION "0.2.3"
diff --git a/drivers/ata/pata_samsung_cf.c b/drivers/ata/pata_samsung_cf.c
index 898e544..a79566d 100644
--- a/drivers/ata/pata_samsung_cf.c
+++ b/drivers/ata/pata_samsung_cf.c
@@ -24,11 +24,34 @@
#include <linux/slab.h>
#include <linux/platform_data/ata-samsung_cf.h>
-#include <plat/regs-ata.h>
#define DRV_NAME "pata_samsung_cf"
#define DRV_VERSION "0.1"
+#define S3C_CFATA_REG(x) (x)
+#define S3C_CFATA_MUX S3C_CFATA_REG(0x0)
+#define S3C_ATA_CTRL S3C_CFATA_REG(0x0)
+#define S3C_ATA_CMD S3C_CFATA_REG(0x8)
+#define S3C_ATA_IRQ S3C_CFATA_REG(0x10)
+#define S3C_ATA_IRQ_MSK S3C_CFATA_REG(0x14)
+#define S3C_ATA_CFG S3C_CFATA_REG(0x18)
+
+#define S3C_ATA_PIO_TIME S3C_CFATA_REG(0x2c)
+#define S3C_ATA_PIO_DTR S3C_CFATA_REG(0x54)
+#define S3C_ATA_PIO_FED S3C_CFATA_REG(0x58)
+#define S3C_ATA_PIO_SCR S3C_CFATA_REG(0x5c)
+#define S3C_ATA_PIO_LLR S3C_CFATA_REG(0x60)
+#define S3C_ATA_PIO_LMR S3C_CFATA_REG(0x64)
+#define S3C_ATA_PIO_LHR S3C_CFATA_REG(0x68)
+#define S3C_ATA_PIO_DVR S3C_CFATA_REG(0x6c)
+#define S3C_ATA_PIO_CSD S3C_CFATA_REG(0x70)
+#define S3C_ATA_PIO_DAD S3C_CFATA_REG(0x74)
+#define S3C_ATA_PIO_RDATA S3C_CFATA_REG(0x7c)
+
+#define S3C_CFATA_MUX_TRUEIDE 0x01
+#define S3C_ATA_CFG_SWAP 0x40
+#define S3C_ATA_CFG_IORDYEN 0x02
+
enum s3c_cpu_type {
TYPE_S3C64XX,
TYPE_S5PC100,
@@ -495,22 +518,10 @@ static int __init pata_s3c_probe(struct platform_device *pdev)
info->irq = platform_get_irq(pdev, 0);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (res == NULL) {
- dev_err(dev, "failed to get mem resource\n");
- return -EINVAL;
- }
-
- if (!devm_request_mem_region(dev, res->start,
- resource_size(res), DRV_NAME)) {
- dev_err(dev, "error requesting register region\n");
- return -EBUSY;
- }
- info->ide_addr = devm_ioremap(dev, res->start, resource_size(res));
- if (!info->ide_addr) {
- dev_err(dev, "failed to map IO base address\n");
- return -ENOMEM;
- }
+ info->ide_addr = devm_ioremap_resource(dev, res);
+ if (IS_ERR(info->ide_addr))
+ return PTR_ERR(info->ide_addr);
info->clk = devm_clk_get(&pdev->dev, "cfcon");
if (IS_ERR(info->clk)) {
diff --git a/drivers/ata/sata_highbank.c b/drivers/ata/sata_highbank.c
index ea3b3dc..870b11e 100644
--- a/drivers/ata/sata_highbank.c
+++ b/drivers/ata/sata_highbank.c
@@ -29,7 +29,6 @@
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/libata.h>
-#include <linux/ahci_platform.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/export.h>
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
index 56be3181..52b8181 100644
--- a/drivers/ata/sata_mv.c
+++ b/drivers/ata/sata_mv.c
@@ -60,6 +60,7 @@
#include <linux/dma-mapping.h>
#include <linux/device.h>
#include <linux/clk.h>
+#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/ata_platform.h>
#include <linux/mbus.h>
@@ -304,6 +305,7 @@ enum {
MV5_LTMODE = 0x30,
MV5_PHY_CTL = 0x0C,
SATA_IFCFG = 0x050,
+ LP_PHY_CTL = 0x058,
MV_M2_PREAMP_MASK = 0x7e0,
@@ -431,6 +433,7 @@ enum {
MV_HP_CUT_THROUGH = (1 << 10), /* can use EDMA cut-through */
MV_HP_FLAG_SOC = (1 << 11), /* SystemOnChip, no PCI */
MV_HP_QUIRK_LED_BLINK_EN = (1 << 12), /* is led blinking enabled? */
+ MV_HP_FIX_LP_PHY_CTL = (1 << 13), /* fix speed in LP_PHY_CTL ? */
/* Port private flags (pp_flags) */
MV_PP_FLAG_EDMA_EN = (1 << 0), /* is EDMA engine enabled? */
@@ -563,6 +566,12 @@ struct mv_host_priv {
struct clk *clk;
struct clk **port_clks;
/*
+ * Some devices have a SATA PHY which can be enabled/disabled
+ * in order to save power. These are optional: if the platform
+ * devices does not have any phy, they won't be used.
+ */
+ struct phy **port_phys;
+ /*
* These consistent DMA memory pools give us guaranteed
* alignment for hardware-accessed data structures,
* and less memory waste in accomplishing the alignment.
@@ -1358,6 +1367,7 @@ static int mv_scr_write(struct ata_link *link, unsigned int sc_reg_in, u32 val)
if (ofs != 0xffffffffU) {
void __iomem *addr = mv_ap_base(link->ap) + ofs;
+ struct mv_host_priv *hpriv = link->ap->host->private_data;
if (sc_reg_in == SCR_CONTROL) {
/*
* Workaround for 88SX60x1 FEr SATA#26:
@@ -1374,6 +1384,18 @@ static int mv_scr_write(struct ata_link *link, unsigned int sc_reg_in, u32 val)
*/
if ((val & 0xf) == 1 || (readl(addr) & 0xf) == 1)
val |= 0xf000;
+
+ if (hpriv->hp_flags & MV_HP_FIX_LP_PHY_CTL) {
+ void __iomem *lp_phy_addr =
+ mv_ap_base(link->ap) + LP_PHY_CTL;
+ /*
+ * Set PHY speed according to SControl speed.
+ */
+ if ((val & 0xf0) == 0x10)
+ writelfl(0x7, lp_phy_addr);
+ else
+ writelfl(0x227, lp_phy_addr);
+ }
}
writelfl(val, addr);
return 0;
@@ -4076,6 +4098,11 @@ static int mv_platform_probe(struct platform_device *pdev)
GFP_KERNEL);
if (!hpriv->port_clks)
return -ENOMEM;
+ hpriv->port_phys = devm_kzalloc(&pdev->dev,
+ sizeof(struct phy *) * n_ports,
+ GFP_KERNEL);
+ if (!hpriv->port_phys)
+ return -ENOMEM;
host->private_data = hpriv;
hpriv->n_ports = n_ports;
hpriv->board_idx = chip_soc;
@@ -4097,6 +4124,19 @@ static int mv_platform_probe(struct platform_device *pdev)
hpriv->port_clks[port] = clk_get(&pdev->dev, port_number);
if (!IS_ERR(hpriv->port_clks[port]))
clk_prepare_enable(hpriv->port_clks[port]);
+
+ sprintf(port_number, "port%d", port);
+ hpriv->port_phys[port] = devm_phy_optional_get(&pdev->dev,
+ port_number);
+ if (IS_ERR(hpriv->port_phys[port])) {
+ rc = PTR_ERR(hpriv->port_phys[port]);
+ hpriv->port_phys[port] = NULL;
+ if (rc != -EPROBE_DEFER)
+ dev_warn(&pdev->dev, "error getting phy %d",
+ rc);
+ goto err;
+ } else
+ phy_power_on(hpriv->port_phys[port]);
}
/*
@@ -4110,6 +4150,15 @@ static int mv_platform_probe(struct platform_device *pdev)
if (rc)
goto err;
+ /*
+ * To allow disk hotplug on Armada 370/XP SoCs, the PHY speed must be
+ * updated in the LP_PHY_CTL register.
+ */
+ if (pdev->dev.of_node &&
+ of_device_is_compatible(pdev->dev.of_node,
+ "marvell,armada-370-sata"))
+ hpriv->hp_flags |= MV_HP_FIX_LP_PHY_CTL;
+
/* initialize adapter */
rc = mv_init_host(host);
if (rc)
@@ -4132,6 +4181,8 @@ err:
clk_disable_unprepare(hpriv->port_clks[port]);
clk_put(hpriv->port_clks[port]);
}
+ if (hpriv->port_phys[port])
+ phy_power_off(hpriv->port_phys[port]);
}
return rc;
@@ -4161,6 +4212,8 @@ static int mv_platform_remove(struct platform_device *pdev)
clk_disable_unprepare(hpriv->port_clks[port]);
clk_put(hpriv->port_clks[port]);
}
+ if (hpriv->port_phys[port])
+ phy_power_off(hpriv->port_phys[port]);
}
return 0;
}
@@ -4209,6 +4262,7 @@ static int mv_platform_resume(struct platform_device *pdev)
#ifdef CONFIG_OF
static struct of_device_id mv_sata_dt_ids[] = {
+ { .compatible = "marvell,armada-370-sata", },
{ .compatible = "marvell,orion-sata", },
{},
};
diff --git a/drivers/ata/sata_rcar.c b/drivers/ata/sata_rcar.c
index 1dae9a9..2b25bd8 100644
--- a/drivers/ata/sata_rcar.c
+++ b/drivers/ata/sata_rcar.c
@@ -15,6 +15,7 @@
#include <linux/module.h>
#include <linux/ata.h>
#include <linux/libata.h>
+#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/err.h>
@@ -123,12 +124,37 @@
#define SATA_RCAR_DMA_BOUNDARY 0x1FFFFFFEUL
+/* Gen2 Physical Layer Control Registers */
+#define RCAR_GEN2_PHY_CTL1_REG 0x1704
+#define RCAR_GEN2_PHY_CTL1 0x34180002
+#define RCAR_GEN2_PHY_CTL1_SS 0xC180 /* Spread Spectrum */
+
+#define RCAR_GEN2_PHY_CTL2_REG 0x170C
+#define RCAR_GEN2_PHY_CTL2 0x00002303
+
+#define RCAR_GEN2_PHY_CTL3_REG 0x171C
+#define RCAR_GEN2_PHY_CTL3 0x000B0194
+
+#define RCAR_GEN2_PHY_CTL4_REG 0x1724
+#define RCAR_GEN2_PHY_CTL4 0x00030994
+
+#define RCAR_GEN2_PHY_CTL5_REG 0x1740
+#define RCAR_GEN2_PHY_CTL5 0x03004001
+#define RCAR_GEN2_PHY_CTL5_DC BIT(1) /* DC connection */
+#define RCAR_GEN2_PHY_CTL5_TR BIT(2) /* Termination Resistor */
+
+enum sata_rcar_type {
+ RCAR_GEN1_SATA,
+ RCAR_GEN2_SATA,
+};
+
struct sata_rcar_priv {
void __iomem *base;
struct clk *clk;
+ enum sata_rcar_type type;
};
-static void sata_rcar_phy_initialize(struct sata_rcar_priv *priv)
+static void sata_rcar_gen1_phy_preinit(struct sata_rcar_priv *priv)
{
void __iomem *base = priv->base;
@@ -141,8 +167,8 @@ static void sata_rcar_phy_initialize(struct sata_rcar_priv *priv)
iowrite32(0, base + SATAPHYRESET_REG);
}
-static void sata_rcar_phy_write(struct sata_rcar_priv *priv, u16 reg, u32 val,
- int group)
+static void sata_rcar_gen1_phy_write(struct sata_rcar_priv *priv, u16 reg,
+ u32 val, int group)
{
void __iomem *base = priv->base;
int timeout;
@@ -170,6 +196,29 @@ static void sata_rcar_phy_write(struct sata_rcar_priv *priv, u16 reg, u32 val,
iowrite32(0, base + SATAPHYADDR_REG);
}
+static void sata_rcar_gen1_phy_init(struct sata_rcar_priv *priv)
+{
+ sata_rcar_gen1_phy_preinit(priv);
+ sata_rcar_gen1_phy_write(priv, SATAPCTLR1_REG, 0x00200188, 0);
+ sata_rcar_gen1_phy_write(priv, SATAPCTLR1_REG, 0x00200188, 1);
+ sata_rcar_gen1_phy_write(priv, SATAPCTLR3_REG, 0x0000A061, 0);
+ sata_rcar_gen1_phy_write(priv, SATAPCTLR2_REG, 0x20000000, 0);
+ sata_rcar_gen1_phy_write(priv, SATAPCTLR2_REG, 0x20000000, 1);
+ sata_rcar_gen1_phy_write(priv, SATAPCTLR4_REG, 0x28E80000, 0);
+}
+
+static void sata_rcar_gen2_phy_init(struct sata_rcar_priv *priv)
+{
+ void __iomem *base = priv->base;
+
+ iowrite32(RCAR_GEN2_PHY_CTL1, base + RCAR_GEN2_PHY_CTL1_REG);
+ iowrite32(RCAR_GEN2_PHY_CTL2, base + RCAR_GEN2_PHY_CTL2_REG);
+ iowrite32(RCAR_GEN2_PHY_CTL3, base + RCAR_GEN2_PHY_CTL3_REG);
+ iowrite32(RCAR_GEN2_PHY_CTL4, base + RCAR_GEN2_PHY_CTL4_REG);
+ iowrite32(RCAR_GEN2_PHY_CTL5 | RCAR_GEN2_PHY_CTL5_DC |
+ RCAR_GEN2_PHY_CTL5_TR, base + RCAR_GEN2_PHY_CTL5_REG);
+}
+
static void sata_rcar_freeze(struct ata_port *ap)
{
struct sata_rcar_priv *priv = ap->host->private_data;
@@ -738,13 +787,17 @@ static void sata_rcar_init_controller(struct ata_host *host)
u32 val;
/* reset and setup phy */
- sata_rcar_phy_initialize(priv);
- sata_rcar_phy_write(priv, SATAPCTLR1_REG, 0x00200188, 0);
- sata_rcar_phy_write(priv, SATAPCTLR1_REG, 0x00200188, 1);
- sata_rcar_phy_write(priv, SATAPCTLR3_REG, 0x0000A061, 0);
- sata_rcar_phy_write(priv, SATAPCTLR2_REG, 0x20000000, 0);
- sata_rcar_phy_write(priv, SATAPCTLR2_REG, 0x20000000, 1);
- sata_rcar_phy_write(priv, SATAPCTLR4_REG, 0x28E80000, 0);
+ switch (priv->type) {
+ case RCAR_GEN1_SATA:
+ sata_rcar_gen1_phy_init(priv);
+ break;
+ case RCAR_GEN2_SATA:
+ sata_rcar_gen2_phy_init(priv);
+ break;
+ default:
+ dev_warn(host->dev, "SATA phy is not initialized\n");
+ break;
+ }
/* SATA-IP reset state */
val = ioread32(base + ATAPI_CONTROL1_REG);
@@ -770,8 +823,40 @@ static void sata_rcar_init_controller(struct ata_host *host)
iowrite32(ATAPI_INT_ENABLE_SATAINT, base + ATAPI_INT_ENABLE_REG);
}
+static struct of_device_id sata_rcar_match[] = {
+ {
+ /* Deprecated by "renesas,sata-r8a7779" */
+ .compatible = "renesas,rcar-sata",
+ .data = (void *)RCAR_GEN1_SATA,
+ },
+ {
+ .compatible = "renesas,sata-r8a7779",
+ .data = (void *)RCAR_GEN1_SATA,
+ },
+ {
+ .compatible = "renesas,sata-r8a7790",
+ .data = (void *)RCAR_GEN2_SATA
+ },
+ {
+ .compatible = "renesas,sata-r8a7791",
+ .data = (void *)RCAR_GEN2_SATA
+ },
+ { },
+};
+MODULE_DEVICE_TABLE(of, sata_rcar_match);
+
+static const struct platform_device_id sata_rcar_id_table[] = {
+ { "sata_rcar", RCAR_GEN1_SATA }, /* Deprecated by "sata-r8a7779" */
+ { "sata-r8a7779", RCAR_GEN1_SATA },
+ { "sata-r8a7790", RCAR_GEN2_SATA },
+ { "sata-r8a7791", RCAR_GEN2_SATA },
+ { },
+};
+MODULE_DEVICE_TABLE(platform, sata_rcar_id_table);
+
static int sata_rcar_probe(struct platform_device *pdev)
{
+ const struct of_device_id *of_id;
struct ata_host *host;
struct sata_rcar_priv *priv;
struct resource *mem;
@@ -787,6 +872,12 @@ static int sata_rcar_probe(struct platform_device *pdev)
if (!priv)
return -ENOMEM;
+ of_id = of_match_device(sata_rcar_match, &pdev->dev);
+ if (of_id)
+ priv->type = (enum sata_rcar_type)of_id->data;
+ else
+ priv->type = platform_get_device_id(pdev)->driver_data;
+
priv->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(priv->clk)) {
dev_err(&pdev->dev, "failed to get access to sata clock\n");
@@ -892,15 +983,10 @@ static const struct dev_pm_ops sata_rcar_pm_ops = {
};
#endif
-static struct of_device_id sata_rcar_match[] = {
- { .compatible = "renesas,rcar-sata", },
- {},
-};
-MODULE_DEVICE_TABLE(of, sata_rcar_match);
-
static struct platform_driver sata_rcar_driver = {
.probe = sata_rcar_probe,
.remove = sata_rcar_remove,
+ .id_table = sata_rcar_id_table,
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
diff --git a/drivers/ata/sata_sis.c b/drivers/ata/sata_sis.c
index fe3ca09..1ad2f62 100644
--- a/drivers/ata/sata_sis.c
+++ b/drivers/ata/sata_sis.c
@@ -83,6 +83,10 @@ static struct pci_driver sis_pci_driver = {
.id_table = sis_pci_tbl,
.probe = sis_init_one,
.remove = ata_pci_remove_one,
+#ifdef CONFIG_PM
+ .suspend = ata_pci_device_suspend,
+ .resume = ata_pci_device_resume,
+#endif
};
static struct scsi_host_template sis_sht = {
OpenPOWER on IntegriCloud