📄 sata_sil3114.c
字号:
} udelay (1000); max--; } while ((status & bits) && (max > 0)); return status;}static u8 sata_chk_status (struct sata_ioports *ioaddr, u8 usealtstatus){ if (!usealtstatus) { return readb (ioaddr->status_addr); } else { return readb (ioaddr->altstatus_addr); }}static void msleep (int count){ int i; for (i = 0; i < count; i++) udelay (1000);}/* Read up to 255 sectors * * Returns sectors read*/static u8 do_one_read (int device, ulong block, u8 blkcnt, u16 * buff, uchar lba48){ u8 sr = 0; u8 status; u64 blknr = (u64) block; if (!(sata_chk_status (&port[device].ioaddr, 0) & ATA_DRDY)) { printf ("Device ata%d not ready\n", device); return 0; } /* Set up transfer */#ifdef CONFIG_LBA48 if (lba48) { /* write high bits */ writeb (0, port[device].ioaddr.nsect_addr); writeb ((blknr >> 24) & 0xFF, port[device].ioaddr.lbal_addr); writeb ((blknr >> 32) & 0xFF, port[device].ioaddr.lbam_addr); writeb ((blknr >> 40) & 0xFF, port[device].ioaddr.lbah_addr); }#endif writeb (blkcnt, port[device].ioaddr.nsect_addr); writeb (((blknr) >> 0) & 0xFF, port[device].ioaddr.lbal_addr); writeb ((blknr >> 8) & 0xFF, port[device].ioaddr.lbam_addr); writeb ((blknr >> 16) & 0xFF, port[device].ioaddr.lbah_addr);#ifdef CONFIG_LBA48 if (lba48) { writeb (ATA_LBA, port[device].ioaddr.device_addr); writeb (ATA_CMD_PIO_READ_EXT, port[device].ioaddr.command_addr); } else#endif { writeb (ATA_LBA | ((blknr >> 24) & 0xF), port[device].ioaddr.device_addr); writeb (ATA_CMD_PIO_READ, port[device].ioaddr.command_addr); } status = sata_busy_wait (&port[device].ioaddr, ATA_BUSY, 10000, 1); if (status & ATA_BUSY) { u8 err = 0; printf ("Device %d not responding status %d\n", device, status); err = readb (port[device].ioaddr.error_addr); printf ("Error reg = 0x%x\n", err); return (sr); } while (blkcnt--) { if (wait_for_irq (device, 500)) { printf ("ata%u irq failed\n", device); return sr; } status = sata_chk_status (&port[device].ioaddr, 0); if (status & ATA_ERR) { printf ("ata%u error %d\n", device, readb (port[device].ioaddr.error_addr)); return sr; } /* Read one sector */ input_data (&port[device].ioaddr, buff, ATA_SECTOR_WORDS); buff += ATA_SECTOR_WORDS; sr++; } return sr;}ulong sata_read (int device, ulong block, lbaint_t blkcnt, void *buff){ ulong n = 0, sread; u16 *buffer = (u16 *) buff; u8 status = 0; u64 blknr = (u64) block; unsigned char lba48 = 0;#ifdef CONFIG_LBA48 if (blknr > 0xfffffff) { if (!sata_dev_desc[device].lba48) { printf ("Drive doesn't support 48-bit addressing\n"); return 0; } /* more than 28 bits used, use 48bit mode */ lba48 = 1; }#endif while (blkcnt > 0) { if (blkcnt > 255) { sread = 255; } else { sread = blkcnt; } status = do_one_read (device, blknr, sread, buffer, lba48); if (status != sread) { printf ("Read failed\n"); return n; } blkcnt -= sread; blknr += sread; n += sread; buffer += sread * ATA_SECTOR_WORDS; } return n;}ulong sata_write (int device, ulong block, lbaint_t blkcnt, const void *buff){ ulong n = 0; u16 *buffer = (u16 *) buff; unsigned char status = 0, num = 0; u64 blknr = (u64) block;#ifdef CONFIG_LBA48 unsigned char lba48 = 0; if (blknr > 0xfffffff) { if (!sata_dev_desc[device].lba48) { printf ("Drive doesn't support 48-bit addressing\n"); return 0; } /* more than 28 bits used, use 48bit mode */ lba48 = 1; }#endif /*Port Number */ num = device; while (blkcnt-- > 0) { status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 500, 0); if (status & ATA_BUSY) { printf ("ata%u failed to respond\n", port[num].port_no); return n; }#ifdef CONFIG_LBA48 if (lba48) { /* write high bits */ writeb (0, port[num].ioaddr.nsect_addr); writeb ((blknr >> 24) & 0xFF, port[num].ioaddr.lbal_addr); writeb ((blknr >> 32) & 0xFF, port[num].ioaddr.lbam_addr); writeb ((blknr >> 40) & 0xFF, port[num].ioaddr.lbah_addr); }#endif writeb (1, port[num].ioaddr.nsect_addr); writeb ((blknr >> 0) & 0xFF, port[num].ioaddr.lbal_addr); writeb ((blknr >> 8) & 0xFF, port[num].ioaddr.lbam_addr); writeb ((blknr >> 16) & 0xFF, port[num].ioaddr.lbah_addr);#ifdef CONFIG_LBA48 if (lba48) { writeb (ATA_LBA, port[num].ioaddr.device_addr); writeb (ATA_CMD_PIO_WRITE_EXT, port[num].ioaddr.command_addr); } else#endif { writeb (ATA_LBA | ((blknr >> 24) & 0xF), port[num].ioaddr.device_addr); writeb (ATA_CMD_PIO_WRITE, port[num].ioaddr.command_addr); } msleep (50); /*may take up to 4 sec */ status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 4000, 0); if ((status & (ATA_DRQ | ATA_BUSY | ATA_ERR)) != ATA_DRQ) { printf ("Error no DRQ dev %d blk %ld: sts 0x%02x\n", device, (ulong) blknr, status); return (n); } output_data (&port[num].ioaddr, buffer, ATA_SECTOR_WORDS); readb (port[num].ioaddr.altstatus_addr); udelay (50); ++n; ++blknr; buffer += ATA_SECTOR_WORDS; } return n;}/* Driver implementation */static u8 sil_get_device_cache_line (pci_dev_t pdev){ u8 cache_line = 0; pci_read_config_byte (pdev, PCI_CACHE_LINE_SIZE, &cache_line); return cache_line;}int init_sata (int dev){ static u8 init_done = 0; static int res = 1; pci_dev_t devno; u8 cls = 0; u16 cmd = 0; u32 sconf = 0; if (init_done) { return res; } init_done = 1; if ((devno = pci_find_device (SIL_VEND_ID, SIL3114_DEVICE_ID, 0)) == -1) { res = 1; return res; } /* Read out all BARs, even though we only use MMIO from BAR5 */ pci_read_config_dword (devno, PCI_BASE_ADDRESS_0, &iobase[0]); pci_read_config_dword (devno, PCI_BASE_ADDRESS_1, &iobase[1]); pci_read_config_dword (devno, PCI_BASE_ADDRESS_2, &iobase[2]); pci_read_config_dword (devno, PCI_BASE_ADDRESS_3, &iobase[3]); pci_read_config_dword (devno, PCI_BASE_ADDRESS_4, &iobase[4]); pci_read_config_dword (devno, PCI_BASE_ADDRESS_5, &iobase[5]); if ((iobase[0] == 0xFFFFFFFF) || (iobase[1] == 0xFFFFFFFF) || (iobase[2] == 0xFFFFFFFF) || (iobase[3] == 0xFFFFFFFF) || (iobase[4] == 0xFFFFFFFF) || (iobase[5] == 0xFFFFFFFF)) { printf ("Error no base addr for SATA controller\n"); res = 1; return res; } /* mask off unused bits */ iobase[0] &= 0xfffffffc; iobase[1] &= 0xfffffff8; iobase[2] &= 0xfffffffc; iobase[3] &= 0xfffffff8; iobase[4] &= 0xfffffff0; iobase[5] &= 0xfffffc00; /* from sata_sil in Linux kernel */ cls = sil_get_device_cache_line (devno); if (cls) { cls >>= 3; cls++; /* cls = (line_size/8)+1 */ writel (cls << 8 | cls, iobase[5] + VND_FIFOCFG_CH0); writel (cls << 8 | cls, iobase[5] + VND_FIFOCFG_CH1); writel (cls << 8 | cls, iobase[5] + VND_FIFOCFG_CH2); writel (cls << 8 | cls, iobase[5] + VND_FIFOCFG_CH3); } else { printf ("Cache line not set. Driver may not function\n"); } /* Enable operation */ pci_read_config_word (devno, PCI_COMMAND, &cmd); cmd |= PCI_COMMAND_MASTER | PCI_COMMAND_IO | PCI_COMMAND_MEMORY; pci_write_config_word (devno, PCI_COMMAND, cmd); /* Disable interrupt usage */ pci_read_config_dword (devno, VND_SYSCONFSTAT, &sconf); sconf |= (VND_SYSCONFSTAT_CHN_0_INTBLOCK | VND_SYSCONFSTAT_CHN_1_INTBLOCK); pci_write_config_dword (devno, VND_SYSCONFSTAT, sconf); res = 0; return res;}/* Check if device is connected to port */int sata_bus_probe (int portno){ u32 port = iobase[5]; u32 val; switch (portno) { case 0: port += VND_SSTATUS_CH0; break; case 1: port += VND_SSTATUS_CH1; break; case 2: port += VND_SSTATUS_CH2; break; case 3: port += VND_SSTATUS_CH3; break; default: return 0; } val = readl (port); if ((val & SATA_DET_PRES) == SATA_DET_PRES) { return 1; } else { return 0; }}int sata_phy_reset (int portno){ u32 port = iobase[5]; u32 val; switch (portno) { case 0: port += VND_SCONTROL_CH0; break; case 1: port += VND_SCONTROL_CH1; break; case 2: port += VND_SCONTROL_CH2; break; case 3: port += VND_SCONTROL_CH3; break; default: return 0; } val = readl (port); writel (val | SATA_SC_DET_RST, port); msleep (150); writel (val & ~SATA_SC_DET_RST, port); return 0;}int scan_sata (int dev){ /* A bit brain dead, but the code has a legacy */ switch (dev) { case 0: port[0].port_no = 0; port[0].ioaddr.cmd_addr = iobase[5] + VND_TF0_CH0; port[0].ioaddr.altstatus_addr = port[0].ioaddr.ctl_addr = (iobase[5] + VND_TF2_CH0) | ATA_PCI_CTL_OFS; port[0].ioaddr.bmdma_addr = iobase[5] + VND_BMDMA_CH0; break; case 1: port[1].port_no = 0; port[1].ioaddr.cmd_addr = iobase[5] + VND_TF0_CH1; port[1].ioaddr.altstatus_addr = port[1].ioaddr.ctl_addr = (iobase[5] + VND_TF2_CH1) | ATA_PCI_CTL_OFS; port[1].ioaddr.bmdma_addr = iobase[5] + VND_BMDMA_CH1; break; case 2: port[2].port_no = 0; port[2].ioaddr.cmd_addr = iobase[5] + VND_TF0_CH2; port[2].ioaddr.altstatus_addr = port[2].ioaddr.ctl_addr = (iobase[5] + VND_TF2_CH2) | ATA_PCI_CTL_OFS; port[2].ioaddr.bmdma_addr = iobase[5] + VND_BMDMA_CH2; break; case 3: port[3].port_no = 0; port[3].ioaddr.cmd_addr = iobase[5] + VND_TF0_CH3; port[3].ioaddr.altstatus_addr = port[3].ioaddr.ctl_addr = (iobase[5] + VND_TF2_CH3) | ATA_PCI_CTL_OFS; port[3].ioaddr.bmdma_addr = iobase[5] + VND_BMDMA_CH3; break; default: printf ("Tried to scan unknown port: ata%d\n", dev); return 1; } /* Initialize other registers */ sata_port (&port[dev].ioaddr); /* Check for attached device */ if (!sata_bus_probe (dev)) { port[dev].port_state = 0; debug ("SATA#%d port is not present\n", dev); } else { debug ("SATA#%d port is present\n", dev); if (sata_bus_softreset (dev)) { /* soft reset failed, try a hard one */ sata_phy_reset (dev); if (sata_bus_softreset (dev)) { port[dev].port_state = 0; } else { port[dev].port_state = 1; } } else { port[dev].port_state = 1; } } if (port[dev].port_state == 1) { /* Probe device and set xfer mode */ sata_identify (dev, 0); set_Feature_cmd (dev, 0); } return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -