xref: /openbmc/linux/drivers/ata/ahci_st.c (revision a7eb54d4)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
276884cb2SLee Jones /*
376884cb2SLee Jones  * Copyright (C) 2012 STMicroelectronics Limited
476884cb2SLee Jones  *
576884cb2SLee Jones  * Authors: Francesco Virlinzi <francesco.virlinzi@st.com>
676884cb2SLee Jones  *	    Alexandre Torgue <alexandre.torgue@st.com>
776884cb2SLee Jones  */
876884cb2SLee Jones 
976884cb2SLee Jones #include <linux/init.h>
1076884cb2SLee Jones #include <linux/module.h>
1176884cb2SLee Jones #include <linux/export.h>
1276884cb2SLee Jones #include <linux/platform_device.h>
1376884cb2SLee Jones #include <linux/clk.h>
1476884cb2SLee Jones #include <linux/of.h>
1576884cb2SLee Jones #include <linux/ahci_platform.h>
1676884cb2SLee Jones #include <linux/libata.h>
1776884cb2SLee Jones #include <linux/reset.h>
1876884cb2SLee Jones #include <linux/io.h>
1976884cb2SLee Jones #include <linux/dma-mapping.h>
2076884cb2SLee Jones 
2176884cb2SLee Jones #include "ahci.h"
2276884cb2SLee Jones 
23018d5ef2SAkinobu Mita #define DRV_NAME  "st_ahci"
24018d5ef2SAkinobu Mita 
2576884cb2SLee Jones #define ST_AHCI_OOBR			0xbc
2676884cb2SLee Jones #define ST_AHCI_OOBR_WE			BIT(31)
2776884cb2SLee Jones #define ST_AHCI_OOBR_CWMIN_SHIFT	24
2876884cb2SLee Jones #define ST_AHCI_OOBR_CWMAX_SHIFT	16
2976884cb2SLee Jones #define ST_AHCI_OOBR_CIMIN_SHIFT	8
3076884cb2SLee Jones #define ST_AHCI_OOBR_CIMAX_SHIFT	0
3176884cb2SLee Jones 
3276884cb2SLee Jones struct st_ahci_drv_data {
3376884cb2SLee Jones 	struct platform_device *ahci;
3476884cb2SLee Jones 	struct reset_control *pwr;
3576884cb2SLee Jones 	struct reset_control *sw_rst;
3676884cb2SLee Jones 	struct reset_control *pwr_rst;
3776884cb2SLee Jones };
3876884cb2SLee Jones 
st_ahci_configure_oob(void __iomem * mmio)3976884cb2SLee Jones static void st_ahci_configure_oob(void __iomem *mmio)
4076884cb2SLee Jones {
4176884cb2SLee Jones 	unsigned long old_val, new_val;
4276884cb2SLee Jones 
4376884cb2SLee Jones 	new_val = (0x02 << ST_AHCI_OOBR_CWMIN_SHIFT) |
4476884cb2SLee Jones 		  (0x04 << ST_AHCI_OOBR_CWMAX_SHIFT) |
4576884cb2SLee Jones 		  (0x08 << ST_AHCI_OOBR_CIMIN_SHIFT) |
4676884cb2SLee Jones 		  (0x0C << ST_AHCI_OOBR_CIMAX_SHIFT);
4776884cb2SLee Jones 
4876884cb2SLee Jones 	old_val = readl(mmio + ST_AHCI_OOBR);
4976884cb2SLee Jones 	writel(old_val | ST_AHCI_OOBR_WE, mmio + ST_AHCI_OOBR);
5076884cb2SLee Jones 	writel(new_val | ST_AHCI_OOBR_WE, mmio + ST_AHCI_OOBR);
5176884cb2SLee Jones 	writel(new_val, mmio + ST_AHCI_OOBR);
5276884cb2SLee Jones }
5376884cb2SLee Jones 
st_ahci_deassert_resets(struct ahci_host_priv * hpriv,struct device * dev)54e0e2674bSPeter Griffin static int st_ahci_deassert_resets(struct ahci_host_priv *hpriv,
55e0e2674bSPeter Griffin 				struct device *dev)
5676884cb2SLee Jones {
57e0e2674bSPeter Griffin 	struct st_ahci_drv_data *drv_data = hpriv->plat_data;
5876884cb2SLee Jones 	int err;
5976884cb2SLee Jones 
6076884cb2SLee Jones 	if (drv_data->pwr) {
6176884cb2SLee Jones 		err = reset_control_deassert(drv_data->pwr);
6276884cb2SLee Jones 		if (err) {
6376884cb2SLee Jones 			dev_err(dev, "unable to bring out of pwrdwn\n");
6476884cb2SLee Jones 			return err;
6576884cb2SLee Jones 		}
6676884cb2SLee Jones 	}
6776884cb2SLee Jones 
6876884cb2SLee Jones 	if (drv_data->sw_rst) {
6976884cb2SLee Jones 		err = reset_control_deassert(drv_data->sw_rst);
7076884cb2SLee Jones 		if (err) {
7176884cb2SLee Jones 			dev_err(dev, "unable to bring out of sw-rst\n");
7276884cb2SLee Jones 			return err;
7376884cb2SLee Jones 		}
7476884cb2SLee Jones 	}
7576884cb2SLee Jones 
7676884cb2SLee Jones 	if (drv_data->pwr_rst) {
7776884cb2SLee Jones 		err = reset_control_deassert(drv_data->pwr_rst);
7876884cb2SLee Jones 		if (err) {
7976884cb2SLee Jones 			dev_err(dev, "unable to bring out of pwr-rst\n");
8076884cb2SLee Jones 			return err;
8176884cb2SLee Jones 		}
8276884cb2SLee Jones 	}
8376884cb2SLee Jones 
8476884cb2SLee Jones 	return 0;
8576884cb2SLee Jones }
8676884cb2SLee Jones 
st_ahci_host_stop(struct ata_host * host)87b032378bSBartlomiej Zolnierkiewicz static void st_ahci_host_stop(struct ata_host *host)
88a8237084SLee Jones {
89b032378bSBartlomiej Zolnierkiewicz 	struct ahci_host_priv *hpriv = host->private_data;
90e0e2674bSPeter Griffin 	struct st_ahci_drv_data *drv_data = hpriv->plat_data;
91b032378bSBartlomiej Zolnierkiewicz 	struct device *dev = host->dev;
92a8237084SLee Jones 	int err;
93a8237084SLee Jones 
94a8237084SLee Jones 	if (drv_data->pwr) {
95a8237084SLee Jones 		err = reset_control_assert(drv_data->pwr);
96a8237084SLee Jones 		if (err)
9733081b34SBartlomiej Zolnierkiewicz 			dev_err(dev, "unable to pwrdwn\n");
98a8237084SLee Jones 	}
99a8237084SLee Jones 
100a8237084SLee Jones 	ahci_platform_disable_resources(hpriv);
101a8237084SLee Jones }
102a8237084SLee Jones 
st_ahci_probe_resets(struct ahci_host_priv * hpriv,struct device * dev)103e0e2674bSPeter Griffin static int st_ahci_probe_resets(struct ahci_host_priv *hpriv,
104e0e2674bSPeter Griffin 				struct device *dev)
10576884cb2SLee Jones {
106e0e2674bSPeter Griffin 	struct st_ahci_drv_data *drv_data = hpriv->plat_data;
10776884cb2SLee Jones 
108e0e2674bSPeter Griffin 	drv_data->pwr = devm_reset_control_get(dev, "pwr-dwn");
10976884cb2SLee Jones 	if (IS_ERR(drv_data->pwr)) {
110e0e2674bSPeter Griffin 		dev_info(dev, "power reset control not defined\n");
11176884cb2SLee Jones 		drv_data->pwr = NULL;
11276884cb2SLee Jones 	}
11376884cb2SLee Jones 
114e0e2674bSPeter Griffin 	drv_data->sw_rst = devm_reset_control_get(dev, "sw-rst");
11576884cb2SLee Jones 	if (IS_ERR(drv_data->sw_rst)) {
116e0e2674bSPeter Griffin 		dev_info(dev, "soft reset control not defined\n");
11776884cb2SLee Jones 		drv_data->sw_rst = NULL;
11876884cb2SLee Jones 	}
11976884cb2SLee Jones 
120e0e2674bSPeter Griffin 	drv_data->pwr_rst = devm_reset_control_get(dev, "pwr-rst");
12176884cb2SLee Jones 	if (IS_ERR(drv_data->pwr_rst)) {
122e0e2674bSPeter Griffin 		dev_dbg(dev, "power soft reset control not defined\n");
12376884cb2SLee Jones 		drv_data->pwr_rst = NULL;
12476884cb2SLee Jones 	}
12576884cb2SLee Jones 
126e0e2674bSPeter Griffin 	return st_ahci_deassert_resets(hpriv, dev);
12776884cb2SLee Jones }
12876884cb2SLee Jones 
129b032378bSBartlomiej Zolnierkiewicz static struct ata_port_operations st_ahci_port_ops = {
130b032378bSBartlomiej Zolnierkiewicz 	.inherits	= &ahci_platform_ops,
131b032378bSBartlomiej Zolnierkiewicz 	.host_stop	= st_ahci_host_stop,
132b032378bSBartlomiej Zolnierkiewicz };
133b032378bSBartlomiej Zolnierkiewicz 
13476884cb2SLee Jones static const struct ata_port_info st_ahci_port_info = {
13576884cb2SLee Jones 	.flags          = AHCI_FLAG_COMMON,
13676884cb2SLee Jones 	.pio_mask       = ATA_PIO4,
13776884cb2SLee Jones 	.udma_mask      = ATA_UDMA6,
138b032378bSBartlomiej Zolnierkiewicz 	.port_ops       = &st_ahci_port_ops,
13976884cb2SLee Jones };
14076884cb2SLee Jones 
14125df73d9SBart Van Assche static const struct scsi_host_template ahci_platform_sht = {
142018d5ef2SAkinobu Mita 	AHCI_SHT(DRV_NAME),
143018d5ef2SAkinobu Mita };
144018d5ef2SAkinobu Mita 
st_ahci_probe(struct platform_device * pdev)14576884cb2SLee Jones static int st_ahci_probe(struct platform_device *pdev)
14676884cb2SLee Jones {
14776884cb2SLee Jones 	struct st_ahci_drv_data *drv_data;
14876884cb2SLee Jones 	struct ahci_host_priv *hpriv;
14976884cb2SLee Jones 	int err;
15076884cb2SLee Jones 
15176884cb2SLee Jones 	drv_data = devm_kzalloc(&pdev->dev, sizeof(*drv_data), GFP_KERNEL);
15276884cb2SLee Jones 	if (!drv_data)
15376884cb2SLee Jones 		return -ENOMEM;
15476884cb2SLee Jones 
15516af2d65SKunihiko Hayashi 	hpriv = ahci_platform_get_resources(pdev, 0);
15676884cb2SLee Jones 	if (IS_ERR(hpriv))
15776884cb2SLee Jones 		return PTR_ERR(hpriv);
158e0e2674bSPeter Griffin 	hpriv->plat_data = drv_data;
15976884cb2SLee Jones 
160e0e2674bSPeter Griffin 	err = st_ahci_probe_resets(hpriv, &pdev->dev);
16176884cb2SLee Jones 	if (err)
16276884cb2SLee Jones 		return err;
16376884cb2SLee Jones 
16476884cb2SLee Jones 	err = ahci_platform_enable_resources(hpriv);
16576884cb2SLee Jones 	if (err)
16676884cb2SLee Jones 		return err;
16776884cb2SLee Jones 
168e0e2674bSPeter Griffin 	st_ahci_configure_oob(hpriv->mmio);
1699a1e75e1SPeter Griffin 
170018d5ef2SAkinobu Mita 	err = ahci_platform_init_host(pdev, hpriv, &st_ahci_port_info,
171018d5ef2SAkinobu Mita 				      &ahci_platform_sht);
17276884cb2SLee Jones 	if (err) {
17376884cb2SLee Jones 		ahci_platform_disable_resources(hpriv);
17476884cb2SLee Jones 		return err;
17576884cb2SLee Jones 	}
17676884cb2SLee Jones 
17776884cb2SLee Jones 	return 0;
17876884cb2SLee Jones }
17976884cb2SLee Jones 
18076884cb2SLee Jones #ifdef CONFIG_PM_SLEEP
st_ahci_suspend(struct device * dev)18176884cb2SLee Jones static int st_ahci_suspend(struct device *dev)
18276884cb2SLee Jones {
183e0e2674bSPeter Griffin 	struct ata_host *host = dev_get_drvdata(dev);
184e0e2674bSPeter Griffin 	struct ahci_host_priv *hpriv = host->private_data;
185e0e2674bSPeter Griffin 	struct st_ahci_drv_data *drv_data = hpriv->plat_data;
18676884cb2SLee Jones 	int err;
18776884cb2SLee Jones 
18833081b34SBartlomiej Zolnierkiewicz 	err = ahci_platform_suspend_host(dev);
18933081b34SBartlomiej Zolnierkiewicz 	if (err)
19033081b34SBartlomiej Zolnierkiewicz 		return err;
191761a8c27SLee Jones 
19276884cb2SLee Jones 	if (drv_data->pwr) {
19376884cb2SLee Jones 		err = reset_control_assert(drv_data->pwr);
19476884cb2SLee Jones 		if (err) {
19576884cb2SLee Jones 			dev_err(dev, "unable to pwrdwn");
19676884cb2SLee Jones 			return err;
19776884cb2SLee Jones 		}
19876884cb2SLee Jones 	}
19976884cb2SLee Jones 
20076884cb2SLee Jones 	ahci_platform_disable_resources(hpriv);
20176884cb2SLee Jones 
20276884cb2SLee Jones 	return 0;
20376884cb2SLee Jones }
20476884cb2SLee Jones 
st_ahci_resume(struct device * dev)20576884cb2SLee Jones static int st_ahci_resume(struct device *dev)
20676884cb2SLee Jones {
207e0e2674bSPeter Griffin 	struct ata_host *host = dev_get_drvdata(dev);
208e0e2674bSPeter Griffin 	struct ahci_host_priv *hpriv = host->private_data;
20976884cb2SLee Jones 	int err;
21076884cb2SLee Jones 
21176884cb2SLee Jones 	err = ahci_platform_enable_resources(hpriv);
21276884cb2SLee Jones 	if (err)
21376884cb2SLee Jones 		return err;
21476884cb2SLee Jones 
215e0e2674bSPeter Griffin 	err = st_ahci_deassert_resets(hpriv, dev);
21676884cb2SLee Jones 	if (err) {
21776884cb2SLee Jones 		ahci_platform_disable_resources(hpriv);
21876884cb2SLee Jones 		return err;
21976884cb2SLee Jones 	}
22076884cb2SLee Jones 
221e0e2674bSPeter Griffin 	st_ahci_configure_oob(hpriv->mmio);
2229a1e75e1SPeter Griffin 
223761a8c27SLee Jones 	return ahci_platform_resume_host(dev);
22476884cb2SLee Jones }
22576884cb2SLee Jones #endif
22676884cb2SLee Jones 
22776884cb2SLee Jones static SIMPLE_DEV_PM_OPS(st_ahci_pm_ops, st_ahci_suspend, st_ahci_resume);
22876884cb2SLee Jones 
22909de99dbSKiran Padwal static const struct of_device_id st_ahci_match[] = {
23076884cb2SLee Jones 	{ .compatible = "st,ahci", },
2315e776d7bSGeert Uytterhoeven 	{ /* sentinel */ }
23276884cb2SLee Jones };
23376884cb2SLee Jones MODULE_DEVICE_TABLE(of, st_ahci_match);
23476884cb2SLee Jones 
23576884cb2SLee Jones static struct platform_driver st_ahci_driver = {
23676884cb2SLee Jones 	.driver = {
237018d5ef2SAkinobu Mita 		.name = DRV_NAME,
23876884cb2SLee Jones 		.pm = &st_ahci_pm_ops,
23917cc1ee6SDamien Le Moal 		.of_match_table = st_ahci_match,
24076884cb2SLee Jones 	},
24176884cb2SLee Jones 	.probe = st_ahci_probe,
242*a7eb54d4SUwe Kleine-König 	.remove_new = ata_platform_remove_one,
24376884cb2SLee Jones };
24476884cb2SLee Jones module_platform_driver(st_ahci_driver);
24576884cb2SLee Jones 
24676884cb2SLee Jones MODULE_AUTHOR("Alexandre Torgue <alexandre.torgue@st.com>");
24776884cb2SLee Jones MODULE_AUTHOR("Francesco Virlinzi <francesco.virlinzi@st.com>");
2484a2e5123SLee Jones MODULE_DESCRIPTION("STMicroelectronics SATA AHCI Driver");
24976884cb2SLee Jones MODULE_LICENSE("GPL v2");
250