/*
- * Copyright (C) 2008 Freescale Semiconductor, Inc.
+ * Copyright (C) 2008,2010 Freescale Semiconductor, Inc.
* Dave Liu <daveliu@freescale.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 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
+ * SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <command.h>
+#include <console.h>
#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/fsl_serdes.h>
#include <malloc.h>
#include <libata.h>
#include <fis.h>
+#include <sata.h>
#include "fsl_sata.h"
-extern block_dev_desc_t sata_dev_desc[CFG_SATA_MAX_DEVICE];
-
-#ifndef CFG_SATA1_FLAGS
- #define CFG_SATA1_FLAGS FLAGS_DMA
+#ifndef CONFIG_SYS_SATA1_FLAGS
+ #define CONFIG_SYS_SATA1_FLAGS FLAGS_DMA
#endif
-#ifndef CFG_SATA2_FLAGS
- #define CFG_SATA2_FLAGS FLAGS_DMA
+#ifndef CONFIG_SYS_SATA2_FLAGS
+ #define CONFIG_SYS_SATA2_FLAGS FLAGS_DMA
#endif
static struct fsl_sata_info fsl_sata_info[] = {
#ifdef CONFIG_SATA1
- {CFG_SATA1, CFG_SATA1_FLAGS},
+ {CONFIG_SYS_SATA1, CONFIG_SYS_SATA1_FLAGS},
#else
{0, 0},
#endif
#ifdef CONFIG_SATA2
- {CFG_SATA2, CFG_SATA2_FLAGS},
+ {CONFIG_SYS_SATA2, CONFIG_SYS_SATA2_FLAGS},
#else
{0, 0},
#endif
};
-static inline void mdelay(unsigned long msec)
-{
- unsigned long i;
- for (i = 0; i < msec; i++)
- udelay(1000);
-}
-
static inline void sdelay(unsigned long sec)
{
unsigned long i;
mdelay(1000);
}
-void dprint_buffer(unsigned char *buf, int len)
-{
- int i, j;
-
- i = 0;
- j = 0;
- printf("\n\r");
-
- for (i = 0; i < len; i++) {
- printf("%02x ", *buf++);
- j++;
- if (j == 16) {
- printf("\n\r");
- j = 0;
- }
- }
- printf("\n\r");
-}
-
-static void fsl_sata_dump_sfis(struct sfis *s)
+static void fsl_sata_dump_sfis(struct sata_fis_d2h *s)
{
printf("Status FIS dump:\n\r");
printf("fis_type: %02x\n\r", s->fis_type);
printf("sector_count_exp: %02x\n\r", s->sector_count_exp);
}
-static int ata_wait_register(volatile unsigned *addr, u32 mask,
+static int ata_wait_register(unsigned __iomem *addr, u32 mask,
u32 val, u32 timeout_msec)
{
int i;
cmd_hdr_tbl_t *cmd_hdr;
u32 cda;
u32 val32;
- fsl_sata_reg_t *reg;
+ fsl_sata_reg_t __iomem *reg;
u32 sig;
int i;
fsl_sata_t *sata;
- if (dev < 0 || dev > (CFG_SATA_MAX_DEVICE - 1)) {
+ if (dev < 0 || dev > (CONFIG_SYS_SATA_MAX_DEVICE - 1)) {
printf("the sata index %d is out of ranges\n\r", dev);
return -1;
}
+#ifdef CONFIG_MPC85xx
+ if ((dev == 0) && (!is_serdes_configured(SATA1))) {
+ printf("SATA%d [dev = %d] is not enabled\n", dev+1, dev);
+ return -1;
+ }
+ if ((dev == 1) && (!is_serdes_configured(SATA2))) {
+ printf("SATA%d [dev = %d] is not enabled\n", dev+1, dev);
+ return -1;
+ }
+#endif
+
/* Allocate SATA device driver struct */
sata = (fsl_sata_t *)malloc(sizeof(fsl_sata_t));
if (!sata) {
/* Save the private struct to block device struct */
sata_dev_desc[dev].priv = (void *)sata;
- sprintf(sata->name, "SATA%d", dev);
+ snprintf(sata->name, 12, "SATA%d", dev);
/* Set the controller register base address to device struct */
reg = (fsl_sata_reg_t *)(fsl_sata_info[dev].sata_reg_base);
length = sizeof(struct cmd_hdr_tbl);
align = SATA_HC_CMD_HDR_TBL_ALIGN;
sata->cmd_hdr_tbl_offset = (void *)malloc(length + align);
- if (!sata) {
+ if (!sata->cmd_hdr_tbl_offset) {
printf("alloc the command header failed\n\r");
return -1;
}
else
printf(" %s ", sata->name);
+ /* Wait PHY RDY signal changed for 500ms */
+ ata_wait_register(®->hstatus, HSTATUS_PHY_RDY,
+ HSTATUS_PHY_RDY, 500);
+
/* Check PHYRDY */
val32 = in_le32(®->hstatus);
if (val32 & HSTATUS_PHY_RDY) {
return -1;
}
+ /* Wait for signature updated, which is 1st D2H */
+ ata_wait_register(®->hstatus, HSTATUS_SIGNATURE,
+ HSTATUS_SIGNATURE, 10000);
+
if (val32 & HSTATUS_SIGNATURE) {
sig = in_le32(®->sig);
debug("Signature updated, the sig =%08x\n\r", sig);
return 0;
}
-/* Hardware reset, like Power-on and COMRESET */
-void fsl_sata_hardware_reset(u32 reg_base)
+int reset_sata(int dev)
{
- fsl_sata_reg_t *reg = (fsl_sata_reg_t *)reg_base;
- u32 scontrol;
-
- /* Disable the SATA interface and put PHY offline */
- scontrol = in_le32(®->scontrol);
- scontrol = (scontrol & 0x0f0) | 0x304;
- out_le32(®->scontrol, scontrol);
-
- /* No speed strict */
- scontrol = in_le32(®->scontrol);
- scontrol = scontrol & ~0x0f0;
- out_le32(®->scontrol, scontrol);
-
- /* Issue PHY wake/reset, Hardware_reset_asserted */
- scontrol = in_le32(®->scontrol);
- scontrol = (scontrol & 0x0f0) | 0x301;
- out_le32(®->scontrol, scontrol);
-
- mdelay(100);
-
- /* Resume PHY, COMRESET negated, the device initialize hardware
- * and execute diagnostics, send good status-signature to host,
- * which is D2H register FIS, and then the device enter idle state.
- */
- scontrol = in_le32(®->scontrol);
- scontrol = (scontrol & 0x0f0) | 0x300;
- out_le32(®->scontrol, scontrol);
-
- mdelay(100);
- return;
+ return 0;
}
-static void fsl_sata_dump_regs(fsl_sata_reg_t *reg)
+static void fsl_sata_dump_regs(fsl_sata_reg_t __iomem *reg)
{
printf("\n\rSATA: %08x\n\r", (u32)reg);
printf("CQR: %08x\n\r", in_le32(®->cqr));
printf("SYSPR: %08x\n\r", in_be32(®->syspr));
}
-static int fsl_ata_exec_ata_cmd(struct fsl_sata *sata, struct cfis *cfis,
+static int fsl_ata_exec_ata_cmd(struct fsl_sata *sata, struct sata_fis_h2d *cfis,
int is_ncq, int tag, u8 *buffer, u32 len)
{
cmd_hdr_entry_t *cmd_hdr;
u32 prde_count;
u32 val32;
u32 ttl;
- fsl_sata_reg_t *reg = sata->reg_base;
+ fsl_sata_reg_t __iomem *reg = sata->reg_base;
int i;
/* Check xfer length */
debug("attribute = %08x\n\r", val32);
cmd_hdr->attribute = cpu_to_le32(val32);
- /* Make sure cmd desc and cmd slot valid before commmand issue */
+ /* Make sure cmd desc and cmd slot valid before command issue */
sync();
/* PMP*/
if (val32) {
u32 der;
- fsl_sata_dump_sfis((struct sfis *)cmd_desc->sfis);
+ fsl_sata_dump_sfis((struct sata_fis_d2h *)cmd_desc->sfis);
printf("CE at device\n\r");
fsl_sata_dump_regs(reg);
der = in_le32(®->der);
return len;
}
-static int fsl_ata_exec_reset_cmd(struct fsl_sata *sata, struct cfis *cfis,
+static int fsl_ata_exec_reset_cmd(struct fsl_sata *sata, struct sata_fis_h2d *cfis,
int tag, u8 *buffer, u32 len)
{
return 0;
}
-static int fsl_sata_exec_cmd(struct fsl_sata *sata, struct cfis *cfis,
+static int fsl_sata_exec_cmd(struct fsl_sata *sata, struct sata_fis_h2d *cfis,
enum cmd_type command_type, int tag, u8 *buffer, u32 len)
{
int rc;
if (tag > SATA_HC_MAX_CMD || tag < 0) {
- printf("tag is out of range, tag=\n\r", tag);
+ printf("tag is out of range, tag=%d\n\r", tag);
return -1;
}
static void fsl_sata_identify(int dev, u16 *id)
{
fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv;
- struct sata_fis_h2d h2d;
- struct cfis *cfis;
+ struct sata_fis_h2d h2d, *cfis = &h2d;
- cfis = (struct cfis *)&h2d;
- memset((void *)cfis, 0, sizeof(struct cfis));
+ memset(cfis, 0, sizeof(struct sata_fis_h2d));
cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D;
cfis->pm_port_c = 0x80; /* is command */
static void fsl_sata_set_features(int dev)
{
fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv;
- struct sata_fis_h2d h2d;
- struct cfis *cfis;
+ struct sata_fis_h2d h2d, *cfis = &h2d;
u8 udma_cap;
- cfis = (struct cfis *)&h2d;
- memset((void *)cfis, 0, sizeof(struct cfis));
+ memset(cfis, 0, sizeof(struct sata_fis_h2d));
cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D;
cfis->pm_port_c = 0x80; /* is command */
static u32 fsl_sata_rw_cmd(int dev, u32 start, u32 blkcnt, u8 *buffer, int is_write)
{
fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv;
- struct sata_fis_h2d h2d;
- struct cfis *cfis;
+ struct sata_fis_h2d h2d, *cfis = &h2d;
u32 block;
block = start;
- cfis = (struct cfis *)&h2d;
- memset((void *)cfis, 0, sizeof(struct cfis));
+ memset(cfis, 0, sizeof(struct sata_fis_h2d));
cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D;
cfis->pm_port_c = 0x80; /* is command */
return blkcnt;
}
-void fsl_sata_flush_cache(int dev)
+static void fsl_sata_flush_cache(int dev)
{
fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv;
- struct sata_fis_h2d h2d;
- struct cfis *cfis;
+ struct sata_fis_h2d h2d, *cfis = &h2d;
- cfis = (struct cfis *)&h2d;
-
- memset((void *)cfis, 0, sizeof(struct cfis));
+ memset(cfis, 0, sizeof(struct sata_fis_h2d));
cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D;
cfis->pm_port_c = 0x80; /* is command */
static u32 fsl_sata_rw_cmd_ext(int dev, u32 start, u32 blkcnt, u8 *buffer, int is_write)
{
fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv;
- struct sata_fis_h2d h2d;
- struct cfis *cfis;
+ struct sata_fis_h2d h2d, *cfis = &h2d;
u64 block;
block = (u64)start;
- cfis = (struct cfis *)&h2d;
- memset((void *)cfis, 0, sizeof(struct cfis));
+ memset(cfis, 0, sizeof(struct sata_fis_h2d));
cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D;
cfis->pm_port_c = 0x80; /* is command */
return blkcnt;
}
-u32 fsl_sata_rw_ncq_cmd(int dev, u32 start, u32 blkcnt, u8 *buffer, int is_write)
+static u32 fsl_sata_rw_ncq_cmd(int dev, u32 start, u32 blkcnt, u8 *buffer,
+ int is_write)
{
fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv;
- struct sata_fis_h2d h2d;
- struct cfis *cfis;
+ struct sata_fis_h2d h2d, *cfis = &h2d;
int ncq_channel;
u64 block;
- if (sata_dev_desc[dev].lba48 != 1) {
+ if (sata->lba48 != 1) {
printf("execute FPDMA command on non-LBA48 hard disk\n\r");
return -1;
}
block = (u64)start;
- cfis = (struct cfis *)&h2d;
- memset((void *)cfis, 0, sizeof(struct cfis));
+ memset(cfis, 0, sizeof(struct sata_fis_h2d));
cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D;
cfis->pm_port_c = 0x80; /* is command */
return blkcnt;
}
-void fsl_sata_flush_cache_ext(int dev)
+static void fsl_sata_flush_cache_ext(int dev)
{
fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv;
- struct sata_fis_h2d h2d;
- struct cfis *cfis;
-
- cfis = (struct cfis *)&h2d;
+ struct sata_fis_h2d h2d, *cfis = &h2d;
- memset((void *)cfis, 0, sizeof(struct cfis));
+ memset(cfis, 0, sizeof(struct sata_fis_h2d));
cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D;
cfis->pm_port_c = 0x80; /* is command */
fsl_sata_exec_cmd(sata, cfis, CMD_ATA, 0, NULL, 0);
}
-/* Software reset, set SRST of the Device Control register */
-void fsl_sata_software_reset(int dev)
-{
- return;
-}
-
static void fsl_sata_init_wcache(int dev, u16 *id)
{
fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv;
return sata->flush_ext;
}
-u32 ata_low_level_rw_lba48(int dev, u32 blknr, u32 blkcnt, void *buffer, int is_write)
+static u32 ata_low_level_rw_lba48(int dev, u32 blknr, lbaint_t blkcnt,
+ const void *buffer, int is_write)
{
u32 start, blks;
u8 *addr;
return blkcnt;
}
-u32 ata_low_level_rw_lba28(int dev, u32 blknr, u32 blkcnt, void *buffer, int is_write)
+static u32 ata_low_level_rw_lba28(int dev, u32 blknr, u32 blkcnt,
+ const void *buffer, int is_write)
{
u32 start, blks;
u8 *addr;
/*
* SATA interface between low level driver and command layer
*/
-ulong sata_read(int dev, u32 blknr, u32 blkcnt, void *buffer)
+ulong sata_read(int dev, ulong blknr, lbaint_t blkcnt, void *buffer)
{
u32 rc;
+ fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv;
- if (sata_dev_desc[dev].lba48)
+ if (sata->lba48)
rc = ata_low_level_rw_lba48(dev, blknr, blkcnt, buffer, READ_CMD);
else
rc = ata_low_level_rw_lba28(dev, blknr, blkcnt, buffer, READ_CMD);
return rc;
}
-ulong sata_write(int dev, u32 blknr, u32 blkcnt, void *buffer)
+ulong sata_write(int dev, ulong blknr, lbaint_t blkcnt, const void *buffer)
{
u32 rc;
+ fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv;
- if (sata_dev_desc[dev].lba48) {
+ if (sata->lba48) {
rc = ata_low_level_rw_lba48(dev, blknr, blkcnt, buffer, WRITE_CMD);
if (fsl_sata_get_wcache(dev) && fsl_sata_get_flush_ext(dev))
fsl_sata_flush_cache_ext(dev);
n_sectors = ata_id_n_sectors(id);
sata_dev_desc[dev].lba = (u32)n_sectors;
+#ifdef CONFIG_LBA48
/* Check if support LBA48 */
if (ata_id_has_lba48(id)) {
- sata_dev_desc[dev].lba48 = 1;
+ sata->lba48 = 1;
debug("Device support LBA48\n\r");
- }
+ } else
+ debug("Device supports LBA28\n\r");
+#endif
/* Get the NCQ queue depth from device */
sata->queue_depth = ata_id_queue_depth(id);