1*f2105c61SSimon Glass /* 2*f2105c61SSimon Glass * Copyright (C) 2011 Freescale Semiconductor, Inc. 3*f2105c61SSimon Glass * Author: Tang Yuantian <b29983@freescale.com> 4*f2105c61SSimon Glass * 5*f2105c61SSimon Glass * SPDX-License-Identifier: GPL-2.0+ 6*f2105c61SSimon Glass */ 7*f2105c61SSimon Glass 8*f2105c61SSimon Glass #include <common.h> 9*f2105c61SSimon Glass #include <pci.h> 10*f2105c61SSimon Glass #include <command.h> 11*f2105c61SSimon Glass #include <asm/byteorder.h> 12*f2105c61SSimon Glass #include <malloc.h> 13*f2105c61SSimon Glass #include <asm/io.h> 14*f2105c61SSimon Glass #include <fis.h> 15*f2105c61SSimon Glass #include <sata.h> 16*f2105c61SSimon Glass #include <libata.h> 17*f2105c61SSimon Glass #include <sata.h> 18*f2105c61SSimon Glass #include "sata_sil.h" 19*f2105c61SSimon Glass 20*f2105c61SSimon Glass /* Convert sectorsize to wordsize */ 21*f2105c61SSimon Glass #define ATA_SECTOR_WORDS (ATA_SECT_SIZE/2) 22*f2105c61SSimon Glass #define virt_to_bus(devno, v) pci_virt_to_mem(devno, (void *) (v)) 23*f2105c61SSimon Glass 24*f2105c61SSimon Glass static struct sata_info sata_info; 25*f2105c61SSimon Glass 26*f2105c61SSimon Glass static struct pci_device_id supported[] = { 27*f2105c61SSimon Glass {PCI_VENDOR_ID_SILICONIMAGE, PCI_DEVICE_ID_SIL3131}, 28*f2105c61SSimon Glass {PCI_VENDOR_ID_SILICONIMAGE, PCI_DEVICE_ID_SIL3132}, 29*f2105c61SSimon Glass {PCI_VENDOR_ID_SILICONIMAGE, PCI_DEVICE_ID_SIL3124}, 30*f2105c61SSimon Glass {} 31*f2105c61SSimon Glass }; 32*f2105c61SSimon Glass 33*f2105c61SSimon Glass static void sil_sata_dump_fis(struct sata_fis_d2h *s) 34*f2105c61SSimon Glass { 35*f2105c61SSimon Glass printf("Status FIS dump:\n"); 36*f2105c61SSimon Glass printf("fis_type: %02x\n", s->fis_type); 37*f2105c61SSimon Glass printf("pm_port_i: %02x\n", s->pm_port_i); 38*f2105c61SSimon Glass printf("status: %02x\n", s->status); 39*f2105c61SSimon Glass printf("error: %02x\n", s->error); 40*f2105c61SSimon Glass printf("lba_low: %02x\n", s->lba_low); 41*f2105c61SSimon Glass printf("lba_mid: %02x\n", s->lba_mid); 42*f2105c61SSimon Glass printf("lba_high: %02x\n", s->lba_high); 43*f2105c61SSimon Glass printf("device: %02x\n", s->device); 44*f2105c61SSimon Glass printf("lba_low_exp: %02x\n", s->lba_low_exp); 45*f2105c61SSimon Glass printf("lba_mid_exp: %02x\n", s->lba_mid_exp); 46*f2105c61SSimon Glass printf("lba_high_exp: %02x\n", s->lba_high_exp); 47*f2105c61SSimon Glass printf("res1: %02x\n", s->res1); 48*f2105c61SSimon Glass printf("sector_count: %02x\n", s->sector_count); 49*f2105c61SSimon Glass printf("sector_count_exp: %02x\n", s->sector_count_exp); 50*f2105c61SSimon Glass } 51*f2105c61SSimon Glass 52*f2105c61SSimon Glass static const char *sata_spd_string(unsigned int speed) 53*f2105c61SSimon Glass { 54*f2105c61SSimon Glass static const char * const spd_str[] = { 55*f2105c61SSimon Glass "1.5 Gbps", 56*f2105c61SSimon Glass "3.0 Gbps", 57*f2105c61SSimon Glass "6.0 Gbps", 58*f2105c61SSimon Glass }; 59*f2105c61SSimon Glass 60*f2105c61SSimon Glass if ((speed - 1) > 2) 61*f2105c61SSimon Glass return "<unknown>"; 62*f2105c61SSimon Glass 63*f2105c61SSimon Glass return spd_str[speed - 1]; 64*f2105c61SSimon Glass } 65*f2105c61SSimon Glass 66*f2105c61SSimon Glass static u32 ata_wait_register(void *reg, u32 mask, 67*f2105c61SSimon Glass u32 val, int timeout_msec) 68*f2105c61SSimon Glass { 69*f2105c61SSimon Glass u32 tmp; 70*f2105c61SSimon Glass 71*f2105c61SSimon Glass tmp = readl(reg); 72*f2105c61SSimon Glass while ((tmp & mask) == val && timeout_msec > 0) { 73*f2105c61SSimon Glass mdelay(1); 74*f2105c61SSimon Glass timeout_msec--; 75*f2105c61SSimon Glass tmp = readl(reg); 76*f2105c61SSimon Glass } 77*f2105c61SSimon Glass 78*f2105c61SSimon Glass return tmp; 79*f2105c61SSimon Glass } 80*f2105c61SSimon Glass 81*f2105c61SSimon Glass static void sil_config_port(void *port) 82*f2105c61SSimon Glass { 83*f2105c61SSimon Glass /* configure IRQ WoC */ 84*f2105c61SSimon Glass writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR); 85*f2105c61SSimon Glass 86*f2105c61SSimon Glass /* zero error counters. */ 87*f2105c61SSimon Glass writew(0x8000, port + PORT_DECODE_ERR_THRESH); 88*f2105c61SSimon Glass writew(0x8000, port + PORT_CRC_ERR_THRESH); 89*f2105c61SSimon Glass writew(0x8000, port + PORT_HSHK_ERR_THRESH); 90*f2105c61SSimon Glass writew(0x0000, port + PORT_DECODE_ERR_CNT); 91*f2105c61SSimon Glass writew(0x0000, port + PORT_CRC_ERR_CNT); 92*f2105c61SSimon Glass writew(0x0000, port + PORT_HSHK_ERR_CNT); 93*f2105c61SSimon Glass 94*f2105c61SSimon Glass /* always use 64bit activation */ 95*f2105c61SSimon Glass writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR); 96*f2105c61SSimon Glass 97*f2105c61SSimon Glass /* clear port multiplier enable and resume bits */ 98*f2105c61SSimon Glass writel(PORT_CS_PMP_EN | PORT_CS_PMP_RESUME, port + PORT_CTRL_CLR); 99*f2105c61SSimon Glass } 100*f2105c61SSimon Glass 101*f2105c61SSimon Glass static int sil_init_port(void *port) 102*f2105c61SSimon Glass { 103*f2105c61SSimon Glass u32 tmp; 104*f2105c61SSimon Glass 105*f2105c61SSimon Glass writel(PORT_CS_INIT, port + PORT_CTRL_STAT); 106*f2105c61SSimon Glass ata_wait_register(port + PORT_CTRL_STAT, 107*f2105c61SSimon Glass PORT_CS_INIT, PORT_CS_INIT, 100); 108*f2105c61SSimon Glass tmp = ata_wait_register(port + PORT_CTRL_STAT, 109*f2105c61SSimon Glass PORT_CS_RDY, 0, 100); 110*f2105c61SSimon Glass 111*f2105c61SSimon Glass if ((tmp & (PORT_CS_INIT | PORT_CS_RDY)) != PORT_CS_RDY) 112*f2105c61SSimon Glass return 1; 113*f2105c61SSimon Glass 114*f2105c61SSimon Glass return 0; 115*f2105c61SSimon Glass } 116*f2105c61SSimon Glass 117*f2105c61SSimon Glass static void sil_read_fis(int dev, int tag, struct sata_fis_d2h *fis) 118*f2105c61SSimon Glass { 119*f2105c61SSimon Glass struct sil_sata *sata = sata_dev_desc[dev].priv; 120*f2105c61SSimon Glass void *port = sata->port; 121*f2105c61SSimon Glass struct sil_prb *prb; 122*f2105c61SSimon Glass int i; 123*f2105c61SSimon Glass u32 *src, *dst; 124*f2105c61SSimon Glass 125*f2105c61SSimon Glass prb = port + PORT_LRAM + tag * PORT_LRAM_SLOT_SZ; 126*f2105c61SSimon Glass src = (u32 *)&prb->fis; 127*f2105c61SSimon Glass dst = (u32 *)fis; 128*f2105c61SSimon Glass for (i = 0; i < sizeof(struct sata_fis_h2d); i += 4) 129*f2105c61SSimon Glass *dst++ = readl(src++); 130*f2105c61SSimon Glass } 131*f2105c61SSimon Glass 132*f2105c61SSimon Glass static int sil_exec_cmd(int dev, struct sil_cmd_block *pcmd, int tag) 133*f2105c61SSimon Glass { 134*f2105c61SSimon Glass struct sil_sata *sata = sata_dev_desc[dev].priv; 135*f2105c61SSimon Glass void *port = sata->port; 136*f2105c61SSimon Glass u64 paddr = virt_to_bus(sata->devno, pcmd); 137*f2105c61SSimon Glass u32 irq_mask, irq_stat; 138*f2105c61SSimon Glass int rc; 139*f2105c61SSimon Glass 140*f2105c61SSimon Glass writel(PORT_IRQ_COMPLETE | PORT_IRQ_ERROR, port + PORT_IRQ_ENABLE_CLR); 141*f2105c61SSimon Glass 142*f2105c61SSimon Glass /* better to add momery barrior here */ 143*f2105c61SSimon Glass writel((u32)paddr, port + PORT_CMD_ACTIVATE + tag * 8); 144*f2105c61SSimon Glass writel((u64)paddr >> 32, port + PORT_CMD_ACTIVATE + tag * 8 + 4); 145*f2105c61SSimon Glass 146*f2105c61SSimon Glass irq_mask = (PORT_IRQ_COMPLETE | PORT_IRQ_ERROR) << PORT_IRQ_RAW_SHIFT; 147*f2105c61SSimon Glass irq_stat = ata_wait_register(port + PORT_IRQ_STAT, irq_mask, 148*f2105c61SSimon Glass 0, 10000); 149*f2105c61SSimon Glass 150*f2105c61SSimon Glass /* clear IRQs */ 151*f2105c61SSimon Glass writel(irq_mask, port + PORT_IRQ_STAT); 152*f2105c61SSimon Glass irq_stat >>= PORT_IRQ_RAW_SHIFT; 153*f2105c61SSimon Glass 154*f2105c61SSimon Glass if (irq_stat & PORT_IRQ_COMPLETE) 155*f2105c61SSimon Glass rc = 0; 156*f2105c61SSimon Glass else { 157*f2105c61SSimon Glass /* force port into known state */ 158*f2105c61SSimon Glass sil_init_port(port); 159*f2105c61SSimon Glass if (irq_stat & PORT_IRQ_ERROR) 160*f2105c61SSimon Glass rc = 1; /* error */ 161*f2105c61SSimon Glass else 162*f2105c61SSimon Glass rc = 2; /* busy */ 163*f2105c61SSimon Glass } 164*f2105c61SSimon Glass 165*f2105c61SSimon Glass return rc; 166*f2105c61SSimon Glass } 167*f2105c61SSimon Glass 168*f2105c61SSimon Glass static int sil_cmd_set_feature(int dev) 169*f2105c61SSimon Glass { 170*f2105c61SSimon Glass struct sil_sata *sata = sata_dev_desc[dev].priv; 171*f2105c61SSimon Glass struct sil_cmd_block cmdb, *pcmd = &cmdb; 172*f2105c61SSimon Glass struct sata_fis_d2h fis; 173*f2105c61SSimon Glass u8 udma_cap; 174*f2105c61SSimon Glass int ret; 175*f2105c61SSimon Glass 176*f2105c61SSimon Glass memset((void *)&cmdb, 0, sizeof(struct sil_cmd_block)); 177*f2105c61SSimon Glass pcmd->prb.fis.fis_type = SATA_FIS_TYPE_REGISTER_H2D; 178*f2105c61SSimon Glass pcmd->prb.fis.pm_port_c = (1 << 7); 179*f2105c61SSimon Glass pcmd->prb.fis.command = ATA_CMD_SET_FEATURES; 180*f2105c61SSimon Glass pcmd->prb.fis.features = SETFEATURES_XFER; 181*f2105c61SSimon Glass 182*f2105c61SSimon Glass /* First check the device capablity */ 183*f2105c61SSimon Glass udma_cap = (u8)(sata->udma & 0xff); 184*f2105c61SSimon Glass debug("udma_cap %02x\n", udma_cap); 185*f2105c61SSimon Glass 186*f2105c61SSimon Glass if (udma_cap == ATA_UDMA6) 187*f2105c61SSimon Glass pcmd->prb.fis.sector_count = XFER_UDMA_6; 188*f2105c61SSimon Glass if (udma_cap == ATA_UDMA5) 189*f2105c61SSimon Glass pcmd->prb.fis.sector_count = XFER_UDMA_5; 190*f2105c61SSimon Glass if (udma_cap == ATA_UDMA4) 191*f2105c61SSimon Glass pcmd->prb.fis.sector_count = XFER_UDMA_4; 192*f2105c61SSimon Glass if (udma_cap == ATA_UDMA3) 193*f2105c61SSimon Glass pcmd->prb.fis.sector_count = XFER_UDMA_3; 194*f2105c61SSimon Glass 195*f2105c61SSimon Glass ret = sil_exec_cmd(dev, pcmd, 0); 196*f2105c61SSimon Glass if (ret) { 197*f2105c61SSimon Glass sil_read_fis(dev, 0, &fis); 198*f2105c61SSimon Glass printf("Err: exe cmd(0x%x).\n", 199*f2105c61SSimon Glass readl(sata->port + PORT_SERROR)); 200*f2105c61SSimon Glass sil_sata_dump_fis(&fis); 201*f2105c61SSimon Glass return 1; 202*f2105c61SSimon Glass } 203*f2105c61SSimon Glass 204*f2105c61SSimon Glass return 0; 205*f2105c61SSimon Glass } 206*f2105c61SSimon Glass 207*f2105c61SSimon Glass static int sil_cmd_identify_device(int dev, u16 *id) 208*f2105c61SSimon Glass { 209*f2105c61SSimon Glass struct sil_sata *sata = sata_dev_desc[dev].priv; 210*f2105c61SSimon Glass struct sil_cmd_block cmdb, *pcmd = &cmdb; 211*f2105c61SSimon Glass struct sata_fis_d2h fis; 212*f2105c61SSimon Glass int ret; 213*f2105c61SSimon Glass 214*f2105c61SSimon Glass memset((void *)&cmdb, 0, sizeof(struct sil_cmd_block)); 215*f2105c61SSimon Glass pcmd->prb.ctrl = cpu_to_le16(PRB_CTRL_PROTOCOL); 216*f2105c61SSimon Glass pcmd->prb.prot = cpu_to_le16(PRB_PROT_READ); 217*f2105c61SSimon Glass pcmd->prb.fis.fis_type = SATA_FIS_TYPE_REGISTER_H2D; 218*f2105c61SSimon Glass pcmd->prb.fis.pm_port_c = (1 << 7); 219*f2105c61SSimon Glass pcmd->prb.fis.command = ATA_CMD_ID_ATA; 220*f2105c61SSimon Glass pcmd->sge.addr = cpu_to_le64(virt_to_bus(sata->devno, id)); 221*f2105c61SSimon Glass pcmd->sge.cnt = cpu_to_le32(sizeof(id[0]) * ATA_ID_WORDS); 222*f2105c61SSimon Glass pcmd->sge.flags = cpu_to_le32(SGE_TRM); 223*f2105c61SSimon Glass 224*f2105c61SSimon Glass ret = sil_exec_cmd(dev, pcmd, 0); 225*f2105c61SSimon Glass if (ret) { 226*f2105c61SSimon Glass sil_read_fis(dev, 0, &fis); 227*f2105c61SSimon Glass printf("Err: id cmd(0x%x).\n", readl(sata->port + PORT_SERROR)); 228*f2105c61SSimon Glass sil_sata_dump_fis(&fis); 229*f2105c61SSimon Glass return 1; 230*f2105c61SSimon Glass } 231*f2105c61SSimon Glass ata_swap_buf_le16(id, ATA_ID_WORDS); 232*f2105c61SSimon Glass 233*f2105c61SSimon Glass return 0; 234*f2105c61SSimon Glass } 235*f2105c61SSimon Glass 236*f2105c61SSimon Glass static int sil_cmd_soft_reset(int dev) 237*f2105c61SSimon Glass { 238*f2105c61SSimon Glass struct sil_cmd_block cmdb, *pcmd = &cmdb; 239*f2105c61SSimon Glass struct sil_sata *sata = sata_dev_desc[dev].priv; 240*f2105c61SSimon Glass struct sata_fis_d2h fis; 241*f2105c61SSimon Glass void *port = sata->port; 242*f2105c61SSimon Glass int ret; 243*f2105c61SSimon Glass 244*f2105c61SSimon Glass /* put the port into known state */ 245*f2105c61SSimon Glass if (sil_init_port(port)) { 246*f2105c61SSimon Glass printf("SRST: port %d not ready\n", dev); 247*f2105c61SSimon Glass return 1; 248*f2105c61SSimon Glass } 249*f2105c61SSimon Glass 250*f2105c61SSimon Glass memset((void *)&cmdb, 0, sizeof(struct sil_cmd_block)); 251*f2105c61SSimon Glass 252*f2105c61SSimon Glass pcmd->prb.ctrl = cpu_to_le16(PRB_CTRL_SRST); 253*f2105c61SSimon Glass pcmd->prb.fis.fis_type = SATA_FIS_TYPE_REGISTER_H2D; 254*f2105c61SSimon Glass pcmd->prb.fis.pm_port_c = 0xf; 255*f2105c61SSimon Glass 256*f2105c61SSimon Glass ret = sil_exec_cmd(dev, &cmdb, 0); 257*f2105c61SSimon Glass if (ret) { 258*f2105c61SSimon Glass sil_read_fis(dev, 0, &fis); 259*f2105c61SSimon Glass printf("SRST cmd error.\n"); 260*f2105c61SSimon Glass sil_sata_dump_fis(&fis); 261*f2105c61SSimon Glass return 1; 262*f2105c61SSimon Glass } 263*f2105c61SSimon Glass 264*f2105c61SSimon Glass return 0; 265*f2105c61SSimon Glass } 266*f2105c61SSimon Glass 267*f2105c61SSimon Glass static ulong sil_sata_rw_cmd(int dev, ulong start, ulong blkcnt, 268*f2105c61SSimon Glass u8 *buffer, int is_write) 269*f2105c61SSimon Glass { 270*f2105c61SSimon Glass struct sil_sata *sata = sata_dev_desc[dev].priv; 271*f2105c61SSimon Glass struct sil_cmd_block cmdb, *pcmd = &cmdb; 272*f2105c61SSimon Glass struct sata_fis_d2h fis; 273*f2105c61SSimon Glass u64 block; 274*f2105c61SSimon Glass int ret; 275*f2105c61SSimon Glass 276*f2105c61SSimon Glass block = (u64)start; 277*f2105c61SSimon Glass memset(pcmd, 0, sizeof(struct sil_cmd_block)); 278*f2105c61SSimon Glass pcmd->prb.ctrl = cpu_to_le16(PRB_CTRL_PROTOCOL); 279*f2105c61SSimon Glass pcmd->prb.fis.fis_type = SATA_FIS_TYPE_REGISTER_H2D; 280*f2105c61SSimon Glass pcmd->prb.fis.pm_port_c = (1 << 7); 281*f2105c61SSimon Glass if (is_write) { 282*f2105c61SSimon Glass pcmd->prb.fis.command = ATA_CMD_WRITE; 283*f2105c61SSimon Glass pcmd->prb.prot = cpu_to_le16(PRB_PROT_WRITE); 284*f2105c61SSimon Glass } else { 285*f2105c61SSimon Glass pcmd->prb.fis.command = ATA_CMD_READ; 286*f2105c61SSimon Glass pcmd->prb.prot = cpu_to_le16(PRB_PROT_READ); 287*f2105c61SSimon Glass } 288*f2105c61SSimon Glass 289*f2105c61SSimon Glass pcmd->prb.fis.device = ATA_LBA; 290*f2105c61SSimon Glass pcmd->prb.fis.device |= (block >> 24) & 0xf; 291*f2105c61SSimon Glass pcmd->prb.fis.lba_high = (block >> 16) & 0xff; 292*f2105c61SSimon Glass pcmd->prb.fis.lba_mid = (block >> 8) & 0xff; 293*f2105c61SSimon Glass pcmd->prb.fis.lba_low = block & 0xff; 294*f2105c61SSimon Glass pcmd->prb.fis.sector_count = (u8)blkcnt & 0xff; 295*f2105c61SSimon Glass 296*f2105c61SSimon Glass pcmd->sge.addr = cpu_to_le64(virt_to_bus(sata->devno, buffer)); 297*f2105c61SSimon Glass pcmd->sge.cnt = cpu_to_le32(blkcnt * ATA_SECT_SIZE); 298*f2105c61SSimon Glass pcmd->sge.flags = cpu_to_le32(SGE_TRM); 299*f2105c61SSimon Glass 300*f2105c61SSimon Glass ret = sil_exec_cmd(dev, pcmd, 0); 301*f2105c61SSimon Glass if (ret) { 302*f2105c61SSimon Glass sil_read_fis(dev, 0, &fis); 303*f2105c61SSimon Glass printf("Err: rw cmd(0x%08x).\n", 304*f2105c61SSimon Glass readl(sata->port + PORT_SERROR)); 305*f2105c61SSimon Glass sil_sata_dump_fis(&fis); 306*f2105c61SSimon Glass return 1; 307*f2105c61SSimon Glass } 308*f2105c61SSimon Glass 309*f2105c61SSimon Glass return blkcnt; 310*f2105c61SSimon Glass } 311*f2105c61SSimon Glass 312*f2105c61SSimon Glass static ulong sil_sata_rw_cmd_ext(int dev, ulong start, ulong blkcnt, 313*f2105c61SSimon Glass u8 *buffer, int is_write) 314*f2105c61SSimon Glass { 315*f2105c61SSimon Glass struct sil_sata *sata = sata_dev_desc[dev].priv; 316*f2105c61SSimon Glass struct sil_cmd_block cmdb, *pcmd = &cmdb; 317*f2105c61SSimon Glass struct sata_fis_d2h fis; 318*f2105c61SSimon Glass u64 block; 319*f2105c61SSimon Glass int ret; 320*f2105c61SSimon Glass 321*f2105c61SSimon Glass block = (u64)start; 322*f2105c61SSimon Glass memset(pcmd, 0, sizeof(struct sil_cmd_block)); 323*f2105c61SSimon Glass pcmd->prb.ctrl = cpu_to_le16(PRB_CTRL_PROTOCOL); 324*f2105c61SSimon Glass pcmd->prb.fis.fis_type = SATA_FIS_TYPE_REGISTER_H2D; 325*f2105c61SSimon Glass pcmd->prb.fis.pm_port_c = (1 << 7); 326*f2105c61SSimon Glass if (is_write) { 327*f2105c61SSimon Glass pcmd->prb.fis.command = ATA_CMD_WRITE_EXT; 328*f2105c61SSimon Glass pcmd->prb.prot = cpu_to_le16(PRB_PROT_WRITE); 329*f2105c61SSimon Glass } else { 330*f2105c61SSimon Glass pcmd->prb.fis.command = ATA_CMD_READ_EXT; 331*f2105c61SSimon Glass pcmd->prb.prot = cpu_to_le16(PRB_PROT_READ); 332*f2105c61SSimon Glass } 333*f2105c61SSimon Glass 334*f2105c61SSimon Glass pcmd->prb.fis.lba_high_exp = (block >> 40) & 0xff; 335*f2105c61SSimon Glass pcmd->prb.fis.lba_mid_exp = (block >> 32) & 0xff; 336*f2105c61SSimon Glass pcmd->prb.fis.lba_low_exp = (block >> 24) & 0xff; 337*f2105c61SSimon Glass pcmd->prb.fis.lba_high = (block >> 16) & 0xff; 338*f2105c61SSimon Glass pcmd->prb.fis.lba_mid = (block >> 8) & 0xff; 339*f2105c61SSimon Glass pcmd->prb.fis.lba_low = block & 0xff; 340*f2105c61SSimon Glass pcmd->prb.fis.device = ATA_LBA; 341*f2105c61SSimon Glass pcmd->prb.fis.sector_count_exp = (blkcnt >> 8) & 0xff; 342*f2105c61SSimon Glass pcmd->prb.fis.sector_count = blkcnt & 0xff; 343*f2105c61SSimon Glass 344*f2105c61SSimon Glass pcmd->sge.addr = cpu_to_le64(virt_to_bus(sata->devno, buffer)); 345*f2105c61SSimon Glass pcmd->sge.cnt = cpu_to_le32(blkcnt * ATA_SECT_SIZE); 346*f2105c61SSimon Glass pcmd->sge.flags = cpu_to_le32(SGE_TRM); 347*f2105c61SSimon Glass 348*f2105c61SSimon Glass ret = sil_exec_cmd(dev, pcmd, 0); 349*f2105c61SSimon Glass if (ret) { 350*f2105c61SSimon Glass sil_read_fis(dev, 0, &fis); 351*f2105c61SSimon Glass printf("Err: rw ext cmd(0x%08x).\n", 352*f2105c61SSimon Glass readl(sata->port + PORT_SERROR)); 353*f2105c61SSimon Glass sil_sata_dump_fis(&fis); 354*f2105c61SSimon Glass return 1; 355*f2105c61SSimon Glass } 356*f2105c61SSimon Glass 357*f2105c61SSimon Glass return blkcnt; 358*f2105c61SSimon Glass } 359*f2105c61SSimon Glass 360*f2105c61SSimon Glass static ulong sil_sata_rw_lba28(int dev, ulong blknr, lbaint_t blkcnt, 361*f2105c61SSimon Glass const void *buffer, int is_write) 362*f2105c61SSimon Glass { 363*f2105c61SSimon Glass ulong start, blks, max_blks; 364*f2105c61SSimon Glass u8 *addr; 365*f2105c61SSimon Glass 366*f2105c61SSimon Glass start = blknr; 367*f2105c61SSimon Glass blks = blkcnt; 368*f2105c61SSimon Glass addr = (u8 *)buffer; 369*f2105c61SSimon Glass 370*f2105c61SSimon Glass max_blks = ATA_MAX_SECTORS; 371*f2105c61SSimon Glass do { 372*f2105c61SSimon Glass if (blks > max_blks) { 373*f2105c61SSimon Glass sil_sata_rw_cmd(dev, start, max_blks, addr, is_write); 374*f2105c61SSimon Glass start += max_blks; 375*f2105c61SSimon Glass blks -= max_blks; 376*f2105c61SSimon Glass addr += ATA_SECT_SIZE * max_blks; 377*f2105c61SSimon Glass } else { 378*f2105c61SSimon Glass sil_sata_rw_cmd(dev, start, blks, addr, is_write); 379*f2105c61SSimon Glass start += blks; 380*f2105c61SSimon Glass blks = 0; 381*f2105c61SSimon Glass addr += ATA_SECT_SIZE * blks; 382*f2105c61SSimon Glass } 383*f2105c61SSimon Glass } while (blks != 0); 384*f2105c61SSimon Glass 385*f2105c61SSimon Glass return blkcnt; 386*f2105c61SSimon Glass } 387*f2105c61SSimon Glass 388*f2105c61SSimon Glass static ulong sil_sata_rw_lba48(int dev, ulong blknr, lbaint_t blkcnt, 389*f2105c61SSimon Glass const void *buffer, int is_write) 390*f2105c61SSimon Glass { 391*f2105c61SSimon Glass ulong start, blks, max_blks; 392*f2105c61SSimon Glass u8 *addr; 393*f2105c61SSimon Glass 394*f2105c61SSimon Glass start = blknr; 395*f2105c61SSimon Glass blks = blkcnt; 396*f2105c61SSimon Glass addr = (u8 *)buffer; 397*f2105c61SSimon Glass 398*f2105c61SSimon Glass max_blks = ATA_MAX_SECTORS_LBA48; 399*f2105c61SSimon Glass do { 400*f2105c61SSimon Glass if (blks > max_blks) { 401*f2105c61SSimon Glass sil_sata_rw_cmd_ext(dev, start, max_blks, 402*f2105c61SSimon Glass addr, is_write); 403*f2105c61SSimon Glass start += max_blks; 404*f2105c61SSimon Glass blks -= max_blks; 405*f2105c61SSimon Glass addr += ATA_SECT_SIZE * max_blks; 406*f2105c61SSimon Glass } else { 407*f2105c61SSimon Glass sil_sata_rw_cmd_ext(dev, start, blks, 408*f2105c61SSimon Glass addr, is_write); 409*f2105c61SSimon Glass start += blks; 410*f2105c61SSimon Glass blks = 0; 411*f2105c61SSimon Glass addr += ATA_SECT_SIZE * blks; 412*f2105c61SSimon Glass } 413*f2105c61SSimon Glass } while (blks != 0); 414*f2105c61SSimon Glass 415*f2105c61SSimon Glass return blkcnt; 416*f2105c61SSimon Glass } 417*f2105c61SSimon Glass 418*f2105c61SSimon Glass static void sil_sata_cmd_flush_cache(int dev) 419*f2105c61SSimon Glass { 420*f2105c61SSimon Glass struct sil_cmd_block cmdb, *pcmd = &cmdb; 421*f2105c61SSimon Glass 422*f2105c61SSimon Glass memset((void *)pcmd, 0, sizeof(struct sil_cmd_block)); 423*f2105c61SSimon Glass pcmd->prb.fis.fis_type = SATA_FIS_TYPE_REGISTER_H2D; 424*f2105c61SSimon Glass pcmd->prb.fis.pm_port_c = (1 << 7); 425*f2105c61SSimon Glass pcmd->prb.fis.command = ATA_CMD_FLUSH; 426*f2105c61SSimon Glass 427*f2105c61SSimon Glass sil_exec_cmd(dev, pcmd, 0); 428*f2105c61SSimon Glass } 429*f2105c61SSimon Glass 430*f2105c61SSimon Glass static void sil_sata_cmd_flush_cache_ext(int dev) 431*f2105c61SSimon Glass { 432*f2105c61SSimon Glass struct sil_cmd_block cmdb, *pcmd = &cmdb; 433*f2105c61SSimon Glass 434*f2105c61SSimon Glass memset((void *)pcmd, 0, sizeof(struct sil_cmd_block)); 435*f2105c61SSimon Glass pcmd->prb.fis.fis_type = SATA_FIS_TYPE_REGISTER_H2D; 436*f2105c61SSimon Glass pcmd->prb.fis.pm_port_c = (1 << 7); 437*f2105c61SSimon Glass pcmd->prb.fis.command = ATA_CMD_FLUSH_EXT; 438*f2105c61SSimon Glass 439*f2105c61SSimon Glass sil_exec_cmd(dev, pcmd, 0); 440*f2105c61SSimon Glass } 441*f2105c61SSimon Glass 442*f2105c61SSimon Glass static void sil_sata_init_wcache(int dev, u16 *id) 443*f2105c61SSimon Glass { 444*f2105c61SSimon Glass struct sil_sata *sata = sata_dev_desc[dev].priv; 445*f2105c61SSimon Glass 446*f2105c61SSimon Glass if (ata_id_has_wcache(id) && ata_id_wcache_enabled(id)) 447*f2105c61SSimon Glass sata->wcache = 1; 448*f2105c61SSimon Glass if (ata_id_has_flush(id)) 449*f2105c61SSimon Glass sata->flush = 1; 450*f2105c61SSimon Glass if (ata_id_has_flush_ext(id)) 451*f2105c61SSimon Glass sata->flush_ext = 1; 452*f2105c61SSimon Glass } 453*f2105c61SSimon Glass 454*f2105c61SSimon Glass static int sil_sata_get_wcache(int dev) 455*f2105c61SSimon Glass { 456*f2105c61SSimon Glass struct sil_sata *sata = sata_dev_desc[dev].priv; 457*f2105c61SSimon Glass 458*f2105c61SSimon Glass return sata->wcache; 459*f2105c61SSimon Glass } 460*f2105c61SSimon Glass 461*f2105c61SSimon Glass static int sil_sata_get_flush(int dev) 462*f2105c61SSimon Glass { 463*f2105c61SSimon Glass struct sil_sata *sata = sata_dev_desc[dev].priv; 464*f2105c61SSimon Glass 465*f2105c61SSimon Glass return sata->flush; 466*f2105c61SSimon Glass } 467*f2105c61SSimon Glass 468*f2105c61SSimon Glass static int sil_sata_get_flush_ext(int dev) 469*f2105c61SSimon Glass { 470*f2105c61SSimon Glass struct sil_sata *sata = sata_dev_desc[dev].priv; 471*f2105c61SSimon Glass 472*f2105c61SSimon Glass return sata->flush_ext; 473*f2105c61SSimon Glass } 474*f2105c61SSimon Glass 475*f2105c61SSimon Glass /* 476*f2105c61SSimon Glass * SATA interface between low level driver and command layer 477*f2105c61SSimon Glass */ 478*f2105c61SSimon Glass ulong sata_read(int dev, ulong blknr, lbaint_t blkcnt, void *buffer) 479*f2105c61SSimon Glass { 480*f2105c61SSimon Glass struct sil_sata *sata = sata_dev_desc[dev].priv; 481*f2105c61SSimon Glass ulong rc; 482*f2105c61SSimon Glass 483*f2105c61SSimon Glass if (sata->lba48) 484*f2105c61SSimon Glass rc = sil_sata_rw_lba48(dev, blknr, blkcnt, buffer, READ_CMD); 485*f2105c61SSimon Glass else 486*f2105c61SSimon Glass rc = sil_sata_rw_lba28(dev, blknr, blkcnt, buffer, READ_CMD); 487*f2105c61SSimon Glass 488*f2105c61SSimon Glass return rc; 489*f2105c61SSimon Glass } 490*f2105c61SSimon Glass 491*f2105c61SSimon Glass /* 492*f2105c61SSimon Glass * SATA interface between low level driver and command layer 493*f2105c61SSimon Glass */ 494*f2105c61SSimon Glass ulong sata_write(int dev, ulong blknr, lbaint_t blkcnt, const void *buffer) 495*f2105c61SSimon Glass { 496*f2105c61SSimon Glass struct sil_sata *sata = sata_dev_desc[dev].priv; 497*f2105c61SSimon Glass ulong rc; 498*f2105c61SSimon Glass 499*f2105c61SSimon Glass if (sata->lba48) { 500*f2105c61SSimon Glass rc = sil_sata_rw_lba48(dev, blknr, blkcnt, buffer, WRITE_CMD); 501*f2105c61SSimon Glass if (sil_sata_get_wcache(dev) && sil_sata_get_flush_ext(dev)) 502*f2105c61SSimon Glass sil_sata_cmd_flush_cache_ext(dev); 503*f2105c61SSimon Glass } else { 504*f2105c61SSimon Glass rc = sil_sata_rw_lba28(dev, blknr, blkcnt, buffer, WRITE_CMD); 505*f2105c61SSimon Glass if (sil_sata_get_wcache(dev) && sil_sata_get_flush(dev)) 506*f2105c61SSimon Glass sil_sata_cmd_flush_cache(dev); 507*f2105c61SSimon Glass } 508*f2105c61SSimon Glass 509*f2105c61SSimon Glass return rc; 510*f2105c61SSimon Glass } 511*f2105c61SSimon Glass 512*f2105c61SSimon Glass /* 513*f2105c61SSimon Glass * SATA interface between low level driver and command layer 514*f2105c61SSimon Glass */ 515*f2105c61SSimon Glass int init_sata(int dev) 516*f2105c61SSimon Glass { 517*f2105c61SSimon Glass static int init_done, idx; 518*f2105c61SSimon Glass pci_dev_t devno; 519*f2105c61SSimon Glass u16 word; 520*f2105c61SSimon Glass 521*f2105c61SSimon Glass if (init_done == 1 && dev < sata_info.maxport) 522*f2105c61SSimon Glass return 0; 523*f2105c61SSimon Glass 524*f2105c61SSimon Glass init_done = 1; 525*f2105c61SSimon Glass 526*f2105c61SSimon Glass /* Find PCI device(s) */ 527*f2105c61SSimon Glass devno = pci_find_devices(supported, idx++); 528*f2105c61SSimon Glass if (devno == -1) 529*f2105c61SSimon Glass return 1; 530*f2105c61SSimon Glass 531*f2105c61SSimon Glass pci_read_config_word(devno, PCI_DEVICE_ID, &word); 532*f2105c61SSimon Glass 533*f2105c61SSimon Glass /* get the port count */ 534*f2105c61SSimon Glass word &= 0xf; 535*f2105c61SSimon Glass 536*f2105c61SSimon Glass sata_info.portbase = sata_info.maxport; 537*f2105c61SSimon Glass sata_info.maxport = sata_info.portbase + word; 538*f2105c61SSimon Glass sata_info.devno = devno; 539*f2105c61SSimon Glass 540*f2105c61SSimon Glass /* Read out all BARs */ 541*f2105c61SSimon Glass sata_info.iobase[0] = (ulong)pci_map_bar(devno, 542*f2105c61SSimon Glass PCI_BASE_ADDRESS_0, PCI_REGION_MEM); 543*f2105c61SSimon Glass sata_info.iobase[1] = (ulong)pci_map_bar(devno, 544*f2105c61SSimon Glass PCI_BASE_ADDRESS_2, PCI_REGION_MEM); 545*f2105c61SSimon Glass sata_info.iobase[2] = (ulong)pci_map_bar(devno, 546*f2105c61SSimon Glass PCI_BASE_ADDRESS_4, PCI_REGION_MEM); 547*f2105c61SSimon Glass 548*f2105c61SSimon Glass /* mask out the unused bits */ 549*f2105c61SSimon Glass sata_info.iobase[0] &= 0xffffff80; 550*f2105c61SSimon Glass sata_info.iobase[1] &= 0xfffffc00; 551*f2105c61SSimon Glass sata_info.iobase[2] &= 0xffffff80; 552*f2105c61SSimon Glass 553*f2105c61SSimon Glass /* Enable Bus Mastering and memory region */ 554*f2105c61SSimon Glass pci_write_config_word(devno, PCI_COMMAND, 555*f2105c61SSimon Glass PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); 556*f2105c61SSimon Glass 557*f2105c61SSimon Glass /* Check if mem accesses and Bus Mastering are enabled. */ 558*f2105c61SSimon Glass pci_read_config_word(devno, PCI_COMMAND, &word); 559*f2105c61SSimon Glass if (!(word & PCI_COMMAND_MEMORY) || 560*f2105c61SSimon Glass (!(word & PCI_COMMAND_MASTER))) { 561*f2105c61SSimon Glass printf("Error: Can not enable MEM access or Bus Mastering.\n"); 562*f2105c61SSimon Glass debug("PCI command: %04x\n", word); 563*f2105c61SSimon Glass return 1; 564*f2105c61SSimon Glass } 565*f2105c61SSimon Glass 566*f2105c61SSimon Glass /* GPIO off */ 567*f2105c61SSimon Glass writel(0, (void *)(sata_info.iobase[0] + HOST_FLASH_CMD)); 568*f2105c61SSimon Glass /* clear global reset & mask interrupts during initialization */ 569*f2105c61SSimon Glass writel(0, (void *)(sata_info.iobase[0] + HOST_CTRL)); 570*f2105c61SSimon Glass 571*f2105c61SSimon Glass return 0; 572*f2105c61SSimon Glass } 573*f2105c61SSimon Glass 574*f2105c61SSimon Glass int reset_sata(int dev) 575*f2105c61SSimon Glass { 576*f2105c61SSimon Glass return 0; 577*f2105c61SSimon Glass } 578*f2105c61SSimon Glass 579*f2105c61SSimon Glass /* 580*f2105c61SSimon Glass * SATA interface between low level driver and command layer 581*f2105c61SSimon Glass */ 582*f2105c61SSimon Glass int scan_sata(int dev) 583*f2105c61SSimon Glass { 584*f2105c61SSimon Glass unsigned char serial[ATA_ID_SERNO_LEN + 1]; 585*f2105c61SSimon Glass unsigned char firmware[ATA_ID_FW_REV_LEN + 1]; 586*f2105c61SSimon Glass unsigned char product[ATA_ID_PROD_LEN + 1]; 587*f2105c61SSimon Glass struct sil_sata *sata; 588*f2105c61SSimon Glass void *port; 589*f2105c61SSimon Glass int cnt; 590*f2105c61SSimon Glass u16 *id; 591*f2105c61SSimon Glass u32 tmp; 592*f2105c61SSimon Glass 593*f2105c61SSimon Glass if (dev >= sata_info.maxport) { 594*f2105c61SSimon Glass printf("SATA#%d is not present\n", dev); 595*f2105c61SSimon Glass return 1; 596*f2105c61SSimon Glass } 597*f2105c61SSimon Glass 598*f2105c61SSimon Glass printf("SATA#%d\n", dev); 599*f2105c61SSimon Glass port = (void *)sata_info.iobase[1] + 600*f2105c61SSimon Glass PORT_REGS_SIZE * (dev - sata_info.portbase); 601*f2105c61SSimon Glass 602*f2105c61SSimon Glass /* Initial PHY setting */ 603*f2105c61SSimon Glass writel(0x20c, port + PORT_PHY_CFG); 604*f2105c61SSimon Glass 605*f2105c61SSimon Glass /* clear port RST */ 606*f2105c61SSimon Glass tmp = readl(port + PORT_CTRL_STAT); 607*f2105c61SSimon Glass if (tmp & PORT_CS_PORT_RST) { 608*f2105c61SSimon Glass writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR); 609*f2105c61SSimon Glass tmp = ata_wait_register(port + PORT_CTRL_STAT, 610*f2105c61SSimon Glass PORT_CS_PORT_RST, PORT_CS_PORT_RST, 100); 611*f2105c61SSimon Glass if (tmp & PORT_CS_PORT_RST) 612*f2105c61SSimon Glass printf("Err: Failed to clear port RST\n"); 613*f2105c61SSimon Glass } 614*f2105c61SSimon Glass 615*f2105c61SSimon Glass /* Check if device is present */ 616*f2105c61SSimon Glass for (cnt = 0; cnt < 100; cnt++) { 617*f2105c61SSimon Glass tmp = readl(port + PORT_SSTATUS); 618*f2105c61SSimon Glass if ((tmp & 0xF) == 0x3) 619*f2105c61SSimon Glass break; 620*f2105c61SSimon Glass mdelay(1); 621*f2105c61SSimon Glass } 622*f2105c61SSimon Glass 623*f2105c61SSimon Glass tmp = readl(port + PORT_SSTATUS); 624*f2105c61SSimon Glass if ((tmp & 0xf) != 0x3) { 625*f2105c61SSimon Glass printf(" (No RDY)\n"); 626*f2105c61SSimon Glass return 1; 627*f2105c61SSimon Glass } 628*f2105c61SSimon Glass 629*f2105c61SSimon Glass /* Wait for port ready */ 630*f2105c61SSimon Glass tmp = ata_wait_register(port + PORT_CTRL_STAT, 631*f2105c61SSimon Glass PORT_CS_RDY, PORT_CS_RDY, 100); 632*f2105c61SSimon Glass if ((tmp & PORT_CS_RDY) != PORT_CS_RDY) { 633*f2105c61SSimon Glass printf("%d port not ready.\n", dev); 634*f2105c61SSimon Glass return 1; 635*f2105c61SSimon Glass } 636*f2105c61SSimon Glass 637*f2105c61SSimon Glass /* configure port */ 638*f2105c61SSimon Glass sil_config_port(port); 639*f2105c61SSimon Glass 640*f2105c61SSimon Glass /* Reset port */ 641*f2105c61SSimon Glass writel(PORT_CS_DEV_RST, port + PORT_CTRL_STAT); 642*f2105c61SSimon Glass readl(port + PORT_CTRL_STAT); 643*f2105c61SSimon Glass tmp = ata_wait_register(port + PORT_CTRL_STAT, PORT_CS_DEV_RST, 644*f2105c61SSimon Glass PORT_CS_DEV_RST, 100); 645*f2105c61SSimon Glass if (tmp & PORT_CS_DEV_RST) { 646*f2105c61SSimon Glass printf("%d port reset failed.\n", dev); 647*f2105c61SSimon Glass return 1; 648*f2105c61SSimon Glass } 649*f2105c61SSimon Glass 650*f2105c61SSimon Glass sata = (struct sil_sata *)malloc(sizeof(struct sil_sata)); 651*f2105c61SSimon Glass if (!sata) { 652*f2105c61SSimon Glass printf("%d no memory.\n", dev); 653*f2105c61SSimon Glass return 1; 654*f2105c61SSimon Glass } 655*f2105c61SSimon Glass memset((void *)sata, 0, sizeof(struct sil_sata)); 656*f2105c61SSimon Glass 657*f2105c61SSimon Glass /* turn on port interrupt */ 658*f2105c61SSimon Glass tmp = readl((void *)(sata_info.iobase[0] + HOST_CTRL)); 659*f2105c61SSimon Glass tmp |= (1 << (dev - sata_info.portbase)); 660*f2105c61SSimon Glass writel(tmp, (void *)(sata_info.iobase[0] + HOST_CTRL)); 661*f2105c61SSimon Glass 662*f2105c61SSimon Glass /* Save the private struct to block device struct */ 663*f2105c61SSimon Glass sata_dev_desc[dev].priv = (void *)sata; 664*f2105c61SSimon Glass sata->port = port; 665*f2105c61SSimon Glass sata->devno = sata_info.devno; 666*f2105c61SSimon Glass sprintf(sata->name, "SATA#%d", dev); 667*f2105c61SSimon Glass sil_cmd_soft_reset(dev); 668*f2105c61SSimon Glass tmp = readl(port + PORT_SSTATUS); 669*f2105c61SSimon Glass tmp = (tmp >> 4) & 0xf; 670*f2105c61SSimon Glass printf(" (%s)\n", sata_spd_string(tmp)); 671*f2105c61SSimon Glass 672*f2105c61SSimon Glass id = (u16 *)malloc(ATA_ID_WORDS * 2); 673*f2105c61SSimon Glass if (!id) { 674*f2105c61SSimon Glass printf("Id malloc failed\n"); 675*f2105c61SSimon Glass free((void *)sata); 676*f2105c61SSimon Glass return 1; 677*f2105c61SSimon Glass } 678*f2105c61SSimon Glass sil_cmd_identify_device(dev, id); 679*f2105c61SSimon Glass 680*f2105c61SSimon Glass #ifdef CONFIG_LBA48 681*f2105c61SSimon Glass /* Check if support LBA48 */ 682*f2105c61SSimon Glass if (ata_id_has_lba48(id)) { 683*f2105c61SSimon Glass sata_dev_desc[dev].lba48 = 1; 684*f2105c61SSimon Glass sata->lba48 = 1; 685*f2105c61SSimon Glass debug("Device supports LBA48\n"); 686*f2105c61SSimon Glass } else 687*f2105c61SSimon Glass debug("Device supports LBA28\n"); 688*f2105c61SSimon Glass #endif 689*f2105c61SSimon Glass 690*f2105c61SSimon Glass /* Serial number */ 691*f2105c61SSimon Glass ata_id_c_string(id, serial, ATA_ID_SERNO, sizeof(serial)); 692*f2105c61SSimon Glass memcpy(sata_dev_desc[dev].product, serial, sizeof(serial)); 693*f2105c61SSimon Glass 694*f2105c61SSimon Glass /* Firmware version */ 695*f2105c61SSimon Glass ata_id_c_string(id, firmware, ATA_ID_FW_REV, sizeof(firmware)); 696*f2105c61SSimon Glass memcpy(sata_dev_desc[dev].revision, firmware, sizeof(firmware)); 697*f2105c61SSimon Glass 698*f2105c61SSimon Glass /* Product model */ 699*f2105c61SSimon Glass ata_id_c_string(id, product, ATA_ID_PROD, sizeof(product)); 700*f2105c61SSimon Glass memcpy(sata_dev_desc[dev].vendor, product, sizeof(product)); 701*f2105c61SSimon Glass 702*f2105c61SSimon Glass /* Totoal sectors */ 703*f2105c61SSimon Glass sata_dev_desc[dev].lba = ata_id_n_sectors(id); 704*f2105c61SSimon Glass 705*f2105c61SSimon Glass sil_sata_init_wcache(dev, id); 706*f2105c61SSimon Glass sil_cmd_set_feature(dev); 707*f2105c61SSimon Glass 708*f2105c61SSimon Glass #ifdef DEBUG 709*f2105c61SSimon Glass sil_cmd_identify_device(dev, id); 710*f2105c61SSimon Glass ata_dump_id(id); 711*f2105c61SSimon Glass #endif 712*f2105c61SSimon Glass free((void *)id); 713*f2105c61SSimon Glass 714*f2105c61SSimon Glass return 0; 715*f2105c61SSimon Glass } 716