|
@@ -158,6 +158,9 @@ enum {
|
|
PHY_MODE3 = 0x310,
|
|
PHY_MODE3 = 0x310,
|
|
PHY_MODE4 = 0x314,
|
|
PHY_MODE4 = 0x314,
|
|
PHY_MODE2 = 0x330,
|
|
PHY_MODE2 = 0x330,
|
|
|
|
+ MV5_PHY_MODE = 0x74,
|
|
|
|
+ MV5_LT_MODE = 0x30,
|
|
|
|
+ MV5_PHY_CTL = 0x0C,
|
|
SATA_INTERFACE_CTL = 0x050,
|
|
SATA_INTERFACE_CTL = 0x050,
|
|
|
|
|
|
MV_M2_PREAMP_MASK = 0x7e0,
|
|
MV_M2_PREAMP_MASK = 0x7e0,
|
|
@@ -214,6 +217,7 @@ enum {
|
|
EDMA_DS = (1 << 1),
|
|
EDMA_DS = (1 << 1),
|
|
ATA_RST = (1 << 2),
|
|
ATA_RST = (1 << 2),
|
|
|
|
|
|
|
|
+ EDMA_IORDY_TMOUT = 0x34,
|
|
EDMA_ARB_CFG = 0x38,
|
|
EDMA_ARB_CFG = 0x38,
|
|
|
|
|
|
/* Host private flags (hp_flags) */
|
|
/* Host private flags (hp_flags) */
|
|
@@ -229,6 +233,7 @@ enum {
|
|
MV_PP_FLAG_EDMA_DS_ACT = (1 << 1),
|
|
MV_PP_FLAG_EDMA_DS_ACT = (1 << 1),
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+#define IS_50XX(hpriv) ((hpriv)->hp_flags & MV_HP_50XX)
|
|
#define IS_60XX(hpriv) (((hpriv)->hp_flags & MV_HP_50XX) == 0)
|
|
#define IS_60XX(hpriv) (((hpriv)->hp_flags & MV_HP_50XX) == 0)
|
|
|
|
|
|
enum {
|
|
enum {
|
|
@@ -298,7 +303,8 @@ struct mv_hw_ops {
|
|
void (*enable_leds)(struct mv_host_priv *hpriv, void __iomem *mmio);
|
|
void (*enable_leds)(struct mv_host_priv *hpriv, void __iomem *mmio);
|
|
void (*read_preamp)(struct mv_host_priv *hpriv, int idx,
|
|
void (*read_preamp)(struct mv_host_priv *hpriv, int idx,
|
|
void __iomem *mmio);
|
|
void __iomem *mmio);
|
|
- int (*reset_hc)(struct mv_host_priv *hpriv, void __iomem *mmio);
|
|
|
|
|
|
+ int (*reset_hc)(struct mv_host_priv *hpriv, void __iomem *mmio,
|
|
|
|
+ unsigned int n_hc);
|
|
void (*reset_flash)(struct mv_host_priv *hpriv, void __iomem *mmio);
|
|
void (*reset_flash)(struct mv_host_priv *hpriv, void __iomem *mmio);
|
|
void (*reset_bus)(struct pci_dev *pdev, void __iomem *mmio);
|
|
void (*reset_bus)(struct pci_dev *pdev, void __iomem *mmio);
|
|
};
|
|
};
|
|
@@ -312,6 +318,8 @@ struct mv_host_priv {
|
|
static void mv_irq_clear(struct ata_port *ap);
|
|
static void mv_irq_clear(struct ata_port *ap);
|
|
static u32 mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in);
|
|
static u32 mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in);
|
|
static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
|
|
static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
|
|
|
|
+static u32 mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in);
|
|
|
|
+static void mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
|
|
static void mv_phy_reset(struct ata_port *ap);
|
|
static void mv_phy_reset(struct ata_port *ap);
|
|
static void mv_host_stop(struct ata_host_set *host_set);
|
|
static void mv_host_stop(struct ata_host_set *host_set);
|
|
static int mv_port_start(struct ata_port *ap);
|
|
static int mv_port_start(struct ata_port *ap);
|
|
@@ -328,7 +336,8 @@ static void mv5_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
|
|
static void mv5_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio);
|
|
static void mv5_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio);
|
|
static void mv5_read_preamp(struct mv_host_priv *hpriv, int idx,
|
|
static void mv5_read_preamp(struct mv_host_priv *hpriv, int idx,
|
|
void __iomem *mmio);
|
|
void __iomem *mmio);
|
|
-static int mv5_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio);
|
|
|
|
|
|
+static int mv5_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
|
|
|
|
+ unsigned int n_hc);
|
|
static void mv5_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio);
|
|
static void mv5_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio);
|
|
static void mv5_reset_bus(struct pci_dev *pdev, void __iomem *mmio);
|
|
static void mv5_reset_bus(struct pci_dev *pdev, void __iomem *mmio);
|
|
|
|
|
|
@@ -337,9 +346,13 @@ static void mv6_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
|
|
static void mv6_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio);
|
|
static void mv6_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio);
|
|
static void mv6_read_preamp(struct mv_host_priv *hpriv, int idx,
|
|
static void mv6_read_preamp(struct mv_host_priv *hpriv, int idx,
|
|
void __iomem *mmio);
|
|
void __iomem *mmio);
|
|
-static int mv6_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio);
|
|
|
|
|
|
+static int mv6_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
|
|
|
|
+ unsigned int n_hc);
|
|
static void mv6_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio);
|
|
static void mv6_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio);
|
|
static void mv_reset_pci_bus(struct pci_dev *pdev, void __iomem *mmio);
|
|
static void mv_reset_pci_bus(struct pci_dev *pdev, void __iomem *mmio);
|
|
|
|
+static void mv_channel_reset(struct mv_host_priv *hpriv, void __iomem *mmio,
|
|
|
|
+ unsigned int port_no);
|
|
|
|
+static void mv_stop_and_reset(struct ata_port *ap);
|
|
|
|
|
|
static struct scsi_host_template mv_sht = {
|
|
static struct scsi_host_template mv_sht = {
|
|
.module = THIS_MODULE,
|
|
.module = THIS_MODULE,
|
|
@@ -361,7 +374,34 @@ static struct scsi_host_template mv_sht = {
|
|
.ordered_flush = 1,
|
|
.ordered_flush = 1,
|
|
};
|
|
};
|
|
|
|
|
|
-static const struct ata_port_operations mv_ops = {
|
|
|
|
|
|
+static const struct ata_port_operations mv5_ops = {
|
|
|
|
+ .port_disable = ata_port_disable,
|
|
|
|
+
|
|
|
|
+ .tf_load = ata_tf_load,
|
|
|
|
+ .tf_read = ata_tf_read,
|
|
|
|
+ .check_status = ata_check_status,
|
|
|
|
+ .exec_command = ata_exec_command,
|
|
|
|
+ .dev_select = ata_std_dev_select,
|
|
|
|
+
|
|
|
|
+ .phy_reset = mv_phy_reset,
|
|
|
|
+
|
|
|
|
+ .qc_prep = mv_qc_prep,
|
|
|
|
+ .qc_issue = mv_qc_issue,
|
|
|
|
+
|
|
|
|
+ .eng_timeout = mv_eng_timeout,
|
|
|
|
+
|
|
|
|
+ .irq_handler = mv_interrupt,
|
|
|
|
+ .irq_clear = mv_irq_clear,
|
|
|
|
+
|
|
|
|
+ .scr_read = mv5_scr_read,
|
|
|
|
+ .scr_write = mv5_scr_write,
|
|
|
|
+
|
|
|
|
+ .port_start = mv_port_start,
|
|
|
|
+ .port_stop = mv_port_stop,
|
|
|
|
+ .host_stop = mv_host_stop,
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static const struct ata_port_operations mv6_ops = {
|
|
.port_disable = ata_port_disable,
|
|
.port_disable = ata_port_disable,
|
|
|
|
|
|
.tf_load = ata_tf_load,
|
|
.tf_load = ata_tf_load,
|
|
@@ -393,29 +433,29 @@ static struct ata_port_info mv_port_info[] = {
|
|
.sht = &mv_sht,
|
|
.sht = &mv_sht,
|
|
.host_flags = MV_COMMON_FLAGS,
|
|
.host_flags = MV_COMMON_FLAGS,
|
|
.pio_mask = 0x1f, /* pio0-4 */
|
|
.pio_mask = 0x1f, /* pio0-4 */
|
|
- .udma_mask = 0, /* 0x7f (udma0-6 disabled for now) */
|
|
|
|
- .port_ops = &mv_ops,
|
|
|
|
|
|
+ .udma_mask = 0x7f, /* udma0-6 */
|
|
|
|
+ .port_ops = &mv5_ops,
|
|
},
|
|
},
|
|
{ /* chip_508x */
|
|
{ /* chip_508x */
|
|
.sht = &mv_sht,
|
|
.sht = &mv_sht,
|
|
.host_flags = (MV_COMMON_FLAGS | MV_FLAG_DUAL_HC),
|
|
.host_flags = (MV_COMMON_FLAGS | MV_FLAG_DUAL_HC),
|
|
.pio_mask = 0x1f, /* pio0-4 */
|
|
.pio_mask = 0x1f, /* pio0-4 */
|
|
- .udma_mask = 0, /* 0x7f (udma0-6 disabled for now) */
|
|
|
|
- .port_ops = &mv_ops,
|
|
|
|
|
|
+ .udma_mask = 0x7f, /* udma0-6 */
|
|
|
|
+ .port_ops = &mv5_ops,
|
|
},
|
|
},
|
|
{ /* chip_5080 */
|
|
{ /* chip_5080 */
|
|
.sht = &mv_sht,
|
|
.sht = &mv_sht,
|
|
.host_flags = (MV_COMMON_FLAGS | MV_FLAG_DUAL_HC),
|
|
.host_flags = (MV_COMMON_FLAGS | MV_FLAG_DUAL_HC),
|
|
.pio_mask = 0x1f, /* pio0-4 */
|
|
.pio_mask = 0x1f, /* pio0-4 */
|
|
- .udma_mask = 0, /* 0x7f (udma0-6 disabled for now) */
|
|
|
|
- .port_ops = &mv_ops,
|
|
|
|
|
|
+ .udma_mask = 0x7f, /* udma0-6 */
|
|
|
|
+ .port_ops = &mv5_ops,
|
|
},
|
|
},
|
|
{ /* chip_604x */
|
|
{ /* chip_604x */
|
|
.sht = &mv_sht,
|
|
.sht = &mv_sht,
|
|
.host_flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS),
|
|
.host_flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS),
|
|
.pio_mask = 0x1f, /* pio0-4 */
|
|
.pio_mask = 0x1f, /* pio0-4 */
|
|
.udma_mask = 0x7f, /* udma0-6 */
|
|
.udma_mask = 0x7f, /* udma0-6 */
|
|
- .port_ops = &mv_ops,
|
|
|
|
|
|
+ .port_ops = &mv6_ops,
|
|
},
|
|
},
|
|
{ /* chip_608x */
|
|
{ /* chip_608x */
|
|
.sht = &mv_sht,
|
|
.sht = &mv_sht,
|
|
@@ -423,17 +463,15 @@ static struct ata_port_info mv_port_info[] = {
|
|
MV_FLAG_DUAL_HC),
|
|
MV_FLAG_DUAL_HC),
|
|
.pio_mask = 0x1f, /* pio0-4 */
|
|
.pio_mask = 0x1f, /* pio0-4 */
|
|
.udma_mask = 0x7f, /* udma0-6 */
|
|
.udma_mask = 0x7f, /* udma0-6 */
|
|
- .port_ops = &mv_ops,
|
|
|
|
|
|
+ .port_ops = &mv6_ops,
|
|
},
|
|
},
|
|
};
|
|
};
|
|
|
|
|
|
static const struct pci_device_id mv_pci_tbl[] = {
|
|
static const struct pci_device_id mv_pci_tbl[] = {
|
|
-#if 0 /* unusably broken right now */
|
|
|
|
{PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5040), 0, 0, chip_504x},
|
|
{PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5040), 0, 0, chip_504x},
|
|
{PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5041), 0, 0, chip_504x},
|
|
{PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5041), 0, 0, chip_504x},
|
|
{PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5080), 0, 0, chip_5080},
|
|
{PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5080), 0, 0, chip_5080},
|
|
{PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5081), 0, 0, chip_508x},
|
|
{PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5081), 0, 0, chip_508x},
|
|
-#endif
|
|
|
|
|
|
|
|
{PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6040), 0, 0, chip_604x},
|
|
{PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6040), 0, 0, chip_604x},
|
|
{PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6041), 0, 0, chip_604x},
|
|
{PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6041), 0, 0, chip_604x},
|
|
@@ -484,11 +522,27 @@ static inline void __iomem *mv_hc_base(void __iomem *base, unsigned int hc)
|
|
return (base + MV_SATAHC0_REG_BASE + (hc * MV_SATAHC_REG_SZ));
|
|
return (base + MV_SATAHC0_REG_BASE + (hc * MV_SATAHC_REG_SZ));
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static inline unsigned int mv_hc_from_port(unsigned int port)
|
|
|
|
+{
|
|
|
|
+ return port >> MV_PORT_HC_SHIFT;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static inline unsigned int mv_hardport_from_port(unsigned int port)
|
|
|
|
+{
|
|
|
|
+ return port & MV_PORT_MASK;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static inline void __iomem *mv_hc_base_from_port(void __iomem *base,
|
|
|
|
+ unsigned int port)
|
|
|
|
+{
|
|
|
|
+ return mv_hc_base(base, mv_hc_from_port(port));
|
|
|
|
+}
|
|
|
|
+
|
|
static inline void __iomem *mv_port_base(void __iomem *base, unsigned int port)
|
|
static inline void __iomem *mv_port_base(void __iomem *base, unsigned int port)
|
|
{
|
|
{
|
|
- return (mv_hc_base(base, port >> MV_PORT_HC_SHIFT) +
|
|
|
|
|
|
+ return mv_hc_base_from_port(base, port) +
|
|
MV_SATAHC_ARBTR_REG_SZ +
|
|
MV_SATAHC_ARBTR_REG_SZ +
|
|
- ((port & MV_PORT_MASK) * MV_PORT_REG_SZ));
|
|
|
|
|
|
+ (mv_hardport_from_port(port) * MV_PORT_REG_SZ);
|
|
}
|
|
}
|
|
|
|
|
|
static inline void __iomem *mv_ap_base(struct ata_port *ap)
|
|
static inline void __iomem *mv_ap_base(struct ata_port *ap)
|
|
@@ -1089,7 +1143,7 @@ static void mv_err_intr(struct ata_port *ap)
|
|
|
|
|
|
/* check for fatal here and recover if needed */
|
|
/* check for fatal here and recover if needed */
|
|
if (EDMA_ERR_FATAL & edma_err_cause) {
|
|
if (EDMA_ERR_FATAL & edma_err_cause) {
|
|
- mv_phy_reset(ap);
|
|
|
|
|
|
+ mv_stop_and_reset(ap);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1236,6 +1290,51 @@ static irqreturn_t mv_interrupt(int irq, void *dev_instance,
|
|
return IRQ_RETVAL(handled);
|
|
return IRQ_RETVAL(handled);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static void __iomem *mv5_phy_base(void __iomem *mmio, unsigned int port)
|
|
|
|
+{
|
|
|
|
+ void __iomem *hc_mmio = mv_hc_base_from_port(mmio, port);
|
|
|
|
+ unsigned long ofs = (mv_hardport_from_port(port) + 1) * 0x100UL;
|
|
|
|
+
|
|
|
|
+ return hc_mmio + ofs;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static unsigned int mv5_scr_offset(unsigned int sc_reg_in)
|
|
|
|
+{
|
|
|
|
+ unsigned int ofs;
|
|
|
|
+
|
|
|
|
+ switch (sc_reg_in) {
|
|
|
|
+ case SCR_STATUS:
|
|
|
|
+ case SCR_ERROR:
|
|
|
|
+ case SCR_CONTROL:
|
|
|
|
+ ofs = sc_reg_in * sizeof(u32);
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ ofs = 0xffffffffU;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ return ofs;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static u32 mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in)
|
|
|
|
+{
|
|
|
|
+ void __iomem *mmio = mv5_phy_base(ap->host_set->mmio_base, ap->port_no);
|
|
|
|
+ unsigned int ofs = mv5_scr_offset(sc_reg_in);
|
|
|
|
+
|
|
|
|
+ if (ofs != 0xffffffffU)
|
|
|
|
+ return readl(mmio + ofs);
|
|
|
|
+ else
|
|
|
|
+ return (u32) ofs;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
|
|
|
|
+{
|
|
|
|
+ void __iomem *mmio = mv5_phy_base(ap->host_set->mmio_base, ap->port_no);
|
|
|
|
+ unsigned int ofs = mv5_scr_offset(sc_reg_in);
|
|
|
|
+
|
|
|
|
+ if (ofs != 0xffffffffU)
|
|
|
|
+ writelfl(val, mmio + ofs);
|
|
|
|
+}
|
|
|
|
+
|
|
static void mv5_reset_bus(struct pci_dev *pdev, void __iomem *mmio)
|
|
static void mv5_reset_bus(struct pci_dev *pdev, void __iomem *mmio)
|
|
{
|
|
{
|
|
u8 rev_id;
|
|
u8 rev_id;
|
|
@@ -1262,7 +1361,13 @@ static void mv5_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio)
|
|
static void mv5_read_preamp(struct mv_host_priv *hpriv, int idx,
|
|
static void mv5_read_preamp(struct mv_host_priv *hpriv, int idx,
|
|
void __iomem *mmio)
|
|
void __iomem *mmio)
|
|
{
|
|
{
|
|
- /* FIXME */
|
|
|
|
|
|
+ void __iomem *phy_mmio = mv5_phy_base(mmio, idx);
|
|
|
|
+ u32 tmp;
|
|
|
|
+
|
|
|
|
+ tmp = readl(phy_mmio + MV5_PHY_MODE);
|
|
|
|
+
|
|
|
|
+ hpriv->signal[idx].pre = tmp & 0x1800; /* bits 12:11 */
|
|
|
|
+ hpriv->signal[idx].amps = tmp & 0xe0; /* bits 7:5 */
|
|
}
|
|
}
|
|
|
|
|
|
static void mv5_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio)
|
|
static void mv5_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio)
|
|
@@ -1281,13 +1386,90 @@ static void mv5_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio)
|
|
static void mv5_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
|
|
static void mv5_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
|
|
unsigned int port)
|
|
unsigned int port)
|
|
{
|
|
{
|
|
- /* FIXME */
|
|
|
|
|
|
+ void __iomem *phy_mmio = mv5_phy_base(mmio, port);
|
|
|
|
+ const u32 mask = (1<<12) | (1<<11) | (1<<7) | (1<<6) | (1<<5);
|
|
|
|
+ u32 tmp;
|
|
|
|
+ int fix_apm_sq = (hpriv->hp_flags & MV_HP_ERRATA_50XXB0);
|
|
|
|
+
|
|
|
|
+ if (fix_apm_sq) {
|
|
|
|
+ tmp = readl(phy_mmio + MV5_LT_MODE);
|
|
|
|
+ tmp |= (1 << 19);
|
|
|
|
+ writel(tmp, phy_mmio + MV5_LT_MODE);
|
|
|
|
+
|
|
|
|
+ tmp = readl(phy_mmio + MV5_PHY_CTL);
|
|
|
|
+ tmp &= ~0x3;
|
|
|
|
+ tmp |= 0x1;
|
|
|
|
+ writel(tmp, phy_mmio + MV5_PHY_CTL);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ tmp = readl(phy_mmio + MV5_PHY_MODE);
|
|
|
|
+ tmp &= ~mask;
|
|
|
|
+ tmp |= hpriv->signal[port].pre;
|
|
|
|
+ tmp |= hpriv->signal[port].amps;
|
|
|
|
+ writel(tmp, phy_mmio + MV5_PHY_MODE);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+#undef ZERO
|
|
|
|
+#define ZERO(reg) writel(0, port_mmio + (reg))
|
|
|
|
+static void mv5_reset_hc_port(struct mv_host_priv *hpriv, void __iomem *mmio,
|
|
|
|
+ unsigned int port)
|
|
|
|
+{
|
|
|
|
+ void __iomem *port_mmio = mv_port_base(mmio, port);
|
|
|
|
+
|
|
|
|
+ writelfl(EDMA_DS, port_mmio + EDMA_CMD_OFS);
|
|
|
|
+
|
|
|
|
+ mv_channel_reset(hpriv, mmio, port);
|
|
|
|
+
|
|
|
|
+ ZERO(0x028); /* command */
|
|
|
|
+ writel(0x11f, port_mmio + EDMA_CFG_OFS);
|
|
|
|
+ ZERO(0x004); /* timer */
|
|
|
|
+ ZERO(0x008); /* irq err cause */
|
|
|
|
+ ZERO(0x00c); /* irq err mask */
|
|
|
|
+ ZERO(0x010); /* rq bah */
|
|
|
|
+ ZERO(0x014); /* rq inp */
|
|
|
|
+ ZERO(0x018); /* rq outp */
|
|
|
|
+ ZERO(0x01c); /* respq bah */
|
|
|
|
+ ZERO(0x024); /* respq outp */
|
|
|
|
+ ZERO(0x020); /* respq inp */
|
|
|
|
+ ZERO(0x02c); /* test control */
|
|
|
|
+ writel(0xbc, port_mmio + EDMA_IORDY_TMOUT);
|
|
}
|
|
}
|
|
|
|
+#undef ZERO
|
|
|
|
|
|
-static int mv5_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio)
|
|
|
|
|
|
+#define ZERO(reg) writel(0, hc_mmio + (reg))
|
|
|
|
+static void mv5_reset_one_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
|
|
|
|
+ unsigned int hc)
|
|
{
|
|
{
|
|
- /* FIXME */
|
|
|
|
- return 1;
|
|
|
|
|
|
+ void __iomem *hc_mmio = mv_hc_base(mmio, hc);
|
|
|
|
+ u32 tmp;
|
|
|
|
+
|
|
|
|
+ ZERO(0x00c);
|
|
|
|
+ ZERO(0x010);
|
|
|
|
+ ZERO(0x014);
|
|
|
|
+ ZERO(0x018);
|
|
|
|
+
|
|
|
|
+ tmp = readl(hc_mmio + 0x20);
|
|
|
|
+ tmp &= 0x1c1c1c1c;
|
|
|
|
+ tmp |= 0x03030303;
|
|
|
|
+ writel(tmp, hc_mmio + 0x20);
|
|
|
|
+}
|
|
|
|
+#undef ZERO
|
|
|
|
+
|
|
|
|
+static int mv5_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
|
|
|
|
+ unsigned int n_hc)
|
|
|
|
+{
|
|
|
|
+ unsigned int hc, port;
|
|
|
|
+
|
|
|
|
+ for (hc = 0; hc < n_hc; hc++) {
|
|
|
|
+ for (port = 0; port < MV_PORTS_PER_HC; port++)
|
|
|
|
+ mv5_reset_hc_port(hpriv, mmio,
|
|
|
|
+ (hc * MV_PORTS_PER_HC) + port);
|
|
|
|
+
|
|
|
|
+ mv5_reset_one_hc(hpriv, mmio, hc);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
}
|
|
}
|
|
|
|
|
|
#undef ZERO
|
|
#undef ZERO
|
|
@@ -1335,7 +1517,8 @@ static void mv6_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio)
|
|
* LOCKING:
|
|
* LOCKING:
|
|
* Inherited from caller.
|
|
* Inherited from caller.
|
|
*/
|
|
*/
|
|
-static int mv6_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio)
|
|
|
|
|
|
+static int mv6_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
|
|
|
|
+ unsigned int n_hc)
|
|
{
|
|
{
|
|
void __iomem *reg = mmio + PCI_MAIN_CMD_STS_OFS;
|
|
void __iomem *reg = mmio + PCI_MAIN_CMD_STS_OFS;
|
|
int i, rc = 0;
|
|
int i, rc = 0;
|
|
@@ -1415,9 +1598,11 @@ static void mv6_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio)
|
|
writel(0x00000060, mmio + MV_GPIO_PORT_CTL);
|
|
writel(0x00000060, mmio + MV_GPIO_PORT_CTL);
|
|
}
|
|
}
|
|
|
|
|
|
-static void mv6_phy_errata(struct mv_host_priv *hpriv, void __iomem *port_mmio,
|
|
|
|
|
|
+static void mv6_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
|
|
unsigned int port)
|
|
unsigned int port)
|
|
{
|
|
{
|
|
|
|
+ void __iomem *port_mmio = mv_port_base(mmio, port);
|
|
|
|
+
|
|
u32 hp_flags = hpriv->hp_flags;
|
|
u32 hp_flags = hpriv->hp_flags;
|
|
int fix_phy_mode2 =
|
|
int fix_phy_mode2 =
|
|
hp_flags & (MV_HP_ERRATA_60X1B2 | MV_HP_ERRATA_60X1C0);
|
|
hp_flags & (MV_HP_ERRATA_60X1B2 | MV_HP_ERRATA_60X1C0);
|
|
@@ -1473,6 +1658,44 @@ static void mv6_phy_errata(struct mv_host_priv *hpriv, void __iomem *port_mmio,
|
|
writel(m2, port_mmio + PHY_MODE2);
|
|
writel(m2, port_mmio + PHY_MODE2);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static void mv_channel_reset(struct mv_host_priv *hpriv, void __iomem *mmio,
|
|
|
|
+ unsigned int port_no)
|
|
|
|
+{
|
|
|
|
+ void __iomem *port_mmio = mv_port_base(mmio, port_no);
|
|
|
|
+
|
|
|
|
+ writelfl(ATA_RST, port_mmio + EDMA_CMD_OFS);
|
|
|
|
+
|
|
|
|
+ if (IS_60XX(hpriv)) {
|
|
|
|
+ u32 ifctl = readl(port_mmio + SATA_INTERFACE_CTL);
|
|
|
|
+ ifctl |= (1 << 12) | (1 << 7);
|
|
|
|
+ writelfl(ifctl, port_mmio + SATA_INTERFACE_CTL);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ udelay(25); /* allow reset propagation */
|
|
|
|
+
|
|
|
|
+ /* Spec never mentions clearing the bit. Marvell's driver does
|
|
|
|
+ * clear the bit, however.
|
|
|
|
+ */
|
|
|
|
+ writelfl(0, port_mmio + EDMA_CMD_OFS);
|
|
|
|
+
|
|
|
|
+ hpriv->ops->phy_errata(hpriv, mmio, port_no);
|
|
|
|
+
|
|
|
|
+ if (IS_50XX(hpriv))
|
|
|
|
+ mdelay(1);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void mv_stop_and_reset(struct ata_port *ap)
|
|
|
|
+{
|
|
|
|
+ struct mv_host_priv *hpriv = ap->host_set->private_data;
|
|
|
|
+ void __iomem *mmio = ap->host_set->mmio_base;
|
|
|
|
+
|
|
|
|
+ mv_stop_dma(ap);
|
|
|
|
+
|
|
|
|
+ mv_channel_reset(hpriv, mmio, ap->port_no);
|
|
|
|
+
|
|
|
|
+ mv_phy_reset(ap);
|
|
|
|
+}
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* mv_phy_reset - Perform eDMA reset followed by COMRESET
|
|
* mv_phy_reset - Perform eDMA reset followed by COMRESET
|
|
* @ap: ATA channel to manipulate
|
|
* @ap: ATA channel to manipulate
|
|
@@ -1487,7 +1710,6 @@ static void mv6_phy_errata(struct mv_host_priv *hpriv, void __iomem *port_mmio,
|
|
static void mv_phy_reset(struct ata_port *ap)
|
|
static void mv_phy_reset(struct ata_port *ap)
|
|
{
|
|
{
|
|
struct mv_port_priv *pp = ap->private_data;
|
|
struct mv_port_priv *pp = ap->private_data;
|
|
- struct mv_host_priv *hpriv = ap->host_set->private_data;
|
|
|
|
void __iomem *port_mmio = mv_ap_base(ap);
|
|
void __iomem *port_mmio = mv_ap_base(ap);
|
|
struct ata_taskfile tf;
|
|
struct ata_taskfile tf;
|
|
struct ata_device *dev = &ap->device[0];
|
|
struct ata_device *dev = &ap->device[0];
|
|
@@ -1495,25 +1717,6 @@ static void mv_phy_reset(struct ata_port *ap)
|
|
|
|
|
|
VPRINTK("ENTER, port %u, mmio 0x%p\n", ap->port_no, port_mmio);
|
|
VPRINTK("ENTER, port %u, mmio 0x%p\n", ap->port_no, port_mmio);
|
|
|
|
|
|
- mv_stop_dma(ap);
|
|
|
|
-
|
|
|
|
- writelfl(ATA_RST, port_mmio + EDMA_CMD_OFS);
|
|
|
|
-
|
|
|
|
- if (IS_60XX(hpriv)) {
|
|
|
|
- u32 ifctl = readl(port_mmio + SATA_INTERFACE_CTL);
|
|
|
|
- ifctl |= (1 << 12) | (1 << 7);
|
|
|
|
- writelfl(ifctl, port_mmio + SATA_INTERFACE_CTL);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- udelay(25); /* allow reset propagation */
|
|
|
|
-
|
|
|
|
- /* Spec never mentions clearing the bit. Marvell's driver does
|
|
|
|
- * clear the bit, however.
|
|
|
|
- */
|
|
|
|
- writelfl(0, port_mmio + EDMA_CMD_OFS);
|
|
|
|
-
|
|
|
|
- hpriv->ops->phy_errata(hpriv, port_mmio, ap->port_no);
|
|
|
|
-
|
|
|
|
DPRINTK("S-regs after ATA_RST: SStat 0x%08x SErr 0x%08x "
|
|
DPRINTK("S-regs after ATA_RST: SStat 0x%08x SErr 0x%08x "
|
|
"SCtrl 0x%08x\n", mv_scr_read(ap, SCR_STATUS),
|
|
"SCtrl 0x%08x\n", mv_scr_read(ap, SCR_STATUS),
|
|
mv_scr_read(ap, SCR_ERROR), mv_scr_read(ap, SCR_CONTROL));
|
|
mv_scr_read(ap, SCR_ERROR), mv_scr_read(ap, SCR_CONTROL));
|
|
@@ -1589,7 +1792,7 @@ static void mv_eng_timeout(struct ata_port *ap)
|
|
&qc->scsicmd->cmnd);
|
|
&qc->scsicmd->cmnd);
|
|
|
|
|
|
mv_err_intr(ap);
|
|
mv_err_intr(ap);
|
|
- mv_phy_reset(ap);
|
|
|
|
|
|
+ mv_stop_and_reset(ap);
|
|
|
|
|
|
if (!qc) {
|
|
if (!qc) {
|
|
printk(KERN_ERR "ata%u: BUG: timeout without command\n",
|
|
printk(KERN_ERR "ata%u: BUG: timeout without command\n",
|
|
@@ -1765,7 +1968,7 @@ static int mv_init_host(struct pci_dev *pdev, struct ata_probe_ent *probe_ent,
|
|
for (port = 0; port < probe_ent->n_ports; port++)
|
|
for (port = 0; port < probe_ent->n_ports; port++)
|
|
hpriv->ops->read_preamp(hpriv, port, mmio);
|
|
hpriv->ops->read_preamp(hpriv, port, mmio);
|
|
|
|
|
|
- rc = hpriv->ops->reset_hc(hpriv, mmio);
|
|
|
|
|
|
+ rc = hpriv->ops->reset_hc(hpriv, mmio, n_hc);
|
|
if (rc)
|
|
if (rc)
|
|
goto done;
|
|
goto done;
|
|
|
|
|
|
@@ -1774,15 +1977,15 @@ static int mv_init_host(struct pci_dev *pdev, struct ata_probe_ent *probe_ent,
|
|
hpriv->ops->enable_leds(hpriv, mmio);
|
|
hpriv->ops->enable_leds(hpriv, mmio);
|
|
|
|
|
|
for (port = 0; port < probe_ent->n_ports; port++) {
|
|
for (port = 0; port < probe_ent->n_ports; port++) {
|
|
- void __iomem *port_mmio = mv_port_base(mmio, port);
|
|
|
|
-
|
|
|
|
if (IS_60XX(hpriv)) {
|
|
if (IS_60XX(hpriv)) {
|
|
|
|
+ void __iomem *port_mmio = mv_port_base(mmio, port);
|
|
|
|
+
|
|
u32 ifctl = readl(port_mmio + SATA_INTERFACE_CTL);
|
|
u32 ifctl = readl(port_mmio + SATA_INTERFACE_CTL);
|
|
ifctl |= (1 << 12);
|
|
ifctl |= (1 << 12);
|
|
writelfl(ifctl, port_mmio + SATA_INTERFACE_CTL);
|
|
writelfl(ifctl, port_mmio + SATA_INTERFACE_CTL);
|
|
}
|
|
}
|
|
|
|
|
|
- hpriv->ops->phy_errata(hpriv, port_mmio, port);
|
|
|
|
|
|
+ hpriv->ops->phy_errata(hpriv, mmio, port);
|
|
}
|
|
}
|
|
|
|
|
|
for (port = 0; port < probe_ent->n_ports; port++) {
|
|
for (port = 0; port < probe_ent->n_ports; port++) {
|