Merge branch 'for-3.20' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata
Pull libata changes from Tejun Heo: "Mostly driver-specific changes. Nothing too noteworthy. This pull request contains three merges from for-3.19-fixes. The first two are to pull ahci_xgene and sata_dwc_460ex fix commits which are depended upon by later changes. The last one is to pull in a fix patch which missed the v3.19-rc window" * 'for-3.20' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata: (24 commits) ahci_xgene: Fix the dma state machine lockup for the ATA_CMD_SMART PIO mode command. ata: libahci: Use of_platform_device_create only if supported sata_mv: Delete unnecessary checks before the function call "phy_power_off" ata: Delete unnecessary checks before the function call "pci_dev_put" ata: pata_platform: fix owner module reference mismatch for scsi host ata: ahci_platform: fix owner module reference mismatch for scsi host pata_pdc2027x: Use 64-bit timekeeping ata: libahci: Fix devres cleanup on failure ata: libahci: Allow using multiple regulators Documentation: bindings: Add the regulator property to the sub-nodes AHCI bindings ata: libahci: Clean-up the ahci_platform_en/disable_phys functions sata_rcar: extend PM methods sata_dwc_460ex: disable compilation on ARM and ARM64 ata: libata-core: Remove unused function sata_dwc_460ex: convert to devm_kzalloc in ->probe() sata_dwc_460ex: remove extra message sata_dwc_460ex: use np local variable in ->probe() sata_dwc_460ex: fix most of the sparse warnings sata_dwc_460ex: enable COMPILE_TEST for the driver sata_dwc_460ex: remove redundant dev_set_drvdata ...
This commit is contained in:
commit
3e8c04eb11
|
@ -37,9 +37,10 @@ Required properties when using sub-nodes:
|
||||||
|
|
||||||
|
|
||||||
Sub-nodes required properties:
|
Sub-nodes required properties:
|
||||||
- reg : the port number
|
- reg : the port number
|
||||||
- phys : reference to the SATA PHY node
|
And at least one of the following properties:
|
||||||
|
- phys : reference to the SATA PHY node
|
||||||
|
- target-supply : regulator for SATA target power
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
sata@ffe08000 {
|
sata@ffe08000 {
|
||||||
|
@ -68,10 +69,12 @@ With sub-nodes:
|
||||||
sata0: sata-port@0 {
|
sata0: sata-port@0 {
|
||||||
reg = <0>;
|
reg = <0>;
|
||||||
phys = <&sata_phy 0>;
|
phys = <&sata_phy 0>;
|
||||||
|
target-supply = <®_sata0>;
|
||||||
};
|
};
|
||||||
|
|
||||||
sata1: sata-port@1 {
|
sata1: sata-port@1 {
|
||||||
reg = <1>;
|
reg = <1>;
|
||||||
phys = <&sata_phy 1>;
|
phys = <&sata_phy 1>;
|
||||||
|
target-supply = <®_sata1>;;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -269,7 +269,7 @@ config ATA_PIIX
|
||||||
|
|
||||||
config SATA_DWC
|
config SATA_DWC
|
||||||
tristate "DesignWare Cores SATA support"
|
tristate "DesignWare Cores SATA support"
|
||||||
depends on 460EX
|
depends on 460EX || (COMPILE_TEST && !(ARM || ARM64))
|
||||||
help
|
help
|
||||||
This option enables support for the on-chip SATA controller of the
|
This option enables support for the on-chip SATA controller of the
|
||||||
AppliedMicro processor 460EX.
|
AppliedMicro processor 460EX.
|
||||||
|
|
|
@ -333,7 +333,7 @@ struct ahci_host_priv {
|
||||||
u32 em_msg_type; /* EM message type */
|
u32 em_msg_type; /* EM message type */
|
||||||
bool got_runtime_pm; /* Did we do pm_runtime_get? */
|
bool got_runtime_pm; /* Did we do pm_runtime_get? */
|
||||||
struct clk *clks[AHCI_MAX_CLKS]; /* Optional */
|
struct clk *clks[AHCI_MAX_CLKS]; /* Optional */
|
||||||
struct regulator *target_pwr; /* Optional */
|
struct regulator **target_pwrs; /* Optional */
|
||||||
/*
|
/*
|
||||||
* If platform uses PHYs. There is a 1:1 relation between the port number and
|
* If platform uses PHYs. There is a 1:1 relation between the port number and
|
||||||
* the PHY position in this array.
|
* the PHY position in this array.
|
||||||
|
@ -354,6 +354,10 @@ extern int ahci_ignore_sss;
|
||||||
extern struct device_attribute *ahci_shost_attrs[];
|
extern struct device_attribute *ahci_shost_attrs[];
|
||||||
extern struct device_attribute *ahci_sdev_attrs[];
|
extern struct device_attribute *ahci_sdev_attrs[];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This must be instantiated by the edge drivers. Read the comments
|
||||||
|
* for ATA_BASE_SHT
|
||||||
|
*/
|
||||||
#define AHCI_SHT(drv_name) \
|
#define AHCI_SHT(drv_name) \
|
||||||
ATA_NCQ_SHT(drv_name), \
|
ATA_NCQ_SHT(drv_name), \
|
||||||
.can_queue = AHCI_MAX_CMDS - 1, \
|
.can_queue = AHCI_MAX_CMDS - 1, \
|
||||||
|
|
|
@ -16,6 +16,8 @@
|
||||||
#include <linux/ahci_platform.h>
|
#include <linux/ahci_platform.h>
|
||||||
#include "ahci.h"
|
#include "ahci.h"
|
||||||
|
|
||||||
|
#define DRV_NAME "ahci_da850"
|
||||||
|
|
||||||
/* SATA PHY Control Register offset from AHCI base */
|
/* SATA PHY Control Register offset from AHCI base */
|
||||||
#define SATA_P0PHYCR_REG 0x178
|
#define SATA_P0PHYCR_REG 0x178
|
||||||
|
|
||||||
|
@ -59,6 +61,10 @@ static const struct ata_port_info ahci_da850_port_info = {
|
||||||
.port_ops = &ahci_platform_ops,
|
.port_ops = &ahci_platform_ops,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct scsi_host_template ahci_platform_sht = {
|
||||||
|
AHCI_SHT(DRV_NAME),
|
||||||
|
};
|
||||||
|
|
||||||
static int ahci_da850_probe(struct platform_device *pdev)
|
static int ahci_da850_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pdev->dev;
|
||||||
|
@ -85,7 +91,8 @@ static int ahci_da850_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
da850_sata_init(dev, pwrdn_reg, hpriv->mmio);
|
da850_sata_init(dev, pwrdn_reg, hpriv->mmio);
|
||||||
|
|
||||||
rc = ahci_platform_init_host(pdev, hpriv, &ahci_da850_port_info);
|
rc = ahci_platform_init_host(pdev, hpriv, &ahci_da850_port_info,
|
||||||
|
&ahci_platform_sht);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto disable_resources;
|
goto disable_resources;
|
||||||
|
|
||||||
|
@ -102,7 +109,7 @@ static struct platform_driver ahci_da850_driver = {
|
||||||
.probe = ahci_da850_probe,
|
.probe = ahci_da850_probe,
|
||||||
.remove = ata_platform_remove_one,
|
.remove = ata_platform_remove_one,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "ahci_da850",
|
.name = DRV_NAME,
|
||||||
.pm = &ahci_da850_pm_ops,
|
.pm = &ahci_da850_pm_ops,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -28,6 +28,8 @@
|
||||||
#include <linux/libata.h>
|
#include <linux/libata.h>
|
||||||
#include "ahci.h"
|
#include "ahci.h"
|
||||||
|
|
||||||
|
#define DRV_NAME "ahci-imx"
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
/* Timer 1-ms Register */
|
/* Timer 1-ms Register */
|
||||||
IMX_TIMER1MS = 0x00e0,
|
IMX_TIMER1MS = 0x00e0,
|
||||||
|
@ -221,11 +223,9 @@ static int imx_sata_enable(struct ahci_host_priv *hpriv)
|
||||||
if (imxpriv->no_device)
|
if (imxpriv->no_device)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (hpriv->target_pwr) {
|
ret = ahci_platform_enable_regulators(hpriv);
|
||||||
ret = regulator_enable(hpriv->target_pwr);
|
if (ret)
|
||||||
if (ret)
|
return ret;
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = clk_prepare_enable(imxpriv->sata_ref_clk);
|
ret = clk_prepare_enable(imxpriv->sata_ref_clk);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
@ -270,8 +270,7 @@ static int imx_sata_enable(struct ahci_host_priv *hpriv)
|
||||||
disable_clk:
|
disable_clk:
|
||||||
clk_disable_unprepare(imxpriv->sata_ref_clk);
|
clk_disable_unprepare(imxpriv->sata_ref_clk);
|
||||||
disable_regulator:
|
disable_regulator:
|
||||||
if (hpriv->target_pwr)
|
ahci_platform_disable_regulators(hpriv);
|
||||||
regulator_disable(hpriv->target_pwr);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -291,8 +290,7 @@ static void imx_sata_disable(struct ahci_host_priv *hpriv)
|
||||||
|
|
||||||
clk_disable_unprepare(imxpriv->sata_ref_clk);
|
clk_disable_unprepare(imxpriv->sata_ref_clk);
|
||||||
|
|
||||||
if (hpriv->target_pwr)
|
ahci_platform_disable_regulators(hpriv);
|
||||||
regulator_disable(hpriv->target_pwr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ahci_imx_error_handler(struct ata_port *ap)
|
static void ahci_imx_error_handler(struct ata_port *ap)
|
||||||
|
@ -524,6 +522,10 @@ static u32 imx_ahci_parse_props(struct device *dev,
|
||||||
return reg_value;
|
return reg_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct scsi_host_template ahci_platform_sht = {
|
||||||
|
AHCI_SHT(DRV_NAME),
|
||||||
|
};
|
||||||
|
|
||||||
static int imx_ahci_probe(struct platform_device *pdev)
|
static int imx_ahci_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pdev->dev;
|
||||||
|
@ -620,7 +622,8 @@ static int imx_ahci_probe(struct platform_device *pdev)
|
||||||
reg_val = clk_get_rate(imxpriv->ahb_clk) / 1000;
|
reg_val = clk_get_rate(imxpriv->ahb_clk) / 1000;
|
||||||
writel(reg_val, hpriv->mmio + IMX_TIMER1MS);
|
writel(reg_val, hpriv->mmio + IMX_TIMER1MS);
|
||||||
|
|
||||||
ret = ahci_platform_init_host(pdev, hpriv, &ahci_imx_port_info);
|
ret = ahci_platform_init_host(pdev, hpriv, &ahci_imx_port_info,
|
||||||
|
&ahci_platform_sht);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto disable_sata;
|
goto disable_sata;
|
||||||
|
|
||||||
|
@ -678,7 +681,7 @@ static struct platform_driver imx_ahci_driver = {
|
||||||
.probe = imx_ahci_probe,
|
.probe = imx_ahci_probe,
|
||||||
.remove = ata_platform_remove_one,
|
.remove = ata_platform_remove_one,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "ahci-imx",
|
.name = DRV_NAME,
|
||||||
.of_match_table = imx_ahci_of_match,
|
.of_match_table = imx_ahci_of_match,
|
||||||
.pm = &ahci_imx_pm_ops,
|
.pm = &ahci_imx_pm_ops,
|
||||||
},
|
},
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include "ahci.h"
|
#include "ahci.h"
|
||||||
|
|
||||||
|
#define DRV_NAME "ahci-mvebu"
|
||||||
|
|
||||||
#define AHCI_VENDOR_SPECIFIC_0_ADDR 0xa0
|
#define AHCI_VENDOR_SPECIFIC_0_ADDR 0xa0
|
||||||
#define AHCI_VENDOR_SPECIFIC_0_DATA 0xa4
|
#define AHCI_VENDOR_SPECIFIC_0_DATA 0xa4
|
||||||
|
|
||||||
|
@ -67,6 +69,10 @@ static const struct ata_port_info ahci_mvebu_port_info = {
|
||||||
.port_ops = &ahci_platform_ops,
|
.port_ops = &ahci_platform_ops,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct scsi_host_template ahci_platform_sht = {
|
||||||
|
AHCI_SHT(DRV_NAME),
|
||||||
|
};
|
||||||
|
|
||||||
static int ahci_mvebu_probe(struct platform_device *pdev)
|
static int ahci_mvebu_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct ahci_host_priv *hpriv;
|
struct ahci_host_priv *hpriv;
|
||||||
|
@ -88,7 +94,8 @@ static int ahci_mvebu_probe(struct platform_device *pdev)
|
||||||
ahci_mvebu_mbus_config(hpriv, dram);
|
ahci_mvebu_mbus_config(hpriv, dram);
|
||||||
ahci_mvebu_regret_option(hpriv);
|
ahci_mvebu_regret_option(hpriv);
|
||||||
|
|
||||||
rc = ahci_platform_init_host(pdev, hpriv, &ahci_mvebu_port_info);
|
rc = ahci_platform_init_host(pdev, hpriv, &ahci_mvebu_port_info,
|
||||||
|
&ahci_platform_sht);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto disable_resources;
|
goto disable_resources;
|
||||||
|
|
||||||
|
@ -114,7 +121,7 @@ static struct platform_driver ahci_mvebu_driver = {
|
||||||
.probe = ahci_mvebu_probe,
|
.probe = ahci_mvebu_probe,
|
||||||
.remove = ata_platform_remove_one,
|
.remove = ata_platform_remove_one,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "ahci-mvebu",
|
.name = DRV_NAME,
|
||||||
.of_match_table = ahci_mvebu_of_match,
|
.of_match_table = ahci_mvebu_of_match,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -22,6 +22,8 @@
|
||||||
#include <linux/ahci_platform.h>
|
#include <linux/ahci_platform.h>
|
||||||
#include "ahci.h"
|
#include "ahci.h"
|
||||||
|
|
||||||
|
#define DRV_NAME "ahci"
|
||||||
|
|
||||||
static const struct ata_port_info ahci_port_info = {
|
static const struct ata_port_info ahci_port_info = {
|
||||||
.flags = AHCI_FLAG_COMMON,
|
.flags = AHCI_FLAG_COMMON,
|
||||||
.pio_mask = ATA_PIO4,
|
.pio_mask = ATA_PIO4,
|
||||||
|
@ -29,6 +31,10 @@ static const struct ata_port_info ahci_port_info = {
|
||||||
.port_ops = &ahci_platform_ops,
|
.port_ops = &ahci_platform_ops,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct scsi_host_template ahci_platform_sht = {
|
||||||
|
AHCI_SHT(DRV_NAME),
|
||||||
|
};
|
||||||
|
|
||||||
static int ahci_probe(struct platform_device *pdev)
|
static int ahci_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pdev->dev;
|
||||||
|
@ -46,7 +52,8 @@ static int ahci_probe(struct platform_device *pdev)
|
||||||
if (of_device_is_compatible(dev->of_node, "hisilicon,hisi-ahci"))
|
if (of_device_is_compatible(dev->of_node, "hisilicon,hisi-ahci"))
|
||||||
hpriv->flags |= AHCI_HFLAG_NO_FBS | AHCI_HFLAG_NO_NCQ;
|
hpriv->flags |= AHCI_HFLAG_NO_FBS | AHCI_HFLAG_NO_NCQ;
|
||||||
|
|
||||||
rc = ahci_platform_init_host(pdev, hpriv, &ahci_port_info);
|
rc = ahci_platform_init_host(pdev, hpriv, &ahci_port_info,
|
||||||
|
&ahci_platform_sht);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto disable_resources;
|
goto disable_resources;
|
||||||
|
|
||||||
|
@ -75,7 +82,7 @@ static struct platform_driver ahci_driver = {
|
||||||
.probe = ahci_probe,
|
.probe = ahci_probe,
|
||||||
.remove = ata_platform_remove_one,
|
.remove = ata_platform_remove_one,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "ahci",
|
.name = DRV_NAME,
|
||||||
.of_match_table = ahci_of_match,
|
.of_match_table = ahci_of_match,
|
||||||
.pm = &ahci_pm_ops,
|
.pm = &ahci_pm_ops,
|
||||||
},
|
},
|
||||||
|
|
|
@ -23,6 +23,8 @@
|
||||||
|
|
||||||
#include "ahci.h"
|
#include "ahci.h"
|
||||||
|
|
||||||
|
#define DRV_NAME "st_ahci"
|
||||||
|
|
||||||
#define ST_AHCI_OOBR 0xbc
|
#define ST_AHCI_OOBR 0xbc
|
||||||
#define ST_AHCI_OOBR_WE BIT(31)
|
#define ST_AHCI_OOBR_WE BIT(31)
|
||||||
#define ST_AHCI_OOBR_CWMIN_SHIFT 24
|
#define ST_AHCI_OOBR_CWMIN_SHIFT 24
|
||||||
|
@ -140,6 +142,10 @@ static const struct ata_port_info st_ahci_port_info = {
|
||||||
.port_ops = &st_ahci_port_ops,
|
.port_ops = &st_ahci_port_ops,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct scsi_host_template ahci_platform_sht = {
|
||||||
|
AHCI_SHT(DRV_NAME),
|
||||||
|
};
|
||||||
|
|
||||||
static int st_ahci_probe(struct platform_device *pdev)
|
static int st_ahci_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct st_ahci_drv_data *drv_data;
|
struct st_ahci_drv_data *drv_data;
|
||||||
|
@ -166,7 +172,8 @@ static int st_ahci_probe(struct platform_device *pdev)
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
err = ahci_platform_init_host(pdev, hpriv, &st_ahci_port_info);
|
err = ahci_platform_init_host(pdev, hpriv, &st_ahci_port_info,
|
||||||
|
&ahci_platform_sht);
|
||||||
if (err) {
|
if (err) {
|
||||||
ahci_platform_disable_resources(hpriv);
|
ahci_platform_disable_resources(hpriv);
|
||||||
return err;
|
return err;
|
||||||
|
@ -229,7 +236,7 @@ MODULE_DEVICE_TABLE(of, st_ahci_match);
|
||||||
|
|
||||||
static struct platform_driver st_ahci_driver = {
|
static struct platform_driver st_ahci_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "st_ahci",
|
.name = DRV_NAME,
|
||||||
.pm = &st_ahci_pm_ops,
|
.pm = &st_ahci_pm_ops,
|
||||||
.of_match_table = of_match_ptr(st_ahci_match),
|
.of_match_table = of_match_ptr(st_ahci_match),
|
||||||
},
|
},
|
||||||
|
|
|
@ -27,6 +27,8 @@
|
||||||
#include <linux/regulator/consumer.h>
|
#include <linux/regulator/consumer.h>
|
||||||
#include "ahci.h"
|
#include "ahci.h"
|
||||||
|
|
||||||
|
#define DRV_NAME "ahci-sunxi"
|
||||||
|
|
||||||
/* Insmod parameters */
|
/* Insmod parameters */
|
||||||
static bool enable_pmp;
|
static bool enable_pmp;
|
||||||
module_param(enable_pmp, bool, 0);
|
module_param(enable_pmp, bool, 0);
|
||||||
|
@ -169,6 +171,10 @@ static const struct ata_port_info ahci_sunxi_port_info = {
|
||||||
.port_ops = &ahci_platform_ops,
|
.port_ops = &ahci_platform_ops,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct scsi_host_template ahci_platform_sht = {
|
||||||
|
AHCI_SHT(DRV_NAME),
|
||||||
|
};
|
||||||
|
|
||||||
static int ahci_sunxi_probe(struct platform_device *pdev)
|
static int ahci_sunxi_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pdev->dev;
|
||||||
|
@ -200,7 +206,8 @@ static int ahci_sunxi_probe(struct platform_device *pdev)
|
||||||
if (!enable_pmp)
|
if (!enable_pmp)
|
||||||
hpriv->flags |= AHCI_HFLAG_NO_PMP;
|
hpriv->flags |= AHCI_HFLAG_NO_PMP;
|
||||||
|
|
||||||
rc = ahci_platform_init_host(pdev, hpriv, &ahci_sunxi_port_info);
|
rc = ahci_platform_init_host(pdev, hpriv, &ahci_sunxi_port_info,
|
||||||
|
&ahci_platform_sht);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto disable_resources;
|
goto disable_resources;
|
||||||
|
|
||||||
|
@ -251,7 +258,7 @@ static struct platform_driver ahci_sunxi_driver = {
|
||||||
.probe = ahci_sunxi_probe,
|
.probe = ahci_sunxi_probe,
|
||||||
.remove = ata_platform_remove_one,
|
.remove = ata_platform_remove_one,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "ahci-sunxi",
|
.name = DRV_NAME,
|
||||||
.of_match_table = ahci_sunxi_of_match,
|
.of_match_table = ahci_sunxi_of_match,
|
||||||
.pm = &ahci_sunxi_pm_ops,
|
.pm = &ahci_sunxi_pm_ops,
|
||||||
},
|
},
|
||||||
|
|
|
@ -31,6 +31,8 @@
|
||||||
|
|
||||||
#include "ahci.h"
|
#include "ahci.h"
|
||||||
|
|
||||||
|
#define DRV_NAME "tegra-ahci"
|
||||||
|
|
||||||
#define SATA_CONFIGURATION_0 0x180
|
#define SATA_CONFIGURATION_0 0x180
|
||||||
#define SATA_CONFIGURATION_EN_FPCI BIT(0)
|
#define SATA_CONFIGURATION_EN_FPCI BIT(0)
|
||||||
|
|
||||||
|
@ -289,6 +291,10 @@ static const struct of_device_id tegra_ahci_of_match[] = {
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(of, tegra_ahci_of_match);
|
MODULE_DEVICE_TABLE(of, tegra_ahci_of_match);
|
||||||
|
|
||||||
|
static struct scsi_host_template ahci_platform_sht = {
|
||||||
|
AHCI_SHT(DRV_NAME),
|
||||||
|
};
|
||||||
|
|
||||||
static int tegra_ahci_probe(struct platform_device *pdev)
|
static int tegra_ahci_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct ahci_host_priv *hpriv;
|
struct ahci_host_priv *hpriv;
|
||||||
|
@ -354,7 +360,8 @@ static int tegra_ahci_probe(struct platform_device *pdev)
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
ret = ahci_platform_init_host(pdev, hpriv, &ahci_tegra_port_info);
|
ret = ahci_platform_init_host(pdev, hpriv, &ahci_tegra_port_info,
|
||||||
|
&ahci_platform_sht);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto deinit_controller;
|
goto deinit_controller;
|
||||||
|
|
||||||
|
@ -370,7 +377,7 @@ static struct platform_driver tegra_ahci_driver = {
|
||||||
.probe = tegra_ahci_probe,
|
.probe = tegra_ahci_probe,
|
||||||
.remove = ata_platform_remove_one,
|
.remove = ata_platform_remove_one,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "tegra-ahci",
|
.name = DRV_NAME,
|
||||||
.of_match_table = tegra_ahci_of_match,
|
.of_match_table = tegra_ahci_of_match,
|
||||||
},
|
},
|
||||||
/* LP0 suspend support not implemented */
|
/* LP0 suspend support not implemented */
|
||||||
|
|
|
@ -30,6 +30,8 @@
|
||||||
#include <linux/phy/phy.h>
|
#include <linux/phy/phy.h>
|
||||||
#include "ahci.h"
|
#include "ahci.h"
|
||||||
|
|
||||||
|
#define DRV_NAME "xgene-ahci"
|
||||||
|
|
||||||
/* Max # of disk per a controller */
|
/* Max # of disk per a controller */
|
||||||
#define MAX_AHCI_CHN_PERCTR 2
|
#define MAX_AHCI_CHN_PERCTR 2
|
||||||
|
|
||||||
|
@ -85,6 +87,7 @@ struct xgene_ahci_context {
|
||||||
struct ahci_host_priv *hpriv;
|
struct ahci_host_priv *hpriv;
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
u8 last_cmd[MAX_AHCI_CHN_PERCTR]; /* tracking the last command issued*/
|
u8 last_cmd[MAX_AHCI_CHN_PERCTR]; /* tracking the last command issued*/
|
||||||
|
u32 class[MAX_AHCI_CHN_PERCTR]; /* tracking the class of device */
|
||||||
void __iomem *csr_core; /* Core CSR address of IP */
|
void __iomem *csr_core; /* Core CSR address of IP */
|
||||||
void __iomem *csr_diag; /* Diag CSR address of IP */
|
void __iomem *csr_diag; /* Diag CSR address of IP */
|
||||||
void __iomem *csr_axi; /* AXI CSR address of IP */
|
void __iomem *csr_axi; /* AXI CSR address of IP */
|
||||||
|
@ -104,18 +107,70 @@ static int xgene_ahci_init_memram(struct xgene_ahci_context *ctx)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* xgene_ahci_poll_reg_val- Poll a register on a specific value.
|
||||||
|
* @ap : ATA port of interest.
|
||||||
|
* @reg : Register of interest.
|
||||||
|
* @val : Value to be attained.
|
||||||
|
* @interval : waiting interval for polling.
|
||||||
|
* @timeout : timeout for achieving the value.
|
||||||
|
*/
|
||||||
|
static int xgene_ahci_poll_reg_val(struct ata_port *ap,
|
||||||
|
void __iomem *reg, unsigned
|
||||||
|
int val, unsigned long interval,
|
||||||
|
unsigned long timeout)
|
||||||
|
{
|
||||||
|
unsigned long deadline;
|
||||||
|
unsigned int tmp;
|
||||||
|
|
||||||
|
tmp = ioread32(reg);
|
||||||
|
deadline = ata_deadline(jiffies, timeout);
|
||||||
|
|
||||||
|
while (tmp != val && time_before(jiffies, deadline)) {
|
||||||
|
ata_msleep(ap, interval);
|
||||||
|
tmp = ioread32(reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* xgene_ahci_restart_engine - Restart the dma engine.
|
* xgene_ahci_restart_engine - Restart the dma engine.
|
||||||
* @ap : ATA port of interest
|
* @ap : ATA port of interest
|
||||||
*
|
*
|
||||||
* Restarts the dma engine inside the controller.
|
* Waits for completion of multiple commands and restarts
|
||||||
|
* the DMA engine inside the controller.
|
||||||
*/
|
*/
|
||||||
static int xgene_ahci_restart_engine(struct ata_port *ap)
|
static int xgene_ahci_restart_engine(struct ata_port *ap)
|
||||||
{
|
{
|
||||||
struct ahci_host_priv *hpriv = ap->host->private_data;
|
struct ahci_host_priv *hpriv = ap->host->private_data;
|
||||||
|
struct ahci_port_priv *pp = ap->private_data;
|
||||||
|
void __iomem *port_mmio = ahci_port_base(ap);
|
||||||
|
u32 fbs;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* In case of PMP multiple IDENTIFY DEVICE commands can be
|
||||||
|
* issued inside PxCI. So need to poll PxCI for the
|
||||||
|
* completion of outstanding IDENTIFY DEVICE commands before
|
||||||
|
* we restart the DMA engine.
|
||||||
|
*/
|
||||||
|
if (xgene_ahci_poll_reg_val(ap, port_mmio +
|
||||||
|
PORT_CMD_ISSUE, 0x0, 1, 100))
|
||||||
|
return -EBUSY;
|
||||||
|
|
||||||
ahci_stop_engine(ap);
|
ahci_stop_engine(ap);
|
||||||
ahci_start_fis_rx(ap);
|
ahci_start_fis_rx(ap);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enable the PxFBS.FBS_EN bit as it
|
||||||
|
* gets cleared due to stopping the engine.
|
||||||
|
*/
|
||||||
|
if (pp->fbs_supported) {
|
||||||
|
fbs = readl(port_mmio + PORT_FBS);
|
||||||
|
writel(fbs | PORT_FBS_EN, port_mmio + PORT_FBS);
|
||||||
|
fbs = readl(port_mmio + PORT_FBS);
|
||||||
|
}
|
||||||
|
|
||||||
hpriv->start_engine(ap);
|
hpriv->start_engine(ap);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -125,11 +180,17 @@ static int xgene_ahci_restart_engine(struct ata_port *ap)
|
||||||
* xgene_ahci_qc_issue - Issue commands to the device
|
* xgene_ahci_qc_issue - Issue commands to the device
|
||||||
* @qc: Command to issue
|
* @qc: Command to issue
|
||||||
*
|
*
|
||||||
* Due to Hardware errata for IDENTIFY DEVICE command and PACKET
|
* Due to Hardware errata for IDENTIFY DEVICE command, the controller cannot
|
||||||
* command of ATAPI protocol set, the controller cannot clear the BSY bit
|
* clear the BSY bit after receiving the PIO setup FIS. This results in the dma
|
||||||
* after receiving the PIO setup FIS. This results in the DMA state machine
|
* state machine goes into the CMFatalErrorUpdate state and locks up. By
|
||||||
* going into the CMFatalErrorUpdate state and locks up. By restarting the
|
* restarting the dma engine, it removes the controller out of lock up state.
|
||||||
* DMA engine, it removes the controller out of lock up state.
|
*
|
||||||
|
* Due to H/W errata, the controller is unable to save the PMP
|
||||||
|
* field fetched from command header before sending the H2D FIS.
|
||||||
|
* When the device returns the PMP port field in the D2H FIS, there is
|
||||||
|
* a mismatch and results in command completion failure. The
|
||||||
|
* workaround is to write the pmp value to PxFBS.DEV field before issuing
|
||||||
|
* any command to PMP.
|
||||||
*/
|
*/
|
||||||
static unsigned int xgene_ahci_qc_issue(struct ata_queued_cmd *qc)
|
static unsigned int xgene_ahci_qc_issue(struct ata_queued_cmd *qc)
|
||||||
{
|
{
|
||||||
|
@ -137,9 +198,23 @@ static unsigned int xgene_ahci_qc_issue(struct ata_queued_cmd *qc)
|
||||||
struct ahci_host_priv *hpriv = ap->host->private_data;
|
struct ahci_host_priv *hpriv = ap->host->private_data;
|
||||||
struct xgene_ahci_context *ctx = hpriv->plat_data;
|
struct xgene_ahci_context *ctx = hpriv->plat_data;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
u32 port_fbs;
|
||||||
|
void *port_mmio = ahci_port_base(ap);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write the pmp value to PxFBS.DEV
|
||||||
|
* for case of Port Mulitplier.
|
||||||
|
*/
|
||||||
|
if (ctx->class[ap->port_no] == ATA_DEV_PMP) {
|
||||||
|
port_fbs = readl(port_mmio + PORT_FBS);
|
||||||
|
port_fbs &= ~PORT_FBS_DEV_MASK;
|
||||||
|
port_fbs |= qc->dev->link->pmp << PORT_FBS_DEV_OFFSET;
|
||||||
|
writel(port_fbs, port_mmio + PORT_FBS);
|
||||||
|
}
|
||||||
|
|
||||||
if (unlikely((ctx->last_cmd[ap->port_no] == ATA_CMD_ID_ATA) ||
|
if (unlikely((ctx->last_cmd[ap->port_no] == ATA_CMD_ID_ATA) ||
|
||||||
(ctx->last_cmd[ap->port_no] == ATA_CMD_PACKET)))
|
(ctx->last_cmd[ap->port_no] == ATA_CMD_PACKET) ||
|
||||||
|
(ctx->last_cmd[ap->port_no] == ATA_CMD_SMART)))
|
||||||
xgene_ahci_restart_engine(ap);
|
xgene_ahci_restart_engine(ap);
|
||||||
|
|
||||||
rc = ahci_qc_issue(qc);
|
rc = ahci_qc_issue(qc);
|
||||||
|
@ -365,16 +440,119 @@ static void xgene_ahci_host_stop(struct ata_host *host)
|
||||||
ahci_platform_disable_resources(hpriv);
|
ahci_platform_disable_resources(hpriv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* xgene_ahci_pmp_softreset - Issue the softreset to the drives connected
|
||||||
|
* to Port Multiplier.
|
||||||
|
* @link: link to reset
|
||||||
|
* @class: Return value to indicate class of device
|
||||||
|
* @deadline: deadline jiffies for the operation
|
||||||
|
*
|
||||||
|
* Due to H/W errata, the controller is unable to save the PMP
|
||||||
|
* field fetched from command header before sending the H2D FIS.
|
||||||
|
* When the device returns the PMP port field in the D2H FIS, there is
|
||||||
|
* a mismatch and results in command completion failure. The workaround
|
||||||
|
* is to write the pmp value to PxFBS.DEV field before issuing any command
|
||||||
|
* to PMP.
|
||||||
|
*/
|
||||||
|
static int xgene_ahci_pmp_softreset(struct ata_link *link, unsigned int *class,
|
||||||
|
unsigned long deadline)
|
||||||
|
{
|
||||||
|
int pmp = sata_srst_pmp(link);
|
||||||
|
struct ata_port *ap = link->ap;
|
||||||
|
u32 rc;
|
||||||
|
void *port_mmio = ahci_port_base(ap);
|
||||||
|
u32 port_fbs;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set PxFBS.DEV field with pmp
|
||||||
|
* value.
|
||||||
|
*/
|
||||||
|
port_fbs = readl(port_mmio + PORT_FBS);
|
||||||
|
port_fbs &= ~PORT_FBS_DEV_MASK;
|
||||||
|
port_fbs |= pmp << PORT_FBS_DEV_OFFSET;
|
||||||
|
writel(port_fbs, port_mmio + PORT_FBS);
|
||||||
|
|
||||||
|
rc = ahci_do_softreset(link, class, pmp, deadline, ahci_check_ready);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* xgene_ahci_softreset - Issue the softreset to the drive.
|
||||||
|
* @link: link to reset
|
||||||
|
* @class: Return value to indicate class of device
|
||||||
|
* @deadline: deadline jiffies for the operation
|
||||||
|
*
|
||||||
|
* Due to H/W errata, the controller is unable to save the PMP
|
||||||
|
* field fetched from command header before sending the H2D FIS.
|
||||||
|
* When the device returns the PMP port field in the D2H FIS, there is
|
||||||
|
* a mismatch and results in command completion failure. The workaround
|
||||||
|
* is to write the pmp value to PxFBS.DEV field before issuing any command
|
||||||
|
* to PMP. Here is the algorithm to detect PMP :
|
||||||
|
*
|
||||||
|
* 1. Save the PxFBS value
|
||||||
|
* 2. Program PxFBS.DEV with pmp value send by framework. Framework sends
|
||||||
|
* 0xF for both PMP/NON-PMP initially
|
||||||
|
* 3. Issue softreset
|
||||||
|
* 4. If signature class is PMP goto 6
|
||||||
|
* 5. restore the original PxFBS and goto 3
|
||||||
|
* 6. return
|
||||||
|
*/
|
||||||
|
static int xgene_ahci_softreset(struct ata_link *link, unsigned int *class,
|
||||||
|
unsigned long deadline)
|
||||||
|
{
|
||||||
|
int pmp = sata_srst_pmp(link);
|
||||||
|
struct ata_port *ap = link->ap;
|
||||||
|
struct ahci_host_priv *hpriv = ap->host->private_data;
|
||||||
|
struct xgene_ahci_context *ctx = hpriv->plat_data;
|
||||||
|
void *port_mmio = ahci_port_base(ap);
|
||||||
|
u32 port_fbs;
|
||||||
|
u32 port_fbs_save;
|
||||||
|
u32 retry = 1;
|
||||||
|
u32 rc;
|
||||||
|
|
||||||
|
port_fbs_save = readl(port_mmio + PORT_FBS);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set PxFBS.DEV field with pmp
|
||||||
|
* value.
|
||||||
|
*/
|
||||||
|
port_fbs = readl(port_mmio + PORT_FBS);
|
||||||
|
port_fbs &= ~PORT_FBS_DEV_MASK;
|
||||||
|
port_fbs |= pmp << PORT_FBS_DEV_OFFSET;
|
||||||
|
writel(port_fbs, port_mmio + PORT_FBS);
|
||||||
|
|
||||||
|
softreset_retry:
|
||||||
|
rc = ahci_do_softreset(link, class, pmp,
|
||||||
|
deadline, ahci_check_ready);
|
||||||
|
|
||||||
|
ctx->class[ap->port_no] = *class;
|
||||||
|
if (*class != ATA_DEV_PMP) {
|
||||||
|
/*
|
||||||
|
* Retry for normal drives without
|
||||||
|
* setting PxFBS.DEV field with pmp value.
|
||||||
|
*/
|
||||||
|
if (retry--) {
|
||||||
|
writel(port_fbs_save, port_mmio + PORT_FBS);
|
||||||
|
goto softreset_retry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
static struct ata_port_operations xgene_ahci_ops = {
|
static struct ata_port_operations xgene_ahci_ops = {
|
||||||
.inherits = &ahci_ops,
|
.inherits = &ahci_ops,
|
||||||
.host_stop = xgene_ahci_host_stop,
|
.host_stop = xgene_ahci_host_stop,
|
||||||
.hardreset = xgene_ahci_hardreset,
|
.hardreset = xgene_ahci_hardreset,
|
||||||
.read_id = xgene_ahci_read_id,
|
.read_id = xgene_ahci_read_id,
|
||||||
.qc_issue = xgene_ahci_qc_issue,
|
.qc_issue = xgene_ahci_qc_issue,
|
||||||
|
.softreset = xgene_ahci_softreset,
|
||||||
|
.pmp_softreset = xgene_ahci_pmp_softreset
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct ata_port_info xgene_ahci_port_info = {
|
static const struct ata_port_info xgene_ahci_port_info = {
|
||||||
.flags = AHCI_FLAG_COMMON,
|
.flags = AHCI_FLAG_COMMON | ATA_FLAG_PMP,
|
||||||
.pio_mask = ATA_PIO4,
|
.pio_mask = ATA_PIO4,
|
||||||
.udma_mask = ATA_UDMA6,
|
.udma_mask = ATA_UDMA6,
|
||||||
.port_ops = &xgene_ahci_ops,
|
.port_ops = &xgene_ahci_ops,
|
||||||
|
@ -446,6 +624,10 @@ static int xgene_ahci_mux_select(struct xgene_ahci_context *ctx)
|
||||||
return val & CFG_SATA_ENET_SELECT_MASK ? -1 : 0;
|
return val & CFG_SATA_ENET_SELECT_MASK ? -1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct scsi_host_template ahci_platform_sht = {
|
||||||
|
AHCI_SHT(DRV_NAME),
|
||||||
|
};
|
||||||
|
|
||||||
static int xgene_ahci_probe(struct platform_device *pdev)
|
static int xgene_ahci_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pdev->dev;
|
||||||
|
@ -523,7 +705,8 @@ static int xgene_ahci_probe(struct platform_device *pdev)
|
||||||
skip_clk_phy:
|
skip_clk_phy:
|
||||||
hpriv->flags = AHCI_HFLAG_NO_PMP | AHCI_HFLAG_NO_NCQ;
|
hpriv->flags = AHCI_HFLAG_NO_PMP | AHCI_HFLAG_NO_NCQ;
|
||||||
|
|
||||||
rc = ahci_platform_init_host(pdev, hpriv, &xgene_ahci_port_info);
|
rc = ahci_platform_init_host(pdev, hpriv, &xgene_ahci_port_info,
|
||||||
|
&ahci_platform_sht);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto disable_resources;
|
goto disable_resources;
|
||||||
|
|
||||||
|
@ -545,7 +728,7 @@ static struct platform_driver xgene_ahci_driver = {
|
||||||
.probe = xgene_ahci_probe,
|
.probe = xgene_ahci_probe,
|
||||||
.remove = ata_platform_remove_one,
|
.remove = ata_platform_remove_one,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "xgene-ahci",
|
.name = DRV_NAME,
|
||||||
.of_match_table = xgene_ahci_of_match,
|
.of_match_table = xgene_ahci_of_match,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include <linux/ahci_platform.h>
|
#include <linux/ahci_platform.h>
|
||||||
#include <linux/phy/phy.h>
|
#include <linux/phy/phy.h>
|
||||||
#include <linux/pm_runtime.h>
|
#include <linux/pm_runtime.h>
|
||||||
|
#include <linux/of_platform.h>
|
||||||
#include "ahci.h"
|
#include "ahci.h"
|
||||||
|
|
||||||
static void ahci_host_stop(struct ata_host *host);
|
static void ahci_host_stop(struct ata_host *host);
|
||||||
|
@ -34,10 +35,6 @@ struct ata_port_operations ahci_platform_ops = {
|
||||||
};
|
};
|
||||||
EXPORT_SYMBOL_GPL(ahci_platform_ops);
|
EXPORT_SYMBOL_GPL(ahci_platform_ops);
|
||||||
|
|
||||||
static struct scsi_host_template ahci_platform_sht = {
|
|
||||||
AHCI_SHT("ahci_platform"),
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ahci_platform_enable_phys - Enable PHYs
|
* ahci_platform_enable_phys - Enable PHYs
|
||||||
* @hpriv: host private area to store config values
|
* @hpriv: host private area to store config values
|
||||||
|
@ -54,9 +51,6 @@ static int ahci_platform_enable_phys(struct ahci_host_priv *hpriv)
|
||||||
int rc, i;
|
int rc, i;
|
||||||
|
|
||||||
for (i = 0; i < hpriv->nports; i++) {
|
for (i = 0; i < hpriv->nports; i++) {
|
||||||
if (!hpriv->phys[i])
|
|
||||||
continue;
|
|
||||||
|
|
||||||
rc = phy_init(hpriv->phys[i]);
|
rc = phy_init(hpriv->phys[i]);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto disable_phys;
|
goto disable_phys;
|
||||||
|
@ -89,9 +83,6 @@ static void ahci_platform_disable_phys(struct ahci_host_priv *hpriv)
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < hpriv->nports; i++) {
|
for (i = 0; i < hpriv->nports; i++) {
|
||||||
if (!hpriv->phys[i])
|
|
||||||
continue;
|
|
||||||
|
|
||||||
phy_power_off(hpriv->phys[i]);
|
phy_power_off(hpriv->phys[i]);
|
||||||
phy_exit(hpriv->phys[i]);
|
phy_exit(hpriv->phys[i]);
|
||||||
}
|
}
|
||||||
|
@ -143,6 +134,59 @@ void ahci_platform_disable_clks(struct ahci_host_priv *hpriv)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(ahci_platform_disable_clks);
|
EXPORT_SYMBOL_GPL(ahci_platform_disable_clks);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ahci_platform_enable_regulators - Enable regulators
|
||||||
|
* @hpriv: host private area to store config values
|
||||||
|
*
|
||||||
|
* This function enables all the regulators found in
|
||||||
|
* hpriv->target_pwrs, if any. If a regulator fails to be enabled, it
|
||||||
|
* disables all the regulators already enabled in reverse order and
|
||||||
|
* returns an error.
|
||||||
|
*
|
||||||
|
* RETURNS:
|
||||||
|
* 0 on success otherwise a negative error code
|
||||||
|
*/
|
||||||
|
int ahci_platform_enable_regulators(struct ahci_host_priv *hpriv)
|
||||||
|
{
|
||||||
|
int rc, i;
|
||||||
|
|
||||||
|
for (i = 0; i < hpriv->nports; i++) {
|
||||||
|
if (!hpriv->target_pwrs[i])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
rc = regulator_enable(hpriv->target_pwrs[i]);
|
||||||
|
if (rc)
|
||||||
|
goto disable_target_pwrs;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
disable_target_pwrs:
|
||||||
|
while (--i >= 0)
|
||||||
|
if (hpriv->target_pwrs[i])
|
||||||
|
regulator_disable(hpriv->target_pwrs[i]);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(ahci_platform_enable_regulators);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ahci_platform_disable_regulators - Disable regulators
|
||||||
|
* @hpriv: host private area to store config values
|
||||||
|
*
|
||||||
|
* This function disables all regulators found in hpriv->target_pwrs.
|
||||||
|
*/
|
||||||
|
void ahci_platform_disable_regulators(struct ahci_host_priv *hpriv)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < hpriv->nports; i++) {
|
||||||
|
if (!hpriv->target_pwrs[i])
|
||||||
|
continue;
|
||||||
|
regulator_disable(hpriv->target_pwrs[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(ahci_platform_disable_regulators);
|
||||||
/**
|
/**
|
||||||
* ahci_platform_enable_resources - Enable platform resources
|
* ahci_platform_enable_resources - Enable platform resources
|
||||||
* @hpriv: host private area to store config values
|
* @hpriv: host private area to store config values
|
||||||
|
@ -163,11 +207,9 @@ int ahci_platform_enable_resources(struct ahci_host_priv *hpriv)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if (hpriv->target_pwr) {
|
rc = ahci_platform_enable_regulators(hpriv);
|
||||||
rc = regulator_enable(hpriv->target_pwr);
|
if (rc)
|
||||||
if (rc)
|
return rc;
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = ahci_platform_enable_clks(hpriv);
|
rc = ahci_platform_enable_clks(hpriv);
|
||||||
if (rc)
|
if (rc)
|
||||||
|
@ -183,8 +225,8 @@ disable_clks:
|
||||||
ahci_platform_disable_clks(hpriv);
|
ahci_platform_disable_clks(hpriv);
|
||||||
|
|
||||||
disable_regulator:
|
disable_regulator:
|
||||||
if (hpriv->target_pwr)
|
ahci_platform_disable_regulators(hpriv);
|
||||||
regulator_disable(hpriv->target_pwr);
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(ahci_platform_enable_resources);
|
EXPORT_SYMBOL_GPL(ahci_platform_enable_resources);
|
||||||
|
@ -205,8 +247,7 @@ void ahci_platform_disable_resources(struct ahci_host_priv *hpriv)
|
||||||
|
|
||||||
ahci_platform_disable_clks(hpriv);
|
ahci_platform_disable_clks(hpriv);
|
||||||
|
|
||||||
if (hpriv->target_pwr)
|
ahci_platform_disable_regulators(hpriv);
|
||||||
regulator_disable(hpriv->target_pwr);
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(ahci_platform_disable_resources);
|
EXPORT_SYMBOL_GPL(ahci_platform_disable_resources);
|
||||||
|
|
||||||
|
@ -222,6 +263,69 @@ static void ahci_platform_put_resources(struct device *dev, void *res)
|
||||||
|
|
||||||
for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++)
|
for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++)
|
||||||
clk_put(hpriv->clks[c]);
|
clk_put(hpriv->clks[c]);
|
||||||
|
/*
|
||||||
|
* The regulators are tied to child node device and not to the
|
||||||
|
* SATA device itself. So we can't use devm for automatically
|
||||||
|
* releasing them. We have to do it manually here.
|
||||||
|
*/
|
||||||
|
for (c = 0; c < hpriv->nports; c++)
|
||||||
|
if (hpriv->target_pwrs && hpriv->target_pwrs[c])
|
||||||
|
regulator_put(hpriv->target_pwrs[c]);
|
||||||
|
|
||||||
|
kfree(hpriv->target_pwrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ahci_platform_get_phy(struct ahci_host_priv *hpriv, u32 port,
|
||||||
|
struct device *dev, struct device_node *node)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
hpriv->phys[port] = devm_of_phy_get(dev, node, NULL);
|
||||||
|
|
||||||
|
if (!IS_ERR(hpriv->phys[port]))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
rc = PTR_ERR(hpriv->phys[port]);
|
||||||
|
switch (rc) {
|
||||||
|
case -ENOSYS:
|
||||||
|
/* No PHY support. Check if PHY is required. */
|
||||||
|
if (of_find_property(node, "phys", NULL)) {
|
||||||
|
dev_err(dev,
|
||||||
|
"couldn't get PHY in node %s: ENOSYS\n",
|
||||||
|
node->name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case -ENODEV:
|
||||||
|
/* continue normally */
|
||||||
|
hpriv->phys[port] = NULL;
|
||||||
|
rc = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
dev_err(dev,
|
||||||
|
"couldn't get PHY in node %s: %d\n",
|
||||||
|
node->name, rc);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ahci_platform_get_regulator(struct ahci_host_priv *hpriv, u32 port,
|
||||||
|
struct device *dev)
|
||||||
|
{
|
||||||
|
struct regulator *target_pwr;
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
target_pwr = regulator_get_optional(dev, "target");
|
||||||
|
|
||||||
|
if (!IS_ERR(target_pwr))
|
||||||
|
hpriv->target_pwrs[port] = target_pwr;
|
||||||
|
else
|
||||||
|
rc = PTR_ERR(target_pwr);
|
||||||
|
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -246,7 +350,7 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev)
|
||||||
struct ahci_host_priv *hpriv;
|
struct ahci_host_priv *hpriv;
|
||||||
struct clk *clk;
|
struct clk *clk;
|
||||||
struct device_node *child;
|
struct device_node *child;
|
||||||
int i, enabled_ports = 0, rc = -ENOMEM;
|
int i, sz, enabled_ports = 0, rc = -ENOMEM, child_nodes;
|
||||||
u32 mask_port_map = 0;
|
u32 mask_port_map = 0;
|
||||||
|
|
||||||
if (!devres_open_group(dev, NULL, GFP_KERNEL))
|
if (!devres_open_group(dev, NULL, GFP_KERNEL))
|
||||||
|
@ -267,14 +371,6 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev)
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
hpriv->target_pwr = devm_regulator_get_optional(dev, "target");
|
|
||||||
if (IS_ERR(hpriv->target_pwr)) {
|
|
||||||
rc = PTR_ERR(hpriv->target_pwr);
|
|
||||||
if (rc == -EPROBE_DEFER)
|
|
||||||
goto err_out;
|
|
||||||
hpriv->target_pwr = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < AHCI_MAX_CLKS; i++) {
|
for (i = 0; i < AHCI_MAX_CLKS; i++) {
|
||||||
/*
|
/*
|
||||||
* For now we must use clk_get(dev, NULL) for the first clock,
|
* For now we must use clk_get(dev, NULL) for the first clock,
|
||||||
|
@ -296,19 +392,33 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev)
|
||||||
hpriv->clks[i] = clk;
|
hpriv->clks[i] = clk;
|
||||||
}
|
}
|
||||||
|
|
||||||
hpriv->nports = of_get_child_count(dev->of_node);
|
hpriv->nports = child_nodes = of_get_child_count(dev->of_node);
|
||||||
|
|
||||||
if (hpriv->nports) {
|
/*
|
||||||
hpriv->phys = devm_kzalloc(dev,
|
* If no sub-node was found, we still need to set nports to
|
||||||
hpriv->nports * sizeof(*hpriv->phys),
|
* one in order to be able to use the
|
||||||
GFP_KERNEL);
|
* ahci_platform_[en|dis]able_[phys|regulators] functions.
|
||||||
if (!hpriv->phys) {
|
*/
|
||||||
rc = -ENOMEM;
|
if (!child_nodes)
|
||||||
goto err_out;
|
hpriv->nports = 1;
|
||||||
}
|
|
||||||
|
|
||||||
|
sz = hpriv->nports * sizeof(*hpriv->phys);
|
||||||
|
hpriv->phys = devm_kzalloc(dev, sz, GFP_KERNEL);
|
||||||
|
if (!hpriv->phys) {
|
||||||
|
rc = -ENOMEM;
|
||||||
|
goto err_out;
|
||||||
|
}
|
||||||
|
sz = hpriv->nports * sizeof(*hpriv->target_pwrs);
|
||||||
|
hpriv->target_pwrs = kzalloc(sz, GFP_KERNEL);
|
||||||
|
if (!hpriv->target_pwrs) {
|
||||||
|
rc = -ENOMEM;
|
||||||
|
goto err_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (child_nodes) {
|
||||||
for_each_child_of_node(dev->of_node, child) {
|
for_each_child_of_node(dev->of_node, child) {
|
||||||
u32 port;
|
u32 port;
|
||||||
|
struct platform_device *port_dev __maybe_unused;
|
||||||
|
|
||||||
if (!of_device_is_available(child))
|
if (!of_device_is_available(child))
|
||||||
continue;
|
continue;
|
||||||
|
@ -322,17 +432,24 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev)
|
||||||
dev_warn(dev, "invalid port number %d\n", port);
|
dev_warn(dev, "invalid port number %d\n", port);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
mask_port_map |= BIT(port);
|
mask_port_map |= BIT(port);
|
||||||
|
|
||||||
hpriv->phys[port] = devm_of_phy_get(dev, child, NULL);
|
#ifdef CONFIG_OF_ADDRESS
|
||||||
if (IS_ERR(hpriv->phys[port])) {
|
of_platform_device_create(child, NULL, NULL);
|
||||||
rc = PTR_ERR(hpriv->phys[port]);
|
|
||||||
dev_err(dev,
|
port_dev = of_find_device_by_node(child);
|
||||||
"couldn't get PHY in node %s: %d\n",
|
|
||||||
child->name, rc);
|
if (port_dev) {
|
||||||
goto err_out;
|
rc = ahci_platform_get_regulator(hpriv, port,
|
||||||
|
&port_dev->dev);
|
||||||
|
if (rc == -EPROBE_DEFER)
|
||||||
|
goto err_out;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
rc = ahci_platform_get_phy(hpriv, port, dev, child);
|
||||||
|
if (rc)
|
||||||
|
goto err_out;
|
||||||
|
|
||||||
enabled_ports++;
|
enabled_ports++;
|
||||||
}
|
}
|
||||||
|
@ -349,38 +466,14 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev)
|
||||||
* If no sub-node was found, keep this for device tree
|
* If no sub-node was found, keep this for device tree
|
||||||
* compatibility
|
* compatibility
|
||||||
*/
|
*/
|
||||||
struct phy *phy = devm_phy_get(dev, "sata-phy");
|
rc = ahci_platform_get_phy(hpriv, 0, dev, dev->of_node);
|
||||||
if (!IS_ERR(phy)) {
|
if (rc)
|
||||||
hpriv->phys = devm_kzalloc(dev, sizeof(*hpriv->phys),
|
goto err_out;
|
||||||
GFP_KERNEL);
|
|
||||||
if (!hpriv->phys) {
|
|
||||||
rc = -ENOMEM;
|
|
||||||
goto err_out;
|
|
||||||
}
|
|
||||||
|
|
||||||
hpriv->phys[0] = phy;
|
rc = ahci_platform_get_regulator(hpriv, 0, dev);
|
||||||
hpriv->nports = 1;
|
if (rc == -EPROBE_DEFER)
|
||||||
} else {
|
goto err_out;
|
||||||
rc = PTR_ERR(phy);
|
|
||||||
switch (rc) {
|
|
||||||
case -ENOSYS:
|
|
||||||
/* No PHY support. Check if PHY is required. */
|
|
||||||
if (of_find_property(dev->of_node, "phys", NULL)) {
|
|
||||||
dev_err(dev, "couldn't get sata-phy: ENOSYS\n");
|
|
||||||
goto err_out;
|
|
||||||
}
|
|
||||||
case -ENODEV:
|
|
||||||
/* continue normally */
|
|
||||||
hpriv->phys = NULL;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
goto err_out;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pm_runtime_enable(dev);
|
pm_runtime_enable(dev);
|
||||||
pm_runtime_get_sync(dev);
|
pm_runtime_get_sync(dev);
|
||||||
hpriv->got_runtime_pm = true;
|
hpriv->got_runtime_pm = true;
|
||||||
|
@ -399,6 +492,7 @@ EXPORT_SYMBOL_GPL(ahci_platform_get_resources);
|
||||||
* @pdev: platform device pointer for the host
|
* @pdev: platform device pointer for the host
|
||||||
* @hpriv: ahci-host private data for the host
|
* @hpriv: ahci-host private data for the host
|
||||||
* @pi_template: template for the ata_port_info to use
|
* @pi_template: template for the ata_port_info to use
|
||||||
|
* @sht: scsi_host_template to use when registering
|
||||||
*
|
*
|
||||||
* This function does all the usual steps needed to bring up an
|
* This function does all the usual steps needed to bring up an
|
||||||
* ahci-platform host, note any necessary resources (ie clks, phys, etc.)
|
* ahci-platform host, note any necessary resources (ie clks, phys, etc.)
|
||||||
|
@ -409,7 +503,8 @@ EXPORT_SYMBOL_GPL(ahci_platform_get_resources);
|
||||||
*/
|
*/
|
||||||
int ahci_platform_init_host(struct platform_device *pdev,
|
int ahci_platform_init_host(struct platform_device *pdev,
|
||||||
struct ahci_host_priv *hpriv,
|
struct ahci_host_priv *hpriv,
|
||||||
const struct ata_port_info *pi_template)
|
const struct ata_port_info *pi_template,
|
||||||
|
struct scsi_host_template *sht)
|
||||||
{
|
{
|
||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pdev->dev;
|
||||||
struct ata_port_info pi = *pi_template;
|
struct ata_port_info pi = *pi_template;
|
||||||
|
@ -493,7 +588,7 @@ int ahci_platform_init_host(struct platform_device *pdev,
|
||||||
ahci_init_controller(host);
|
ahci_init_controller(host);
|
||||||
ahci_print_info(host, "platform");
|
ahci_print_info(host, "platform");
|
||||||
|
|
||||||
return ahci_host_activate(host, irq, &ahci_platform_sht);
|
return ahci_host_activate(host, irq, sht);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(ahci_platform_init_host);
|
EXPORT_SYMBOL_GPL(ahci_platform_init_host);
|
||||||
|
|
||||||
|
|
|
@ -1751,33 +1751,6 @@ unsigned ata_exec_internal(struct ata_device *dev,
|
||||||
timeout);
|
timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* ata_do_simple_cmd - execute simple internal command
|
|
||||||
* @dev: Device to which the command is sent
|
|
||||||
* @cmd: Opcode to execute
|
|
||||||
*
|
|
||||||
* Execute a 'simple' command, that only consists of the opcode
|
|
||||||
* 'cmd' itself, without filling any other registers
|
|
||||||
*
|
|
||||||
* LOCKING:
|
|
||||||
* Kernel thread context (may sleep).
|
|
||||||
*
|
|
||||||
* RETURNS:
|
|
||||||
* Zero on success, AC_ERR_* mask on failure
|
|
||||||
*/
|
|
||||||
unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd)
|
|
||||||
{
|
|
||||||
struct ata_taskfile tf;
|
|
||||||
|
|
||||||
ata_tf_init(dev, &tf);
|
|
||||||
|
|
||||||
tf.command = cmd;
|
|
||||||
tf.flags |= ATA_TFLAG_DEVICE;
|
|
||||||
tf.protocol = ATA_PROT_NODATA;
|
|
||||||
|
|
||||||
return ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ata_pio_need_iordy - check if iordy needed
|
* ata_pio_need_iordy - check if iordy needed
|
||||||
* @adev: ATA device
|
* @adev: ATA device
|
||||||
|
|
|
@ -1635,7 +1635,6 @@ unsigned int atapi_eh_request_sense(struct ata_device *dev,
|
||||||
|
|
||||||
DPRINTK("ATAPI request sense\n");
|
DPRINTK("ATAPI request sense\n");
|
||||||
|
|
||||||
/* FIXME: is this needed? */
|
|
||||||
memset(sense_buf, 0, SCSI_SENSE_BUFFERSIZE);
|
memset(sense_buf, 0, SCSI_SENSE_BUFFERSIZE);
|
||||||
|
|
||||||
/* initialize sense_buf with the error register,
|
/* initialize sense_buf with the error register,
|
||||||
|
|
|
@ -1995,8 +1995,8 @@ static unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf)
|
||||||
|
|
||||||
VPRINTK("ENTER\n");
|
VPRINTK("ENTER\n");
|
||||||
|
|
||||||
/* set scsi removeable (RMB) bit per ata bit */
|
/* set scsi removable (RMB) bit per ata bit */
|
||||||
if (ata_id_removeable(args->id))
|
if (ata_id_removable(args->id))
|
||||||
hdr[1] |= (1 << 7);
|
hdr[1] |= (1 << 7);
|
||||||
|
|
||||||
if (args->dev->class == ATA_DEV_ZAC) {
|
if (args->dev->class == ATA_DEV_ZAC) {
|
||||||
|
|
|
@ -76,7 +76,6 @@ extern unsigned ata_exec_internal_sg(struct ata_device *dev,
|
||||||
struct ata_taskfile *tf, const u8 *cdb,
|
struct ata_taskfile *tf, const u8 *cdb,
|
||||||
int dma_dir, struct scatterlist *sg,
|
int dma_dir, struct scatterlist *sg,
|
||||||
unsigned int n_elem, unsigned long timeout);
|
unsigned int n_elem, unsigned long timeout);
|
||||||
extern unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd);
|
|
||||||
extern int ata_wait_ready(struct ata_link *link, unsigned long deadline,
|
extern int ata_wait_ready(struct ata_link *link, unsigned long deadline,
|
||||||
int (*check_ready)(struct ata_link *link));
|
int (*check_ready)(struct ata_link *link));
|
||||||
extern int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
|
extern int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
|
||||||
|
|
|
@ -276,10 +276,8 @@ static int cs5530_init_chip(void)
|
||||||
pci_dev_put(cs5530_0);
|
pci_dev_put(cs5530_0);
|
||||||
return 0;
|
return 0;
|
||||||
fail_put:
|
fail_put:
|
||||||
if (master_0)
|
pci_dev_put(master_0);
|
||||||
pci_dev_put(master_0);
|
pci_dev_put(cs5530_0);
|
||||||
if (cs5530_0)
|
|
||||||
pci_dev_put(cs5530_0);
|
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,12 @@
|
||||||
#include <linux/ata_platform.h>
|
#include <linux/ata_platform.h>
|
||||||
#include <linux/libata.h>
|
#include <linux/libata.h>
|
||||||
|
|
||||||
|
#define DRV_NAME "pata_of_platform"
|
||||||
|
|
||||||
|
static struct scsi_host_template pata_platform_sht = {
|
||||||
|
ATA_PIO_SHT(DRV_NAME),
|
||||||
|
};
|
||||||
|
|
||||||
static int pata_of_platform_probe(struct platform_device *ofdev)
|
static int pata_of_platform_probe(struct platform_device *ofdev)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -63,7 +69,7 @@ static int pata_of_platform_probe(struct platform_device *ofdev)
|
||||||
pio_mask |= (1 << pio_mode) - 1;
|
pio_mask |= (1 << pio_mode) - 1;
|
||||||
|
|
||||||
return __pata_platform_probe(&ofdev->dev, &io_res, &ctl_res, irq_res,
|
return __pata_platform_probe(&ofdev->dev, &io_res, &ctl_res, irq_res,
|
||||||
reg_shift, pio_mask);
|
reg_shift, pio_mask, &pata_platform_sht);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct of_device_id pata_of_platform_match[] = {
|
static struct of_device_id pata_of_platform_match[] = {
|
||||||
|
@ -74,7 +80,7 @@ MODULE_DEVICE_TABLE(of, pata_of_platform_match);
|
||||||
|
|
||||||
static struct platform_driver pata_of_platform_driver = {
|
static struct platform_driver pata_of_platform_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "pata_of_platform",
|
.name = DRV_NAME,
|
||||||
.of_match_table = pata_of_platform_match,
|
.of_match_table = pata_of_platform_match,
|
||||||
},
|
},
|
||||||
.probe = pata_of_platform_probe,
|
.probe = pata_of_platform_probe,
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include <linux/blkdev.h>
|
#include <linux/blkdev.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
|
#include <linux/ktime.h>
|
||||||
#include <scsi/scsi.h>
|
#include <scsi/scsi.h>
|
||||||
#include <scsi/scsi_host.h>
|
#include <scsi/scsi_host.h>
|
||||||
#include <scsi/scsi_cmnd.h>
|
#include <scsi/scsi_cmnd.h>
|
||||||
|
@ -605,7 +606,7 @@ static long pdc_detect_pll_input_clock(struct ata_host *host)
|
||||||
void __iomem *mmio_base = host->iomap[PDC_MMIO_BAR];
|
void __iomem *mmio_base = host->iomap[PDC_MMIO_BAR];
|
||||||
u32 scr;
|
u32 scr;
|
||||||
long start_count, end_count;
|
long start_count, end_count;
|
||||||
struct timeval start_time, end_time;
|
ktime_t start_time, end_time;
|
||||||
long pll_clock, usec_elapsed;
|
long pll_clock, usec_elapsed;
|
||||||
|
|
||||||
/* Start the test mode */
|
/* Start the test mode */
|
||||||
|
@ -616,14 +617,14 @@ static long pdc_detect_pll_input_clock(struct ata_host *host)
|
||||||
|
|
||||||
/* Read current counter value */
|
/* Read current counter value */
|
||||||
start_count = pdc_read_counter(host);
|
start_count = pdc_read_counter(host);
|
||||||
do_gettimeofday(&start_time);
|
start_time = ktime_get();
|
||||||
|
|
||||||
/* Let the counter run for 100 ms. */
|
/* Let the counter run for 100 ms. */
|
||||||
mdelay(100);
|
mdelay(100);
|
||||||
|
|
||||||
/* Read the counter values again */
|
/* Read the counter values again */
|
||||||
end_count = pdc_read_counter(host);
|
end_count = pdc_read_counter(host);
|
||||||
do_gettimeofday(&end_time);
|
end_time = ktime_get();
|
||||||
|
|
||||||
/* Stop the test mode */
|
/* Stop the test mode */
|
||||||
scr = ioread32(mmio_base + PDC_SYS_CTL);
|
scr = ioread32(mmio_base + PDC_SYS_CTL);
|
||||||
|
@ -632,8 +633,7 @@ static long pdc_detect_pll_input_clock(struct ata_host *host)
|
||||||
ioread32(mmio_base + PDC_SYS_CTL); /* flush */
|
ioread32(mmio_base + PDC_SYS_CTL); /* flush */
|
||||||
|
|
||||||
/* calculate the input clock in Hz */
|
/* calculate the input clock in Hz */
|
||||||
usec_elapsed = (end_time.tv_sec - start_time.tv_sec) * 1000000 +
|
usec_elapsed = (long) ktime_us_delta(end_time, start_time);
|
||||||
(end_time.tv_usec - start_time.tv_usec);
|
|
||||||
|
|
||||||
pll_clock = ((start_count - end_count) & 0x3fffffff) / 100 *
|
pll_clock = ((start_count - end_count) & 0x3fffffff) / 100 *
|
||||||
(100000000 / usec_elapsed);
|
(100000000 / usec_elapsed);
|
||||||
|
|
|
@ -78,6 +78,7 @@ static void pata_platform_setup_port(struct ata_ioports *ioaddr,
|
||||||
* @irq_res: Resource representing IRQ and its flags
|
* @irq_res: Resource representing IRQ and its flags
|
||||||
* @ioport_shift: I/O port shift
|
* @ioport_shift: I/O port shift
|
||||||
* @__pio_mask: PIO mask
|
* @__pio_mask: PIO mask
|
||||||
|
* @sht: scsi_host_template to use when registering
|
||||||
*
|
*
|
||||||
* Register a platform bus IDE interface. Such interfaces are PIO and we
|
* Register a platform bus IDE interface. Such interfaces are PIO and we
|
||||||
* assume do not support IRQ sharing.
|
* assume do not support IRQ sharing.
|
||||||
|
@ -99,7 +100,8 @@ static void pata_platform_setup_port(struct ata_ioports *ioaddr,
|
||||||
*/
|
*/
|
||||||
int __pata_platform_probe(struct device *dev, struct resource *io_res,
|
int __pata_platform_probe(struct device *dev, struct resource *io_res,
|
||||||
struct resource *ctl_res, struct resource *irq_res,
|
struct resource *ctl_res, struct resource *irq_res,
|
||||||
unsigned int ioport_shift, int __pio_mask)
|
unsigned int ioport_shift, int __pio_mask,
|
||||||
|
struct scsi_host_template *sht)
|
||||||
{
|
{
|
||||||
struct ata_host *host;
|
struct ata_host *host;
|
||||||
struct ata_port *ap;
|
struct ata_port *ap;
|
||||||
|
@ -170,7 +172,7 @@ int __pata_platform_probe(struct device *dev, struct resource *io_res,
|
||||||
|
|
||||||
/* activate */
|
/* activate */
|
||||||
return ata_host_activate(host, irq, irq ? ata_sff_interrupt : NULL,
|
return ata_host_activate(host, irq, irq ? ata_sff_interrupt : NULL,
|
||||||
irq_flags, &pata_platform_sht);
|
irq_flags, sht);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(__pata_platform_probe);
|
EXPORT_SYMBOL_GPL(__pata_platform_probe);
|
||||||
|
|
||||||
|
@ -216,7 +218,7 @@ static int pata_platform_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
return __pata_platform_probe(&pdev->dev, io_res, ctl_res, irq_res,
|
return __pata_platform_probe(&pdev->dev, io_res, ctl_res, irq_res,
|
||||||
pp_info ? pp_info->ioport_shift : 0,
|
pp_info ? pp_info->ioport_shift : 0,
|
||||||
pio_mask);
|
pio_mask, &pata_platform_sht);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct platform_driver pata_platform_driver = {
|
static struct platform_driver pata_platform_driver = {
|
||||||
|
|
|
@ -48,6 +48,18 @@
|
||||||
#define DRV_NAME "sata-dwc"
|
#define DRV_NAME "sata-dwc"
|
||||||
#define DRV_VERSION "1.3"
|
#define DRV_VERSION "1.3"
|
||||||
|
|
||||||
|
#ifndef out_le32
|
||||||
|
#define out_le32(a, v) __raw_writel(__cpu_to_le32(v), (void __iomem *)(a))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef in_le32
|
||||||
|
#define in_le32(a) __le32_to_cpu(__raw_readl((void __iomem *)(a)))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef NO_IRQ
|
||||||
|
#define NO_IRQ 0
|
||||||
|
#endif
|
||||||
|
|
||||||
/* SATA DMA driver Globals */
|
/* SATA DMA driver Globals */
|
||||||
#define DMA_NUM_CHANS 1
|
#define DMA_NUM_CHANS 1
|
||||||
#define DMA_NUM_CHAN_REGS 8
|
#define DMA_NUM_CHAN_REGS 8
|
||||||
|
@ -273,7 +285,7 @@ struct sata_dwc_device {
|
||||||
struct device *dev; /* generic device struct */
|
struct device *dev; /* generic device struct */
|
||||||
struct ata_probe_ent *pe; /* ptr to probe-ent */
|
struct ata_probe_ent *pe; /* ptr to probe-ent */
|
||||||
struct ata_host *host;
|
struct ata_host *host;
|
||||||
u8 *reg_base;
|
u8 __iomem *reg_base;
|
||||||
struct sata_dwc_regs *sata_dwc_regs; /* DW Synopsys SATA specific */
|
struct sata_dwc_regs *sata_dwc_regs; /* DW Synopsys SATA specific */
|
||||||
int irq_dma;
|
int irq_dma;
|
||||||
};
|
};
|
||||||
|
@ -323,7 +335,9 @@ struct sata_dwc_host_priv {
|
||||||
struct device *dwc_dev;
|
struct device *dwc_dev;
|
||||||
int dma_channel;
|
int dma_channel;
|
||||||
};
|
};
|
||||||
struct sata_dwc_host_priv host_pvt;
|
|
||||||
|
static struct sata_dwc_host_priv host_pvt;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Prototypes
|
* Prototypes
|
||||||
*/
|
*/
|
||||||
|
@ -580,9 +594,9 @@ static int map_sg_to_lli(struct scatterlist *sg, int num_elems,
|
||||||
|
|
||||||
sms_val = 0;
|
sms_val = 0;
|
||||||
dms_val = 1 + host_pvt.dma_channel;
|
dms_val = 1 + host_pvt.dma_channel;
|
||||||
dev_dbg(host_pvt.dwc_dev, "%s: sg=%p nelem=%d lli=%p dma_lli=0x%08x"
|
dev_dbg(host_pvt.dwc_dev,
|
||||||
" dmadr=0x%08x\n", __func__, sg, num_elems, lli, (u32)dma_lli,
|
"%s: sg=%p nelem=%d lli=%p dma_lli=0x%pad dmadr=0x%p\n",
|
||||||
(u32)dmadr_addr);
|
__func__, sg, num_elems, lli, &dma_lli, dmadr_addr);
|
||||||
|
|
||||||
bl = get_burst_length_encode(AHB_DMA_BRST_DFLT);
|
bl = get_burst_length_encode(AHB_DMA_BRST_DFLT);
|
||||||
|
|
||||||
|
@ -773,7 +787,7 @@ static void dma_dwc_exit(struct sata_dwc_device *hsdev)
|
||||||
{
|
{
|
||||||
dev_dbg(host_pvt.dwc_dev, "%s:\n", __func__);
|
dev_dbg(host_pvt.dwc_dev, "%s:\n", __func__);
|
||||||
if (host_pvt.sata_dma_regs) {
|
if (host_pvt.sata_dma_regs) {
|
||||||
iounmap(host_pvt.sata_dma_regs);
|
iounmap((void __iomem *)host_pvt.sata_dma_regs);
|
||||||
host_pvt.sata_dma_regs = NULL;
|
host_pvt.sata_dma_regs = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -818,7 +832,7 @@ static int sata_dwc_scr_read(struct ata_link *link, unsigned int scr, u32 *val)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
*val = in_le32((void *)link->ap->ioaddr.scr_addr + (scr * 4));
|
*val = in_le32(link->ap->ioaddr.scr_addr + (scr * 4));
|
||||||
dev_dbg(link->ap->dev, "%s: id=%d reg=%d val=val=0x%08x\n",
|
dev_dbg(link->ap->dev, "%s: id=%d reg=%d val=val=0x%08x\n",
|
||||||
__func__, link->ap->print_id, scr, *val);
|
__func__, link->ap->print_id, scr, *val);
|
||||||
|
|
||||||
|
@ -834,21 +848,19 @@ static int sata_dwc_scr_write(struct ata_link *link, unsigned int scr, u32 val)
|
||||||
__func__, scr);
|
__func__, scr);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
out_le32((void *)link->ap->ioaddr.scr_addr + (scr * 4), val);
|
out_le32(link->ap->ioaddr.scr_addr + (scr * 4), val);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 core_scr_read(unsigned int scr)
|
static u32 core_scr_read(unsigned int scr)
|
||||||
{
|
{
|
||||||
return in_le32((void __iomem *)(host_pvt.scr_addr_sstatus) +\
|
return in_le32(host_pvt.scr_addr_sstatus + (scr * 4));
|
||||||
(scr * 4));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void core_scr_write(unsigned int scr, u32 val)
|
static void core_scr_write(unsigned int scr, u32 val)
|
||||||
{
|
{
|
||||||
out_le32((void __iomem *)(host_pvt.scr_addr_sstatus) + (scr * 4),
|
out_le32(host_pvt.scr_addr_sstatus + (scr * 4), val);
|
||||||
val);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void clear_serror(void)
|
static void clear_serror(void)
|
||||||
|
@ -856,7 +868,6 @@ static void clear_serror(void)
|
||||||
u32 val;
|
u32 val;
|
||||||
val = core_scr_read(SCR_ERROR);
|
val = core_scr_read(SCR_ERROR);
|
||||||
core_scr_write(SCR_ERROR, val);
|
core_scr_write(SCR_ERROR, val);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void clear_interrupt_bit(struct sata_dwc_device *hsdev, u32 bit)
|
static void clear_interrupt_bit(struct sata_dwc_device *hsdev, u32 bit)
|
||||||
|
@ -1256,24 +1267,24 @@ static void sata_dwc_enable_interrupts(struct sata_dwc_device *hsdev)
|
||||||
|
|
||||||
static void sata_dwc_setup_port(struct ata_ioports *port, unsigned long base)
|
static void sata_dwc_setup_port(struct ata_ioports *port, unsigned long base)
|
||||||
{
|
{
|
||||||
port->cmd_addr = (void *)base + 0x00;
|
port->cmd_addr = (void __iomem *)base + 0x00;
|
||||||
port->data_addr = (void *)base + 0x00;
|
port->data_addr = (void __iomem *)base + 0x00;
|
||||||
|
|
||||||
port->error_addr = (void *)base + 0x04;
|
port->error_addr = (void __iomem *)base + 0x04;
|
||||||
port->feature_addr = (void *)base + 0x04;
|
port->feature_addr = (void __iomem *)base + 0x04;
|
||||||
|
|
||||||
port->nsect_addr = (void *)base + 0x08;
|
port->nsect_addr = (void __iomem *)base + 0x08;
|
||||||
|
|
||||||
port->lbal_addr = (void *)base + 0x0c;
|
port->lbal_addr = (void __iomem *)base + 0x0c;
|
||||||
port->lbam_addr = (void *)base + 0x10;
|
port->lbam_addr = (void __iomem *)base + 0x10;
|
||||||
port->lbah_addr = (void *)base + 0x14;
|
port->lbah_addr = (void __iomem *)base + 0x14;
|
||||||
|
|
||||||
port->device_addr = (void *)base + 0x18;
|
port->device_addr = (void __iomem *)base + 0x18;
|
||||||
port->command_addr = (void *)base + 0x1c;
|
port->command_addr = (void __iomem *)base + 0x1c;
|
||||||
port->status_addr = (void *)base + 0x1c;
|
port->status_addr = (void __iomem *)base + 0x1c;
|
||||||
|
|
||||||
port->altstatus_addr = (void *)base + 0x20;
|
port->altstatus_addr = (void __iomem *)base + 0x20;
|
||||||
port->ctl_addr = (void *)base + 0x20;
|
port->ctl_addr = (void __iomem *)base + 0x20;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1314,7 +1325,7 @@ static int sata_dwc_port_start(struct ata_port *ap)
|
||||||
for (i = 0; i < SATA_DWC_QCMD_MAX; i++)
|
for (i = 0; i < SATA_DWC_QCMD_MAX; i++)
|
||||||
hsdevp->cmd_issued[i] = SATA_DWC_CMD_ISSUED_NOT;
|
hsdevp->cmd_issued[i] = SATA_DWC_CMD_ISSUED_NOT;
|
||||||
|
|
||||||
ap->bmdma_prd = 0; /* set these so libata doesn't use them */
|
ap->bmdma_prd = NULL; /* set these so libata doesn't use them */
|
||||||
ap->bmdma_prd_dma = 0;
|
ap->bmdma_prd_dma = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1511,8 +1522,8 @@ static void sata_dwc_qc_prep_by_tag(struct ata_queued_cmd *qc, u8 tag)
|
||||||
|
|
||||||
dma_chan = dma_dwc_xfer_setup(sg, qc->n_elem, hsdevp->llit[tag],
|
dma_chan = dma_dwc_xfer_setup(sg, qc->n_elem, hsdevp->llit[tag],
|
||||||
hsdevp->llit_dma[tag],
|
hsdevp->llit_dma[tag],
|
||||||
(void *__iomem)(&hsdev->sata_dwc_regs->\
|
(void __iomem *)&hsdev->sata_dwc_regs->dmadr,
|
||||||
dmadr), qc->dma_dir);
|
qc->dma_dir);
|
||||||
if (dma_chan < 0) {
|
if (dma_chan < 0) {
|
||||||
dev_err(ap->dev, "%s: dma_dwc_xfer_setup returns err %d\n",
|
dev_err(ap->dev, "%s: dma_dwc_xfer_setup returns err %d\n",
|
||||||
__func__, dma_chan);
|
__func__, dma_chan);
|
||||||
|
@ -1585,8 +1596,8 @@ static void sata_dwc_error_handler(struct ata_port *ap)
|
||||||
ata_sff_error_handler(ap);
|
ata_sff_error_handler(ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
int sata_dwc_hardreset(struct ata_link *link, unsigned int *class,
|
static int sata_dwc_hardreset(struct ata_link *link, unsigned int *class,
|
||||||
unsigned long deadline)
|
unsigned long deadline)
|
||||||
{
|
{
|
||||||
struct sata_dwc_device *hsdev = HSDEV_FROM_AP(link->ap);
|
struct sata_dwc_device *hsdev = HSDEV_FROM_AP(link->ap);
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -1618,7 +1629,7 @@ static struct scsi_host_template sata_dwc_sht = {
|
||||||
* max of 1. This will get fixed in in a future release.
|
* max of 1. This will get fixed in in a future release.
|
||||||
*/
|
*/
|
||||||
.sg_tablesize = LIBATA_MAX_PRD,
|
.sg_tablesize = LIBATA_MAX_PRD,
|
||||||
.can_queue = ATA_DEF_QUEUE, /* ATA_MAX_QUEUE */
|
/* .can_queue = ATA_MAX_QUEUE, */
|
||||||
.dma_boundary = ATA_DMA_BOUNDARY,
|
.dma_boundary = ATA_DMA_BOUNDARY,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1655,7 +1666,7 @@ static int sata_dwc_probe(struct platform_device *ofdev)
|
||||||
struct sata_dwc_device *hsdev;
|
struct sata_dwc_device *hsdev;
|
||||||
u32 idr, versionr;
|
u32 idr, versionr;
|
||||||
char *ver = (char *)&versionr;
|
char *ver = (char *)&versionr;
|
||||||
u8 *base = NULL;
|
u8 __iomem *base;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
int irq;
|
int irq;
|
||||||
struct ata_host *host;
|
struct ata_host *host;
|
||||||
|
@ -1665,12 +1676,12 @@ static int sata_dwc_probe(struct platform_device *ofdev)
|
||||||
u32 dma_chan;
|
u32 dma_chan;
|
||||||
|
|
||||||
/* Allocate DWC SATA device */
|
/* Allocate DWC SATA device */
|
||||||
hsdev = kzalloc(sizeof(*hsdev), GFP_KERNEL);
|
host = ata_host_alloc_pinfo(&ofdev->dev, ppi, SATA_DWC_MAX_PORTS);
|
||||||
if (hsdev == NULL) {
|
hsdev = devm_kzalloc(&ofdev->dev, sizeof(*hsdev), GFP_KERNEL);
|
||||||
dev_err(&ofdev->dev, "kmalloc failed for hsdev\n");
|
if (!host || !hsdev)
|
||||||
err = -ENOMEM;
|
return -ENOMEM;
|
||||||
goto error;
|
|
||||||
}
|
host->private_data = hsdev;
|
||||||
|
|
||||||
if (of_property_read_u32(np, "dma-channel", &dma_chan)) {
|
if (of_property_read_u32(np, "dma-channel", &dma_chan)) {
|
||||||
dev_warn(&ofdev->dev, "no dma-channel property set."
|
dev_warn(&ofdev->dev, "no dma-channel property set."
|
||||||
|
@ -1680,12 +1691,11 @@ static int sata_dwc_probe(struct platform_device *ofdev)
|
||||||
host_pvt.dma_channel = dma_chan;
|
host_pvt.dma_channel = dma_chan;
|
||||||
|
|
||||||
/* Ioremap SATA registers */
|
/* Ioremap SATA registers */
|
||||||
base = of_iomap(ofdev->dev.of_node, 0);
|
base = of_iomap(np, 0);
|
||||||
if (!base) {
|
if (!base) {
|
||||||
dev_err(&ofdev->dev, "ioremap failed for SATA register"
|
dev_err(&ofdev->dev, "ioremap failed for SATA register"
|
||||||
" address\n");
|
" address\n");
|
||||||
err = -ENODEV;
|
return -ENODEV;
|
||||||
goto error_kmalloc;
|
|
||||||
}
|
}
|
||||||
hsdev->reg_base = base;
|
hsdev->reg_base = base;
|
||||||
dev_dbg(&ofdev->dev, "ioremap done for SATA register address\n");
|
dev_dbg(&ofdev->dev, "ioremap done for SATA register address\n");
|
||||||
|
@ -1693,16 +1703,6 @@ static int sata_dwc_probe(struct platform_device *ofdev)
|
||||||
/* Synopsys DWC SATA specific Registers */
|
/* Synopsys DWC SATA specific Registers */
|
||||||
hsdev->sata_dwc_regs = (void *__iomem)(base + SATA_DWC_REG_OFFSET);
|
hsdev->sata_dwc_regs = (void *__iomem)(base + SATA_DWC_REG_OFFSET);
|
||||||
|
|
||||||
/* Allocate and fill host */
|
|
||||||
host = ata_host_alloc_pinfo(&ofdev->dev, ppi, SATA_DWC_MAX_PORTS);
|
|
||||||
if (!host) {
|
|
||||||
dev_err(&ofdev->dev, "ata_host_alloc_pinfo failed\n");
|
|
||||||
err = -ENOMEM;
|
|
||||||
goto error_iomap;
|
|
||||||
}
|
|
||||||
|
|
||||||
host->private_data = hsdev;
|
|
||||||
|
|
||||||
/* Setup port */
|
/* Setup port */
|
||||||
host->ports[0]->ioaddr.cmd_addr = base;
|
host->ports[0]->ioaddr.cmd_addr = base;
|
||||||
host->ports[0]->ioaddr.scr_addr = base + SATA_DWC_SCR_OFFSET;
|
host->ports[0]->ioaddr.scr_addr = base + SATA_DWC_SCR_OFFSET;
|
||||||
|
@ -1716,7 +1716,7 @@ static int sata_dwc_probe(struct platform_device *ofdev)
|
||||||
idr, ver[0], ver[1], ver[2]);
|
idr, ver[0], ver[1], ver[2]);
|
||||||
|
|
||||||
/* Get SATA DMA interrupt number */
|
/* Get SATA DMA interrupt number */
|
||||||
irq = irq_of_parse_and_map(ofdev->dev.of_node, 1);
|
irq = irq_of_parse_and_map(np, 1);
|
||||||
if (irq == NO_IRQ) {
|
if (irq == NO_IRQ) {
|
||||||
dev_err(&ofdev->dev, "no SATA DMA irq\n");
|
dev_err(&ofdev->dev, "no SATA DMA irq\n");
|
||||||
err = -ENODEV;
|
err = -ENODEV;
|
||||||
|
@ -1724,7 +1724,7 @@ static int sata_dwc_probe(struct platform_device *ofdev)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get physical SATA DMA register base address */
|
/* Get physical SATA DMA register base address */
|
||||||
host_pvt.sata_dma_regs = of_iomap(ofdev->dev.of_node, 1);
|
host_pvt.sata_dma_regs = (void *)of_iomap(np, 1);
|
||||||
if (!(host_pvt.sata_dma_regs)) {
|
if (!(host_pvt.sata_dma_regs)) {
|
||||||
dev_err(&ofdev->dev, "ioremap failed for AHBDMA register"
|
dev_err(&ofdev->dev, "ioremap failed for AHBDMA register"
|
||||||
" address\n");
|
" address\n");
|
||||||
|
@ -1744,7 +1744,7 @@ static int sata_dwc_probe(struct platform_device *ofdev)
|
||||||
sata_dwc_enable_interrupts(hsdev);
|
sata_dwc_enable_interrupts(hsdev);
|
||||||
|
|
||||||
/* Get SATA interrupt number */
|
/* Get SATA interrupt number */
|
||||||
irq = irq_of_parse_and_map(ofdev->dev.of_node, 0);
|
irq = irq_of_parse_and_map(np, 0);
|
||||||
if (irq == NO_IRQ) {
|
if (irq == NO_IRQ) {
|
||||||
dev_err(&ofdev->dev, "no SATA DMA irq\n");
|
dev_err(&ofdev->dev, "no SATA DMA irq\n");
|
||||||
err = -ENODEV;
|
err = -ENODEV;
|
||||||
|
@ -1770,9 +1770,6 @@ error_dma_iomap:
|
||||||
iounmap((void __iomem *)host_pvt.sata_dma_regs);
|
iounmap((void __iomem *)host_pvt.sata_dma_regs);
|
||||||
error_iomap:
|
error_iomap:
|
||||||
iounmap(base);
|
iounmap(base);
|
||||||
error_kmalloc:
|
|
||||||
kfree(hsdev);
|
|
||||||
error:
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1783,15 +1780,12 @@ static int sata_dwc_remove(struct platform_device *ofdev)
|
||||||
struct sata_dwc_device *hsdev = host->private_data;
|
struct sata_dwc_device *hsdev = host->private_data;
|
||||||
|
|
||||||
ata_host_detach(host);
|
ata_host_detach(host);
|
||||||
dev_set_drvdata(dev, NULL);
|
|
||||||
|
|
||||||
/* Free SATA DMA resources */
|
/* Free SATA DMA resources */
|
||||||
dma_dwc_exit(hsdev);
|
dma_dwc_exit(hsdev);
|
||||||
|
|
||||||
iounmap((void __iomem *)host_pvt.sata_dma_regs);
|
iounmap((void __iomem *)host_pvt.sata_dma_regs);
|
||||||
iounmap(hsdev->reg_base);
|
iounmap(hsdev->reg_base);
|
||||||
kfree(hsdev);
|
|
||||||
kfree(host);
|
|
||||||
dev_dbg(&ofdev->dev, "done\n");
|
dev_dbg(&ofdev->dev, "done\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4185,8 +4185,7 @@ err:
|
||||||
clk_disable_unprepare(hpriv->port_clks[port]);
|
clk_disable_unprepare(hpriv->port_clks[port]);
|
||||||
clk_put(hpriv->port_clks[port]);
|
clk_put(hpriv->port_clks[port]);
|
||||||
}
|
}
|
||||||
if (hpriv->port_phys[port])
|
phy_power_off(hpriv->port_phys[port]);
|
||||||
phy_power_off(hpriv->port_phys[port]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -4216,8 +4215,7 @@ static int mv_platform_remove(struct platform_device *pdev)
|
||||||
clk_disable_unprepare(hpriv->port_clks[port]);
|
clk_disable_unprepare(hpriv->port_clks[port]);
|
||||||
clk_put(hpriv->port_clks[port]);
|
clk_put(hpriv->port_clks[port]);
|
||||||
}
|
}
|
||||||
if (hpriv->port_phys[port])
|
phy_power_off(hpriv->port_phys[port]);
|
||||||
phy_power_off(hpriv->port_phys[port]);
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* Renesas R-Car SATA driver
|
* Renesas R-Car SATA driver
|
||||||
*
|
*
|
||||||
* Author: Vladimir Barinov <source@cogentembedded.com>
|
* Author: Vladimir Barinov <source@cogentembedded.com>
|
||||||
* Copyright (C) 2013 Cogent Embedded, Inc.
|
* Copyright (C) 2013-2015 Cogent Embedded, Inc.
|
||||||
* Copyright (C) 2013 Renesas Solutions Corp.
|
* Copyright (C) 2013-2015 Renesas Solutions Corp.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* 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
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
@ -992,9 +992,30 @@ static int sata_rcar_resume(struct device *dev)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int sata_rcar_restore(struct device *dev)
|
||||||
|
{
|
||||||
|
struct ata_host *host = dev_get_drvdata(dev);
|
||||||
|
struct sata_rcar_priv *priv = host->private_data;
|
||||||
|
|
||||||
|
clk_prepare_enable(priv->clk);
|
||||||
|
|
||||||
|
sata_rcar_setup_port(host);
|
||||||
|
|
||||||
|
/* initialize host controller */
|
||||||
|
sata_rcar_init_controller(host);
|
||||||
|
|
||||||
|
ata_host_resume(host);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static const struct dev_pm_ops sata_rcar_pm_ops = {
|
static const struct dev_pm_ops sata_rcar_pm_ops = {
|
||||||
.suspend = sata_rcar_suspend,
|
.suspend = sata_rcar_suspend,
|
||||||
.resume = sata_rcar_resume,
|
.resume = sata_rcar_resume,
|
||||||
|
.freeze = sata_rcar_suspend,
|
||||||
|
.thaw = sata_rcar_resume,
|
||||||
|
.poweroff = sata_rcar_suspend,
|
||||||
|
.restore = sata_rcar_restore,
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -21,16 +21,20 @@ struct device;
|
||||||
struct ata_port_info;
|
struct ata_port_info;
|
||||||
struct ahci_host_priv;
|
struct ahci_host_priv;
|
||||||
struct platform_device;
|
struct platform_device;
|
||||||
|
struct scsi_host_template;
|
||||||
|
|
||||||
int ahci_platform_enable_clks(struct ahci_host_priv *hpriv);
|
int ahci_platform_enable_clks(struct ahci_host_priv *hpriv);
|
||||||
void ahci_platform_disable_clks(struct ahci_host_priv *hpriv);
|
void ahci_platform_disable_clks(struct ahci_host_priv *hpriv);
|
||||||
|
int ahci_platform_enable_regulators(struct ahci_host_priv *hpriv);
|
||||||
|
void ahci_platform_disable_regulators(struct ahci_host_priv *hpriv);
|
||||||
int ahci_platform_enable_resources(struct ahci_host_priv *hpriv);
|
int ahci_platform_enable_resources(struct ahci_host_priv *hpriv);
|
||||||
void ahci_platform_disable_resources(struct ahci_host_priv *hpriv);
|
void ahci_platform_disable_resources(struct ahci_host_priv *hpriv);
|
||||||
struct ahci_host_priv *ahci_platform_get_resources(
|
struct ahci_host_priv *ahci_platform_get_resources(
|
||||||
struct platform_device *pdev);
|
struct platform_device *pdev);
|
||||||
int ahci_platform_init_host(struct platform_device *pdev,
|
int ahci_platform_init_host(struct platform_device *pdev,
|
||||||
struct ahci_host_priv *hpriv,
|
struct ahci_host_priv *hpriv,
|
||||||
const struct ata_port_info *pi_template);
|
const struct ata_port_info *pi_template,
|
||||||
|
struct scsi_host_template *sht);
|
||||||
|
|
||||||
int ahci_platform_suspend_host(struct device *dev);
|
int ahci_platform_suspend_host(struct device *dev);
|
||||||
int ahci_platform_resume_host(struct device *dev);
|
int ahci_platform_resume_host(struct device *dev);
|
||||||
|
|
|
@ -503,7 +503,7 @@ struct ata_bmdma_prd {
|
||||||
#define ata_id_has_dma(id) ((id)[ATA_ID_CAPABILITY] & (1 << 8))
|
#define ata_id_has_dma(id) ((id)[ATA_ID_CAPABILITY] & (1 << 8))
|
||||||
#define ata_id_has_ncq(id) ((id)[ATA_ID_SATA_CAPABILITY] & (1 << 8))
|
#define ata_id_has_ncq(id) ((id)[ATA_ID_SATA_CAPABILITY] & (1 << 8))
|
||||||
#define ata_id_queue_depth(id) (((id)[ATA_ID_QUEUE_DEPTH] & 0x1f) + 1)
|
#define ata_id_queue_depth(id) (((id)[ATA_ID_QUEUE_DEPTH] & 0x1f) + 1)
|
||||||
#define ata_id_removeable(id) ((id)[ATA_ID_CONFIG] & (1 << 7))
|
#define ata_id_removable(id) ((id)[ATA_ID_CONFIG] & (1 << 7))
|
||||||
#define ata_id_has_atapi_AN(id) \
|
#define ata_id_has_atapi_AN(id) \
|
||||||
((((id)[ATA_ID_SATA_CAPABILITY] != 0x0000) && \
|
((((id)[ATA_ID_SATA_CAPABILITY] != 0x0000) && \
|
||||||
((id)[ATA_ID_SATA_CAPABILITY] != 0xffff)) && \
|
((id)[ATA_ID_SATA_CAPABILITY] != 0xffff)) && \
|
||||||
|
|
|
@ -10,12 +10,15 @@ struct pata_platform_info {
|
||||||
unsigned int ioport_shift;
|
unsigned int ioport_shift;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct scsi_host_template;
|
||||||
|
|
||||||
extern int __pata_platform_probe(struct device *dev,
|
extern int __pata_platform_probe(struct device *dev,
|
||||||
struct resource *io_res,
|
struct resource *io_res,
|
||||||
struct resource *ctl_res,
|
struct resource *ctl_res,
|
||||||
struct resource *irq_res,
|
struct resource *irq_res,
|
||||||
unsigned int ioport_shift,
|
unsigned int ioport_shift,
|
||||||
int __pio_mask);
|
int __pio_mask,
|
||||||
|
struct scsi_host_template *sht);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Marvell SATA private data
|
* Marvell SATA private data
|
||||||
|
|
|
@ -1340,6 +1340,12 @@ extern const struct ata_port_operations ata_base_port_ops;
|
||||||
extern const struct ata_port_operations sata_port_ops;
|
extern const struct ata_port_operations sata_port_ops;
|
||||||
extern struct device_attribute *ata_common_sdev_attrs[];
|
extern struct device_attribute *ata_common_sdev_attrs[];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* All sht initializers (BASE, PIO, BMDMA, NCQ) must be instantiated
|
||||||
|
* by the edge drivers. Because the 'module' field of sht must be the
|
||||||
|
* edge driver's module reference, otherwise the driver can be unloaded
|
||||||
|
* even if the scsi_device is being accessed.
|
||||||
|
*/
|
||||||
#define ATA_BASE_SHT(drv_name) \
|
#define ATA_BASE_SHT(drv_name) \
|
||||||
.module = THIS_MODULE, \
|
.module = THIS_MODULE, \
|
||||||
.name = drv_name, \
|
.name = drv_name, \
|
||||||
|
|
Loading…
Reference in New Issue