162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * AHCI SATA platform driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright 2004-2005  Red Hat, Inc.
662306a36Sopenharmony_ci *   Jeff Garzik <jgarzik@pobox.com>
762306a36Sopenharmony_ci * Copyright 2010  MontaVista Software, LLC.
862306a36Sopenharmony_ci *   Anton Vorontsov <avorontsov@ru.mvista.com>
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/kernel.h>
1262306a36Sopenharmony_ci#include <linux/mod_devicetable.h>
1362306a36Sopenharmony_ci#include <linux/module.h>
1462306a36Sopenharmony_ci#include <linux/pm.h>
1562306a36Sopenharmony_ci#include <linux/device.h>
1662306a36Sopenharmony_ci#include <linux/platform_device.h>
1762306a36Sopenharmony_ci#include <linux/property.h>
1862306a36Sopenharmony_ci#include <linux/libata.h>
1962306a36Sopenharmony_ci#include <linux/ahci_platform.h>
2062306a36Sopenharmony_ci#include <linux/pci_ids.h>
2162306a36Sopenharmony_ci#include "ahci.h"
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#define DRV_NAME "ahci"
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_cistatic const struct ata_port_info ahci_port_info = {
2662306a36Sopenharmony_ci	.flags		= AHCI_FLAG_COMMON,
2762306a36Sopenharmony_ci	.pio_mask	= ATA_PIO4,
2862306a36Sopenharmony_ci	.udma_mask	= ATA_UDMA6,
2962306a36Sopenharmony_ci	.port_ops	= &ahci_platform_ops,
3062306a36Sopenharmony_ci};
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_cistatic const struct ata_port_info ahci_port_info_nolpm = {
3362306a36Sopenharmony_ci	.flags		= AHCI_FLAG_COMMON | ATA_FLAG_NO_LPM,
3462306a36Sopenharmony_ci	.pio_mask	= ATA_PIO4,
3562306a36Sopenharmony_ci	.udma_mask	= ATA_UDMA6,
3662306a36Sopenharmony_ci	.port_ops	= &ahci_platform_ops,
3762306a36Sopenharmony_ci};
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_cistatic const struct scsi_host_template ahci_platform_sht = {
4062306a36Sopenharmony_ci	AHCI_SHT(DRV_NAME),
4162306a36Sopenharmony_ci};
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cistatic int ahci_probe(struct platform_device *pdev)
4462306a36Sopenharmony_ci{
4562306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
4662306a36Sopenharmony_ci	struct ahci_host_priv *hpriv;
4762306a36Sopenharmony_ci	const struct ata_port_info *port;
4862306a36Sopenharmony_ci	int rc;
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	hpriv = ahci_platform_get_resources(pdev,
5162306a36Sopenharmony_ci					    AHCI_PLATFORM_GET_RESETS);
5262306a36Sopenharmony_ci	if (IS_ERR(hpriv))
5362306a36Sopenharmony_ci		return PTR_ERR(hpriv);
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	rc = ahci_platform_enable_resources(hpriv);
5662306a36Sopenharmony_ci	if (rc)
5762306a36Sopenharmony_ci		return rc;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	if (device_is_compatible(dev, "hisilicon,hisi-ahci"))
6062306a36Sopenharmony_ci		hpriv->flags |= AHCI_HFLAG_NO_FBS | AHCI_HFLAG_NO_NCQ;
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	port = device_get_match_data(dev);
6362306a36Sopenharmony_ci	if (!port)
6462306a36Sopenharmony_ci		port = &ahci_port_info;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	rc = ahci_platform_init_host(pdev, hpriv, port,
6762306a36Sopenharmony_ci				     &ahci_platform_sht);
6862306a36Sopenharmony_ci	if (rc)
6962306a36Sopenharmony_ci		goto disable_resources;
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	return 0;
7262306a36Sopenharmony_cidisable_resources:
7362306a36Sopenharmony_ci	ahci_platform_disable_resources(hpriv);
7462306a36Sopenharmony_ci	return rc;
7562306a36Sopenharmony_ci}
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(ahci_pm_ops, ahci_platform_suspend,
7862306a36Sopenharmony_ci			 ahci_platform_resume);
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_cistatic const struct of_device_id ahci_of_match[] = {
8162306a36Sopenharmony_ci	{ .compatible = "generic-ahci", },
8262306a36Sopenharmony_ci	/* Keep the following compatibles for device tree compatibility */
8362306a36Sopenharmony_ci	{ .compatible = "ibm,476gtr-ahci", },
8462306a36Sopenharmony_ci	{ .compatible = "hisilicon,hisi-ahci", },
8562306a36Sopenharmony_ci	{ .compatible = "cavium,octeon-7130-ahci", },
8662306a36Sopenharmony_ci	{ /* sentinel */ }
8762306a36Sopenharmony_ci};
8862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, ahci_of_match);
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_cistatic const struct acpi_device_id ahci_acpi_match[] = {
9162306a36Sopenharmony_ci	{ "APMC0D33", (unsigned long)&ahci_port_info_nolpm },
9262306a36Sopenharmony_ci	{ ACPI_DEVICE_CLASS(PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff) },
9362306a36Sopenharmony_ci	{},
9462306a36Sopenharmony_ci};
9562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, ahci_acpi_match);
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_cistatic struct platform_driver ahci_driver = {
9862306a36Sopenharmony_ci	.probe = ahci_probe,
9962306a36Sopenharmony_ci	.remove_new = ata_platform_remove_one,
10062306a36Sopenharmony_ci	.shutdown = ahci_platform_shutdown,
10162306a36Sopenharmony_ci	.driver = {
10262306a36Sopenharmony_ci		.name = DRV_NAME,
10362306a36Sopenharmony_ci		.of_match_table = ahci_of_match,
10462306a36Sopenharmony_ci		.acpi_match_table = ahci_acpi_match,
10562306a36Sopenharmony_ci		.pm = &ahci_pm_ops,
10662306a36Sopenharmony_ci	},
10762306a36Sopenharmony_ci};
10862306a36Sopenharmony_cimodule_platform_driver(ahci_driver);
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ciMODULE_DESCRIPTION("AHCI SATA platform driver");
11162306a36Sopenharmony_ciMODULE_AUTHOR("Anton Vorontsov <avorontsov@ru.mvista.com>");
11262306a36Sopenharmony_ciMODULE_LICENSE("GPL");
11362306a36Sopenharmony_ciMODULE_ALIAS("platform:ahci");
114