diff options
Diffstat (limited to 'drivers/ata')
-rw-r--r-- | drivers/ata/Kconfig | 10 | ||||
-rw-r--r-- | drivers/ata/Makefile | 1 | ||||
-rw-r--r-- | drivers/ata/ahci.c | 9 | ||||
-rw-r--r-- | drivers/ata/ahci_mtk.c | 196 | ||||
-rw-r--r-- | drivers/ata/ahci_platform.c | 1 | ||||
-rw-r--r-- | drivers/ata/libahci_platform.c | 34 | ||||
-rw-r--r-- | drivers/ata/libata-zpodd.c | 4 | ||||
-rw-r--r-- | drivers/ata/pata_amd.c | 1 | ||||
-rw-r--r-- | drivers/ata/pata_cs5536.c | 1 | ||||
-rw-r--r-- | drivers/ata/pata_octeon_cf.c | 10 | ||||
-rw-r--r-- | drivers/ata/sata_gemini.c | 67 | ||||
-rw-r--r-- | drivers/ata/sata_svw.c | 2 |
12 files changed, 293 insertions, 43 deletions
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 363fc5330c21..488c93724220 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -153,6 +153,16 @@ config AHCI_CEVA If unsure, say N. +config AHCI_MTK + tristate "MediaTek AHCI SATA support" + depends on ARCH_MEDIATEK + select MFD_SYSCON + help + This option enables support for the MediaTek SoC's + onboard AHCI SATA controller. + + If unsure, say N. + config AHCI_MVEBU tristate "Marvell EBU AHCI SATA support" depends on ARCH_MVEBU diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index a26ef5a93919..ff9cd2e37458 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_AHCI_CEVA) += ahci_ceva.o libahci.o libahci_platform.o obj-$(CONFIG_AHCI_DA850) += ahci_da850.o libahci.o libahci_platform.o obj-$(CONFIG_AHCI_DM816) += ahci_dm816.o libahci.o libahci_platform.o obj-$(CONFIG_AHCI_IMX) += ahci_imx.o libahci.o libahci_platform.o +obj-$(CONFIG_AHCI_MTK) += ahci_mtk.o libahci.o libahci_platform.o obj-$(CONFIG_AHCI_MVEBU) += ahci_mvebu.o libahci.o libahci_platform.o obj-$(CONFIG_AHCI_OCTEON) += ahci_octeon.o obj-$(CONFIG_AHCI_SUNXI) += ahci_sunxi.o libahci.o libahci_platform.o diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 5a5fd0b404eb..cb9b0e9090e3 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1469,7 +1469,14 @@ static void ahci_remap_check(struct pci_dev *pdev, int bar, return; dev_warn(&pdev->dev, "Found %d remapped NVMe devices.\n", count); - dev_warn(&pdev->dev, "Switch your BIOS from RAID to AHCI mode to use them.\n"); + dev_warn(&pdev->dev, + "Switch your BIOS from RAID to AHCI mode to use them.\n"); + + /* + * Don't rely on the msi-x capability in the remap case, + * share the legacy interrupt across ahci and remapped devices. + */ + hpriv->flags |= AHCI_HFLAG_NO_MSI; } static int ahci_get_irq_vector(struct ata_host *host, int port) diff --git a/drivers/ata/ahci_mtk.c b/drivers/ata/ahci_mtk.c new file mode 100644 index 000000000000..80854f71559a --- /dev/null +++ b/drivers/ata/ahci_mtk.c @@ -0,0 +1,196 @@ +/* + * MeidaTek AHCI SATA driver + * + * Copyright (c) 2017 MediaTek Inc. + * Author: Ryder Lee <ryder.lee@mediatek.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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 <linux/ahci_platform.h> +#include <linux/kernel.h> +#include <linux/libata.h> +#include <linux/mfd/syscon.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/pm.h> +#include <linux/regmap.h> +#include <linux/reset.h> +#include "ahci.h" + +#define DRV_NAME "ahci" + +#define SYS_CFG 0x14 +#define SYS_CFG_SATA_MSK GENMASK(31, 30) +#define SYS_CFG_SATA_EN BIT(31) + +struct mtk_ahci_plat { + struct regmap *mode; + struct reset_control *axi_rst; + struct reset_control *sw_rst; + struct reset_control *reg_rst; +}; + +static const struct ata_port_info ahci_port_info = { + .flags = AHCI_FLAG_COMMON, + .pio_mask = ATA_PIO4, + .udma_mask = ATA_UDMA6, + .port_ops = &ahci_platform_ops, +}; + +static struct scsi_host_template ahci_platform_sht = { + AHCI_SHT(DRV_NAME), +}; + +static int mtk_ahci_platform_resets(struct ahci_host_priv *hpriv, + struct device *dev) +{ + struct mtk_ahci_plat *plat = hpriv->plat_data; + int err; + + /* reset AXI bus and PHY part */ + plat->axi_rst = devm_reset_control_get_optional_exclusive(dev, "axi"); + if (PTR_ERR(plat->axi_rst) == -EPROBE_DEFER) + return PTR_ERR(plat->axi_rst); + + plat->sw_rst = devm_reset_control_get_optional_exclusive(dev, "sw"); + if (PTR_ERR(plat->sw_rst) == -EPROBE_DEFER) + return PTR_ERR(plat->sw_rst); + + plat->reg_rst = devm_reset_control_get_optional_exclusive(dev, "reg"); + if (PTR_ERR(plat->reg_rst) == -EPROBE_DEFER) + return PTR_ERR(plat->reg_rst); + + err = reset_control_assert(plat->axi_rst); + if (err) { + dev_err(dev, "failed to assert AXI bus\n"); + return err; + } + + err = reset_control_assert(plat->sw_rst); + if (err) { + dev_err(dev, "failed to assert PHY digital part\n"); + return err; + } + + err = reset_control_assert(plat->reg_rst); + if (err) { + dev_err(dev, "failed to assert PHY register part\n"); + return err; + } + + err = reset_control_deassert(plat->reg_rst); + if (err) { + dev_err(dev, "failed to deassert PHY register part\n"); + return err; + } + + err = reset_control_deassert(plat->sw_rst); + if (err) { + dev_err(dev, "failed to deassert PHY digital part\n"); + return err; + } + + err = reset_control_deassert(plat->axi_rst); + if (err) { + dev_err(dev, "failed to deassert AXI bus\n"); + return err; + } + + return 0; +} + +static int mtk_ahci_parse_property(struct ahci_host_priv *hpriv, + struct device *dev) +{ + struct mtk_ahci_plat *plat = hpriv->plat_data; + struct device_node *np = dev->of_node; + + /* enable SATA function if needed */ + if (of_find_property(np, "mediatek,phy-mode", NULL)) { + plat->mode = syscon_regmap_lookup_by_phandle( + np, "mediatek,phy-mode"); + if (IS_ERR(plat->mode)) { + dev_err(dev, "missing phy-mode phandle\n"); + return PTR_ERR(plat->mode); + } + + regmap_update_bits(plat->mode, SYS_CFG, SYS_CFG_SATA_MSK, + SYS_CFG_SATA_EN); + } + + of_property_read_u32(np, "ports-implemented", &hpriv->force_port_map); + + return 0; +} + +static int mtk_ahci_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct mtk_ahci_plat *plat; + struct ahci_host_priv *hpriv; + int err; + + plat = devm_kzalloc(dev, sizeof(*plat), GFP_KERNEL); + if (!plat) + return -ENOMEM; + + hpriv = ahci_platform_get_resources(pdev); + if (IS_ERR(hpriv)) + return PTR_ERR(hpriv); + + hpriv->plat_data = plat; + + err = mtk_ahci_parse_property(hpriv, dev); + if (err) + return err; + + err = mtk_ahci_platform_resets(hpriv, dev); + if (err) + return err; + + err = ahci_platform_enable_resources(hpriv); + if (err) + return err; + + err = ahci_platform_init_host(pdev, hpriv, &ahci_port_info, + &ahci_platform_sht); + if (err) + goto disable_resources; + + return 0; + +disable_resources: + ahci_platform_disable_resources(hpriv); + return err; +} + +static SIMPLE_DEV_PM_OPS(ahci_pm_ops, ahci_platform_suspend, + ahci_platform_resume); + +static const struct of_device_id ahci_of_match[] = { + { .compatible = "mediatek,mtk-ahci", }, + {}, +}; +MODULE_DEVICE_TABLE(of, ahci_of_match); + +static struct platform_driver mtk_ahci_driver = { + .probe = mtk_ahci_probe, + .remove = ata_platform_remove_one, + .driver = { + .name = DRV_NAME, + .of_match_table = ahci_of_match, + .pm = &ahci_pm_ops, + }, +}; +module_platform_driver(mtk_ahci_driver); + +MODULE_DESCRIPTION("MeidaTek SATA AHCI Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c index 62a04c8fb5c9..99f9a895a459 100644 --- a/drivers/ata/ahci_platform.c +++ b/drivers/ata/ahci_platform.c @@ -93,6 +93,7 @@ MODULE_DEVICE_TABLE(acpi, ahci_acpi_match); static struct platform_driver ahci_driver = { .probe = ahci_probe, .remove = ata_platform_remove_one, + .shutdown = ahci_platform_shutdown, .driver = { .name = DRV_NAME, .of_match_table = ahci_of_match, diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c index cd2eab6aa92e..a270a1173c8c 100644 --- a/drivers/ata/libahci_platform.c +++ b/drivers/ata/libahci_platform.c @@ -602,6 +602,40 @@ static void ahci_host_stop(struct ata_host *host) ahci_platform_disable_resources(hpriv); } +/** + * ahci_platform_shutdown - Disable interrupts and stop DMA for host ports + * @dev: platform device pointer for the host + * + * This function is called during system shutdown and performs the minimal + * deconfiguration required to ensure that an ahci_platform host cannot + * corrupt or otherwise interfere with a new kernel being started with kexec. + */ +void ahci_platform_shutdown(struct platform_device *pdev) +{ + struct ata_host *host = platform_get_drvdata(pdev); + struct ahci_host_priv *hpriv = host->private_data; + void __iomem *mmio = hpriv->mmio; + int i; + + for (i = 0; i < host->n_ports; i++) { + struct ata_port *ap = host->ports[i]; + + /* Disable port interrupts */ + if (ap->ops->freeze) + ap->ops->freeze(ap); + + /* Stop the port DMA engines */ + if (ap->ops->port_stop) + ap->ops->port_stop(ap); + } + + /* Disable and clear host interrupts */ + writel(readl(mmio + HOST_CTL) & ~HOST_IRQ_EN, mmio + HOST_CTL); + readl(mmio + HOST_CTL); /* flush */ + writel(GENMASK(host->n_ports, 0), mmio + HOST_IRQ_STAT); +} +EXPORT_SYMBOL_GPL(ahci_platform_shutdown); + #ifdef CONFIG_PM_SLEEP /** * ahci_platform_suspend_host - Suspend an ahci-platform host diff --git a/drivers/ata/libata-zpodd.c b/drivers/ata/libata-zpodd.c index 8a01d09ac4db..23a62e4015d0 100644 --- a/drivers/ata/libata-zpodd.c +++ b/drivers/ata/libata-zpodd.c @@ -34,7 +34,7 @@ struct zpodd { static int eject_tray(struct ata_device *dev) { struct ata_taskfile tf; - const char cdb[] = { GPCMD_START_STOP_UNIT, + static const char cdb[] = { GPCMD_START_STOP_UNIT, 0, 0, 0, 0x02, /* LoEj */ 0, 0, 0, 0, 0, 0, 0, @@ -55,7 +55,7 @@ static enum odd_mech_type zpodd_get_mech_type(struct ata_device *dev) unsigned int ret; struct rm_feature_desc *desc = (void *)(buf + 8); struct ata_taskfile tf; - char cdb[] = { GPCMD_GET_CONFIGURATION, + static const char cdb[] = { GPCMD_GET_CONFIGURATION, 2, /* only 1 feature descriptor requested */ 0, 3, /* 3, removable medium feature */ 0, 0, 0,/* reserved */ diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c index 8d4d959a821c..8706533db57b 100644 --- a/drivers/ata/pata_amd.c +++ b/drivers/ata/pata_amd.c @@ -616,6 +616,7 @@ static const struct pci_device_id amd[] = { { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP73_IDE), 8 }, { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP77_IDE), 8 }, { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CS5536_IDE), 9 }, + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CS5536_DEV_IDE), 9 }, { }, }; diff --git a/drivers/ata/pata_cs5536.c b/drivers/ata/pata_cs5536.c index 6c15a554efbe..dc1255294628 100644 --- a/drivers/ata/pata_cs5536.c +++ b/drivers/ata/pata_cs5536.c @@ -289,6 +289,7 @@ static int cs5536_init_one(struct pci_dev *dev, const struct pci_device_id *id) static const struct pci_device_id cs5536[] = { { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CS5536_IDE), }, + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CS5536_DEV_IDE), }, { }, }; diff --git a/drivers/ata/pata_octeon_cf.c b/drivers/ata/pata_octeon_cf.c index 1ba03d6df951..d3d851b014a3 100644 --- a/drivers/ata/pata_octeon_cf.c +++ b/drivers/ata/pata_octeon_cf.c @@ -840,7 +840,6 @@ static int octeon_cf_probe(struct platform_device *pdev) struct property *reg_prop; int n_addr, n_size, reg_len; struct device_node *node; - const void *prop; void __iomem *cs0; void __iomem *cs1 = NULL; struct ata_host *host; @@ -850,7 +849,7 @@ static int octeon_cf_probe(struct platform_device *pdev) void __iomem *base; struct octeon_cf_port *cf_port; int rv = -ENOMEM; - + u32 bus_width; node = pdev->dev.of_node; if (node == NULL) @@ -860,11 +859,10 @@ static int octeon_cf_probe(struct platform_device *pdev) if (!cf_port) return -ENOMEM; - cf_port->is_true_ide = (of_find_property(node, "cavium,true-ide", NULL) != NULL); + cf_port->is_true_ide = of_property_read_bool(node, "cavium,true-ide"); - prop = of_get_property(node, "cavium,bus-width", NULL); - if (prop) - is_16bit = (be32_to_cpup(prop) == 16); + if (of_property_read_u32(node, "cavium,bus-width", &bus_width) == 0) + is_16bit = (bus_width == 16); else is_16bit = false; diff --git a/drivers/ata/sata_gemini.c b/drivers/ata/sata_gemini.c index 8c704523bae7..46950e0267e0 100644 --- a/drivers/ata/sata_gemini.c +++ b/drivers/ata/sata_gemini.c @@ -15,6 +15,7 @@ #include <linux/of_device.h> #include <linux/clk.h> #include <linux/io.h> +#include <linux/pinctrl/consumer.h> #include "sata_gemini.h" #define DRV_NAME "gemini_sata_bridge" @@ -43,17 +44,6 @@ struct sata_gemini { struct clk *sata1_pclk; }; -/* Global IDE PAD Skew Control Register */ -#define GEMINI_GLOBAL_IDE_SKEW_CTRL 0x18 -#define GEMINI_IDE1_HOST_STROBE_DELAY_SHIFT 28 -#define GEMINI_IDE1_DEVICE_STROBE_DELAY_SHIFT 24 -#define GEMINI_IDE1_OUTPUT_IO_SKEW_SHIFT 20 -#define GEMINI_IDE1_INPUT_IO_SKEW_SHIFT 16 -#define GEMINI_IDE0_HOST_STROBE_DELAY_SHIFT 12 -#define GEMINI_IDE0_DEVICE_STROBE_DELAY_SHIFT 8 -#define GEMINI_IDE0_OUTPUT_IO_SKEW_SHIFT 4 -#define GEMINI_IDE0_INPUT_IO_SKEW_SHIFT 0 - /* Miscellaneous Control Register */ #define GEMINI_GLOBAL_MISC_CTRL 0x30 /* @@ -91,8 +81,6 @@ struct sata_gemini { #define GEMINI_IDE_IOMUX_MODE2 (2 << 24) #define GEMINI_IDE_IOMUX_MODE3 (3 << 24) #define GEMINI_IDE_IOMUX_SHIFT (24) -#define GEMINI_IDE_PADS_ENABLE BIT(4) -#define GEMINI_PFLASH_PADS_DISABLE BIT(1) /* * Registers directly controlling the PATA<->SATA adapters @@ -274,14 +262,14 @@ static int gemini_sata_bridge_init(struct sata_gemini *sg) return ret; } - sg->sata0_reset = devm_reset_control_get(dev, "sata0"); + sg->sata0_reset = devm_reset_control_get_exclusive(dev, "sata0"); if (IS_ERR(sg->sata0_reset)) { dev_err(dev, "no SATA0 reset controller\n"); clk_disable_unprepare(sg->sata1_pclk); clk_disable_unprepare(sg->sata0_pclk); return PTR_ERR(sg->sata0_reset); } - sg->sata1_reset = devm_reset_control_get(dev, "sata1"); + sg->sata1_reset = devm_reset_control_get_exclusive(dev, "sata1"); if (IS_ERR(sg->sata1_reset)) { dev_err(dev, "no SATA1 reset controller\n"); clk_disable_unprepare(sg->sata1_pclk); @@ -300,17 +288,39 @@ static int gemini_sata_bridge_init(struct sata_gemini *sg) return 0; } +static int gemini_setup_ide_pins(struct device *dev) +{ + struct pinctrl *p; + struct pinctrl_state *ide_state; + int ret; + + p = devm_pinctrl_get(dev); + if (IS_ERR(p)) + return PTR_ERR(p); + + ide_state = pinctrl_lookup_state(p, "ide"); + if (IS_ERR(ide_state)) + return PTR_ERR(ide_state); + + ret = pinctrl_select_state(p, ide_state); + if (ret) { + dev_err(dev, "could not select IDE state\n"); + return ret; + } + + return 0; +} + static int gemini_sata_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; struct sata_gemini *sg; - static struct regmap *map; + struct regmap *map; struct resource *res; enum gemini_muxmode muxmode; u32 gmode; u32 gmask; - u32 val; int ret; sg = devm_kzalloc(dev, sizeof(*sg), GFP_KERNEL); @@ -362,16 +372,6 @@ static int gemini_sata_probe(struct platform_device *pdev) gmask = GEMINI_IDE_IOMUX_MASK; gmode = (muxmode << GEMINI_IDE_IOMUX_SHIFT); - /* - * If we mux out the IDE, parallel flash must be disabled. - * SATA0 and SATA1 have dedicated pins and may coexist with - * parallel flash. - */ - if (sg->ide_pins) - gmode |= GEMINI_IDE_PADS_ENABLE | GEMINI_PFLASH_PADS_DISABLE; - else - gmask |= GEMINI_IDE_PADS_ENABLE; - ret = regmap_update_bits(map, GEMINI_GLOBAL_MISC_CTRL, gmask, gmode); if (ret) { dev_err(dev, "unable to set up IDE muxing\n"); @@ -379,14 +379,15 @@ static int gemini_sata_probe(struct platform_device *pdev) goto out_unprep_clk; } - /* FIXME: add more elaborate IDE skew control handling */ + /* + * Route out the IDE pins if desired. + * This is done by looking up a special pin control state called + * "ide" that will route out the IDE pins. + */ if (sg->ide_pins) { - ret = regmap_read(map, GEMINI_GLOBAL_IDE_SKEW_CTRL, &val); - if (ret) { - dev_err(dev, "cannot read IDE skew control register\n"); + ret = gemini_setup_ide_pins(dev); + if (ret) return ret; - } - dev_info(dev, "IDE skew control: %08x\n", val); } dev_info(dev, "set up the Gemini IDE/SATA nexus\n"); diff --git a/drivers/ata/sata_svw.c b/drivers/ata/sata_svw.c index 0fd6ac7e57ba..a9d692c6c182 100644 --- a/drivers/ata/sata_svw.c +++ b/drivers/ata/sata_svw.c @@ -339,7 +339,7 @@ static int k2_sata_show_info(struct seq_file *m, struct Scsi_Host *shost) if (!reg) continue; if (index == *reg) { - seq_printf(m, "devspec: %s\n", np->full_name); + seq_printf(m, "devspec: %pOF\n", np); break; } } |