brintos

brintos / linux-shallow public Read only

0
0
Text · 15.2 KiB · 2f16524 Raw
588 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Broadcom SATA3 AHCI Controller Driver4 *5 * Copyright © 2009-2015 Broadcom Corporation6 */7 8#include <linux/ahci_platform.h>9#include <linux/compiler.h>10#include <linux/device.h>11#include <linux/init.h>12#include <linux/interrupt.h>13#include <linux/io.h>14#include <linux/kernel.h>15#include <linux/libata.h>16#include <linux/module.h>17#include <linux/of.h>18#include <linux/platform_device.h>19#include <linux/reset.h>20#include <linux/string.h>21 22#include "ahci.h"23 24#define DRV_NAME					"brcm-ahci"25 26#define SATA_TOP_CTRL_VERSION				0x027#define SATA_TOP_CTRL_BUS_CTRL				0x428 #define MMIO_ENDIAN_SHIFT				0 /* CPU->AHCI */29 #define DMADESC_ENDIAN_SHIFT				2 /* AHCI->DDR */30 #define DMADATA_ENDIAN_SHIFT				4 /* AHCI->DDR */31 #define PIODATA_ENDIAN_SHIFT				632  #define ENDIAN_SWAP_NONE				033  #define ENDIAN_SWAP_FULL				234#define SATA_TOP_CTRL_TP_CTRL				0x835#define SATA_TOP_CTRL_PHY_CTRL				0xc36 #define SATA_TOP_CTRL_PHY_CTRL_1			0x037  #define SATA_TOP_CTRL_1_PHY_DEFAULT_POWER_STATE	BIT(14)38 #define SATA_TOP_CTRL_PHY_CTRL_2			0x439  #define SATA_TOP_CTRL_2_SW_RST_MDIOREG		BIT(0)40  #define SATA_TOP_CTRL_2_SW_RST_OOB			BIT(1)41  #define SATA_TOP_CTRL_2_SW_RST_RX			BIT(2)42  #define SATA_TOP_CTRL_2_SW_RST_TX			BIT(3)43  #define SATA_TOP_CTRL_2_PHY_GLOBAL_RESET		BIT(14)44 #define SATA_TOP_CTRL_PHY_OFFS				0x845 #define SATA_TOP_MAX_PHYS				246 47#define SATA_FIRST_PORT_CTRL				0x70048#define SATA_NEXT_PORT_CTRL_OFFSET			0x8049#define SATA_PORT_PCTRL6(reg_base)			(reg_base + 0x18)50 51/* On big-endian MIPS, buses are reversed to big endian, so switch them back */52#if defined(CONFIG_MIPS) && defined(__BIG_ENDIAN)53#define DATA_ENDIAN			 2 /* AHCI->DDR inbound accesses */54#define MMIO_ENDIAN			 2 /* CPU->AHCI outbound accesses */55#else56#define DATA_ENDIAN			 057#define MMIO_ENDIAN			 058#endif59 60#define BUS_CTRL_ENDIAN_CONF				\61	((DATA_ENDIAN << DMADATA_ENDIAN_SHIFT) |	\62	(DATA_ENDIAN << DMADESC_ENDIAN_SHIFT) |		\63	(MMIO_ENDIAN << MMIO_ENDIAN_SHIFT))64 65#define BUS_CTRL_ENDIAN_NSP_CONF			\66	(0x02 << DMADATA_ENDIAN_SHIFT | 0x02 << DMADESC_ENDIAN_SHIFT)67 68#define BUS_CTRL_ENDIAN_CONF_MASK			\69	(0x3 << MMIO_ENDIAN_SHIFT | 0x3 << DMADESC_ENDIAN_SHIFT |	\70	 0x3 << DMADATA_ENDIAN_SHIFT | 0x3 << PIODATA_ENDIAN_SHIFT)71 72enum brcm_ahci_version {73	BRCM_SATA_BCM7425 = 1,74	BRCM_SATA_BCM7445,75	BRCM_SATA_NSP,76	BRCM_SATA_BCM7216,77};78 79enum brcm_ahci_quirks {80	BRCM_AHCI_QUIRK_SKIP_PHY_ENABLE	= BIT(0),81};82 83struct brcm_ahci_priv {84	struct device *dev;85	void __iomem *top_ctrl;86	u32 port_mask;87	u32 quirks;88	enum brcm_ahci_version version;89	struct reset_control *rcdev_rescal;90	struct reset_control *rcdev_ahci;91};92 93static inline u32 brcm_sata_readreg(void __iomem *addr)94{95	/*96	 * MIPS endianness is configured by boot strap, which also reverses all97	 * bus endianness (i.e., big-endian CPU + big endian bus ==> native98	 * endian I/O).99	 *100	 * Other architectures (e.g., ARM) either do not support big endian, or101	 * else leave I/O in little endian mode.102	 */103	if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))104		return __raw_readl(addr);105	else106		return readl_relaxed(addr);107}108 109static inline void brcm_sata_writereg(u32 val, void __iomem *addr)110{111	/* See brcm_sata_readreg() comments */112	if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))113		__raw_writel(val, addr);114	else115		writel_relaxed(val, addr);116}117 118static void brcm_sata_alpm_init(struct ahci_host_priv *hpriv)119{120	struct brcm_ahci_priv *priv = hpriv->plat_data;121	u32 port_ctrl, host_caps;122	int i;123 124	/* Enable support for ALPM */125	host_caps = readl(hpriv->mmio + HOST_CAP);126	if (!(host_caps & HOST_CAP_ALPM))127		hpriv->flags |= AHCI_HFLAG_YES_ALPM;128 129	/*130	 * Adjust timeout to allow PLL sufficient time to lock while waking131	 * up from slumber mode.132	 */133	for (i = 0, port_ctrl = SATA_FIRST_PORT_CTRL;134	     i < SATA_TOP_MAX_PHYS;135	     i++, port_ctrl += SATA_NEXT_PORT_CTRL_OFFSET) {136		if (priv->port_mask & BIT(i))137			writel(0xff1003fc,138			       hpriv->mmio + SATA_PORT_PCTRL6(port_ctrl));139	}140}141 142static void brcm_sata_phy_enable(struct brcm_ahci_priv *priv, int port)143{144	void __iomem *phyctrl = priv->top_ctrl + SATA_TOP_CTRL_PHY_CTRL +145				(port * SATA_TOP_CTRL_PHY_OFFS);146	void __iomem *p;147	u32 reg;148 149	if (priv->quirks & BRCM_AHCI_QUIRK_SKIP_PHY_ENABLE)150		return;151 152	/* clear PHY_DEFAULT_POWER_STATE */153	p = phyctrl + SATA_TOP_CTRL_PHY_CTRL_1;154	reg = brcm_sata_readreg(p);155	reg &= ~SATA_TOP_CTRL_1_PHY_DEFAULT_POWER_STATE;156	brcm_sata_writereg(reg, p);157 158	/* reset the PHY digital logic */159	p = phyctrl + SATA_TOP_CTRL_PHY_CTRL_2;160	reg = brcm_sata_readreg(p);161	reg &= ~(SATA_TOP_CTRL_2_SW_RST_MDIOREG | SATA_TOP_CTRL_2_SW_RST_OOB |162		 SATA_TOP_CTRL_2_SW_RST_RX);163	reg |= SATA_TOP_CTRL_2_SW_RST_TX;164	brcm_sata_writereg(reg, p);165	reg = brcm_sata_readreg(p);166	reg |= SATA_TOP_CTRL_2_PHY_GLOBAL_RESET;167	brcm_sata_writereg(reg, p);168	reg = brcm_sata_readreg(p);169	reg &= ~SATA_TOP_CTRL_2_PHY_GLOBAL_RESET;170	brcm_sata_writereg(reg, p);171	(void)brcm_sata_readreg(p);172}173 174static void brcm_sata_phy_disable(struct brcm_ahci_priv *priv, int port)175{176	void __iomem *phyctrl = priv->top_ctrl + SATA_TOP_CTRL_PHY_CTRL +177				(port * SATA_TOP_CTRL_PHY_OFFS);178	void __iomem *p;179	u32 reg;180 181	if (priv->quirks & BRCM_AHCI_QUIRK_SKIP_PHY_ENABLE)182		return;183 184	/* power-off the PHY digital logic */185	p = phyctrl + SATA_TOP_CTRL_PHY_CTRL_2;186	reg = brcm_sata_readreg(p);187	reg |= (SATA_TOP_CTRL_2_SW_RST_MDIOREG | SATA_TOP_CTRL_2_SW_RST_OOB |188		SATA_TOP_CTRL_2_SW_RST_RX | SATA_TOP_CTRL_2_SW_RST_TX |189		SATA_TOP_CTRL_2_PHY_GLOBAL_RESET);190	brcm_sata_writereg(reg, p);191 192	/* set PHY_DEFAULT_POWER_STATE */193	p = phyctrl + SATA_TOP_CTRL_PHY_CTRL_1;194	reg = brcm_sata_readreg(p);195	reg |= SATA_TOP_CTRL_1_PHY_DEFAULT_POWER_STATE;196	brcm_sata_writereg(reg, p);197}198 199static void brcm_sata_phys_enable(struct brcm_ahci_priv *priv)200{201	int i;202 203	for (i = 0; i < SATA_TOP_MAX_PHYS; i++)204		if (priv->port_mask & BIT(i))205			brcm_sata_phy_enable(priv, i);206}207 208static void brcm_sata_phys_disable(struct brcm_ahci_priv *priv)209{210	int i;211 212	for (i = 0; i < SATA_TOP_MAX_PHYS; i++)213		if (priv->port_mask & BIT(i))214			brcm_sata_phy_disable(priv, i);215}216 217static u32 brcm_ahci_get_portmask(struct ahci_host_priv *hpriv,218				  struct brcm_ahci_priv *priv)219{220	u32 impl;221 222	impl = readl(hpriv->mmio + HOST_PORTS_IMPL);223 224	if (fls(impl) > SATA_TOP_MAX_PHYS)225		dev_warn(priv->dev, "warning: more ports than PHYs (%#x)\n",226			 impl);227	else if (!impl)228		dev_info(priv->dev, "no ports found\n");229 230	return impl;231}232 233static void brcm_sata_init(struct brcm_ahci_priv *priv)234{235	void __iomem *ctrl = priv->top_ctrl + SATA_TOP_CTRL_BUS_CTRL;236	u32 data;237 238	/* Configure endianness */239	data = brcm_sata_readreg(ctrl);240	data &= ~BUS_CTRL_ENDIAN_CONF_MASK;241	if (priv->version == BRCM_SATA_NSP)242		data |= BUS_CTRL_ENDIAN_NSP_CONF;243	else244		data |= BUS_CTRL_ENDIAN_CONF;245	brcm_sata_writereg(data, ctrl);246}247 248static unsigned int brcm_ahci_read_id(struct ata_device *dev,249				      struct ata_taskfile *tf, __le16 *id)250{251	struct ata_port *ap = dev->link->ap;252	struct ata_host *host = ap->host;253	struct ahci_host_priv *hpriv = host->private_data;254	struct brcm_ahci_priv *priv = hpriv->plat_data;255	void __iomem *mmio = hpriv->mmio;256	unsigned int err_mask;257	unsigned long flags;258	int i, rc;259	u32 ctl;260 261	/* Try to read the device ID and, if this fails, proceed with the262	 * recovery sequence below263	 */264	err_mask = ata_do_dev_read_id(dev, tf, id);265	if (likely(!err_mask))266		return err_mask;267 268	/* Disable host interrupts */269	spin_lock_irqsave(&host->lock, flags);270	ctl = readl(mmio + HOST_CTL);271	ctl &= ~HOST_IRQ_EN;272	writel(ctl, mmio + HOST_CTL);273	readl(mmio + HOST_CTL); /* flush */274	spin_unlock_irqrestore(&host->lock, flags);275 276	/* Perform the SATA PHY reset sequence */277	brcm_sata_phy_disable(priv, ap->port_no);278 279	/* Reset the SATA clock */280	ahci_platform_disable_clks(hpriv);281	msleep(10);282 283	ahci_platform_enable_clks(hpriv);284	msleep(10);285 286	/* Bring the PHY back on */287	brcm_sata_phy_enable(priv, ap->port_no);288 289	/* Re-initialize and calibrate the PHY */290	for (i = 0; i < hpriv->nports; i++) {291		rc = phy_init(hpriv->phys[i]);292		if (rc)293			goto disable_phys;294 295		rc = phy_calibrate(hpriv->phys[i]);296		if (rc) {297			phy_exit(hpriv->phys[i]);298			goto disable_phys;299		}300	}301 302	/* Re-enable host interrupts */303	spin_lock_irqsave(&host->lock, flags);304	ctl = readl(mmio + HOST_CTL);305	ctl |= HOST_IRQ_EN;306	writel(ctl, mmio + HOST_CTL);307	readl(mmio + HOST_CTL); /* flush */308	spin_unlock_irqrestore(&host->lock, flags);309 310	return ata_do_dev_read_id(dev, tf, id);311 312disable_phys:313	while (--i >= 0) {314		phy_power_off(hpriv->phys[i]);315		phy_exit(hpriv->phys[i]);316	}317 318	return AC_ERR_OTHER;319}320 321static void brcm_ahci_host_stop(struct ata_host *host)322{323	struct ahci_host_priv *hpriv = host->private_data;324 325	ahci_platform_disable_resources(hpriv);326}327 328static struct ata_port_operations ahci_brcm_platform_ops = {329	.inherits	= &ahci_ops,330	.host_stop	= brcm_ahci_host_stop,331	.read_id	= brcm_ahci_read_id,332};333 334static const struct ata_port_info ahci_brcm_port_info = {335	.flags		= AHCI_FLAG_COMMON | ATA_FLAG_NO_DIPM,336	.link_flags	= ATA_LFLAG_NO_DEBOUNCE_DELAY,337	.pio_mask	= ATA_PIO4,338	.udma_mask	= ATA_UDMA6,339	.port_ops	= &ahci_brcm_platform_ops,340};341 342static int brcm_ahci_suspend(struct device *dev)343{344	struct ata_host *host = dev_get_drvdata(dev);345	struct ahci_host_priv *hpriv = host->private_data;346	struct brcm_ahci_priv *priv = hpriv->plat_data;347	int ret;348 349	brcm_sata_phys_disable(priv);350 351	if (IS_ENABLED(CONFIG_PM_SLEEP))352		ret = ahci_platform_suspend(dev);353	else354		ret = 0;355 356	reset_control_assert(priv->rcdev_ahci);357	reset_control_rearm(priv->rcdev_rescal);358 359	return ret;360}361 362static int __maybe_unused brcm_ahci_resume(struct device *dev)363{364	struct ata_host *host = dev_get_drvdata(dev);365	struct ahci_host_priv *hpriv = host->private_data;366	struct brcm_ahci_priv *priv = hpriv->plat_data;367	int ret = 0;368 369	ret = reset_control_deassert(priv->rcdev_ahci);370	if (ret)371		return ret;372	ret = reset_control_reset(priv->rcdev_rescal);373	if (ret)374		return ret;375 376	/* Make sure clocks are turned on before re-configuration */377	ret = ahci_platform_enable_clks(hpriv);378	if (ret)379		return ret;380 381	ret = ahci_platform_enable_regulators(hpriv);382	if (ret)383		goto out_disable_clks;384 385	brcm_sata_init(priv);386	brcm_sata_phys_enable(priv);387	brcm_sata_alpm_init(hpriv);388 389	/* Since we had to enable clocks earlier on, we cannot use390	 * ahci_platform_resume() as-is since a second call to391	 * ahci_platform_enable_resources() would bump up the resources392	 * (regulators, clocks, PHYs) count artificially so we copy the part393	 * after ahci_platform_enable_resources().394	 */395	ret = ahci_platform_enable_phys(hpriv);396	if (ret)397		goto out_disable_phys;398 399	ret = ahci_platform_resume_host(dev);400	if (ret)401		goto out_disable_platform_phys;402 403	/* We resumed so update PM runtime state */404	pm_runtime_disable(dev);405	pm_runtime_set_active(dev);406	pm_runtime_enable(dev);407 408	return 0;409 410out_disable_platform_phys:411	ahci_platform_disable_phys(hpriv);412out_disable_phys:413	brcm_sata_phys_disable(priv);414	ahci_platform_disable_regulators(hpriv);415out_disable_clks:416	ahci_platform_disable_clks(hpriv);417	return ret;418}419 420static const struct scsi_host_template ahci_platform_sht = {421	AHCI_SHT(DRV_NAME),422};423 424static const struct of_device_id ahci_of_match[] = {425	{.compatible = "brcm,bcm7425-ahci", .data = (void *)BRCM_SATA_BCM7425},426	{.compatible = "brcm,bcm7445-ahci", .data = (void *)BRCM_SATA_BCM7445},427	{.compatible = "brcm,bcm63138-ahci", .data = (void *)BRCM_SATA_BCM7445},428	{.compatible = "brcm,bcm-nsp-ahci", .data = (void *)BRCM_SATA_NSP},429	{.compatible = "brcm,bcm7216-ahci", .data = (void *)BRCM_SATA_BCM7216},430	{ /* sentinel */ }431};432MODULE_DEVICE_TABLE(of, ahci_of_match);433 434static int brcm_ahci_probe(struct platform_device *pdev)435{436	const struct of_device_id *of_id;437	struct device *dev = &pdev->dev;438	struct brcm_ahci_priv *priv;439	struct ahci_host_priv *hpriv;440	int ret;441 442	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);443	if (!priv)444		return -ENOMEM;445 446	of_id = of_match_node(ahci_of_match, pdev->dev.of_node);447	if (!of_id)448		return -ENODEV;449 450	priv->version = (unsigned long)of_id->data;451	priv->dev = dev;452 453	priv->top_ctrl = devm_platform_ioremap_resource_byname(pdev, "top-ctrl");454	if (IS_ERR(priv->top_ctrl))455		return PTR_ERR(priv->top_ctrl);456 457	if (priv->version == BRCM_SATA_BCM7216) {458		priv->rcdev_rescal = devm_reset_control_get_optional_shared(459			&pdev->dev, "rescal");460		if (IS_ERR(priv->rcdev_rescal))461			return PTR_ERR(priv->rcdev_rescal);462	}463	priv->rcdev_ahci = devm_reset_control_get_optional(&pdev->dev, "ahci");464	if (IS_ERR(priv->rcdev_ahci))465		return PTR_ERR(priv->rcdev_ahci);466 467	hpriv = ahci_platform_get_resources(pdev, 0);468	if (IS_ERR(hpriv))469		return PTR_ERR(hpriv);470 471	hpriv->plat_data = priv;472	hpriv->flags = AHCI_HFLAG_WAKE_BEFORE_STOP | AHCI_HFLAG_NO_WRITE_TO_RO;473 474	switch (priv->version) {475	case BRCM_SATA_BCM7425:476		hpriv->flags |= AHCI_HFLAG_DELAY_ENGINE;477		fallthrough;478	case BRCM_SATA_NSP:479		hpriv->flags |= AHCI_HFLAG_NO_NCQ;480		priv->quirks |= BRCM_AHCI_QUIRK_SKIP_PHY_ENABLE;481		break;482	default:483		break;484	}485 486	ret = reset_control_reset(priv->rcdev_rescal);487	if (ret)488		return ret;489	ret = reset_control_deassert(priv->rcdev_ahci);490	if (ret)491		return ret;492 493	ret = ahci_platform_enable_clks(hpriv);494	if (ret)495		goto out_reset;496 497	ret = ahci_platform_enable_regulators(hpriv);498	if (ret)499		goto out_disable_clks;500 501	/* Must be first so as to configure endianness including that502	 * of the standard AHCI register space.503	 */504	brcm_sata_init(priv);505 506	/* Initializes priv->port_mask which is used below */507	priv->port_mask = brcm_ahci_get_portmask(hpriv, priv);508	if (!priv->port_mask) {509		ret = -ENODEV;510		goto out_disable_regulators;511	}512 513	/* Must be done before ahci_platform_enable_phys() */514	brcm_sata_phys_enable(priv);515 516	brcm_sata_alpm_init(hpriv);517 518	ret = ahci_platform_enable_phys(hpriv);519	if (ret)520		goto out_disable_phys;521 522	ret = ahci_platform_init_host(pdev, hpriv, &ahci_brcm_port_info,523				      &ahci_platform_sht);524	if (ret)525		goto out_disable_platform_phys;526 527	dev_info(dev, "Broadcom AHCI SATA3 registered\n");528 529	return 0;530 531out_disable_platform_phys:532	ahci_platform_disable_phys(hpriv);533out_disable_phys:534	brcm_sata_phys_disable(priv);535out_disable_regulators:536	ahci_platform_disable_regulators(hpriv);537out_disable_clks:538	ahci_platform_disable_clks(hpriv);539out_reset:540	reset_control_assert(priv->rcdev_ahci);541	reset_control_rearm(priv->rcdev_rescal);542	return ret;543}544 545static void brcm_ahci_remove(struct platform_device *pdev)546{547	struct ata_host *host = dev_get_drvdata(&pdev->dev);548	struct ahci_host_priv *hpriv = host->private_data;549	struct brcm_ahci_priv *priv = hpriv->plat_data;550 551	brcm_sata_phys_disable(priv);552 553	ata_platform_remove_one(pdev);554}555 556static void brcm_ahci_shutdown(struct platform_device *pdev)557{558	int ret;559 560	/* All resources releasing happens via devres, but our device, unlike a561	 * proper remove is not disappearing, therefore using562	 * brcm_ahci_suspend() here which does explicit power management is563	 * appropriate.564	 */565	ret = brcm_ahci_suspend(&pdev->dev);566	if (ret)567		dev_err(&pdev->dev, "failed to shutdown\n");568}569 570static SIMPLE_DEV_PM_OPS(ahci_brcm_pm_ops, brcm_ahci_suspend, brcm_ahci_resume);571 572static struct platform_driver brcm_ahci_driver = {573	.probe = brcm_ahci_probe,574	.remove_new = brcm_ahci_remove,575	.shutdown = brcm_ahci_shutdown,576	.driver = {577		.name = DRV_NAME,578		.of_match_table = ahci_of_match,579		.pm = &ahci_brcm_pm_ops,580	},581};582module_platform_driver(brcm_ahci_driver);583 584MODULE_DESCRIPTION("Broadcom SATA3 AHCI Controller Driver");585MODULE_AUTHOR("Brian Norris");586MODULE_LICENSE("GPL");587MODULE_ALIAS("platform:sata-brcmstb");588