18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * AHCI SATA platform driver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright 2004-2005  Red Hat, Inc.
68c2ecf20Sopenharmony_ci *   Jeff Garzik <jgarzik@pobox.com>
78c2ecf20Sopenharmony_ci * Copyright 2010  MontaVista Software, LLC.
88c2ecf20Sopenharmony_ci *   Anton Vorontsov <avorontsov@ru.mvista.com>
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/kernel.h>
128c2ecf20Sopenharmony_ci#include <linux/module.h>
138c2ecf20Sopenharmony_ci#include <linux/pm.h>
148c2ecf20Sopenharmony_ci#include <linux/device.h>
158c2ecf20Sopenharmony_ci#include <linux/of_device.h>
168c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
178c2ecf20Sopenharmony_ci#include <linux/libata.h>
188c2ecf20Sopenharmony_ci#include <linux/ahci_platform.h>
198c2ecf20Sopenharmony_ci#include <linux/acpi.h>
208c2ecf20Sopenharmony_ci#include <linux/pci_ids.h>
218c2ecf20Sopenharmony_ci#include "ahci.h"
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#define DRV_NAME "ahci"
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_cistatic const struct ata_port_info ahci_port_info = {
268c2ecf20Sopenharmony_ci	.flags		= AHCI_FLAG_COMMON,
278c2ecf20Sopenharmony_ci	.pio_mask	= ATA_PIO4,
288c2ecf20Sopenharmony_ci	.udma_mask	= ATA_UDMA6,
298c2ecf20Sopenharmony_ci	.port_ops	= &ahci_platform_ops,
308c2ecf20Sopenharmony_ci};
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_cistatic const struct ata_port_info ahci_port_info_nolpm = {
338c2ecf20Sopenharmony_ci	.flags		= AHCI_FLAG_COMMON | ATA_FLAG_NO_LPM,
348c2ecf20Sopenharmony_ci	.pio_mask	= ATA_PIO4,
358c2ecf20Sopenharmony_ci	.udma_mask	= ATA_UDMA6,
368c2ecf20Sopenharmony_ci	.port_ops	= &ahci_platform_ops,
378c2ecf20Sopenharmony_ci};
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_cistatic struct scsi_host_template ahci_platform_sht = {
408c2ecf20Sopenharmony_ci	AHCI_SHT(DRV_NAME),
418c2ecf20Sopenharmony_ci};
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_cistatic int ahci_probe(struct platform_device *pdev)
448c2ecf20Sopenharmony_ci{
458c2ecf20Sopenharmony_ci	struct device *dev = &pdev->dev;
468c2ecf20Sopenharmony_ci	struct ahci_host_priv *hpriv;
478c2ecf20Sopenharmony_ci	const struct ata_port_info *port;
488c2ecf20Sopenharmony_ci	int rc;
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci	hpriv = ahci_platform_get_resources(pdev,
518c2ecf20Sopenharmony_ci					    AHCI_PLATFORM_GET_RESETS);
528c2ecf20Sopenharmony_ci	if (IS_ERR(hpriv))
538c2ecf20Sopenharmony_ci		return PTR_ERR(hpriv);
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	rc = ahci_platform_enable_resources(hpriv);
568c2ecf20Sopenharmony_ci	if (rc)
578c2ecf20Sopenharmony_ci		return rc;
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	of_property_read_u32(dev->of_node,
608c2ecf20Sopenharmony_ci			     "ports-implemented", &hpriv->force_port_map);
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	if (of_device_is_compatible(dev->of_node, "hisilicon,hisi-ahci"))
638c2ecf20Sopenharmony_ci		hpriv->flags |= AHCI_HFLAG_NO_FBS | AHCI_HFLAG_NO_NCQ;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	port = acpi_device_get_match_data(dev);
668c2ecf20Sopenharmony_ci	if (!port)
678c2ecf20Sopenharmony_ci		port = &ahci_port_info;
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	rc = ahci_platform_init_host(pdev, hpriv, port,
708c2ecf20Sopenharmony_ci				     &ahci_platform_sht);
718c2ecf20Sopenharmony_ci	if (rc)
728c2ecf20Sopenharmony_ci		goto disable_resources;
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	return 0;
758c2ecf20Sopenharmony_cidisable_resources:
768c2ecf20Sopenharmony_ci	ahci_platform_disable_resources(hpriv);
778c2ecf20Sopenharmony_ci	return rc;
788c2ecf20Sopenharmony_ci}
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(ahci_pm_ops, ahci_platform_suspend,
818c2ecf20Sopenharmony_ci			 ahci_platform_resume);
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_cistatic const struct of_device_id ahci_of_match[] = {
848c2ecf20Sopenharmony_ci	{ .compatible = "generic-ahci", },
858c2ecf20Sopenharmony_ci	/* Keep the following compatibles for device tree compatibility */
868c2ecf20Sopenharmony_ci	{ .compatible = "snps,spear-ahci", },
878c2ecf20Sopenharmony_ci	{ .compatible = "ibm,476gtr-ahci", },
888c2ecf20Sopenharmony_ci	{ .compatible = "snps,dwc-ahci", },
898c2ecf20Sopenharmony_ci	{ .compatible = "hisilicon,hisi-ahci", },
908c2ecf20Sopenharmony_ci	{ .compatible = "cavium,octeon-7130-ahci", },
918c2ecf20Sopenharmony_ci	{},
928c2ecf20Sopenharmony_ci};
938c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, ahci_of_match);
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_cistatic const struct acpi_device_id ahci_acpi_match[] = {
968c2ecf20Sopenharmony_ci	{ "APMC0D33", (unsigned long)&ahci_port_info_nolpm },
978c2ecf20Sopenharmony_ci	{ ACPI_DEVICE_CLASS(PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff) },
988c2ecf20Sopenharmony_ci	{},
998c2ecf20Sopenharmony_ci};
1008c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, ahci_acpi_match);
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_cistatic struct platform_driver ahci_driver = {
1038c2ecf20Sopenharmony_ci	.probe = ahci_probe,
1048c2ecf20Sopenharmony_ci	.remove = ata_platform_remove_one,
1058c2ecf20Sopenharmony_ci	.shutdown = ahci_platform_shutdown,
1068c2ecf20Sopenharmony_ci	.driver = {
1078c2ecf20Sopenharmony_ci		.name = DRV_NAME,
1088c2ecf20Sopenharmony_ci		.of_match_table = ahci_of_match,
1098c2ecf20Sopenharmony_ci		.acpi_match_table = ahci_acpi_match,
1108c2ecf20Sopenharmony_ci		.pm = &ahci_pm_ops,
1118c2ecf20Sopenharmony_ci	},
1128c2ecf20Sopenharmony_ci};
1138c2ecf20Sopenharmony_cimodule_platform_driver(ahci_driver);
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("AHCI SATA platform driver");
1168c2ecf20Sopenharmony_ciMODULE_AUTHOR("Anton Vorontsov <avorontsov@ru.mvista.com>");
1178c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
1188c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:ahci");
119