From 94463a9cadc7f72a70ec6ee801109c2f1e44a123 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sun, 15 Jun 2014 13:37:32 -0700 Subject: ata: Use dma_zalloc_coherent Use the zeroing function instead of dma_alloc_coherent & memset(,0,) Signed-off-by: Joe Perches Signed-off-by: Tejun Heo --- drivers/ata/sata_fsl.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c index 616a6d2ac20c..07bc7e4dbd04 100644 --- a/drivers/ata/sata_fsl.c +++ b/drivers/ata/sata_fsl.c @@ -734,13 +734,12 @@ static int sata_fsl_port_start(struct ata_port *ap) if (!pp) return -ENOMEM; - mem = dma_alloc_coherent(dev, SATA_FSL_PORT_PRIV_DMA_SZ, &mem_dma, - GFP_KERNEL); + mem = dma_zalloc_coherent(dev, SATA_FSL_PORT_PRIV_DMA_SZ, &mem_dma, + GFP_KERNEL); if (!mem) { kfree(pp); return -ENOMEM; } - memset(mem, 0, SATA_FSL_PORT_PRIV_DMA_SZ); pp->cmdslot = mem; pp->cmdslot_paddr = mem_dma; -- cgit v1.2.3 From cc7a9e27562cd78a1dc885504086fab24addce40 Mon Sep 17 00:00:00 2001 From: Suravee Suthikulpanit Date: Thu, 12 Jun 2014 12:40:23 -0500 Subject: ahci: Check and set 64-bit DMA mask for platform AHCI driver The current platform AHCI driver does not set the dma_mask correctly for 64-bit DMA capable AHCI controller. This patch checks the AHCI capability bit and set the dma_mask and coherent_dma_mask accordingly. Signed-off-by: Suravee Suthikulpanit Reviewed-by: Bartlomiej Zolnierkiewicz Reviewed-by: Hans de Goede Tested-by: Hans de Goede Tested-by: Suman Tripathi Signed-off-by: Tejun Heo --- drivers/ata/libahci_platform.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c index 3a5b4ed25a4f..a958a2b8fd93 100644 --- a/drivers/ata/libahci_platform.c +++ b/drivers/ata/libahci_platform.c @@ -364,6 +364,19 @@ int ahci_platform_init_host(struct platform_device *pdev, ap->ops = &ata_dummy_port_ops; } + if (hpriv->cap & HOST_CAP_64) { + rc = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(64)); + if (rc) { + rc = dma_coerce_mask_and_coherent(dev, + DMA_BIT_MASK(32)); + if (rc) { + dev_err(dev, "Failed to enable 64-bit DMA.\n"); + return rc; + } + dev_warn(dev, "Enable 32-bit DMA instead of 64-bit.\n"); + } + } + rc = ahci_reset_controller(host); if (rc) return rc; -- cgit v1.2.3 From be64beb40df808385f7883d2e6f01ff7c79eeae4 Mon Sep 17 00:00:00 2001 From: Suravee Suthikulpanit Date: Thu, 12 Jun 2014 12:40:24 -0500 Subject: ahci/xgene: Remove logic to set 64-bit DMA mask Instead of doing the check here, this should be handled in the common AHCI platform code. Signed-off-by: Suravee Suthikulpanit Suggested-by: Bartlomiej Zolnierkiewicz Cc: Loc Ho Cc: Tuan Phan Cc: Suman Triphati Signed-off-by: Tejun Heo --- drivers/ata/ahci_xgene.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/drivers/ata/ahci_xgene.c b/drivers/ata/ahci_xgene.c index 042a9bb45c86..a9fc2ae2e6e2 100644 --- a/drivers/ata/ahci_xgene.c +++ b/drivers/ata/ahci_xgene.c @@ -440,16 +440,6 @@ static int xgene_ahci_probe(struct platform_device *pdev) /* Configure the host controller */ xgene_ahci_hw_init(hpriv); - /* - * Setup DMA mask. This is preliminary until the DMA range is sorted - * out. - */ - rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); - if (rc) { - dev_err(dev, "Unable to set dma mask\n"); - goto disable_resources; - } - hflags = AHCI_HFLAG_NO_PMP | AHCI_HFLAG_YES_NCQ; rc = ahci_platform_init_host(pdev, hpriv, &xgene_ahci_port_info, -- cgit v1.2.3 From a1a6cc1d2ea9e3adf81faab87b834bc903856207 Mon Sep 17 00:00:00 2001 From: Kukjin Kim Date: Tue, 1 Jul 2014 06:32:23 +0900 Subject: ata: pata_samsung_cf: removes s5pc100 related ata codes This patch removes support for s5pc100 ata because of no more support S5PC100 SoC in mainline. Signed-off-by: Kukjin Kim Signed-off-by: Tejun Heo --- drivers/ata/pata_samsung_cf.c | 13 ------------- include/linux/platform_data/ata-samsung_cf.h | 1 - 2 files changed, 14 deletions(-) diff --git a/drivers/ata/pata_samsung_cf.c b/drivers/ata/pata_samsung_cf.c index fb528831fb92..2578fc16960a 100644 --- a/drivers/ata/pata_samsung_cf.c +++ b/drivers/ata/pata_samsung_cf.c @@ -54,7 +54,6 @@ enum s3c_cpu_type { TYPE_S3C64XX, - TYPE_S5PC100, TYPE_S5PV210, }; @@ -476,10 +475,6 @@ static void pata_s3c_hwinit(struct s3c_ide_info *info, writel(0x1b, info->ide_addr + S3C_ATA_IRQ_MSK); break; - case TYPE_S5PC100: - pata_s3c_cfg_mode(info->sfr_addr); - /* FALLTHROUGH */ - case TYPE_S5PV210: /* Configure as little endian */ pata_s3c_set_endian(info->ide_addr, 0); @@ -549,11 +544,6 @@ static int __init pata_s3c_probe(struct platform_device *pdev) info->sfr_addr = info->ide_addr + 0x1800; info->ide_addr += 0x1900; info->fifo_status_reg = 0x94; - } else if (cpu_type == TYPE_S5PC100) { - ap->ops = &pata_s5p_port_ops; - info->sfr_addr = info->ide_addr + 0x1800; - info->ide_addr += 0x1900; - info->fifo_status_reg = 0x84; } else { ap->ops = &pata_s5p_port_ops; info->fifo_status_reg = 0x84; @@ -652,9 +642,6 @@ static struct platform_device_id pata_s3c_driver_ids[] = { { .name = "s3c64xx-pata", .driver_data = TYPE_S3C64XX, - }, { - .name = "s5pc100-pata", - .driver_data = TYPE_S5PC100, }, { .name = "s5pv210-pata", .driver_data = TYPE_S5PV210, diff --git a/include/linux/platform_data/ata-samsung_cf.h b/include/linux/platform_data/ata-samsung_cf.h index c2049e3d7444..748e71642c4a 100644 --- a/include/linux/platform_data/ata-samsung_cf.h +++ b/include/linux/platform_data/ata-samsung_cf.h @@ -29,7 +29,6 @@ extern void s3c_ide_set_platdata(struct s3c_ide_platdata *pdata); /* architecture-specific IDE configuration */ extern void s3c64xx_ide_setup_gpio(void); -extern void s5pc100_ide_setup_gpio(void); extern void s5pv210_ide_setup_gpio(void); #endif /*__ATA_SAMSUNG_CF_H */ -- cgit v1.2.3 From 23a7c31e4a1c2e0acfa91c6360636e4ac6d8dd40 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Tue, 24 Jun 2014 11:19:27 +0100 Subject: dt-bindings: ata: create bindings for imx sata controller To: Tejun Heo ,linux-ide@vger.kernel.org The Freescale i.MX SATA controller mostly conforms to the AHCI interface, but there are some special extensions at integration level like clocks settings and hardware parameters. Let's create a separate bindings doc for imx sata controller, so that more imx specific properties can be added later without messing up the generic ahci-platform bindings. Signed-off-by: Shawn Guo Signed-off-by: Russell King Signed-off-by: Tejun Heo --- .../devicetree/bindings/ata/ahci-platform.txt | 6 ----- Documentation/devicetree/bindings/ata/imx-sata.txt | 26 ++++++++++++++++++++++ 2 files changed, 26 insertions(+), 6 deletions(-) create mode 100644 Documentation/devicetree/bindings/ata/imx-sata.txt diff --git a/Documentation/devicetree/bindings/ata/ahci-platform.txt b/Documentation/devicetree/bindings/ata/ahci-platform.txt index c96d8dcf98fd..549ceb8cb93b 100644 --- a/Documentation/devicetree/bindings/ata/ahci-platform.txt +++ b/Documentation/devicetree/bindings/ata/ahci-platform.txt @@ -6,8 +6,6 @@ Each SATA controller should have its own node. Required properties: - compatible : compatible string, one of: - "allwinner,sun4i-a10-ahci" - - "fsl,imx53-ahci" - - "fsl,imx6q-ahci" - "hisilicon,hisi-ahci" - "ibm,476gtr-ahci" - "marvell,armada-380-ahci" @@ -22,10 +20,6 @@ Optional properties: - clocks : a list of phandle + clock specifier pairs - target-supply : regulator for SATA target power -"fsl,imx53-ahci", "fsl,imx6q-ahci" required properties: -- clocks : must contain the sata, sata_ref and ahb clocks -- clock-names : must contain "ahb" for the ahb clock - Examples: sata@ffe08000 { compatible = "snps,spear-ahci"; diff --git a/Documentation/devicetree/bindings/ata/imx-sata.txt b/Documentation/devicetree/bindings/ata/imx-sata.txt new file mode 100644 index 000000000000..aeb99dd986b0 --- /dev/null +++ b/Documentation/devicetree/bindings/ata/imx-sata.txt @@ -0,0 +1,26 @@ +* Freescale i.MX AHCI SATA Controller + +The Freescale i.MX SATA controller mostly conforms to the AHCI interface +with some special extensions at integration level. + +Required properties: +- compatible : should be one of the following: + - "fsl,imx53-ahci" for i.MX53 SATA controller + - "fsl,imx6q-ahci" for i.MX6Q SATA controller +- interrupts : interrupt mapping for SATA IRQ +- reg : registers mapping +- clocks : list of clock specifiers, must contain an entry for each + required entry in clock-names +- clock-names : should include "sata", "sata_ref" and "ahb" entries + +Examples: + +sata@02200000 { + compatible = "fsl,imx6q-ahci"; + reg = <0x02200000 0x4000>; + interrupts = <0 39 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6QDL_CLK_SATA>, + <&clks IMX6QDL_CLK_SATA_REF_100M>, + <&clks IMX6QDL_CLK_AHB>; + clock-names = "sata", "sata_ref", "ahb"; +}; -- cgit v1.2.3 From 29e69413666f085d9eb79b29ebfedb163e0e8ef2 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 24 Jun 2014 11:19:37 +0100 Subject: ata: ahci_imx: allow hardware parameters to be specified in DT Various SATA phy parameters are board specific, and therefore need to be configured. Signed-off-by: Russell King Reviewed-by: Shawn Guo Signed-off-by: Tejun Heo --- drivers/ata/ahci_imx.c | 168 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 160 insertions(+), 8 deletions(-) diff --git a/drivers/ata/ahci_imx.c b/drivers/ata/ahci_imx.c index 3a901520c62b..e032e95ddee3 100644 --- a/drivers/ata/ahci_imx.c +++ b/drivers/ata/ahci_imx.c @@ -62,6 +62,7 @@ struct imx_ahci_priv { struct regmap *gpr; bool no_device; bool first_time; + u32 phy_params; }; static int ahci_imx_hotplug; @@ -246,14 +247,7 @@ static int imx_sata_enable(struct ahci_host_priv *hpriv) 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); + imxpriv->phy_params); regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13, IMX6Q_GPR13_SATA_MPLL_CLK_EN, IMX6Q_GPR13_SATA_MPLL_CLK_EN); @@ -364,6 +358,152 @@ static const struct of_device_id imx_ahci_of_match[] = { }; MODULE_DEVICE_TABLE(of, imx_ahci_of_match); +struct reg_value { + u32 of_value; + u32 reg_value; +}; + +struct reg_property { + const char *name; + const struct reg_value *values; + size_t num_values; + u32 def_value; +}; + +static const struct reg_value gpr13_tx_level[] = { + { 937, IMX6Q_GPR13_SATA_TX_LVL_0_937_V }, + { 947, IMX6Q_GPR13_SATA_TX_LVL_0_947_V }, + { 957, IMX6Q_GPR13_SATA_TX_LVL_0_957_V }, + { 966, IMX6Q_GPR13_SATA_TX_LVL_0_966_V }, + { 976, IMX6Q_GPR13_SATA_TX_LVL_0_976_V }, + { 986, IMX6Q_GPR13_SATA_TX_LVL_0_986_V }, + { 996, IMX6Q_GPR13_SATA_TX_LVL_0_996_V }, + { 1005, IMX6Q_GPR13_SATA_TX_LVL_1_005_V }, + { 1015, IMX6Q_GPR13_SATA_TX_LVL_1_015_V }, + { 1025, IMX6Q_GPR13_SATA_TX_LVL_1_025_V }, + { 1035, IMX6Q_GPR13_SATA_TX_LVL_1_035_V }, + { 1045, IMX6Q_GPR13_SATA_TX_LVL_1_045_V }, + { 1054, IMX6Q_GPR13_SATA_TX_LVL_1_054_V }, + { 1064, IMX6Q_GPR13_SATA_TX_LVL_1_064_V }, + { 1074, IMX6Q_GPR13_SATA_TX_LVL_1_074_V }, + { 1084, IMX6Q_GPR13_SATA_TX_LVL_1_084_V }, + { 1094, IMX6Q_GPR13_SATA_TX_LVL_1_094_V }, + { 1104, IMX6Q_GPR13_SATA_TX_LVL_1_104_V }, + { 1113, IMX6Q_GPR13_SATA_TX_LVL_1_113_V }, + { 1123, IMX6Q_GPR13_SATA_TX_LVL_1_123_V }, + { 1133, IMX6Q_GPR13_SATA_TX_LVL_1_133_V }, + { 1143, IMX6Q_GPR13_SATA_TX_LVL_1_143_V }, + { 1152, IMX6Q_GPR13_SATA_TX_LVL_1_152_V }, + { 1162, IMX6Q_GPR13_SATA_TX_LVL_1_162_V }, + { 1172, IMX6Q_GPR13_SATA_TX_LVL_1_172_V }, + { 1182, IMX6Q_GPR13_SATA_TX_LVL_1_182_V }, + { 1191, IMX6Q_GPR13_SATA_TX_LVL_1_191_V }, + { 1201, IMX6Q_GPR13_SATA_TX_LVL_1_201_V }, + { 1211, IMX6Q_GPR13_SATA_TX_LVL_1_211_V }, + { 1221, IMX6Q_GPR13_SATA_TX_LVL_1_221_V }, + { 1230, IMX6Q_GPR13_SATA_TX_LVL_1_230_V }, + { 1240, IMX6Q_GPR13_SATA_TX_LVL_1_240_V } +}; + +static const struct reg_value gpr13_tx_boost[] = { + { 0, IMX6Q_GPR13_SATA_TX_BOOST_0_00_DB }, + { 370, IMX6Q_GPR13_SATA_TX_BOOST_0_37_DB }, + { 740, IMX6Q_GPR13_SATA_TX_BOOST_0_74_DB }, + { 1110, IMX6Q_GPR13_SATA_TX_BOOST_1_11_DB }, + { 1480, IMX6Q_GPR13_SATA_TX_BOOST_1_48_DB }, + { 1850, IMX6Q_GPR13_SATA_TX_BOOST_1_85_DB }, + { 2220, IMX6Q_GPR13_SATA_TX_BOOST_2_22_DB }, + { 2590, IMX6Q_GPR13_SATA_TX_BOOST_2_59_DB }, + { 2960, IMX6Q_GPR13_SATA_TX_BOOST_2_96_DB }, + { 3330, IMX6Q_GPR13_SATA_TX_BOOST_3_33_DB }, + { 3700, IMX6Q_GPR13_SATA_TX_BOOST_3_70_DB }, + { 4070, IMX6Q_GPR13_SATA_TX_BOOST_4_07_DB }, + { 4440, IMX6Q_GPR13_SATA_TX_BOOST_4_44_DB }, + { 4810, IMX6Q_GPR13_SATA_TX_BOOST_4_81_DB }, + { 5280, IMX6Q_GPR13_SATA_TX_BOOST_5_28_DB }, + { 5750, IMX6Q_GPR13_SATA_TX_BOOST_5_75_DB } +}; + +static const struct reg_value gpr13_tx_atten[] = { + { 8, IMX6Q_GPR13_SATA_TX_ATTEN_8_16 }, + { 9, IMX6Q_GPR13_SATA_TX_ATTEN_9_16 }, + { 10, IMX6Q_GPR13_SATA_TX_ATTEN_10_16 }, + { 12, IMX6Q_GPR13_SATA_TX_ATTEN_12_16 }, + { 14, IMX6Q_GPR13_SATA_TX_ATTEN_14_16 }, + { 16, IMX6Q_GPR13_SATA_TX_ATTEN_16_16 }, +}; + +static const struct reg_value gpr13_rx_eq[] = { + { 500, IMX6Q_GPR13_SATA_RX_EQ_VAL_0_5_DB }, + { 1000, IMX6Q_GPR13_SATA_RX_EQ_VAL_1_0_DB }, + { 1500, IMX6Q_GPR13_SATA_RX_EQ_VAL_1_5_DB }, + { 2000, IMX6Q_GPR13_SATA_RX_EQ_VAL_2_0_DB }, + { 2500, IMX6Q_GPR13_SATA_RX_EQ_VAL_2_5_DB }, + { 3000, IMX6Q_GPR13_SATA_RX_EQ_VAL_3_0_DB }, + { 3500, IMX6Q_GPR13_SATA_RX_EQ_VAL_3_5_DB }, + { 4000, IMX6Q_GPR13_SATA_RX_EQ_VAL_4_0_DB }, +}; + +static const struct reg_property gpr13_props[] = { + { + .name = "fsl,transmit-level-mV", + .values = gpr13_tx_level, + .num_values = ARRAY_SIZE(gpr13_tx_level), + .def_value = IMX6Q_GPR13_SATA_TX_LVL_1_025_V, + }, { + .name = "fsl,transmit-boost-mdB", + .values = gpr13_tx_boost, + .num_values = ARRAY_SIZE(gpr13_tx_boost), + .def_value = IMX6Q_GPR13_SATA_TX_BOOST_3_33_DB, + }, { + .name = "fsl,transmit-atten-16ths", + .values = gpr13_tx_atten, + .num_values = ARRAY_SIZE(gpr13_tx_atten), + .def_value = IMX6Q_GPR13_SATA_TX_ATTEN_9_16, + }, { + .name = "fsl,receive-eq-mdB", + .values = gpr13_rx_eq, + .num_values = ARRAY_SIZE(gpr13_rx_eq), + .def_value = IMX6Q_GPR13_SATA_RX_EQ_VAL_3_0_DB, + }, +}; + +static u32 imx_ahci_parse_props(struct device *dev, + const struct reg_property *prop, size_t num) +{ + struct device_node *np = dev->of_node; + u32 reg_value = 0; + int i, j; + + for (i = 0; i < num; i++, prop++) { + u32 of_val; + + if (of_property_read_u32(np, prop->name, &of_val)) { + dev_info(dev, "%s not specified, using %08x\n", + prop->name, prop->def_value); + reg_value |= prop->def_value; + continue; + } + + for (j = 0; j < prop->num_values; j++) { + if (prop->values[j].of_value == of_val) { + dev_info(dev, "%s value %u, using %08x\n", + prop->name, of_val, prop->values[j].reg_value); + reg_value |= prop->values[j].reg_value; + break; + } + } + + if (j == prop->num_values) { + dev_err(dev, "DT property %s is not a valid value\n", + prop->name); + reg_value |= prop->def_value; + } + } + + return reg_value; +} + static int imx_ahci_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -392,6 +532,8 @@ static int imx_ahci_probe(struct platform_device *pdev) } if (imxpriv->type == AHCI_IMX6Q) { + u32 reg_value; + imxpriv->gpr = syscon_regmap_lookup_by_compatible( "fsl,imx6q-iomuxc-gpr"); if (IS_ERR(imxpriv->gpr)) { @@ -399,6 +541,16 @@ static int imx_ahci_probe(struct platform_device *pdev) "failed to find fsl,imx6q-iomux-gpr regmap\n"); return PTR_ERR(imxpriv->gpr); } + + reg_value = imx_ahci_parse_props(dev, gpr13_props, + ARRAY_SIZE(gpr13_props)); + + imxpriv->phy_params = + 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 | + reg_value; } hpriv = ahci_platform_get_resources(pdev); -- cgit v1.2.3 From dcb1b29b0826c70a94f6fb8dcb1aef7fc66d118a Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 24 Jun 2014 11:19:42 +0100 Subject: dt-bindings: ata: add ahci_imx electrical properties Add the documentation for the electrical properties for the iMX SATA controller. There are many values for these, and listing them would be error prone. Refer readers to the device documentation and driver source code for these details. Signed-off-by: Russell King Reviewed-by: Shawn Guo Signed-off-by: Tejun Heo --- Documentation/devicetree/bindings/ata/imx-sata.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Documentation/devicetree/bindings/ata/imx-sata.txt b/Documentation/devicetree/bindings/ata/imx-sata.txt index aeb99dd986b0..a13f0f603776 100644 --- a/Documentation/devicetree/bindings/ata/imx-sata.txt +++ b/Documentation/devicetree/bindings/ata/imx-sata.txt @@ -13,6 +13,14 @@ Required properties: required entry in clock-names - clock-names : should include "sata", "sata_ref" and "ahb" entries +Optional properties: +- fsl,transmit-level-mV : transmit voltage level, in millivolts. +- fsl,transmit-boost-mdB : transmit boost level, in milli-decibels +- fsl,transmit-atten-16ths : transmit attenuation, in 16ths +- fsl,receive-eq-mdB : receive equalisation, in milli-decibels + Please refer to the technical documentation or the driver source code + for the list of legal values for these options. + Examples: sata@02200000 { -- cgit v1.2.3 From a6e726244c78e04d0af754c625036be8f92a9afd Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 24 Jun 2014 11:19:47 +0100 Subject: ata: ahci_imx: add disable for spread-spectrum Spread-spectrum doesn't work with Cubox-i hardware, so we have to disable this feature. Add a DT property so that platforms can indicate that this feature should not be enabled. Having it as a negative property keeps existing DT files working. Signed-off-by: Russell King Reviewed-by: Shawn Guo Signed-off-by: Tejun Heo --- drivers/ata/ahci_imx.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/ata/ahci_imx.c b/drivers/ata/ahci_imx.c index e032e95ddee3..685a4db030b1 100644 --- a/drivers/ata/ahci_imx.c +++ b/drivers/ata/ahci_imx.c @@ -368,6 +368,7 @@ struct reg_property { const struct reg_value *values; size_t num_values; u32 def_value; + u32 set_value; }; static const struct reg_value gpr13_tx_level[] = { @@ -465,6 +466,10 @@ static const struct reg_property gpr13_props[] = { .values = gpr13_rx_eq, .num_values = ARRAY_SIZE(gpr13_rx_eq), .def_value = IMX6Q_GPR13_SATA_RX_EQ_VAL_3_0_DB, + }, { + .name = "fsl,no-spread-spectrum", + .def_value = IMX6Q_GPR13_SATA_MPLL_SS_EN, + .set_value = 0, }, }; @@ -478,6 +483,14 @@ static u32 imx_ahci_parse_props(struct device *dev, for (i = 0; i < num; i++, prop++) { u32 of_val; + if (prop->num_values == 0) { + if (of_property_read_bool(np, prop->name)) + reg_value |= prop->set_value; + else + reg_value |= prop->def_value; + continue; + } + if (of_property_read_u32(np, prop->name, &of_val)) { dev_info(dev, "%s not specified, using %08x\n", prop->name, prop->def_value); @@ -549,7 +562,6 @@ static int imx_ahci_probe(struct platform_device *pdev) 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 | reg_value; } -- cgit v1.2.3 From 1fc1263bd4d227e51345cd2bedd10ab85ae9871c Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 24 Jun 2014 11:19:53 +0100 Subject: dt-bindings: ata: document ability to disable spread-spectrum clock Add documentation of the fsl,no-spread-spectrum option. Signed-off-by: Russell King Reviewed-by: Shawn Guo Signed-off-by: Tejun Heo --- Documentation/devicetree/bindings/ata/imx-sata.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/ata/imx-sata.txt b/Documentation/devicetree/bindings/ata/imx-sata.txt index a13f0f603776..fa511db18408 100644 --- a/Documentation/devicetree/bindings/ata/imx-sata.txt +++ b/Documentation/devicetree/bindings/ata/imx-sata.txt @@ -20,6 +20,8 @@ Optional properties: - fsl,receive-eq-mdB : receive equalisation, in milli-decibels Please refer to the technical documentation or the driver source code for the list of legal values for these options. +- fsl,no-spread-spectrum : disable spread-spectrum clocking on the SATA + link. Examples: -- cgit v1.2.3 From 4e6d1bbcc2c60e739ecae24314460c4395aafeac Mon Sep 17 00:00:00 2001 From: Mikko Perttunen Date: Fri, 18 Jul 2014 10:11:40 +0300 Subject: of: Add NVIDIA Tegra SATA controller binding This patch adds device tree binding documentation for the SATA controller found on NVIDIA Tegra SoCs. Signed-off-by: Mikko Perttunen Acked-by: Hans de Goede Signed-off-by: Tejun Heo --- .../devicetree/bindings/ata/tegra-sata.txt | 30 ++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 Documentation/devicetree/bindings/ata/tegra-sata.txt diff --git a/Documentation/devicetree/bindings/ata/tegra-sata.txt b/Documentation/devicetree/bindings/ata/tegra-sata.txt new file mode 100644 index 000000000000..946f2072570b --- /dev/null +++ b/Documentation/devicetree/bindings/ata/tegra-sata.txt @@ -0,0 +1,30 @@ +Tegra124 SoC SATA AHCI controller + +Required properties : +- compatible : "nvidia,tegra124-ahci". +- reg : Should contain 2 entries: + - AHCI register set (SATA BAR5) + - SATA register set +- interrupts : Defines the interrupt used by SATA +- clocks : Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. +- clock-names : Must include the following entries: + - sata + - sata-oob + - cml1 + - pll_e +- resets : Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names : Must include the following entries: + - sata + - sata-oob + - sata-cold +- phys : Must contain an entry for each entry in phy-names. + See ../phy/phy-bindings.txt for details. +- phy-names : Must include the following entries: + - sata-phy : XUSB PADCTL SATA PHY +- hvdd-supply : Defines the SATA HVDD regulator +- vddio-supply : Defines the SATA VDDIO regulator +- avdd-supply : Defines the SATA AVDD regulator +- target-5v-supply : Defines the SATA 5V power regulator +- target-12v-supply : Defines the SATA 12V power regulator -- cgit v1.2.3 From 0e38699387fd2fd433618bb67612f3aae676fbae Mon Sep 17 00:00:00 2001 From: Mikko Perttunen Date: Wed, 16 Jul 2014 11:54:21 +0300 Subject: ata: ahci_platform: Increase AHCI_MAX_CLKS to 4 The Tegra124 SATA controller requires 4 clocks. Increase this constant to be able to use them all. Signed-off-by: Mikko Perttunen Acked-by: Hans de Goede Signed-off-by: Tejun Heo --- drivers/ata/ahci.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h index 05882e4445a6..7137e1bbf04a 100644 --- a/drivers/ata/ahci.h +++ b/drivers/ata/ahci.h @@ -53,7 +53,7 @@ enum { AHCI_MAX_PORTS = 32, - AHCI_MAX_CLKS = 3, + AHCI_MAX_CLKS = 4, AHCI_MAX_SG = 168, /* hardware max is 64K */ AHCI_DMA_BOUNDARY = 0xffffffff, AHCI_MAX_CMDS = 32, -- cgit v1.2.3 From ccfde50810ae916564765a2f8ee6d7163b025594 Mon Sep 17 00:00:00 2001 From: Mikko Perttunen Date: Fri, 18 Jul 2014 10:12:30 +0300 Subject: ata: Add support for the Tegra124 SATA controller This adds support for the integrated AHCI-compliant Serial ATA controller present on the NVIDIA Tegra124 system-on-chip. Signed-off-by: Mikko Perttunen Acked-by: Hans de Goede Signed-off-by: Tejun Heo --- drivers/ata/Kconfig | 9 ++ drivers/ata/Makefile | 1 + drivers/ata/ahci_tegra.c | 377 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 387 insertions(+) create mode 100644 drivers/ata/ahci_tegra.c diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 7671dbac6015..e65d400efd44 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -141,6 +141,15 @@ config AHCI_SUNXI If unsure, say N. +config AHCI_TEGRA + tristate "NVIDIA Tegra124 AHCI SATA support" + depends on ARCH_TEGRA + help + This option enables support for the NVIDIA Tegra124 SoC's + onboard AHCI SATA. + + If unsure, say N. + config AHCI_XGENE tristate "APM X-Gene 6.0Gbps AHCI SATA host controller support" depends on PHY_XGENE diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index 5a02aeecef5b..ae41107afc1f 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_AHCI_IMX) += ahci_imx.o libahci.o libahci_platform.o obj-$(CONFIG_AHCI_MVEBU) += ahci_mvebu.o libahci.o libahci_platform.o obj-$(CONFIG_AHCI_SUNXI) += ahci_sunxi.o libahci.o libahci_platform.o obj-$(CONFIG_AHCI_ST) += ahci_st.o libahci.o libahci_platform.o +obj-$(CONFIG_AHCI_TEGRA) += ahci_tegra.o libahci.o libahci_platform.o obj-$(CONFIG_AHCI_XGENE) += ahci_xgene.o libahci.o libahci_platform.o # SFF w/ custom DMA diff --git a/drivers/ata/ahci_tegra.c b/drivers/ata/ahci_tegra.c new file mode 100644 index 000000000000..d30bb21afd67 --- /dev/null +++ b/drivers/ata/ahci_tegra.c @@ -0,0 +1,377 @@ +/* + * drivers/ata/ahci_tegra.c + * + * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved. + * + * Author: + * Mikko Perttunen + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ahci.h" + +#define SATA_CONFIGURATION_0 0x180 +#define SATA_CONFIGURATION_EN_FPCI BIT(0) + +#define SCFG_OFFSET 0x1000 + +#define T_SATA0_CFG_1 0x04 +#define T_SATA0_CFG_1_IO_SPACE BIT(0) +#define T_SATA0_CFG_1_MEMORY_SPACE BIT(1) +#define T_SATA0_CFG_1_BUS_MASTER BIT(2) +#define T_SATA0_CFG_1_SERR BIT(8) + +#define T_SATA0_CFG_9 0x24 +#define T_SATA0_CFG_9_BASE_ADDRESS_SHIFT 13 + +#define SATA_FPCI_BAR5 0x94 +#define SATA_FPCI_BAR5_START_SHIFT 4 + +#define SATA_INTR_MASK 0x188 +#define SATA_INTR_MASK_IP_INT_MASK BIT(16) + +#define T_SATA0_AHCI_HBA_CAP_BKDR 0x300 + +#define T_SATA0_BKDOOR_CC 0x4a4 + +#define T_SATA0_CFG_SATA 0x54c +#define T_SATA0_CFG_SATA_BACKDOOR_PROG_IF_EN BIT(12) + +#define T_SATA0_CFG_MISC 0x550 + +#define T_SATA0_INDEX 0x680 + +#define T_SATA0_CHX_PHY_CTRL1_GEN1 0x690 +#define T_SATA0_CHX_PHY_CTRL1_GEN1_TX_AMP_MASK 0xff +#define T_SATA0_CHX_PHY_CTRL1_GEN1_TX_AMP_SHIFT 0 +#define T_SATA0_CHX_PHY_CTRL1_GEN1_TX_PEAK_MASK (0xff << 8) +#define T_SATA0_CHX_PHY_CTRL1_GEN1_TX_PEAK_SHIFT 8 + +#define T_SATA0_CHX_PHY_CTRL1_GEN2 0x694 +#define T_SATA0_CHX_PHY_CTRL1_GEN2_TX_AMP_MASK 0xff +#define T_SATA0_CHX_PHY_CTRL1_GEN2_TX_AMP_SHIFT 0 +#define T_SATA0_CHX_PHY_CTRL1_GEN2_TX_PEAK_MASK (0xff << 12) +#define T_SATA0_CHX_PHY_CTRL1_GEN2_TX_PEAK_SHIFT 12 + +#define T_SATA0_CHX_PHY_CTRL2 0x69c +#define T_SATA0_CHX_PHY_CTRL2_CDR_CNTL_GEN1 0x23 + +#define T_SATA0_CHX_PHY_CTRL11 0x6d0 +#define T_SATA0_CHX_PHY_CTRL11_GEN2_RX_EQ (0x2800 << 16) + +#define FUSE_SATA_CALIB 0x124 +#define FUSE_SATA_CALIB_MASK 0x3 + +struct sata_pad_calibration { + u8 gen1_tx_amp; + u8 gen1_tx_peak; + u8 gen2_tx_amp; + u8 gen2_tx_peak; +}; + +static const struct sata_pad_calibration tegra124_pad_calibration[] = { + {0x18, 0x04, 0x18, 0x0a}, + {0x0e, 0x04, 0x14, 0x0a}, + {0x0e, 0x07, 0x1a, 0x0e}, + {0x14, 0x0e, 0x1a, 0x0e}, +}; + +struct tegra_ahci_priv { + struct platform_device *pdev; + void __iomem *sata_regs; + struct reset_control *sata_rst; + struct reset_control *sata_oob_rst; + struct reset_control *sata_cold_rst; + /* Needs special handling, cannot use ahci_platform */ + struct clk *sata_clk; + struct regulator_bulk_data supplies[5]; +}; + +static int tegra_ahci_power_on(struct ahci_host_priv *hpriv) +{ + struct tegra_ahci_priv *tegra = hpriv->plat_data; + int ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(tegra->supplies), + tegra->supplies); + if (ret) + return ret; + + ret = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_SATA, + tegra->sata_clk, + tegra->sata_rst); + if (ret) + goto disable_regulators; + + reset_control_assert(tegra->sata_oob_rst); + reset_control_assert(tegra->sata_cold_rst); + + ret = ahci_platform_enable_resources(hpriv); + if (ret) + goto disable_power; + + reset_control_deassert(tegra->sata_cold_rst); + reset_control_deassert(tegra->sata_oob_rst); + + return 0; + +disable_power: + clk_disable_unprepare(tegra->sata_clk); + + tegra_powergate_power_off(TEGRA_POWERGATE_SATA); + +disable_regulators: + regulator_bulk_disable(ARRAY_SIZE(tegra->supplies), tegra->supplies); + + return ret; +} + +static void tegra_ahci_power_off(struct ahci_host_priv *hpriv) +{ + struct tegra_ahci_priv *tegra = hpriv->plat_data; + + ahci_platform_disable_resources(hpriv); + + reset_control_assert(tegra->sata_rst); + reset_control_assert(tegra->sata_oob_rst); + reset_control_assert(tegra->sata_cold_rst); + + clk_disable_unprepare(tegra->sata_clk); + tegra_powergate_power_off(TEGRA_POWERGATE_SATA); + + regulator_bulk_disable(ARRAY_SIZE(tegra->supplies), tegra->supplies); +} + +static int tegra_ahci_controller_init(struct ahci_host_priv *hpriv) +{ + struct tegra_ahci_priv *tegra = hpriv->plat_data; + int ret; + unsigned int val; + struct sata_pad_calibration calib; + + ret = tegra_ahci_power_on(hpriv); + if (ret) { + dev_err(&tegra->pdev->dev, + "failed to power on AHCI controller: %d\n", ret); + return ret; + } + + val = readl(tegra->sata_regs + SATA_CONFIGURATION_0); + val |= SATA_CONFIGURATION_EN_FPCI; + writel(val, tegra->sata_regs + SATA_CONFIGURATION_0); + + /* Pad calibration */ + + /* FIXME Always use calibration 0. Change this to read the calibration + * fuse once the fuse driver has landed. */ + val = 0; + + calib = tegra124_pad_calibration[val & FUSE_SATA_CALIB_MASK]; + + writel(BIT(0), tegra->sata_regs + SCFG_OFFSET + T_SATA0_INDEX); + + val = readl(tegra->sata_regs + + SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL1_GEN1); + val &= ~T_SATA0_CHX_PHY_CTRL1_GEN1_TX_AMP_MASK; + val &= ~T_SATA0_CHX_PHY_CTRL1_GEN1_TX_PEAK_MASK; + val |= calib.gen1_tx_amp << + T_SATA0_CHX_PHY_CTRL1_GEN1_TX_AMP_SHIFT; + val |= calib.gen1_tx_peak << + T_SATA0_CHX_PHY_CTRL1_GEN1_TX_PEAK_SHIFT; + writel(val, tegra->sata_regs + SCFG_OFFSET + + T_SATA0_CHX_PHY_CTRL1_GEN1); + + val = readl(tegra->sata_regs + + SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL1_GEN2); + val &= ~T_SATA0_CHX_PHY_CTRL1_GEN2_TX_AMP_MASK; + val &= ~T_SATA0_CHX_PHY_CTRL1_GEN2_TX_PEAK_MASK; + val |= calib.gen2_tx_amp << + T_SATA0_CHX_PHY_CTRL1_GEN1_TX_AMP_SHIFT; + val |= calib.gen2_tx_peak << + T_SATA0_CHX_PHY_CTRL1_GEN1_TX_PEAK_SHIFT; + writel(val, tegra->sata_regs + SCFG_OFFSET + + T_SATA0_CHX_PHY_CTRL1_GEN2); + + writel(T_SATA0_CHX_PHY_CTRL11_GEN2_RX_EQ, + tegra->sata_regs + SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL11); + writel(T_SATA0_CHX_PHY_CTRL2_CDR_CNTL_GEN1, + tegra->sata_regs + SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL2); + + writel(0, tegra->sata_regs + SCFG_OFFSET + T_SATA0_INDEX); + + /* Program controller device ID */ + + val = readl(tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_SATA); + val |= T_SATA0_CFG_SATA_BACKDOOR_PROG_IF_EN; + writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_SATA); + + writel(0x01060100, tegra->sata_regs + SCFG_OFFSET + T_SATA0_BKDOOR_CC); + + val = readl(tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_SATA); + val &= ~T_SATA0_CFG_SATA_BACKDOOR_PROG_IF_EN; + writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_SATA); + + /* Enable IO & memory access, bus master mode */ + + val = readl(tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_1); + val |= T_SATA0_CFG_1_IO_SPACE | T_SATA0_CFG_1_MEMORY_SPACE | + T_SATA0_CFG_1_BUS_MASTER | T_SATA0_CFG_1_SERR; + writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_1); + + /* Program SATA MMIO */ + + writel(0x10000 << SATA_FPCI_BAR5_START_SHIFT, + tegra->sata_regs + SATA_FPCI_BAR5); + + writel(0x08000 << T_SATA0_CFG_9_BASE_ADDRESS_SHIFT, + tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_9); + + /* Unmask SATA interrupts */ + + val = readl(tegra->sata_regs + SATA_INTR_MASK); + val |= SATA_INTR_MASK_IP_INT_MASK; + writel(val, tegra->sata_regs + SATA_INTR_MASK); + + return 0; +} + +static void tegra_ahci_controller_deinit(struct ahci_host_priv *hpriv) +{ + tegra_ahci_power_off(hpriv); +} + +static void tegra_ahci_host_stop(struct ata_host *host) +{ + struct ahci_host_priv *hpriv = host->private_data; + + tegra_ahci_controller_deinit(hpriv); +} + +static struct ata_port_operations ahci_tegra_port_ops = { + .inherits = &ahci_ops, + .host_stop = tegra_ahci_host_stop, +}; + +static const struct ata_port_info ahci_tegra_port_info = { + .flags = AHCI_FLAG_COMMON, + .pio_mask = ATA_PIO4, + .udma_mask = ATA_UDMA6, + .port_ops = &ahci_tegra_port_ops, +}; + +static const struct of_device_id tegra_ahci_of_match[] = { + { .compatible = "nvidia,tegra124-ahci" }, + {} +}; +MODULE_DEVICE_TABLE(of, tegra_ahci_of_match); + +static int tegra_ahci_probe(struct platform_device *pdev) +{ + struct ahci_host_priv *hpriv; + struct tegra_ahci_priv *tegra; + struct resource *res; + int ret; + + hpriv = ahci_platform_get_resources(pdev); + if (IS_ERR(hpriv)) + return PTR_ERR(hpriv); + + tegra = devm_kzalloc(&pdev->dev, sizeof(*tegra), GFP_KERNEL); + if (!tegra) + return -ENOMEM; + + hpriv->plat_data = tegra; + + tegra->pdev = pdev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + tegra->sata_regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(tegra->sata_regs)) + return PTR_ERR(tegra->sata_regs); + + tegra->sata_rst = devm_reset_control_get(&pdev->dev, "sata"); + if (IS_ERR(tegra->sata_rst)) { + dev_err(&pdev->dev, "Failed to get sata reset\n"); + return PTR_ERR(tegra->sata_rst); + } + + tegra->sata_oob_rst = devm_reset_control_get(&pdev->dev, "sata-oob"); + if (IS_ERR(tegra->sata_oob_rst)) { + dev_err(&pdev->dev, "Failed to get sata-oob reset\n"); + return PTR_ERR(tegra->sata_oob_rst); + } + + tegra->sata_cold_rst = devm_reset_control_get(&pdev->dev, "sata-cold"); + if (IS_ERR(tegra->sata_cold_rst)) { + dev_err(&pdev->dev, "Failed to get sata-cold reset\n"); + return PTR_ERR(tegra->sata_cold_rst); + } + + tegra->sata_clk = devm_clk_get(&pdev->dev, "sata"); + if (IS_ERR(tegra->sata_clk)) { + dev_err(&pdev->dev, "Failed to get sata clock\n"); + return PTR_ERR(tegra->sata_clk); + } + + tegra->supplies[0].supply = "avdd"; + tegra->supplies[1].supply = "hvdd"; + tegra->supplies[2].supply = "vddio"; + tegra->supplies[3].supply = "target-5v"; + tegra->supplies[4].supply = "target-12v"; + + ret = devm_regulator_bulk_get(&pdev->dev, ARRAY_SIZE(tegra->supplies), + tegra->supplies); + if (ret) { + dev_err(&pdev->dev, "Failed to get regulators\n"); + return ret; + } + + ret = tegra_ahci_controller_init(hpriv); + if (ret) + return ret; + + ret = ahci_platform_init_host(pdev, hpriv, &ahci_tegra_port_info, + 0, 0, 0); + if (ret) + goto deinit_controller; + + return 0; + +deinit_controller: + tegra_ahci_controller_deinit(hpriv); + + return ret; +}; + +static struct platform_driver tegra_ahci_driver = { + .probe = tegra_ahci_probe, + .remove = ata_platform_remove_one, + .driver = { + .name = "tegra-ahci", + .of_match_table = tegra_ahci_of_match, + }, + /* LP0 suspend support not implemented */ +}; +module_platform_driver(tegra_ahci_driver); + +MODULE_AUTHOR("Mikko Perttunen "); +MODULE_DESCRIPTION("Tegra124 AHCI SATA driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From af64dce4cb3a848ece2431e1a18feebdcf57f444 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Mon, 21 Jul 2014 09:28:36 +0100 Subject: ahci: st: Provide DT bindings for ST's SATA implementation Cc: devicetree@vger.kernel.org Cc: Srinivas Kandagatla Acked-by: Alexandre Torgue Signed-off-by: Lee Jones Signed-off-by: Tejun Heo --- Documentation/devicetree/bindings/ata/ahci-st.txt | 31 +++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 Documentation/devicetree/bindings/ata/ahci-st.txt diff --git a/Documentation/devicetree/bindings/ata/ahci-st.txt b/Documentation/devicetree/bindings/ata/ahci-st.txt new file mode 100644 index 000000000000..0574a77a0b9f --- /dev/null +++ b/Documentation/devicetree/bindings/ata/ahci-st.txt @@ -0,0 +1,31 @@ +STMicroelectronics STi SATA controller + +This binding describes a SATA device. + +Required properties: + - compatible : Must be "st,sti-ahci" + - reg : Physical base addresses and length of register sets + - interrupts : Interrupt associated with the SATA device + - interrupt-names : Associated name must be; "hostc" + - resets : The power-down and soft-reset lines of SATA IP + - reset-names : Associated names must be; "pwr-dwn" and "sw-rst" + - clocks : The phandle for the clock + - clock-names : Associated name must be; "ahci_clk" + - phys : The phandle for the PHY device + - phy-names : Associated name must be; "ahci_phy" + +Example: + + sata0: sata@fe380000 { + compatible = "st,sti-ahci"; + reg = <0xfe380000 0x1000>; + interrupts = ; + interrupt-names = "hostc"; + phys = <&miphy365x_phy MIPHY_PORT_0 MIPHY_TYPE_SATA>; + phy-names = "ahci_phy"; + resets = <&powerdown STIH416_SATA0_POWERDOWN>, + <&softreset STIH416_SATA0_SOFTRESET>; + reset-names = "pwr-dwn", "sw-rst"; + clocks = <&clk_s_a0_ls CLK_ICN_REG>; + clock-names = "ahci_clk"; + }; -- cgit v1.2.3 From 11838230da18cea5bc26a813b5425fe839248e93 Mon Sep 17 00:00:00 2001 From: Tim Small Date: Tue, 22 Jul 2014 14:28:00 +0100 Subject: sata_sil24: Identify which card suffered IRQ status error In machines with multiple Silicon Image 3124 and/or 3132 cards, there is no way to tell which card is the culprit when the sata_sil24 interrupt handler gets a bad status. Tested-by: Tim Small Signed-off-by: Tim Small Signed-off-by: Tejun Heo --- drivers/ata/sata_sil24.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index 0534890f118a..d81b20ddb527 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -1154,8 +1154,8 @@ static irqreturn_t sil24_interrupt(int irq, void *dev_instance) status = readl(host_base + HOST_IRQ_STAT); if (status == 0xffffffff) { - printk(KERN_ERR DRV_NAME ": IRQ status == 0xffffffff, " - "PCI fault or device removal?\n"); + dev_err(host->dev, "IRQ status == 0xffffffff, " + "PCI fault or device removal?\n"); goto out; } -- cgit v1.2.3 From 09de99db23df55c7415d110f6c62281dedd77384 Mon Sep 17 00:00:00 2001 From: Kiran Padwal Date: Tue, 22 Jul 2014 19:45:43 +0530 Subject: ahci: st: Make of_device_id array const Make of_device_id array const, because all OF functions handle it as const. Signed-off-by: Kiran Padwal Acked-by: Lee Jones Signed-off-by: Tejun Heo --- drivers/ata/ahci_st.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ata/ahci_st.c b/drivers/ata/ahci_st.c index 2595598df9ce..29821b9fd13d 100644 --- a/drivers/ata/ahci_st.c +++ b/drivers/ata/ahci_st.c @@ -221,7 +221,7 @@ static int st_ahci_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(st_ahci_pm_ops, st_ahci_suspend, st_ahci_resume); -static struct of_device_id st_ahci_match[] = { +static const struct of_device_id st_ahci_match[] = { { .compatible = "st,ahci", }, {}, }; -- cgit v1.2.3 From aeae4dcac5a91de9546c42a3be09c96479bfc3ff Mon Sep 17 00:00:00 2001 From: Suman Tripathi Date: Tue, 29 Jul 2014 12:24:49 +0530 Subject: ahci_xgene: Fix the watermark threshold for the APM X-Gene SATA host controller driver. As per SATA IO specification, when Host sends HOLD, the device takes about 20DW latency to reply to HOLDA. In some case, device doesn't response to HOLDA over 20DW and causes FIFO goes into over flow condition. Due to this condition, device enumerations fails with those devices. This patch adjust the watermark FIFO by increasing the FIFO depth from 0x16(default) to 0x30 to address this issue. Signed-off-by: Loc Ho Signed-off-by: Suman Tripathi Signed-off-by: Tejun Heo --- drivers/ata/ahci_xgene.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/ata/ahci_xgene.c b/drivers/ata/ahci_xgene.c index a9fc2ae2e6e2..3db8eaae1576 100644 --- a/drivers/ata/ahci_xgene.c +++ b/drivers/ata/ahci_xgene.c @@ -67,6 +67,9 @@ #define PORTAXICFG 0x000000bc #define PORTAXICFG_OUTTRANS_SET(dst, src) \ (((dst) & ~0x00f00000) | (((u32)(src) << 0x14) & 0x00f00000)) +#define PORTRANSCFG 0x000000c8 +#define PORTRANSCFG_RXWM_SET(dst, src) \ + (((dst) & ~0x0000007f) | (((u32)(src)) & 0x0000007f)) /* SATA host controller AXI CSR */ #define INT_SLV_TMOMASK 0x00000010 @@ -176,6 +179,10 @@ static void xgene_ahci_set_phy_cfg(struct xgene_ahci_context *ctx, int channel) val = PORTAXICFG_OUTTRANS_SET(val, 0xe); /* Set outstanding */ writel(val, mmio + PORTAXICFG); readl(mmio + PORTAXICFG); /* Force a barrier */ + /* Set the watermark threshold of the receive FIFO */ + val = readl(mmio + PORTRANSCFG); + val = PORTRANSCFG_RXWM_SET(val, 0x30); + writel(val, mmio + PORTRANSCFG); } /** -- cgit v1.2.3 From 0185b1b787962db38fdf74e1cab9b7a2619490a1 Mon Sep 17 00:00:00 2001 From: Suman Tripathi Date: Tue, 29 Jul 2014 12:24:51 +0530 Subject: ahci_xgene: Use correct OOB tunning parameters for APM X-Gene SoC AHCI SATA Host controller driver. APM X-Gene SoC AHCI SATA Host controller driver requires some correction of Phy Control OOB timing for the COMINIT/COMWAKE parameters to correctly interoperate with different kinds of disks. Signed-off-by: Loc Ho Signed-off-by: Suman Tripathi Signed-off-by: Tejun Heo --- drivers/ata/ahci_xgene.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/ata/ahci_xgene.c b/drivers/ata/ahci_xgene.c index 3db8eaae1576..997b4178249a 100644 --- a/drivers/ata/ahci_xgene.c +++ b/drivers/ata/ahci_xgene.c @@ -163,11 +163,11 @@ static void xgene_ahci_set_phy_cfg(struct xgene_ahci_context *ctx, int channel) /* Disable fix rate */ writel(0x0001fffe, mmio + PORTPHY1CFG); readl(mmio + PORTPHY1CFG); /* Force a barrier */ - writel(0x5018461c, mmio + PORTPHY2CFG); + writel(0x28183219, mmio + PORTPHY2CFG); readl(mmio + PORTPHY2CFG); /* Force a barrier */ - writel(0x1c081907, mmio + PORTPHY3CFG); + writel(0x13081008, mmio + PORTPHY3CFG); readl(mmio + PORTPHY3CFG); /* Force a barrier */ - writel(0x1c080815, mmio + PORTPHY4CFG); + writel(0x00480815, mmio + PORTPHY4CFG); readl(mmio + PORTPHY4CFG); /* Force a barrier */ /* Set window negotiation */ val = readl(mmio + PORTPHY5CFG); -- cgit v1.2.3 From 19f5be0f40922717e2b6e39a9822e7e7f30fd81f Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 30 Jul 2014 08:54:07 +0800 Subject: ahci: imx: add missing clk_disable_unprepare() on error in imx_sata_enable() Add the missing clk_disable_unprepare() before return from imx_sata_enable() in the phy reset error handling case. Signed-off-by: Wei Yongjun Acked-by: Shawn Guo Signed-off-by: Tejun Heo --- drivers/ata/ahci_imx.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/ata/ahci_imx.c b/drivers/ata/ahci_imx.c index 685a4db030b1..e7be1f87d3e5 100644 --- a/drivers/ata/ahci_imx.c +++ b/drivers/ata/ahci_imx.c @@ -257,7 +257,7 @@ static int imx_sata_enable(struct ahci_host_priv *hpriv) ret = imx_sata_phy_reset(hpriv); if (ret) { dev_err(dev, "failed to reset phy: %d\n", ret); - goto disable_regulator; + goto disable_clk; } } @@ -265,6 +265,8 @@ static int imx_sata_enable(struct ahci_host_priv *hpriv) return 0; +disable_clk: + clk_disable_unprepare(imxpriv->sata_ref_clk); disable_regulator: if (hpriv->target_pwr) regulator_disable(hpriv->target_pwr); -- cgit v1.2.3 From 725c7b570fda4207e465ff8856c2c12c2645a685 Mon Sep 17 00:00:00 2001 From: Antoine Ténart Date: Wed, 30 Jul 2014 20:13:56 +0200 Subject: ata: libahci_platform: move port_map parameters into the AHCI structure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch moves force_port_map and mask_port_map into the ahci_host_priv structure. This allows to modify them into the AHCI framework. This is needed by the new dt bindings representing ports as the port_map mask is computed automatically. Parameters modifying force_port_map, mask_port_map and flags have been removed from the ahci_platform_init_host() function, and inputs in the ahci_host_priv structure are now directly filed. Signed-off-by: Antoine Ténart Signed-off-by: Tejun Heo --- drivers/ata/acard-ahci.c | 2 +- drivers/ata/ahci.c | 3 +-- drivers/ata/ahci.h | 10 ++++++---- drivers/ata/ahci_da850.c | 3 +-- drivers/ata/ahci_imx.c | 3 +-- drivers/ata/ahci_mvebu.c | 3 +-- drivers/ata/ahci_platform.c | 6 ++---- drivers/ata/ahci_st.c | 2 +- drivers/ata/ahci_sunxi.c | 8 +++----- drivers/ata/ahci_tegra.c | 3 +-- drivers/ata/ahci_xgene.c | 6 ++---- drivers/ata/libahci.c | 19 +++++++------------ drivers/ata/libahci_platform.c | 13 +++---------- drivers/ata/sata_highbank.c | 2 +- include/linux/ahci_platform.h | 5 +---- 15 files changed, 32 insertions(+), 56 deletions(-) diff --git a/drivers/ata/acard-ahci.c b/drivers/ata/acard-ahci.c index 0cd7c7a39e5b..25d0ac32e721 100644 --- a/drivers/ata/acard-ahci.c +++ b/drivers/ata/acard-ahci.c @@ -441,7 +441,7 @@ static int acard_ahci_init_one(struct pci_dev *pdev, const struct pci_device_id hpriv->mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR]; /* save initial config */ - ahci_save_initial_config(&pdev->dev, hpriv, 0, 0); + ahci_save_initial_config(&pdev->dev, hpriv); /* prepare host */ if (hpriv->cap & HOST_CAP_NCQ) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 4cd52a4541a9..a29f8012fb08 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -526,8 +526,7 @@ static void ahci_pci_save_initial_config(struct pci_dev *pdev, "Disabling your PATA port. Use the boot option 'ahci.marvell_enable=0' to avoid this.\n"); } - ahci_save_initial_config(&pdev->dev, hpriv, force_port_map, - mask_port_map); + ahci_save_initial_config(&pdev->dev, hpriv); } static int ahci_pci_reset_controller(struct ata_host *host) diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h index 2ed84e1c70ea..15396f0330ae 100644 --- a/drivers/ata/ahci.h +++ b/drivers/ata/ahci.h @@ -316,8 +316,12 @@ struct ahci_port_priv { }; struct ahci_host_priv { - void __iomem * mmio; /* bus-independent mem map */ + /* Input fields */ unsigned int flags; /* AHCI_HFLAG_* */ + u32 force_port_map; /* force port map */ + u32 mask_port_map; /* mask out particular bits */ + + void __iomem * mmio; /* bus-independent mem map */ u32 cap; /* cap to use */ u32 cap2; /* cap2 to use */ u32 port_map; /* port map to use */ @@ -361,9 +365,7 @@ unsigned int ahci_dev_classify(struct ata_port *ap); void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag, u32 opts); void ahci_save_initial_config(struct device *dev, - struct ahci_host_priv *hpriv, - unsigned int force_port_map, - unsigned int mask_port_map); + struct ahci_host_priv *hpriv); void ahci_init_controller(struct ata_host *host); int ahci_reset_controller(struct ata_host *host); diff --git a/drivers/ata/ahci_da850.c b/drivers/ata/ahci_da850.c index 2b77d53bccf8..ad1e71ec10cf 100644 --- a/drivers/ata/ahci_da850.c +++ b/drivers/ata/ahci_da850.c @@ -85,8 +85,7 @@ static int ahci_da850_probe(struct platform_device *pdev) da850_sata_init(dev, pwrdn_reg, hpriv->mmio); - rc = ahci_platform_init_host(pdev, hpriv, &ahci_da850_port_info, - 0, 0, 0); + rc = ahci_platform_init_host(pdev, hpriv, &ahci_da850_port_info); if (rc) goto disable_resources; diff --git a/drivers/ata/ahci_imx.c b/drivers/ata/ahci_imx.c index 1e5fa5f21aff..f3970b4ed889 100644 --- a/drivers/ata/ahci_imx.c +++ b/drivers/ata/ahci_imx.c @@ -620,8 +620,7 @@ static int imx_ahci_probe(struct platform_device *pdev) reg_val = clk_get_rate(imxpriv->ahb_clk) / 1000; writel(reg_val, hpriv->mmio + IMX_TIMER1MS); - ret = ahci_platform_init_host(pdev, hpriv, &ahci_imx_port_info, - 0, 0, 0); + ret = ahci_platform_init_host(pdev, hpriv, &ahci_imx_port_info); if (ret) goto disable_sata; diff --git a/drivers/ata/ahci_mvebu.c b/drivers/ata/ahci_mvebu.c index fd3dfd733b84..68672d2692ee 100644 --- a/drivers/ata/ahci_mvebu.c +++ b/drivers/ata/ahci_mvebu.c @@ -88,8 +88,7 @@ static int ahci_mvebu_probe(struct platform_device *pdev) ahci_mvebu_mbus_config(hpriv, dram); ahci_mvebu_regret_option(hpriv); - rc = ahci_platform_init_host(pdev, hpriv, &ahci_mvebu_port_info, - 0, 0, 0); + rc = ahci_platform_init_host(pdev, hpriv, &ahci_mvebu_port_info); if (rc) goto disable_resources; diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c index b10d81ddb528..fb3eca5cd66c 100644 --- a/drivers/ata/ahci_platform.c +++ b/drivers/ata/ahci_platform.c @@ -34,7 +34,6 @@ static int ahci_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct ahci_platform_data *pdata = dev_get_platdata(dev); struct ahci_host_priv *hpriv; - unsigned long hflags = 0; int rc; hpriv = ahci_platform_get_resources(pdev); @@ -58,10 +57,9 @@ static int ahci_probe(struct platform_device *pdev) } if (of_device_is_compatible(dev->of_node, "hisilicon,hisi-ahci")) - hflags |= 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, - hflags, 0, 0); + rc = ahci_platform_init_host(pdev, hpriv, &ahci_port_info); if (rc) goto pdata_exit; diff --git a/drivers/ata/ahci_st.c b/drivers/ata/ahci_st.c index 29821b9fd13d..835d6eea84fd 100644 --- a/drivers/ata/ahci_st.c +++ b/drivers/ata/ahci_st.c @@ -166,7 +166,7 @@ static int st_ahci_probe(struct platform_device *pdev) if (err) return err; - err = ahci_platform_init_host(pdev, hpriv, &st_ahci_port_info, 0, 0, 0); + err = ahci_platform_init_host(pdev, hpriv, &st_ahci_port_info); if (err) { ahci_platform_disable_resources(hpriv); return err; diff --git a/drivers/ata/ahci_sunxi.c b/drivers/ata/ahci_sunxi.c index 02002f125bd4..e44d675a30ec 100644 --- a/drivers/ata/ahci_sunxi.c +++ b/drivers/ata/ahci_sunxi.c @@ -167,7 +167,6 @@ static int ahci_sunxi_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct ahci_host_priv *hpriv; - unsigned long hflags; int rc; hpriv = ahci_platform_get_resources(pdev); @@ -184,11 +183,10 @@ static int ahci_sunxi_probe(struct platform_device *pdev) if (rc) goto disable_resources; - hflags = AHCI_HFLAG_32BIT_ONLY | AHCI_HFLAG_NO_MSI | - AHCI_HFLAG_NO_PMP | AHCI_HFLAG_YES_NCQ; + hpriv->flags = AHCI_HFLAG_32BIT_ONLY | AHCI_HFLAG_NO_MSI | + AHCI_HFLAG_NO_PMP | AHCI_HFLAG_YES_NCQ; - rc = ahci_platform_init_host(pdev, hpriv, &ahci_sunxi_port_info, - hflags, 0, 0); + rc = ahci_platform_init_host(pdev, hpriv, &ahci_sunxi_port_info); if (rc) goto disable_resources; diff --git a/drivers/ata/ahci_tegra.c b/drivers/ata/ahci_tegra.c index d30bb21afd67..fc3df47fca35 100644 --- a/drivers/ata/ahci_tegra.c +++ b/drivers/ata/ahci_tegra.c @@ -348,8 +348,7 @@ static int tegra_ahci_probe(struct platform_device *pdev) if (ret) return ret; - ret = ahci_platform_init_host(pdev, hpriv, &ahci_tegra_port_info, - 0, 0, 0); + ret = ahci_platform_init_host(pdev, hpriv, &ahci_tegra_port_info); if (ret) goto deinit_controller; diff --git a/drivers/ata/ahci_xgene.c b/drivers/ata/ahci_xgene.c index 1cfbdca638d2..bc281115490b 100644 --- a/drivers/ata/ahci_xgene.c +++ b/drivers/ata/ahci_xgene.c @@ -422,7 +422,6 @@ static int xgene_ahci_probe(struct platform_device *pdev) struct ahci_host_priv *hpriv; struct xgene_ahci_context *ctx; struct resource *res; - unsigned long hflags; int rc; hpriv = ahci_platform_get_resources(pdev); @@ -481,10 +480,9 @@ static int xgene_ahci_probe(struct platform_device *pdev) /* Configure the host controller */ xgene_ahci_hw_init(hpriv); - hflags = AHCI_HFLAG_NO_PMP | AHCI_HFLAG_YES_NCQ; + hpriv->flags = AHCI_HFLAG_NO_PMP | AHCI_HFLAG_YES_NCQ; - rc = ahci_platform_init_host(pdev, hpriv, &xgene_ahci_port_info, - hflags, 0, 0); + rc = ahci_platform_init_host(pdev, hpriv, &xgene_ahci_port_info); if (rc) goto disable_resources; diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index d72ce0470309..b784e9de426a 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -382,8 +382,6 @@ static ssize_t ahci_show_em_supported(struct device *dev, * ahci_save_initial_config - Save and fixup initial config values * @dev: target AHCI device * @hpriv: host private area to store config values - * @force_port_map: force port map to a specified value - * @mask_port_map: mask out particular bits from port map * * Some registers containing configuration info might be setup by * BIOS and might be cleared on reset. This function saves the @@ -398,10 +396,7 @@ static ssize_t ahci_show_em_supported(struct device *dev, * LOCKING: * None. */ -void ahci_save_initial_config(struct device *dev, - struct ahci_host_priv *hpriv, - unsigned int force_port_map, - unsigned int mask_port_map) +void ahci_save_initial_config(struct device *dev, struct ahci_host_priv *hpriv) { void __iomem *mmio = hpriv->mmio; u32 cap, cap2, vers, port_map; @@ -468,17 +463,17 @@ void ahci_save_initial_config(struct device *dev, cap &= ~HOST_CAP_FBS; } - if (force_port_map && port_map != force_port_map) { + if (hpriv->force_port_map && port_map != hpriv->force_port_map) { dev_info(dev, "forcing port_map 0x%x -> 0x%x\n", - port_map, force_port_map); - port_map = force_port_map; + port_map, hpriv->force_port_map); + port_map = hpriv->force_port_map; } - if (mask_port_map) { + if (hpriv->mask_port_map) { dev_warn(dev, "masking port_map 0x%x -> 0x%x\n", port_map, - port_map & mask_port_map); - port_map &= mask_port_map; + port_map & hpriv->mask_port_map); + port_map &= hpriv->mask_port_map; } /* cross check port_map and cap.n_ports */ diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c index 28840a2f470f..00582d3a46a4 100644 --- a/drivers/ata/libahci_platform.c +++ b/drivers/ata/libahci_platform.c @@ -288,9 +288,6 @@ EXPORT_SYMBOL_GPL(ahci_platform_get_resources); * @pdev: platform device pointer for the host * @hpriv: ahci-host private data for the host * @pi_template: template for the ata_port_info to use - * @host_flags: ahci host flags used in ahci_host_priv - * @force_port_map: param passed to ahci_save_initial_config - * @mask_port_map: param passed to ahci_save_initial_config * * This function does all the usual steps needed to bring up an * ahci-platform host, note any necessary resources (ie clks, phy, etc.) @@ -301,10 +298,7 @@ EXPORT_SYMBOL_GPL(ahci_platform_get_resources); */ int ahci_platform_init_host(struct platform_device *pdev, struct ahci_host_priv *hpriv, - const struct ata_port_info *pi_template, - unsigned long host_flags, - unsigned int force_port_map, - unsigned int mask_port_map) + const struct ata_port_info *pi_template) { struct device *dev = &pdev->dev; struct ata_port_info pi = *pi_template; @@ -319,10 +313,9 @@ int ahci_platform_init_host(struct platform_device *pdev, } /* prepare host */ - pi.private_data = (void *)host_flags; - hpriv->flags |= host_flags; + pi.private_data = (void *)hpriv->flags; - ahci_save_initial_config(dev, hpriv, force_port_map, mask_port_map); + ahci_save_initial_config(dev, hpriv); if (hpriv->cap & HOST_CAP_NCQ) pi.flags |= ATA_FLAG_NCQ; diff --git a/drivers/ata/sata_highbank.c b/drivers/ata/sata_highbank.c index 65965cf5af06..da3bc2709c63 100644 --- a/drivers/ata/sata_highbank.c +++ b/drivers/ata/sata_highbank.c @@ -512,7 +512,7 @@ static int ahci_highbank_probe(struct platform_device *pdev) return rc; - ahci_save_initial_config(dev, hpriv, 0, 0); + ahci_save_initial_config(dev, hpriv); /* prepare host */ if (hpriv->cap & HOST_CAP_NCQ) diff --git a/include/linux/ahci_platform.h b/include/linux/ahci_platform.h index 6dfd51a04d77..09a947e8bc87 100644 --- a/include/linux/ahci_platform.h +++ b/include/linux/ahci_platform.h @@ -43,10 +43,7 @@ struct ahci_host_priv *ahci_platform_get_resources( struct platform_device *pdev); int ahci_platform_init_host(struct platform_device *pdev, struct ahci_host_priv *hpriv, - const struct ata_port_info *pi_template, - unsigned long host_flags, - unsigned int force_port_map, - unsigned int mask_port_map); + const struct ata_port_info *pi_template); int ahci_platform_suspend_host(struct device *dev); int ahci_platform_resume_host(struct device *dev); -- cgit v1.2.3 From b1a9edbda040a43583ff14d63ebeb91abe5848b9 Mon Sep 17 00:00:00 2001 From: Antoine Ténart Date: Wed, 30 Jul 2014 20:13:57 +0200 Subject: ata: libahci: allow to use multiple PHYs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current implementation of the libahci does not allow to use multiple PHYs. This patch adds the support of multiple PHYs by the libahci while keeping the old bindings valid for device tree compatibility. This introduce a new way of defining SATA ports in the device tree, with one port per sub-node. This as the advantage of allowing a per port configuration. Because some ports may be accessible but disabled in the device tree, the port_map mask is computed automatically when using this. Signed-off-by: Antoine Ténart Acked-by: Hans de Goede Acked-by: Kishon Vijay Abraham I Signed-off-by: Tejun Heo --- drivers/ata/ahci.h | 7 +- drivers/ata/libahci_platform.c | 189 ++++++++++++++++++++++++++++++++--------- 2 files changed, 157 insertions(+), 39 deletions(-) diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h index 15396f0330ae..59ae0ee00149 100644 --- a/drivers/ata/ahci.h +++ b/drivers/ata/ahci.h @@ -334,7 +334,12 @@ struct ahci_host_priv { bool got_runtime_pm; /* Did we do pm_runtime_get? */ struct clk *clks[AHCI_MAX_CLKS]; /* Optional */ struct regulator *target_pwr; /* Optional */ - struct phy *phy; /* If platform uses phy */ + /* + * If platform uses PHYs. There is a 1:1 relation between the port number and + * the PHY position in this array. + */ + struct phy **phys; + unsigned nports; /* Number of ports */ void *plat_data; /* Other platform data */ /* * Optional ahci_start_engine override, if not set this gets set to the diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c index 00582d3a46a4..a60b8cd40198 100644 --- a/drivers/ata/libahci_platform.c +++ b/drivers/ata/libahci_platform.c @@ -38,6 +38,67 @@ static struct scsi_host_template ahci_platform_sht = { AHCI_SHT("ahci_platform"), }; +/** + * ahci_platform_enable_phys - Enable PHYs + * @hpriv: host private area to store config values + * + * This function enables all the PHYs found in hpriv->phys, if any. + * If a PHY fails to be enabled, it disables all the PHYs already + * enabled in reverse order and returns an error. + * + * RETURNS: + * 0 on success otherwise a negative error code + */ +int ahci_platform_enable_phys(struct ahci_host_priv *hpriv) +{ + int rc, i; + + for (i = 0; i < hpriv->nports; i++) { + if (!hpriv->phys[i]) + continue; + + rc = phy_init(hpriv->phys[i]); + if (rc) + goto disable_phys; + + rc = phy_power_on(hpriv->phys[i]); + if (rc) { + phy_exit(hpriv->phys[i]); + goto disable_phys; + } + } + + return 0; + +disable_phys: + while (--i >= 0) { + phy_power_off(hpriv->phys[i]); + phy_exit(hpriv->phys[i]); + } + return rc; +} +EXPORT_SYMBOL_GPL(ahci_platform_enable_phys); + +/** + * ahci_platform_disable_phys - Disable PHYs + * @hpriv: host private area to store config values + * + * This function disables all PHYs found in hpriv->phys. + */ +void ahci_platform_disable_phys(struct ahci_host_priv *hpriv) +{ + int i; + + for (i = 0; i < hpriv->nports; i++) { + if (!hpriv->phys[i]) + continue; + + phy_power_off(hpriv->phys[i]); + phy_exit(hpriv->phys[i]); + } +} +EXPORT_SYMBOL_GPL(ahci_platform_disable_phys); + /** * ahci_platform_enable_clks - Enable platform clocks * @hpriv: host private area to store config values @@ -92,7 +153,7 @@ EXPORT_SYMBOL_GPL(ahci_platform_disable_clks); * following order: * 1) Regulator * 2) Clocks (through ahci_platform_enable_clks) - * 3) Phy + * 3) Phys * * If resource enabling fails at any point the previous enabled resources * are disabled in reverse order. @@ -114,17 +175,9 @@ int ahci_platform_enable_resources(struct ahci_host_priv *hpriv) if (rc) goto disable_regulator; - if (hpriv->phy) { - rc = phy_init(hpriv->phy); - if (rc) - goto disable_clks; - - rc = phy_power_on(hpriv->phy); - if (rc) { - phy_exit(hpriv->phy); - goto disable_clks; - } - } + rc = ahci_platform_enable_phys(hpriv); + if (rc) + goto disable_clks; return 0; @@ -144,16 +197,13 @@ EXPORT_SYMBOL_GPL(ahci_platform_enable_resources); * * This function disables all ahci_platform managed resources in the * following order: - * 1) Phy + * 1) Phys * 2) Clocks (through ahci_platform_disable_clks) * 3) Regulator */ void ahci_platform_disable_resources(struct ahci_host_priv *hpriv) { - if (hpriv->phy) { - phy_power_off(hpriv->phy); - phy_exit(hpriv->phy); - } + ahci_platform_disable_phys(hpriv); ahci_platform_disable_clks(hpriv); @@ -187,7 +237,7 @@ static void ahci_platform_put_resources(struct device *dev, void *res) * 2) regulator for controlling the targets power (optional) * 3) 0 - AHCI_MAX_CLKS clocks, as specified in the devs devicetree node, * or for non devicetree enabled platforms a single clock - * 4) phy (optional) + * 4) phys (optional) * * RETURNS: * The allocated ahci_host_priv on success, otherwise an ERR_PTR value @@ -197,7 +247,9 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev) struct device *dev = &pdev->dev; struct ahci_host_priv *hpriv; struct clk *clk; - int i, rc = -ENOMEM; + struct device_node *child; + int i, enabled_ports = 0, rc = -ENOMEM; + u32 mask_port_map = 0; if (!devres_open_group(dev, NULL, GFP_KERNEL)) return ERR_PTR(-ENOMEM); @@ -246,28 +298,89 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev) hpriv->clks[i] = clk; } - hpriv->phy = devm_phy_get(dev, "sata-phy"); - if (IS_ERR(hpriv->phy)) { - rc = PTR_ERR(hpriv->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"); + hpriv->nports = of_get_child_count(dev->of_node); + + if (hpriv->nports) { + hpriv->phys = devm_kzalloc(dev, + hpriv->nports * sizeof(*hpriv->phys), + GFP_KERNEL); + if (!hpriv->phys) { + rc = -ENOMEM; + goto err_out; + } + + for_each_child_of_node(dev->of_node, child) { + u32 port; + + if (!of_device_is_available(child)) + continue; + + if (of_property_read_u32(child, "reg", &port)) { + rc = -EINVAL; goto err_out; } - case -ENODEV: - /* continue normally */ - hpriv->phy = NULL; - break; - case -EPROBE_DEFER: - goto err_out; + if (port >= hpriv->nports) { + dev_warn(dev, "invalid port number %d\n", port); + continue; + } + + mask_port_map |= BIT(port); + + hpriv->phys[port] = devm_of_phy_get(dev, child, NULL); + if (IS_ERR(hpriv->phys[port])) { + rc = PTR_ERR(hpriv->phys[port]); + dev_err(dev, + "couldn't get PHY in node %s: %d\n", + child->name, rc); + goto err_out; + } - default: - dev_err(dev, "couldn't get sata-phy\n"); + enabled_ports++; + } + if (!enabled_ports) { + dev_warn(dev, "No port enabled\n"); + rc = -ENODEV; goto err_out; } + + if (!hpriv->mask_port_map) + hpriv->mask_port_map = mask_port_map; + } else { + /* + * If no sub-node was found, keep this for device tree + * compatibility + */ + struct phy *phy = devm_phy_get(dev, "sata-phy"); + if (!IS_ERR(phy)) { + hpriv->phys = devm_kzalloc(dev, sizeof(*hpriv->phys), + GFP_KERNEL); + if (!hpriv->phys) { + rc = -ENOMEM; + goto err_out; + } + + hpriv->phys[0] = phy; + hpriv->nports = 1; + } else { + 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); @@ -290,7 +403,7 @@ EXPORT_SYMBOL_GPL(ahci_platform_get_resources); * @pi_template: template for the ata_port_info to use * * This function does all the usual steps needed to bring up an - * ahci-platform host, note any necessary resources (ie clks, phy, etc.) + * ahci-platform host, note any necessary resources (ie clks, phys, etc.) * must be initialized / enabled before calling this. * * RETURNS: @@ -405,7 +518,7 @@ static void ahci_host_stop(struct ata_host *host) * @dev: device pointer for the host * * This function does all the usual steps needed to suspend an - * ahci-platform host, note any necessary resources (ie clks, phy, etc.) + * ahci-platform host, note any necessary resources (ie clks, phys, etc.) * must be disabled after calling this. * * RETURNS: @@ -442,7 +555,7 @@ EXPORT_SYMBOL_GPL(ahci_platform_suspend_host); * @dev: device pointer for the host * * This function does all the usual steps needed to resume an ahci-platform - * host, note any necessary resources (ie clks, phy, etc.) must be + * host, note any necessary resources (ie clks, phys, etc.) must be * initialized / enabled before calling this. * * RETURNS: -- cgit v1.2.3 From 30f3c73c9b526a88920d098dcb331319e284e1b3 Mon Sep 17 00:00:00 2001 From: Antoine Ténart Date: Wed, 30 Jul 2014 20:13:58 +0200 Subject: ata: ahci_platform: add a generic AHCI compatible MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ahci_platform driver is a generic driver using the libahci_platform functions. Add a generic compatible to avoid having an endless list of compatibles with no differences for the same driver. Signed-off-by: Antoine Ténart --- drivers/ata/ahci_platform.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c index fb3eca5cd66c..f61ddb9146d6 100644 --- a/drivers/ata/ahci_platform.c +++ b/drivers/ata/ahci_platform.c @@ -76,6 +76,8 @@ static SIMPLE_DEV_PM_OPS(ahci_pm_ops, ahci_platform_suspend, ahci_platform_resume); static const struct of_device_id ahci_of_match[] = { + { .compatible = "generic-ahci", }, + /* Keep the following compatibles for device tree compatibility */ { .compatible = "snps,spear-ahci", }, { .compatible = "snps,exynos5440-ahci", }, { .compatible = "ibm,476gtr-ahci", }, -- cgit v1.2.3 From 724f24ee651c59aa3f42a8ea2d441cfac5015013 Mon Sep 17 00:00:00 2001 From: Antoine Ténart Date: Wed, 30 Jul 2014 20:13:59 +0200 Subject: Documentation: bindings: document the sub-nodes AHCI bindings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The libahci now allows to use multiple PHYs and to represent each port as a sub-node. Add these bindings to the documentation. Signed-off-by: Antoine Ténart Signed-off-by: Tejun Heo --- .../devicetree/bindings/ata/ahci-platform.txt | 41 ++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/Documentation/devicetree/bindings/ata/ahci-platform.txt b/Documentation/devicetree/bindings/ata/ahci-platform.txt index 549ceb8cb93b..4ab09f2202d4 100644 --- a/Documentation/devicetree/bindings/ata/ahci-platform.txt +++ b/Documentation/devicetree/bindings/ata/ahci-platform.txt @@ -3,6 +3,10 @@ SATA nodes are defined to describe on-chip Serial ATA controllers. Each SATA controller should have its own node. +It is possible, but not required, to represent each port as a sub-node. +It allows to enable each port independently when dealing with multiple +PHYs. + Required properties: - compatible : compatible string, one of: - "allwinner,sun4i-a10-ahci" @@ -12,13 +16,30 @@ Required properties: - "snps,dwc-ahci" - "snps,exynos5440-ahci" - "snps,spear-ahci" + - "generic-ahci" - interrupts : - reg : +Please note that when using "generic-ahci" you must also specify a SoC specific +compatible: + compatible = "manufacturer,soc-model-ahci", "generic-ahci"; + Optional properties: - dma-coherent : Present if dma operations are coherent - clocks : a list of phandle + clock specifier pairs - target-supply : regulator for SATA target power +- phys : reference to the SATA PHY node +- phy-names : must be "sata-phy" + +Required properties when using sub-nodes: +- #address-cells : number of cells to encode an address +- #size-cells : number of cells representing the size of an address + + +Sub-nodes required properties: +- reg : the port number +- phys : reference to the SATA PHY node + Examples: sata@ffe08000 { @@ -34,3 +55,23 @@ Examples: clocks = <&pll6 0>, <&ahb_gates 25>; target-supply = <®_ahci_5v>; }; + +With sub-nodes: + sata@f7e90000 { + compatible = "marvell,berlin2q-achi", "generic-ahci"; + reg = <0xe90000 0x1000>; + interrupts = ; + clocks = <&chip CLKID_SATA>; + #address-cells = <1>; + #size-cells = <0>; + + sata0: sata-port@0 { + reg = <0>; + phys = <&sata_phy 0>; + }; + + sata1: sata-port@1 { + reg = <1>; + phys = <&sata_phy 1>; + }; + }; -- cgit v1.2.3 From c4121c650e5c798c852e981c245caa6713c0d99e Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 1 Aug 2014 16:30:37 +0200 Subject: ata: libahci: Silence compiler warning on 64-bit Commit 725c7b570fda (ata: libahci_platform: move port_map parameters into the AHCI structure) moves flags into the struct ahci_host_priv's .flags field, which causes compiler warnings on 64-bit builds when that value is cast to a void * pointer. Cast to an unsigned long so that the subsequent cast to a pointer doesn't produce a warning. Signed-off-by: Thierry Reding Signed-off-by: Tejun Heo --- drivers/ata/libahci_platform.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c index a60b8cd40198..5b92c290e6c6 100644 --- a/drivers/ata/libahci_platform.c +++ b/drivers/ata/libahci_platform.c @@ -426,7 +426,7 @@ int ahci_platform_init_host(struct platform_device *pdev, } /* prepare host */ - pi.private_data = (void *)hpriv->flags; + pi.private_data = (void *)(unsigned long)hpriv->flags; ahci_save_initial_config(dev, hpriv); -- cgit v1.2.3