-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This can be used for AHCI-compatible interfaces implemented inside System-On-Chip solutions, or AHCI devices connected via localbus. Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com> Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
- Loading branch information
Anton Vorontsov
authored and
Jeff Garzik
committed
May 14, 2010
1 parent
365cfa1
commit 1c2a49f
Showing
4 changed files
with
229 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,191 @@ | ||
/* | ||
* AHCI SATA platform driver | ||
* | ||
* Copyright 2004-2005 Red Hat, Inc. | ||
* Jeff Garzik <jgarzik@pobox.com> | ||
* Copyright 2010 MontaVista Software, LLC. | ||
* Anton Vorontsov <avorontsov@ru.mvista.com> | ||
* | ||
* This program is free software; you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by | ||
* the Free Software Foundation; either version 2, or (at your option) | ||
* any later version. | ||
*/ | ||
|
||
#include <linux/kernel.h> | ||
#include <linux/module.h> | ||
#include <linux/init.h> | ||
#include <linux/interrupt.h> | ||
#include <linux/device.h> | ||
#include <linux/platform_device.h> | ||
#include <linux/libata.h> | ||
#include <linux/ahci_platform.h> | ||
#include "ahci.h" | ||
|
||
static int __init ahci_probe(struct platform_device *pdev) | ||
{ | ||
struct device *dev = &pdev->dev; | ||
struct ahci_platform_data *pdata = dev->platform_data; | ||
struct ata_port_info pi = { | ||
.flags = AHCI_FLAG_COMMON, | ||
.pio_mask = ATA_PIO4, | ||
.udma_mask = ATA_UDMA6, | ||
.port_ops = &ahci_ops, | ||
}; | ||
const struct ata_port_info *ppi[] = { &pi, NULL }; | ||
struct ahci_host_priv *hpriv; | ||
struct ata_host *host; | ||
struct resource *mem; | ||
int irq; | ||
int n_ports; | ||
int i; | ||
int rc; | ||
|
||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
if (!mem) { | ||
dev_err(dev, "no mmio space\n"); | ||
return -EINVAL; | ||
} | ||
|
||
irq = platform_get_irq(pdev, 0); | ||
if (irq <= 0) { | ||
dev_err(dev, "no irq\n"); | ||
return -EINVAL; | ||
} | ||
|
||
if (pdata && pdata->init) { | ||
rc = pdata->init(dev); | ||
if (rc) | ||
return rc; | ||
} | ||
|
||
if (pdata && pdata->ata_port_info) | ||
pi = *pdata->ata_port_info; | ||
|
||
hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL); | ||
if (!hpriv) { | ||
rc = -ENOMEM; | ||
goto err0; | ||
} | ||
|
||
hpriv->flags |= (unsigned long)pi.private_data; | ||
|
||
hpriv->mmio = devm_ioremap(dev, mem->start, resource_size(mem)); | ||
if (!hpriv->mmio) { | ||
dev_err(dev, "can't map %pR\n", mem); | ||
rc = -ENOMEM; | ||
goto err0; | ||
} | ||
|
||
ahci_save_initial_config(dev, hpriv, | ||
pdata ? pdata->force_port_map : 0, | ||
pdata ? pdata->mask_port_map : 0); | ||
|
||
/* prepare host */ | ||
if (hpriv->cap & HOST_CAP_NCQ) | ||
pi.flags |= ATA_FLAG_NCQ; | ||
|
||
if (hpriv->cap & HOST_CAP_PMP) | ||
pi.flags |= ATA_FLAG_PMP; | ||
|
||
ahci_set_em_messages(hpriv, &pi); | ||
|
||
/* CAP.NP sometimes indicate the index of the last enabled | ||
* port, at other times, that of the last possible port, so | ||
* determining the maximum port number requires looking at | ||
* both CAP.NP and port_map. | ||
*/ | ||
n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map)); | ||
|
||
host = ata_host_alloc_pinfo(dev, ppi, n_ports); | ||
if (!host) { | ||
rc = -ENOMEM; | ||
goto err0; | ||
} | ||
|
||
host->private_data = hpriv; | ||
|
||
if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss) | ||
host->flags |= ATA_HOST_PARALLEL_SCAN; | ||
else | ||
printk(KERN_INFO "ahci: SSS flag set, parallel bus scan disabled\n"); | ||
|
||
if (pi.flags & ATA_FLAG_EM) | ||
ahci_reset_em(host); | ||
|
||
for (i = 0; i < host->n_ports; i++) { | ||
struct ata_port *ap = host->ports[i]; | ||
|
||
ata_port_desc(ap, "mmio %pR", mem); | ||
ata_port_desc(ap, "port 0x%x", 0x100 + ap->port_no * 0x80); | ||
|
||
/* set initial link pm policy */ | ||
ap->pm_policy = NOT_AVAILABLE; | ||
|
||
/* set enclosure management message type */ | ||
if (ap->flags & ATA_FLAG_EM) | ||
ap->em_message_type = ahci_em_messages; | ||
|
||
/* disabled/not-implemented port */ | ||
if (!(hpriv->port_map & (1 << i))) | ||
ap->ops = &ata_dummy_port_ops; | ||
} | ||
|
||
rc = ahci_reset_controller(host); | ||
if (rc) | ||
goto err0; | ||
|
||
ahci_init_controller(host); | ||
ahci_print_info(host, "platform"); | ||
|
||
rc = ata_host_activate(host, irq, ahci_interrupt, IRQF_SHARED, | ||
&ahci_sht); | ||
if (rc) | ||
goto err0; | ||
|
||
return 0; | ||
err0: | ||
if (pdata && pdata->exit) | ||
pdata->exit(dev); | ||
return rc; | ||
} | ||
|
||
static int __devexit ahci_remove(struct platform_device *pdev) | ||
{ | ||
struct device *dev = &pdev->dev; | ||
struct ahci_platform_data *pdata = dev->platform_data; | ||
struct ata_host *host = dev_get_drvdata(dev); | ||
|
||
ata_host_detach(host); | ||
|
||
if (pdata && pdata->exit) | ||
pdata->exit(dev); | ||
|
||
return 0; | ||
} | ||
|
||
static struct platform_driver ahci_driver = { | ||
.probe = ahci_probe, | ||
.remove = __devexit_p(ahci_remove), | ||
.driver = { | ||
.name = "ahci", | ||
.owner = THIS_MODULE, | ||
}, | ||
}; | ||
|
||
static int __init ahci_init(void) | ||
{ | ||
return platform_driver_probe(&ahci_driver, ahci_probe); | ||
} | ||
module_init(ahci_init); | ||
|
||
static void __exit ahci_exit(void) | ||
{ | ||
platform_driver_unregister(&ahci_driver); | ||
} | ||
module_exit(ahci_exit); | ||
|
||
MODULE_DESCRIPTION("AHCI SATA platform driver"); | ||
MODULE_AUTHOR("Anton Vorontsov <avorontsov@ru.mvista.com>"); | ||
MODULE_LICENSE("GPL"); | ||
MODULE_ALIAS("platform:ahci"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
/* | ||
* AHCI SATA platform driver | ||
* | ||
* Copyright 2004-2005 Red Hat, Inc. | ||
* Jeff Garzik <jgarzik@pobox.com> | ||
* Copyright 2010 MontaVista Software, LLC. | ||
* Anton Vorontsov <avorontsov@ru.mvista.com> | ||
* | ||
* This program is free software; you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by | ||
* the Free Software Foundation; either version 2, or (at your option) | ||
* any later version. | ||
*/ | ||
|
||
#ifndef _AHCI_PLATFORM_H | ||
#define _AHCI_PLATFORM_H | ||
|
||
struct device; | ||
struct ata_port_info; | ||
|
||
struct ahci_platform_data { | ||
int (*init)(struct device *dev); | ||
void (*exit)(struct device *dev); | ||
const struct ata_port_info *ata_port_info; | ||
unsigned int force_port_map; | ||
unsigned int mask_port_map; | ||
}; | ||
|
||
#endif /* _AHCI_PLATFORM_H */ |