blob: 58e345d9983cd96c9285bab7864e91fe5c657b4d [file] [log] [blame]
Ian Campbella6e50a82014-07-18 20:38:41 +01001#include <common.h>
2#include <ahci.h>
Simon Glasscf7b2e12017-07-04 13:31:31 -06003#include <dm.h>
Simon Glassf7ae49f2020-05-10 11:40:05 -06004#include <log.h>
Ian Campbella6e50a82014-07-18 20:38:41 +01005#include <scsi.h>
6#include <errno.h>
7#include <asm/io.h>
8#include <asm/gpio.h>
Simon Glassc05ed002020-05-10 11:40:11 -06009#include <linux/delay.h>
Ian Campbella6e50a82014-07-18 20:38:41 +010010
11#define AHCI_PHYCS0R 0x00c0
12#define AHCI_PHYCS1R 0x00c4
13#define AHCI_PHYCS2R 0x00c8
14#define AHCI_RWCR 0x00fc
15
16/* This magic PHY initialisation was taken from the Allwinner releases
17 * and Linux driver, but is completely undocumented.
18 */
Simon Glasscf7b2e12017-07-04 13:31:31 -060019static int sunxi_ahci_phy_init(u8 *reg_base)
Ian Campbella6e50a82014-07-18 20:38:41 +010020{
Ian Campbella6e50a82014-07-18 20:38:41 +010021 u32 reg_val;
22 int timeout;
23
24 writel(0, reg_base + AHCI_RWCR);
25 mdelay(5);
26
27 setbits_le32(reg_base + AHCI_PHYCS1R, 0x1 << 19);
28 clrsetbits_le32(reg_base + AHCI_PHYCS0R,
29 (0x7 << 24),
30 (0x5 << 24) | (0x1 << 23) | (0x1 << 18));
31 clrsetbits_le32(reg_base + AHCI_PHYCS1R,
32 (0x3 << 16) | (0x1f << 8) | (0x3 << 6),
33 (0x2 << 16) | (0x6 << 8) | (0x2 << 6));
34 setbits_le32(reg_base + AHCI_PHYCS1R, (0x1 << 28) | (0x1 << 15));
35 clrbits_le32(reg_base + AHCI_PHYCS1R, (0x1 << 19));
36 clrsetbits_le32(reg_base + AHCI_PHYCS0R, (0x7 << 20), (0x3 << 20));
37 clrsetbits_le32(reg_base + AHCI_PHYCS2R, (0x1f << 5), (0x19 << 5));
38 mdelay(5);
39
40 setbits_le32(reg_base + AHCI_PHYCS0R, (0x1 << 19));
41
42 timeout = 250; /* Power up takes approx 50 us */
43 for (;;) {
44 reg_val = readl(reg_base + AHCI_PHYCS0R) & (0x7 << 28);
45 if (reg_val == (0x2 << 28))
46 break;
47 if (--timeout == 0) {
48 printf("AHCI PHY power up failed.\n");
49 return -EIO;
50 }
51 udelay(1);
52 };
53
54 setbits_le32(reg_base + AHCI_PHYCS2R, (0x1 << 24));
55
56 timeout = 100; /* Calibration takes approx 10 us */
57 for (;;) {
58 reg_val = readl(reg_base + AHCI_PHYCS2R) & (0x1 << 24);
59 if (reg_val == 0x0)
60 break;
61 if (--timeout == 0) {
62 printf("AHCI PHY calibration failed.\n");
63 return -EIO;
64 }
65 udelay(1);
66 }
67
68 mdelay(15);
69
70 writel(0x7, reg_base + AHCI_RWCR);
71
72 return 0;
73}
74
Simon Glasscf7b2e12017-07-04 13:31:31 -060075static int sunxi_sata_probe(struct udevice *dev)
76{
77 ulong base;
78 u8 *reg;
79 int ret;
80
81 base = dev_read_addr(dev);
82 if (base == FDT_ADDR_T_NONE) {
83 debug("%s: Failed to find address (err=%d\n)", __func__, ret);
84 return -EINVAL;
85 }
86 reg = (u8 *)base;
87 ret = sunxi_ahci_phy_init(reg);
88 if (ret) {
89 debug("%s: Failed to init phy (err=%d\n)", __func__, ret);
90 return ret;
91 }
92 ret = ahci_probe_scsi(dev, base);
93 if (ret) {
94 debug("%s: Failed to probe (err=%d\n)", __func__, ret);
95 return ret;
96 }
97
98 return 0;
99}
100
101static int sunxi_sata_bind(struct udevice *dev)
102{
103 struct udevice *scsi_dev;
104 int ret;
105
106 ret = ahci_bind_scsi(dev, &scsi_dev);
107 if (ret) {
108 debug("%s: Failed to bind (err=%d\n)", __func__, ret);
109 return ret;
110 }
111
112 return 0;
113}
114
115static const struct udevice_id sunxi_ahci_ids[] = {
116 { .compatible = "allwinner,sun4i-a10-ahci" },
Jagan Tekicbb9cdc2019-04-12 16:47:56 +0530117 { .compatible = "allwinner,sun8i-r40-ahci" },
Simon Glasscf7b2e12017-07-04 13:31:31 -0600118 { }
119};
120
121U_BOOT_DRIVER(ahci_sunxi_drv) = {
122 .name = "ahci_sunxi",
123 .id = UCLASS_AHCI,
124 .of_match = sunxi_ahci_ids,
125 .bind = sunxi_sata_bind,
126 .probe = sunxi_sata_probe,
127};