brintos

brintos / linux-shallow public Read only

0
0
Text · 12.8 KiB · ed263de Raw
494 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * DWC AHCI SATA Platform driver4 *5 * Copyright (C) 2021 BAIKAL ELECTRONICS, JSC6 */7 8#include <linux/ahci_platform.h>9#include <linux/bitfield.h>10#include <linux/bits.h>11#include <linux/clk.h>12#include <linux/device.h>13#include <linux/kernel.h>14#include <linux/libata.h>15#include <linux/log2.h>16#include <linux/mfd/syscon.h>17#include <linux/module.h>18#include <linux/of.h>19#include <linux/platform_device.h>20#include <linux/pm.h>21#include <linux/regmap.h>22 23#include "ahci.h"24 25#define DRV_NAME "ahci-dwc"26 27#define AHCI_DWC_FBS_PMPN_MAX		1528 29/* DWC AHCI SATA controller specific registers */30#define AHCI_DWC_HOST_OOBR		0xbc31#define AHCI_DWC_HOST_OOB_WE		BIT(31)32#define AHCI_DWC_HOST_CWMIN_MASK	GENMASK(30, 24)33#define AHCI_DWC_HOST_CWMAX_MASK	GENMASK(23, 16)34#define AHCI_DWC_HOST_CIMIN_MASK	GENMASK(15, 8)35#define AHCI_DWC_HOST_CIMAX_MASK	GENMASK(7, 0)36 37#define AHCI_DWC_HOST_GPCR		0xd038#define AHCI_DWC_HOST_GPSR		0xd439 40#define AHCI_DWC_HOST_TIMER1MS		0xe041#define AHCI_DWC_HOST_TIMV_MASK		GENMASK(19, 0)42 43#define AHCI_DWC_HOST_GPARAM1R		0xe844#define AHCI_DWC_HOST_ALIGN_M		BIT(31)45#define AHCI_DWC_HOST_RX_BUFFER		BIT(30)46#define AHCI_DWC_HOST_PHY_DATA_MASK	GENMASK(29, 28)47#define AHCI_DWC_HOST_PHY_RST		BIT(27)48#define AHCI_DWC_HOST_PHY_CTRL_MASK	GENMASK(26, 21)49#define AHCI_DWC_HOST_PHY_STAT_MASK	GENMASK(20, 15)50#define AHCI_DWC_HOST_LATCH_M		BIT(14)51#define AHCI_DWC_HOST_PHY_TYPE_MASK	GENMASK(13, 11)52#define AHCI_DWC_HOST_RET_ERR		BIT(10)53#define AHCI_DWC_HOST_AHB_ENDIAN_MASK	GENMASK(9, 8)54#define AHCI_DWC_HOST_S_HADDR		BIT(7)55#define AHCI_DWC_HOST_M_HADDR		BIT(6)56#define AHCI_DWC_HOST_S_HDATA_MASK	GENMASK(5, 3)57#define AHCI_DWC_HOST_M_HDATA_MASK	GENMASK(2, 0)58 59#define AHCI_DWC_HOST_GPARAM2R		0xec60#define AHCI_DWC_HOST_FBS_MEM_S		BIT(19)61#define AHCI_DWC_HOST_FBS_PMPN_MASK	GENMASK(17, 16)62#define AHCI_DWC_HOST_FBS_SUP		BIT(15)63#define AHCI_DWC_HOST_DEV_CP		BIT(14)64#define AHCI_DWC_HOST_DEV_MP		BIT(13)65#define AHCI_DWC_HOST_ENCODE_M		BIT(12)66#define AHCI_DWC_HOST_RXOOB_CLK_M	BIT(11)67#define AHCI_DWC_HOST_RXOOB_M		BIT(10)68#define AHCI_DWC_HOST_TXOOB_M		BIT(9)69#define AHCI_DWC_HOST_RXOOB_M		BIT(10)70#define AHCI_DWC_HOST_RXOOB_CLK_MASK	GENMASK(8, 0)71 72#define AHCI_DWC_HOST_PPARAMR		0xf073#define AHCI_DWC_HOST_TX_MEM_M		BIT(11)74#define AHCI_DWC_HOST_TX_MEM_S		BIT(10)75#define AHCI_DWC_HOST_RX_MEM_M		BIT(9)76#define AHCI_DWC_HOST_RX_MEM_S		BIT(8)77#define AHCI_DWC_HOST_TXFIFO_DEPTH	GENMASK(7, 4)78#define AHCI_DWC_HOST_RXFIFO_DEPTH	GENMASK(3, 0)79 80#define AHCI_DWC_HOST_TESTR		0xf481#define AHCI_DWC_HOST_PSEL_MASK		GENMASK(18, 16)82#define AHCI_DWC_HOST_TEST_IF		BIT(0)83 84#define AHCI_DWC_HOST_VERSIONR		0xf885#define AHCI_DWC_HOST_IDR		0xfc86 87#define AHCI_DWC_PORT_DMACR		0x7088#define AHCI_DWC_PORT_RXABL_MASK	GENMASK(15, 12)89#define AHCI_DWC_PORT_TXABL_MASK	GENMASK(11, 8)90#define AHCI_DWC_PORT_RXTS_MASK		GENMASK(7, 4)91#define AHCI_DWC_PORT_TXTS_MASK		GENMASK(3, 0)92#define AHCI_DWC_PORT_PHYCR		0x7493#define AHCI_DWC_PORT_PHYSR		0x7894 95/* Baikal-T1 AHCI SATA specific registers */96#define AHCI_BT1_HOST_PHYCR		AHCI_DWC_HOST_GPCR97#define AHCI_BT1_HOST_MPLM_MASK		GENMASK(29, 23)98#define AHCI_BT1_HOST_LOSDT_MASK	GENMASK(22, 20)99#define AHCI_BT1_HOST_CRR		BIT(19)100#define AHCI_BT1_HOST_CRW		BIT(18)101#define AHCI_BT1_HOST_CRCD		BIT(17)102#define AHCI_BT1_HOST_CRCA		BIT(16)103#define AHCI_BT1_HOST_CRDI_MASK		GENMASK(15, 0)104 105#define AHCI_BT1_HOST_PHYSR		AHCI_DWC_HOST_GPSR106#define AHCI_BT1_HOST_CRA		BIT(16)107#define AHCI_BT1_HOST_CRDO_MASK		GENMASK(15, 0)108 109struct ahci_dwc_plat_data {110	unsigned int pflags;111	unsigned int hflags;112	int (*init)(struct ahci_host_priv *hpriv);113	int (*reinit)(struct ahci_host_priv *hpriv);114	void (*clear)(struct ahci_host_priv *hpriv);115};116 117struct ahci_dwc_host_priv {118	const struct ahci_dwc_plat_data *pdata;119	struct platform_device *pdev;120 121	u32 timv;122	u32 dmacr[AHCI_MAX_PORTS];123};124 125static int ahci_bt1_init(struct ahci_host_priv *hpriv)126{127	struct ahci_dwc_host_priv *dpriv = hpriv->plat_data;128	int ret;129 130	/* APB, application and reference clocks are required */131	if (!ahci_platform_find_clk(hpriv, "pclk") ||132	    !ahci_platform_find_clk(hpriv, "aclk") ||133	    !ahci_platform_find_clk(hpriv, "ref")) {134		dev_err(&dpriv->pdev->dev, "No system clocks specified\n");135		return -EINVAL;136	}137 138	/*139	 * Fully reset the SATA AXI and ref clocks domain to ensure the state140	 * machine is working from scratch especially if the reference clocks141	 * source has been changed.142	 */143	ret = ahci_platform_assert_rsts(hpriv);144	if (ret) {145		dev_err(&dpriv->pdev->dev, "Couldn't assert the resets\n");146		return ret;147	}148 149	ret = ahci_platform_deassert_rsts(hpriv);150	if (ret) {151		dev_err(&dpriv->pdev->dev, "Couldn't de-assert the resets\n");152		return ret;153	}154 155	return 0;156}157 158static struct ahci_host_priv *ahci_dwc_get_resources(struct platform_device *pdev)159{160	struct ahci_dwc_host_priv *dpriv;161	struct ahci_host_priv *hpriv;162 163	dpriv = devm_kzalloc(&pdev->dev, sizeof(*dpriv), GFP_KERNEL);164	if (!dpriv)165		return ERR_PTR(-ENOMEM);166 167	dpriv->pdev = pdev;168	dpriv->pdata = device_get_match_data(&pdev->dev);169	if (!dpriv->pdata)170		return ERR_PTR(-EINVAL);171 172	hpriv = ahci_platform_get_resources(pdev, dpriv->pdata->pflags);173	if (IS_ERR(hpriv))174		return hpriv;175 176	hpriv->flags |= dpriv->pdata->hflags;177	hpriv->plat_data = (void *)dpriv;178 179	return hpriv;180}181 182static void ahci_dwc_check_cap(struct ahci_host_priv *hpriv)183{184	unsigned long port_map = hpriv->saved_port_map | hpriv->mask_port_map;185	struct ahci_dwc_host_priv *dpriv = hpriv->plat_data;186	bool dev_mp, dev_cp, fbs_sup;187	unsigned int fbs_pmp;188	u32 param;189	int i;190 191	param = readl(hpriv->mmio + AHCI_DWC_HOST_GPARAM2R);192	dev_mp = !!(param & AHCI_DWC_HOST_DEV_MP);193	dev_cp = !!(param & AHCI_DWC_HOST_DEV_CP);194	fbs_sup = !!(param & AHCI_DWC_HOST_FBS_SUP);195	fbs_pmp = 5 * FIELD_GET(AHCI_DWC_HOST_FBS_PMPN_MASK, param);196 197	if (!dev_mp && hpriv->saved_cap & HOST_CAP_MPS) {198		dev_warn(&dpriv->pdev->dev, "MPS is unsupported\n");199		hpriv->saved_cap &= ~HOST_CAP_MPS;200	}201 202 203	if (fbs_sup && fbs_pmp < AHCI_DWC_FBS_PMPN_MAX) {204		dev_warn(&dpriv->pdev->dev, "PMPn is limited up to %u ports\n",205			 fbs_pmp);206	}207 208	for_each_set_bit(i, &port_map, AHCI_MAX_PORTS) {209		if (!dev_mp && hpriv->saved_port_cap[i] & PORT_CMD_MPSP) {210			dev_warn(&dpriv->pdev->dev, "MPS incapable port %d\n", i);211			hpriv->saved_port_cap[i] &= ~PORT_CMD_MPSP;212		}213 214		if (!dev_cp && hpriv->saved_port_cap[i] & PORT_CMD_CPD) {215			dev_warn(&dpriv->pdev->dev, "CPD incapable port %d\n", i);216			hpriv->saved_port_cap[i] &= ~PORT_CMD_CPD;217		}218 219		if (!fbs_sup && hpriv->saved_port_cap[i] & PORT_CMD_FBSCP) {220			dev_warn(&dpriv->pdev->dev, "FBS incapable port %d\n", i);221			hpriv->saved_port_cap[i] &= ~PORT_CMD_FBSCP;222		}223	}224}225 226static void ahci_dwc_init_timer(struct ahci_host_priv *hpriv)227{228	struct ahci_dwc_host_priv *dpriv = hpriv->plat_data;229	unsigned long rate;230	struct clk *aclk;231	u32 cap, cap2;232 233	/* 1ms tick is generated only for the CCC or DevSleep features */234	cap = readl(hpriv->mmio + HOST_CAP);235	cap2 = readl(hpriv->mmio + HOST_CAP2);236	if (!(cap & HOST_CAP_CCC) && !(cap2 & HOST_CAP2_SDS))237		return;238 239	/*240	 * Tick is generated based on the AXI/AHB application clocks signal241	 * so we need to be sure in the clock we are going to use.242	 */243	aclk = ahci_platform_find_clk(hpriv, "aclk");244	if (!aclk)245		return;246 247	/* 1ms timer interval is set as TIMV = AMBA_FREQ[MHZ] * 1000 */248	dpriv->timv = readl(hpriv->mmio + AHCI_DWC_HOST_TIMER1MS);249	dpriv->timv = FIELD_GET(AHCI_DWC_HOST_TIMV_MASK, dpriv->timv);250	rate = clk_get_rate(aclk) / 1000UL;251	if (rate == dpriv->timv)252		return;253 254	dev_info(&dpriv->pdev->dev, "Update CCC/DevSlp timer for Fapp %lu MHz\n",255		 rate / 1000UL);256	dpriv->timv = FIELD_PREP(AHCI_DWC_HOST_TIMV_MASK, rate);257	writel(dpriv->timv, hpriv->mmio + AHCI_DWC_HOST_TIMER1MS);258}259 260static int ahci_dwc_init_dmacr(struct ahci_host_priv *hpriv)261{262	struct ahci_dwc_host_priv *dpriv = hpriv->plat_data;263	struct device_node *child;264	void __iomem *port_mmio;265	u32 port, dmacr, ts;266 267	/*268	 * Update the DMA Tx/Rx transaction sizes in accordance with the269	 * platform setup. Note values exceeding maximal or minimal limits will270	 * be automatically clamped. Also note the register isn't affected by271	 * the HBA global reset so we can freely initialize it once until the272	 * next system reset.273	 */274	for_each_child_of_node(dpriv->pdev->dev.of_node, child) {275		if (!of_device_is_available(child))276			continue;277 278		if (of_property_read_u32(child, "reg", &port)) {279			of_node_put(child);280			return -EINVAL;281		}282 283		port_mmio = __ahci_port_base(hpriv, port);284		dmacr = readl(port_mmio + AHCI_DWC_PORT_DMACR);285 286		if (!of_property_read_u32(child, "snps,tx-ts-max", &ts)) {287			ts = ilog2(ts);288			dmacr &= ~AHCI_DWC_PORT_TXTS_MASK;289			dmacr |= FIELD_PREP(AHCI_DWC_PORT_TXTS_MASK, ts);290		}291 292		if (!of_property_read_u32(child, "snps,rx-ts-max", &ts)) {293			ts = ilog2(ts);294			dmacr &= ~AHCI_DWC_PORT_RXTS_MASK;295			dmacr |= FIELD_PREP(AHCI_DWC_PORT_RXTS_MASK, ts);296		}297 298		writel(dmacr, port_mmio + AHCI_DWC_PORT_DMACR);299		dpriv->dmacr[port] = dmacr;300	}301 302	return 0;303}304 305static int ahci_dwc_init_host(struct ahci_host_priv *hpriv)306{307	struct ahci_dwc_host_priv *dpriv = hpriv->plat_data;308	int rc;309 310	rc = ahci_platform_enable_resources(hpriv);311	if (rc)312		return rc;313 314	if (dpriv->pdata->init) {315		rc = dpriv->pdata->init(hpriv);316		if (rc)317			goto err_disable_resources;318	}319 320	ahci_dwc_check_cap(hpriv);321 322	ahci_dwc_init_timer(hpriv);323 324	rc = ahci_dwc_init_dmacr(hpriv);325	if (rc)326		goto err_clear_platform;327 328	return 0;329 330err_clear_platform:331	if (dpriv->pdata->clear)332		dpriv->pdata->clear(hpriv);333 334err_disable_resources:335	ahci_platform_disable_resources(hpriv);336 337	return rc;338}339 340static int ahci_dwc_reinit_host(struct ahci_host_priv *hpriv)341{342	struct ahci_dwc_host_priv *dpriv = hpriv->plat_data;343	unsigned long port_map = hpriv->port_map;344	void __iomem *port_mmio;345	int i, rc;346 347	rc = ahci_platform_enable_resources(hpriv);348	if (rc)349		return rc;350 351	if (dpriv->pdata->reinit) {352		rc = dpriv->pdata->reinit(hpriv);353		if (rc)354			goto err_disable_resources;355	}356 357	writel(dpriv->timv, hpriv->mmio + AHCI_DWC_HOST_TIMER1MS);358 359	for_each_set_bit(i, &port_map, AHCI_MAX_PORTS) {360		port_mmio = __ahci_port_base(hpriv, i);361		writel(dpriv->dmacr[i], port_mmio + AHCI_DWC_PORT_DMACR);362	}363 364	return 0;365 366err_disable_resources:367	ahci_platform_disable_resources(hpriv);368 369	return rc;370}371 372static void ahci_dwc_clear_host(struct ahci_host_priv *hpriv)373{374	struct ahci_dwc_host_priv *dpriv = hpriv->plat_data;375 376	if (dpriv->pdata->clear)377		dpriv->pdata->clear(hpriv);378 379	ahci_platform_disable_resources(hpriv);380}381 382static void ahci_dwc_stop_host(struct ata_host *host)383{384	struct ahci_host_priv *hpriv = host->private_data;385 386	ahci_dwc_clear_host(hpriv);387}388 389static struct ata_port_operations ahci_dwc_port_ops = {390	.inherits	= &ahci_platform_ops,391	.host_stop	= ahci_dwc_stop_host,392};393 394static const struct ata_port_info ahci_dwc_port_info = {395	.flags		= AHCI_FLAG_COMMON,396	.pio_mask	= ATA_PIO4,397	.udma_mask	= ATA_UDMA6,398	.port_ops	= &ahci_dwc_port_ops,399};400 401static const struct scsi_host_template ahci_dwc_scsi_info = {402	AHCI_SHT(DRV_NAME),403};404 405static int ahci_dwc_probe(struct platform_device *pdev)406{407	struct ahci_host_priv *hpriv;408	int rc;409 410	hpriv = ahci_dwc_get_resources(pdev);411	if (IS_ERR(hpriv))412		return PTR_ERR(hpriv);413 414	rc = ahci_dwc_init_host(hpriv);415	if (rc)416		return rc;417 418	rc = ahci_platform_init_host(pdev, hpriv, &ahci_dwc_port_info,419				     &ahci_dwc_scsi_info);420	if (rc)421		goto err_clear_host;422 423	return 0;424 425err_clear_host:426	ahci_dwc_clear_host(hpriv);427 428	return rc;429}430 431static int ahci_dwc_suspend(struct device *dev)432{433	struct ata_host *host = dev_get_drvdata(dev);434	struct ahci_host_priv *hpriv = host->private_data;435	int rc;436 437	rc = ahci_platform_suspend_host(dev);438	if (rc)439		return rc;440 441	ahci_dwc_clear_host(hpriv);442 443	return 0;444}445 446static int ahci_dwc_resume(struct device *dev)447{448	struct ata_host *host = dev_get_drvdata(dev);449	struct ahci_host_priv *hpriv = host->private_data;450	int rc;451 452	rc = ahci_dwc_reinit_host(hpriv);453	if (rc)454		return rc;455 456	return ahci_platform_resume_host(dev);457}458 459static DEFINE_SIMPLE_DEV_PM_OPS(ahci_dwc_pm_ops, ahci_dwc_suspend,460				ahci_dwc_resume);461 462static struct ahci_dwc_plat_data ahci_dwc_plat = {463	.pflags = AHCI_PLATFORM_GET_RESETS,464};465 466static struct ahci_dwc_plat_data ahci_bt1_plat = {467	.pflags = AHCI_PLATFORM_GET_RESETS | AHCI_PLATFORM_RST_TRIGGER,468	.init = ahci_bt1_init,469};470 471static const struct of_device_id ahci_dwc_of_match[] = {472	{ .compatible = "snps,dwc-ahci", &ahci_dwc_plat },473	{ .compatible = "snps,spear-ahci", &ahci_dwc_plat },474	{ .compatible = "baikal,bt1-ahci", &ahci_bt1_plat },475	{},476};477MODULE_DEVICE_TABLE(of, ahci_dwc_of_match);478 479static struct platform_driver ahci_dwc_driver = {480	.probe = ahci_dwc_probe,481	.remove_new = ata_platform_remove_one,482	.shutdown = ahci_platform_shutdown,483	.driver = {484		.name = DRV_NAME,485		.of_match_table = ahci_dwc_of_match,486		.pm = &ahci_dwc_pm_ops,487	},488};489module_platform_driver(ahci_dwc_driver);490 491MODULE_DESCRIPTION("DWC AHCI SATA platform driver");492MODULE_AUTHOR("Serge Semin <Sergey.Semin@baikalelectronics.ru>");493MODULE_LICENSE("GPL");494