|
@@ -10,6 +10,7 @@
|
|
|
#include <fis.h>
|
|
|
#include <libata.h>
|
|
|
#include <malloc.h>
|
|
|
+#include <memalign.h>
|
|
|
#include <sata.h>
|
|
|
#include <asm/io.h>
|
|
|
#include <asm/arch/clock.h>
|
|
@@ -720,6 +721,130 @@ static u32 ata_low_level_rw_lba28(struct ahci_uc_priv *uc_priv, u32 blknr,
|
|
|
return blkcnt;
|
|
|
}
|
|
|
|
|
|
+static int dwc_ahci_start_ports(struct ahci_uc_priv *uc_priv)
|
|
|
+{
|
|
|
+ u32 linkmap;
|
|
|
+ int i;
|
|
|
+
|
|
|
+ linkmap = uc_priv->link_port_map;
|
|
|
+
|
|
|
+ if (0 == linkmap) {
|
|
|
+ printf("No port device detected!\n");
|
|
|
+ return -ENXIO;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (i = 0; i < uc_priv->n_ports; i++) {
|
|
|
+ if ((linkmap >> i) && ((linkmap >> i) & 0x01)) {
|
|
|
+ if (ahci_port_start(uc_priv, (u8)i)) {
|
|
|
+ printf("Can not start port %d\n", i);
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ uc_priv->hard_port_no = i;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int dwc_ahsata_scan_common(struct ahci_uc_priv *uc_priv,
|
|
|
+ struct blk_desc *pdev)
|
|
|
+{
|
|
|
+ u8 serial[ATA_ID_SERNO_LEN + 1] = { 0 };
|
|
|
+ u8 firmware[ATA_ID_FW_REV_LEN + 1] = { 0 };
|
|
|
+ u8 product[ATA_ID_PROD_LEN + 1] = { 0 };
|
|
|
+ u64 n_sectors;
|
|
|
+ u8 port = uc_priv->hard_port_no;
|
|
|
+ ALLOC_CACHE_ALIGN_BUFFER(u16, id, ATA_ID_WORDS);
|
|
|
+
|
|
|
+ /* Identify device to get information */
|
|
|
+ dwc_ahsata_identify(uc_priv, id);
|
|
|
+
|
|
|
+ /* Serial number */
|
|
|
+ ata_id_c_string(id, serial, ATA_ID_SERNO, sizeof(serial));
|
|
|
+ memcpy(pdev->product, serial, sizeof(serial));
|
|
|
+
|
|
|
+ /* Firmware version */
|
|
|
+ ata_id_c_string(id, firmware, ATA_ID_FW_REV, sizeof(firmware));
|
|
|
+ memcpy(pdev->revision, firmware, sizeof(firmware));
|
|
|
+
|
|
|
+ /* Product model */
|
|
|
+ ata_id_c_string(id, product, ATA_ID_PROD, sizeof(product));
|
|
|
+ memcpy(pdev->vendor, product, sizeof(product));
|
|
|
+
|
|
|
+ /* Totoal sectors */
|
|
|
+ n_sectors = ata_id_n_sectors(id);
|
|
|
+ pdev->lba = (u32)n_sectors;
|
|
|
+
|
|
|
+ pdev->type = DEV_TYPE_HARDDISK;
|
|
|
+ pdev->blksz = ATA_SECT_SIZE;
|
|
|
+ pdev->lun = 0;
|
|
|
+
|
|
|
+ /* Check if support LBA48 */
|
|
|
+ if (ata_id_has_lba48(id)) {
|
|
|
+ pdev->lba48 = 1;
|
|
|
+ debug("Device support LBA48\n\r");
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Get the NCQ queue depth from device */
|
|
|
+ uc_priv->flags &= (~SATA_FLAG_Q_DEP_MASK);
|
|
|
+ uc_priv->flags |= ata_id_queue_depth(id);
|
|
|
+
|
|
|
+ /* Get the xfer mode from device */
|
|
|
+ dwc_ahsata_xfer_mode(uc_priv, id);
|
|
|
+
|
|
|
+ /* Get the write cache status from device */
|
|
|
+ dwc_ahsata_init_wcache(uc_priv, id);
|
|
|
+
|
|
|
+ /* Set the xfer mode to highest speed */
|
|
|
+ ahci_set_feature(uc_priv, port);
|
|
|
+
|
|
|
+ dwc_ahsata_print_info(pdev);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * SATA interface between low level driver and command layer
|
|
|
+ */
|
|
|
+static ulong sata_read_common(struct ahci_uc_priv *uc_priv,
|
|
|
+ struct blk_desc *desc, ulong blknr,
|
|
|
+ lbaint_t blkcnt, void *buffer)
|
|
|
+{
|
|
|
+ u32 rc;
|
|
|
+
|
|
|
+ if (desc->lba48)
|
|
|
+ rc = ata_low_level_rw_lba48(uc_priv, blknr, blkcnt, buffer,
|
|
|
+ READ_CMD);
|
|
|
+ else
|
|
|
+ rc = ata_low_level_rw_lba28(uc_priv, blknr, blkcnt, buffer,
|
|
|
+ READ_CMD);
|
|
|
+
|
|
|
+ return rc;
|
|
|
+}
|
|
|
+
|
|
|
+static ulong sata_write_common(struct ahci_uc_priv *uc_priv,
|
|
|
+ struct blk_desc *desc, ulong blknr,
|
|
|
+ lbaint_t blkcnt, const void *buffer)
|
|
|
+{
|
|
|
+ u32 rc;
|
|
|
+ u32 flags = uc_priv->flags;
|
|
|
+
|
|
|
+ if (desc->lba48) {
|
|
|
+ rc = ata_low_level_rw_lba48(uc_priv, blknr, blkcnt, buffer,
|
|
|
+ WRITE_CMD);
|
|
|
+ if ((flags & SATA_FLAG_WCACHE) && (flags & SATA_FLAG_FLUSH_EXT))
|
|
|
+ dwc_ahsata_flush_cache_ext(uc_priv);
|
|
|
+ } else {
|
|
|
+ rc = ata_low_level_rw_lba28(uc_priv, blknr, blkcnt, buffer,
|
|
|
+ WRITE_CMD);
|
|
|
+ if ((flags & SATA_FLAG_WCACHE) && (flags & SATA_FLAG_FLUSH))
|
|
|
+ dwc_ahsata_flush_cache(uc_priv);
|
|
|
+ }
|
|
|
+
|
|
|
+ return rc;
|
|
|
+}
|
|
|
+
|
|
|
static int ahci_init_one(int pdev)
|
|
|
{
|
|
|
int rc;
|
|
@@ -755,8 +880,6 @@ err_out:
|
|
|
|
|
|
int init_sata(int dev)
|
|
|
{
|
|
|
- int i;
|
|
|
- u32 linkmap;
|
|
|
struct ahci_uc_priv *uc_priv = NULL;
|
|
|
|
|
|
#if defined(CONFIG_MX6)
|
|
@@ -771,25 +894,8 @@ int init_sata(int dev)
|
|
|
ahci_init_one(dev);
|
|
|
|
|
|
uc_priv = sata_dev_desc[dev].priv;
|
|
|
- linkmap = uc_priv->link_port_map;
|
|
|
-
|
|
|
- if (0 == linkmap) {
|
|
|
- printf("No port device detected!\n");
|
|
|
- return 1;
|
|
|
- }
|
|
|
-
|
|
|
- for (i = 0; i < uc_priv->n_ports; i++) {
|
|
|
- if ((linkmap >> i) && ((linkmap >> i) & 0x01)) {
|
|
|
- if (ahci_port_start(uc_priv, (u8)i)) {
|
|
|
- printf("Can not start port %d\n", i);
|
|
|
- return 1;
|
|
|
- }
|
|
|
- uc_priv->hard_port_no = i;
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
|
|
|
- return 0;
|
|
|
+ return dwc_ahci_start_ports(uc_priv) ? 1 : 0;
|
|
|
}
|
|
|
|
|
|
int reset_sata(int dev)
|
|
@@ -838,103 +944,23 @@ int sata_port_status(int dev, int port)
|
|
|
ulong sata_read(int dev, ulong blknr, lbaint_t blkcnt, void *buffer)
|
|
|
{
|
|
|
struct ahci_uc_priv *uc_priv = sata_dev_desc[dev].priv;
|
|
|
- u32 rc;
|
|
|
|
|
|
- if (sata_dev_desc[dev].lba48)
|
|
|
- rc = ata_low_level_rw_lba48(uc_priv, blknr, blkcnt,
|
|
|
- buffer, READ_CMD);
|
|
|
- else
|
|
|
- rc = ata_low_level_rw_lba28(uc_priv, blknr, blkcnt,
|
|
|
- buffer, READ_CMD);
|
|
|
- return rc;
|
|
|
+ return sata_read_common(uc_priv, &sata_dev_desc[dev], blknr, blkcnt,
|
|
|
+ buffer);
|
|
|
}
|
|
|
|
|
|
ulong sata_write(int dev, ulong blknr, lbaint_t blkcnt, const void *buffer)
|
|
|
{
|
|
|
- u32 rc;
|
|
|
struct ahci_uc_priv *uc_priv = sata_dev_desc[dev].priv;
|
|
|
- u32 flags = uc_priv->flags;
|
|
|
|
|
|
- if (sata_dev_desc[dev].lba48) {
|
|
|
- rc = ata_low_level_rw_lba48(uc_priv, blknr, blkcnt, buffer,
|
|
|
- WRITE_CMD);
|
|
|
- if ((flags & SATA_FLAG_WCACHE) &&
|
|
|
- (flags & SATA_FLAG_FLUSH_EXT))
|
|
|
- dwc_ahsata_flush_cache_ext(uc_priv);
|
|
|
- } else {
|
|
|
- rc = ata_low_level_rw_lba28(uc_priv, blknr, blkcnt, buffer,
|
|
|
- WRITE_CMD);
|
|
|
- if ((flags & SATA_FLAG_WCACHE) &&
|
|
|
- (flags & SATA_FLAG_FLUSH))
|
|
|
- dwc_ahsata_flush_cache(uc_priv);
|
|
|
- }
|
|
|
- return rc;
|
|
|
+ return sata_write_common(uc_priv, &sata_dev_desc[dev], blknr, blkcnt,
|
|
|
+ buffer);
|
|
|
}
|
|
|
|
|
|
int scan_sata(int dev)
|
|
|
{
|
|
|
- u8 serial[ATA_ID_SERNO_LEN + 1] = { 0 };
|
|
|
- u8 firmware[ATA_ID_FW_REV_LEN + 1] = { 0 };
|
|
|
- u8 product[ATA_ID_PROD_LEN + 1] = { 0 };
|
|
|
- u16 *id;
|
|
|
- u64 n_sectors;
|
|
|
struct ahci_uc_priv *uc_priv = sata_dev_desc[dev].priv;
|
|
|
- u8 port = uc_priv->hard_port_no;
|
|
|
struct blk_desc *pdev = &sata_dev_desc[dev];
|
|
|
|
|
|
- id = (u16 *)memalign(ARCH_DMA_MINALIGN,
|
|
|
- roundup(ARCH_DMA_MINALIGN,
|
|
|
- (ATA_ID_WORDS * 2)));
|
|
|
- if (!id) {
|
|
|
- printf("id malloc failed\n\r");
|
|
|
- return -1;
|
|
|
- }
|
|
|
-
|
|
|
- /* Identify device to get information */
|
|
|
- dwc_ahsata_identify(uc_priv, id);
|
|
|
-
|
|
|
- /* Serial number */
|
|
|
- ata_id_c_string(id, serial, ATA_ID_SERNO, sizeof(serial));
|
|
|
- memcpy(pdev->product, serial, sizeof(serial));
|
|
|
-
|
|
|
- /* Firmware version */
|
|
|
- ata_id_c_string(id, firmware, ATA_ID_FW_REV, sizeof(firmware));
|
|
|
- memcpy(pdev->revision, firmware, sizeof(firmware));
|
|
|
-
|
|
|
- /* Product model */
|
|
|
- ata_id_c_string(id, product, ATA_ID_PROD, sizeof(product));
|
|
|
- memcpy(pdev->vendor, product, sizeof(product));
|
|
|
-
|
|
|
- /* Totoal sectors */
|
|
|
- n_sectors = ata_id_n_sectors(id);
|
|
|
- pdev->lba = (u32)n_sectors;
|
|
|
-
|
|
|
- pdev->type = DEV_TYPE_HARDDISK;
|
|
|
- pdev->blksz = ATA_SECT_SIZE;
|
|
|
- pdev->lun = 0 ;
|
|
|
-
|
|
|
- /* Check if support LBA48 */
|
|
|
- if (ata_id_has_lba48(id)) {
|
|
|
- pdev->lba48 = 1;
|
|
|
- debug("Device support LBA48\n\r");
|
|
|
- }
|
|
|
-
|
|
|
- /* Get the NCQ queue depth from device */
|
|
|
- uc_priv->flags &= (~SATA_FLAG_Q_DEP_MASK);
|
|
|
- uc_priv->flags |= ata_id_queue_depth(id);
|
|
|
-
|
|
|
- /* Get the xfer mode from device */
|
|
|
- dwc_ahsata_xfer_mode(uc_priv, id);
|
|
|
-
|
|
|
- /* Get the write cache status from device */
|
|
|
- dwc_ahsata_init_wcache(uc_priv, id);
|
|
|
-
|
|
|
- /* Set the xfer mode to highest speed */
|
|
|
- ahci_set_feature(uc_priv, port);
|
|
|
-
|
|
|
- free((void *)id);
|
|
|
-
|
|
|
- dwc_ahsata_print_info(&sata_dev_desc[dev]);
|
|
|
-
|
|
|
- return 0;
|
|
|
+ return dwc_ahsata_scan_common(uc_priv, pdev);
|
|
|
}
|