1 #include <common.h> 2 #include <ahci.h> 3 #include <scsi.h> 4 #include <errno.h> 5 #include <asm/io.h> 6 #include <asm/gpio.h> 7 8 #define AHCI_PHYCS0R 0x00c0 9 #define AHCI_PHYCS1R 0x00c4 10 #define AHCI_PHYCS2R 0x00c8 11 #define AHCI_RWCR 0x00fc 12 13 /* This magic PHY initialisation was taken from the Allwinner releases 14 * and Linux driver, but is completely undocumented. 15 */ 16 static int sunxi_ahci_phy_init(u32 base) 17 { 18 u8 *reg_base = (u8 *)base; 19 u32 reg_val; 20 int timeout; 21 22 writel(0, reg_base + AHCI_RWCR); 23 mdelay(5); 24 25 setbits_le32(reg_base + AHCI_PHYCS1R, 0x1 << 19); 26 clrsetbits_le32(reg_base + AHCI_PHYCS0R, 27 (0x7 << 24), 28 (0x5 << 24) | (0x1 << 23) | (0x1 << 18)); 29 clrsetbits_le32(reg_base + AHCI_PHYCS1R, 30 (0x3 << 16) | (0x1f << 8) | (0x3 << 6), 31 (0x2 << 16) | (0x6 << 8) | (0x2 << 6)); 32 setbits_le32(reg_base + AHCI_PHYCS1R, (0x1 << 28) | (0x1 << 15)); 33 clrbits_le32(reg_base + AHCI_PHYCS1R, (0x1 << 19)); 34 clrsetbits_le32(reg_base + AHCI_PHYCS0R, (0x7 << 20), (0x3 << 20)); 35 clrsetbits_le32(reg_base + AHCI_PHYCS2R, (0x1f << 5), (0x19 << 5)); 36 mdelay(5); 37 38 setbits_le32(reg_base + AHCI_PHYCS0R, (0x1 << 19)); 39 40 timeout = 250; /* Power up takes approx 50 us */ 41 for (;;) { 42 reg_val = readl(reg_base + AHCI_PHYCS0R) & (0x7 << 28); 43 if (reg_val == (0x2 << 28)) 44 break; 45 if (--timeout == 0) { 46 printf("AHCI PHY power up failed.\n"); 47 return -EIO; 48 } 49 udelay(1); 50 }; 51 52 setbits_le32(reg_base + AHCI_PHYCS2R, (0x1 << 24)); 53 54 timeout = 100; /* Calibration takes approx 10 us */ 55 for (;;) { 56 reg_val = readl(reg_base + AHCI_PHYCS2R) & (0x1 << 24); 57 if (reg_val == 0x0) 58 break; 59 if (--timeout == 0) { 60 printf("AHCI PHY calibration failed.\n"); 61 return -EIO; 62 } 63 udelay(1); 64 } 65 66 mdelay(15); 67 68 writel(0x7, reg_base + AHCI_RWCR); 69 70 return 0; 71 } 72 73 void scsi_init(void) 74 { 75 printf("SUNXI SCSI INIT\n"); 76 #ifdef CONFIG_SATAPWR 77 gpio_direction_output(CONFIG_SATAPWR, 1); 78 #endif 79 80 if (sunxi_ahci_phy_init(SUNXI_SATA_BASE) < 0) 81 return; 82 83 ahci_init(SUNXI_SATA_BASE); 84 } 85