Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * AMD Seattle AHCI SATA driver
0004  *
0005  * Copyright (c) 2015, Advanced Micro Devices
0006  * Author: Brijesh Singh <brijesh.singh@amd.com>
0007  *
0008  * based on the AHCI SATA platform driver by Jeff Garzik and Anton Vorontsov
0009  */
0010 
0011 #include <linux/kernel.h>
0012 #include <linux/module.h>
0013 #include <linux/pm.h>
0014 #include <linux/device.h>
0015 #include <linux/of_device.h>
0016 #include <linux/platform_device.h>
0017 #include <linux/libata.h>
0018 #include <linux/ahci_platform.h>
0019 #include <linux/acpi.h>
0020 #include <linux/pci_ids.h>
0021 #include "ahci.h"
0022 
0023 /* SGPIO Control Register definition
0024  *
0025  * Bit      Type        Description
0026  * 31       RW      OD7.2 (activity)
0027  * 30       RW      OD7.1 (locate)
0028  * 29       RW      OD7.0 (fault)
0029  * 28...8   RW      OD6.2...OD0.0 (3bits per port, 1 bit per LED)
0030  * 7        RO      SGPIO feature flag
0031  * 6:4      RO      Reserved
0032  * 3:0      RO      Number of ports (0 means no port supported)
0033  */
0034 #define ACTIVITY_BIT_POS(x)     (8 + (3 * x))
0035 #define LOCATE_BIT_POS(x)       (ACTIVITY_BIT_POS(x) + 1)
0036 #define FAULT_BIT_POS(x)        (LOCATE_BIT_POS(x) + 1)
0037 
0038 #define ACTIVITY_MASK           0x00010000
0039 #define LOCATE_MASK         0x00080000
0040 #define FAULT_MASK          0x00400000
0041 
0042 #define DRV_NAME "ahci-seattle"
0043 
0044 static ssize_t seattle_transmit_led_message(struct ata_port *ap, u32 state,
0045                         ssize_t size);
0046 
0047 struct seattle_plat_data {
0048     void __iomem *sgpio_ctrl;
0049 };
0050 
0051 static struct ata_port_operations ahci_port_ops = {
0052     .inherits       = &ahci_ops,
0053 };
0054 
0055 static const struct ata_port_info ahci_port_info = {
0056     .flags      = AHCI_FLAG_COMMON,
0057     .pio_mask   = ATA_PIO4,
0058     .udma_mask  = ATA_UDMA6,
0059     .port_ops   = &ahci_port_ops,
0060 };
0061 
0062 static struct ata_port_operations ahci_seattle_ops = {
0063     .inherits       = &ahci_ops,
0064     .transmit_led_message   = seattle_transmit_led_message,
0065 };
0066 
0067 static const struct ata_port_info ahci_port_seattle_info = {
0068     .flags      = AHCI_FLAG_COMMON | ATA_FLAG_EM | ATA_FLAG_SW_ACTIVITY,
0069     .link_flags = ATA_LFLAG_SW_ACTIVITY,
0070     .pio_mask   = ATA_PIO4,
0071     .udma_mask  = ATA_UDMA6,
0072     .port_ops   = &ahci_seattle_ops,
0073 };
0074 
0075 static struct scsi_host_template ahci_platform_sht = {
0076     AHCI_SHT(DRV_NAME),
0077 };
0078 
0079 static ssize_t seattle_transmit_led_message(struct ata_port *ap, u32 state,
0080                         ssize_t size)
0081 {
0082     struct ahci_host_priv *hpriv = ap->host->private_data;
0083     struct ahci_port_priv *pp = ap->private_data;
0084     struct seattle_plat_data *plat_data = hpriv->plat_data;
0085     unsigned long flags;
0086     int pmp;
0087     struct ahci_em_priv *emp;
0088     u32 val;
0089 
0090     /* get the slot number from the message */
0091     pmp = (state & EM_MSG_LED_PMP_SLOT) >> 8;
0092     if (pmp >= EM_MAX_SLOTS)
0093         return -EINVAL;
0094     emp = &pp->em_priv[pmp];
0095 
0096     val = ioread32(plat_data->sgpio_ctrl);
0097     if (state & ACTIVITY_MASK)
0098         val |= 1 << ACTIVITY_BIT_POS((ap->port_no));
0099     else
0100         val &= ~(1 << ACTIVITY_BIT_POS((ap->port_no)));
0101 
0102     if (state & LOCATE_MASK)
0103         val |= 1 << LOCATE_BIT_POS((ap->port_no));
0104     else
0105         val &= ~(1 << LOCATE_BIT_POS((ap->port_no)));
0106 
0107     if (state & FAULT_MASK)
0108         val |= 1 << FAULT_BIT_POS((ap->port_no));
0109     else
0110         val &= ~(1 << FAULT_BIT_POS((ap->port_no)));
0111 
0112     iowrite32(val, plat_data->sgpio_ctrl);
0113 
0114     spin_lock_irqsave(ap->lock, flags);
0115 
0116     /* save off new led state for port/slot */
0117     emp->led_state = state;
0118 
0119     spin_unlock_irqrestore(ap->lock, flags);
0120 
0121     return size;
0122 }
0123 
0124 static const struct ata_port_info *ahci_seattle_get_port_info(
0125         struct platform_device *pdev, struct ahci_host_priv *hpriv)
0126 {
0127     struct device *dev = &pdev->dev;
0128     struct seattle_plat_data *plat_data;
0129     u32 val;
0130 
0131     plat_data = devm_kzalloc(dev, sizeof(*plat_data), GFP_KERNEL);
0132     if (!plat_data)
0133         return &ahci_port_info;
0134 
0135     plat_data->sgpio_ctrl = devm_ioremap_resource(dev,
0136                   platform_get_resource(pdev, IORESOURCE_MEM, 1));
0137     if (IS_ERR(plat_data->sgpio_ctrl))
0138         return &ahci_port_info;
0139 
0140     val = ioread32(plat_data->sgpio_ctrl);
0141 
0142     if (!(val & 0xf))
0143         return &ahci_port_info;
0144 
0145     hpriv->em_loc = 0;
0146     hpriv->em_buf_sz = 4;
0147     hpriv->em_msg_type = EM_MSG_TYPE_LED;
0148     hpriv->plat_data = plat_data;
0149 
0150     dev_info(dev, "SGPIO LED control is enabled.\n");
0151     return &ahci_port_seattle_info;
0152 }
0153 
0154 static int ahci_seattle_probe(struct platform_device *pdev)
0155 {
0156     int rc;
0157     struct ahci_host_priv *hpriv;
0158 
0159     hpriv = ahci_platform_get_resources(pdev, 0);
0160     if (IS_ERR(hpriv))
0161         return PTR_ERR(hpriv);
0162 
0163     rc = ahci_platform_enable_resources(hpriv);
0164     if (rc)
0165         return rc;
0166 
0167     rc = ahci_platform_init_host(pdev, hpriv,
0168                      ahci_seattle_get_port_info(pdev, hpriv),
0169                      &ahci_platform_sht);
0170     if (rc)
0171         goto disable_resources;
0172 
0173     return 0;
0174 disable_resources:
0175     ahci_platform_disable_resources(hpriv);
0176     return rc;
0177 }
0178 
0179 static SIMPLE_DEV_PM_OPS(ahci_pm_ops, ahci_platform_suspend,
0180              ahci_platform_resume);
0181 
0182 static const struct acpi_device_id ahci_acpi_match[] = {
0183     { "AMDI0600", 0 },
0184     {}
0185 };
0186 MODULE_DEVICE_TABLE(acpi, ahci_acpi_match);
0187 
0188 static struct platform_driver ahci_seattle_driver = {
0189     .probe = ahci_seattle_probe,
0190     .remove = ata_platform_remove_one,
0191     .driver = {
0192         .name = DRV_NAME,
0193         .acpi_match_table = ahci_acpi_match,
0194         .pm = &ahci_pm_ops,
0195     },
0196 };
0197 module_platform_driver(ahci_seattle_driver);
0198 
0199 MODULE_DESCRIPTION("Seattle AHCI SATA platform driver");
0200 MODULE_AUTHOR("Brijesh Singh <brijesh.singh@amd.com>");
0201 MODULE_LICENSE("GPL");
0202 MODULE_ALIAS("platform:" DRV_NAME);