* No port multiplier support
*/
-#include <common.h>
#include <ahci.h>
#include <blk.h>
+#include <bootdev.h>
#include <cpu_func.h>
#include <dm.h>
+#include <log.h>
#include <asm/cache.h>
+#include <asm/global_data.h>
#include <dm/device-internal.h>
#include <dm/lists.h>
#include <fis.h>
#include <libata.h>
#include <malloc.h>
#include <sata.h>
+#include <time.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
#include <linux/errno.h>
#include <asm/io.h>
#include <linux/mbus.h>
/* Cut from sata_mv in linux kernel */
static int mv_stop_edma_engine(struct udevice *dev, int port)
{
- struct mv_priv *priv = dev_get_platdata(dev);
+ struct mv_priv *priv = dev_get_plat(dev);
int i;
/* Disable eDMA. The disable bit auto clears. */
static int mv_start_edma_engine(struct udevice *dev, int port)
{
- struct mv_priv *priv = dev_get_platdata(dev);
+ struct mv_priv *priv = dev_get_plat(dev);
u32 tmp;
/* Check preconditions */
static int mv_reset_channel(struct udevice *dev, int port)
{
- struct mv_priv *priv = dev_get_platdata(dev);
+ struct mv_priv *priv = dev_get_plat(dev);
/* Make sure edma is stopped */
mv_stop_edma_engine(dev, port);
static void mv_reset_port(struct udevice *dev, int port)
{
- struct mv_priv *priv = dev_get_platdata(dev);
+ struct mv_priv *priv = dev_get_plat(dev);
mv_reset_channel(dev, port);
static int probe_port(struct udevice *dev, int port)
{
- struct mv_priv *priv = dev_get_platdata(dev);
+ struct mv_priv *priv = dev_get_plat(dev);
int tries, tries2, set15 = 0;
u32 tmp;
/* Get request queue in pointer */
static int get_reqip(struct udevice *dev, int port)
{
- struct mv_priv *priv = dev_get_platdata(dev);
+ struct mv_priv *priv = dev_get_plat(dev);
u32 tmp;
tmp = in_le32(priv->regbase + EDMA_RQIPR) & EDMA_RQIPR_IPMASK;
static void set_reqip(struct udevice *dev, int port, int reqin)
{
- struct mv_priv *priv = dev_get_platdata(dev);
+ struct mv_priv *priv = dev_get_plat(dev);
u32 tmp;
tmp = in_le32(priv->regbase + EDMA_RQIPR) & ~EDMA_RQIPR_IPMASK;
/* Get response queue in pointer */
static int get_rspip(struct udevice *dev, int port)
{
- struct mv_priv *priv = dev_get_platdata(dev);
+ struct mv_priv *priv = dev_get_plat(dev);
u32 tmp;
tmp = in_le32(priv->regbase + EDMA_RSIPR) & EDMA_RSIPR_IPMASK;
/* Get response queue out pointer */
static int get_rspop(struct udevice *dev, int port)
{
- struct mv_priv *priv = dev_get_platdata(dev);
+ struct mv_priv *priv = dev_get_plat(dev);
u32 tmp;
tmp = in_le32(priv->regbase + EDMA_RSOPR) & EDMA_RSOPR_OPMASK;
/* Set response queue pointer */
static void set_rspop(struct udevice *dev, int port, int reqin)
{
- struct mv_priv *priv = dev_get_platdata(dev);
+ struct mv_priv *priv = dev_get_plat(dev);
u32 tmp;
tmp = in_le32(priv->regbase + EDMA_RSOPR) & ~EDMA_RSOPR_OPMASK;
static void process_responses(struct udevice *dev, int port)
{
#ifdef DEBUG
- struct mv_priv *priv = dev_get_platdata(dev);
+ struct mv_priv *priv = dev_get_plat(dev);
#endif
u32 tmp;
u32 outind = get_rspop(dev, port);
struct sata_fis_h2d *cfis,
u8 *buffer, u32 len, u32 iswrite)
{
- struct mv_priv *priv = dev_get_platdata(dev);
+ struct mv_priv *priv = dev_get_plat(dev);
struct crqb *req;
int slot;
u32 start;
static u32 ata_low_level_rw(struct udevice *dev, int port, lbaint_t blknr,
lbaint_t blkcnt, void *buffer, int is_write)
{
- struct blk_desc *desc = dev_get_uclass_platdata(dev);
+ struct blk_desc *desc = dev_get_uclass_plat(dev);
lbaint_t start, blks;
u8 *addr;
int max_blks;
struct sata_fis_h2d *cfis, u8 *buffer,
u32 len, u32 iswrite)
{
- struct mv_priv *priv = dev_get_platdata(dev);
+ struct mv_priv *priv = dev_get_plat(dev);
int i;
u16 *tp;
static int mv_sata_identify(struct udevice *dev, int port, u16 *id)
{
struct sata_fis_h2d h2d;
+ int len;
memset(&h2d, 0, sizeof(struct sata_fis_h2d));
/* Give device time to get operational */
mdelay(10);
- return mv_ata_exec_ata_cmd_nondma(dev, port, &h2d, (u8 *)id,
- ATA_ID_WORDS * 2, READ_CMD);
+ /* During cold start, with some HDDs, the first ATA ID command does
+ * not populate the ID words. In fact, the first ATA ID
+ * command will only power up the drive, and then the ATA ID command
+ * processing is lost in the process.
+ */
+ len = mv_ata_exec_ata_cmd_nondma(dev, port, &h2d, (u8 *)id,
+ ATA_ID_WORDS * 2, READ_CMD);
+
+ /* If drive capacity has been filled in, then it was successfully
+ * identified (the drive has been powered up before, i.e.
+ * this function is invoked during a reboot)
+ */
+ if (ata_id_n_sectors(id) != 0)
+ return len;
+
+ /* Issue the 2nd ATA ID command to make sure the ID words are
+ * populated properly.
+ */
+ mdelay(10);
+ len = mv_ata_exec_ata_cmd_nondma(dev, port, &h2d, (u8 *)id,
+ ATA_ID_WORDS * 2, READ_CMD);
+ if (ata_id_n_sectors(id) != 0)
+ return len;
+
+ printf("Err: Failed to identify SATA device %d\n", port);
+ return -ENODEV;
}
static void mv_sata_xfer_mode(struct udevice *dev, int port, u16 *id)
{
- struct mv_priv *priv = dev_get_platdata(dev);
+ struct mv_priv *priv = dev_get_plat(dev);
priv->pio = id[ATA_ID_PIO_MODES];
priv->mwdma = id[ATA_ID_MWDMA_MODES];
static void mv_sata_set_features(struct udevice *dev, int port)
{
- struct mv_priv *priv = dev_get_platdata(dev);
+ struct mv_priv *priv = dev_get_plat(dev);
struct sata_fis_h2d cfis;
u8 udma_cap;
static int sata_mv_init_sata(struct udevice *dev, int port)
{
- struct mv_priv *priv = dev_get_platdata(dev);
+ struct mv_priv *priv = dev_get_plat(dev);
debug("Initialize sata dev: %d\n", port);
static int sata_mv_scan_sata(struct udevice *dev, int port)
{
- struct blk_desc *desc = dev_get_uclass_platdata(dev);
- struct mv_priv *priv = dev_get_platdata(dev);
+ struct blk_desc *desc = dev_get_uclass_plat(dev);
+ struct mv_priv *priv = dev_get_plat(dev);
unsigned char serial[ATA_ID_SERNO_LEN + 1];
unsigned char firmware[ATA_ID_FW_REV_LEN + 1];
unsigned char product[ATA_ID_PROD_LEN + 1];
static ulong sata_mv_read(struct udevice *blk, lbaint_t blknr,
lbaint_t blkcnt, void *buffer)
{
- struct mv_priv *priv = dev_get_platdata(blk);
+ struct mv_priv *priv = dev_get_plat(blk);
return ata_low_level_rw(blk, priv->dev_nr, blknr, blkcnt,
buffer, READ_CMD);
static ulong sata_mv_write(struct udevice *blk, lbaint_t blknr,
lbaint_t blkcnt, const void *buffer)
{
- struct mv_priv *priv = dev_get_platdata(blk);
+ struct mv_priv *priv = dev_get_plat(blk);
return ata_low_level_rw(blk, priv->dev_nr, blknr, blkcnt,
(void *)buffer, WRITE_CMD);
.name = "sata_mv_blk",
.id = UCLASS_BLK,
.ops = &sata_mv_blk_ops,
- .platdata_auto_alloc_size = sizeof(struct mv_priv),
+ .plat_auto = sizeof(struct mv_priv),
};
static int sata_mv_probe(struct udevice *dev)
int nr_ports;
int ret;
int i;
+ int status = -ENODEV; /* If the probe fails to detected any SATA port */
/* Get number of ports of this SATA controller */
nr_ports = min(fdtdec_get_int(blob, node, "nr-ports", -1),
for (i = 0; i < nr_ports; i++) {
ret = blk_create_devicef(dev, "sata_mv_blk", "blk",
- IF_TYPE_SATA, -1, 512, 0, &blk);
+ UCLASS_AHCI, -1, DEFAULT_BLKSZ,
+ 0, &blk);
if (ret) {
debug("Can't create device\n");
- return ret;
+ continue;
}
- priv = dev_get_platdata(blk);
+ priv = dev_get_plat(blk);
priv->dev_nr = i;
/* Init SATA port */
ret = sata_mv_init_sata(blk, i);
if (ret) {
debug("%s: Failed to init bus\n", __func__);
- return ret;
+ continue;
}
/* Scan SATA port */
ret = sata_mv_scan_sata(blk, i);
if (ret) {
debug("%s: Failed to scan bus\n", __func__);
- return ret;
+ continue;
}
+
+ ret = blk_probe_or_unbind(dev);
+ if (ret < 0)
+ /* TODO: undo create */
+ continue;
+
+ ret = bootdev_setup_for_sibling_blk(blk, "sata_bootdev");
+ if (ret) {
+ printf("%s: Failed to create bootdev\n", __func__);
+ continue;
+ }
+
+ /* If we got here, the current SATA port was probed
+ * successfully, so set the probe status to successful.
+ */
+ status = 0;
}
- return 0;
+ return status;
}
static int sata_mv_scan(struct udevice *dev)
{
/* Nothing to do here */
-
return 0;
}