]>
Commit | Line | Data |
---|---|---|
39419ce5 | 1 | /* |
57b4bce9 | 2 | * Copyright (C) 2010 Albert ARIBAUD <albert.u.boot@aribaud.net> |
39419ce5 | 3 | * |
57b4bce9 | 4 | * Written-by: Albert ARIBAUD <albert.u.boot@aribaud.net> |
39419ce5 | 5 | * |
1a459660 | 6 | * SPDX-License-Identifier: GPL-2.0+ |
39419ce5 AA |
7 | */ |
8 | ||
9 | #include <common.h> | |
10 | #include <asm/io.h> | |
11 | ||
12 | #if defined(CONFIG_ORION5X) | |
13 | #include <asm/arch/orion5x.h> | |
14 | #elif defined(CONFIG_KIRKWOOD) | |
3dc23f78 | 15 | #include <asm/arch/soc.h> |
81e33f4b | 16 | #elif defined(CONFIG_ARCH_MVEBU) |
e863f7f0 | 17 | #include <linux/mbus.h> |
39419ce5 AA |
18 | #endif |
19 | ||
20 | /* SATA port registers */ | |
21 | struct mvsata_port_registers { | |
70c55f5a MW |
22 | u32 reserved0[10]; |
23 | u32 edma_cmd; | |
24 | u32 reserved1[181]; | |
39419ce5 AA |
25 | /* offset 0x300 : ATA Interface registers */ |
26 | u32 sstatus; | |
27 | u32 serror; | |
28 | u32 scontrol; | |
29 | u32 ltmode; | |
30 | u32 phymode3; | |
31 | u32 phymode4; | |
32 | u32 reserved2[5]; | |
33 | u32 phymode1; | |
34 | u32 phymode2; | |
35 | u32 bist_cr; | |
36 | u32 bist_dw1; | |
37 | u32 bist_dw2; | |
38 | u32 serrorintrmask; | |
39 | }; | |
40 | ||
41 | /* | |
42 | * Sanity checks: | |
43 | * - to compile at all, we need CONFIG_SYS_ATA_BASE_ADDR. | |
44 | * - for ide_preinit to make sense, we need at least one of | |
c08349e7 GR |
45 | * CONFIG_SYS_ATA_IDE0_OFFSET or CONFIG_SYS_ATA_IDE1_OFFSET; |
46 | * - for ide_preinit to be called, we need CONFIG_IDE_PREINIT. | |
39419ce5 AA |
47 | * Fail with an explanation message if these conditions are not met. |
48 | * This is particularly important for CONFIG_IDE_PREINIT, because | |
49 | * its lack would not cause a build error. | |
50 | */ | |
51 | ||
52 | #if !defined(CONFIG_SYS_ATA_BASE_ADDR) | |
53 | #error CONFIG_SYS_ATA_BASE_ADDR must be defined | |
54 | #elif !defined(CONFIG_SYS_ATA_IDE0_OFFSET) \ | |
55 | && !defined(CONFIG_SYS_ATA_IDE1_OFFSET) | |
56 | #error CONFIG_SYS_ATA_IDE0_OFFSET or CONFIG_SYS_ATA_IDE1_OFFSET \ | |
57 | must be defined | |
58 | #elif !defined(CONFIG_IDE_PREINIT) | |
59 | #error CONFIG_IDE_PREINIT must be defined | |
60 | #endif | |
61 | ||
62 | /* | |
63 | * Masks and values for SControl DETection and Interface Power Management, | |
64 | * and for SStatus DETection. | |
65 | */ | |
66 | ||
70c55f5a | 67 | #define MVSATA_EDMA_CMD_ATA_RST 0x00000004 |
39419ce5 AA |
68 | #define MVSATA_SCONTROL_DET_MASK 0x0000000F |
69 | #define MVSATA_SCONTROL_DET_NONE 0x00000000 | |
70 | #define MVSATA_SCONTROL_DET_INIT 0x00000001 | |
71 | #define MVSATA_SCONTROL_IPM_MASK 0x00000F00 | |
72 | #define MVSATA_SCONTROL_IPM_NO_LP_ALLOWED 0x00000300 | |
73 | #define MVSATA_SCONTROL_MASK \ | |
74 | (MVSATA_SCONTROL_DET_MASK|MVSATA_SCONTROL_IPM_MASK) | |
75 | #define MVSATA_PORT_INIT \ | |
76 | (MVSATA_SCONTROL_DET_INIT|MVSATA_SCONTROL_IPM_NO_LP_ALLOWED) | |
77 | #define MVSATA_PORT_USE \ | |
78 | (MVSATA_SCONTROL_DET_NONE|MVSATA_SCONTROL_IPM_NO_LP_ALLOWED) | |
79 | #define MVSATA_SSTATUS_DET_MASK 0x0000000F | |
80 | #define MVSATA_SSTATUS_DET_DEVCOMM 0x00000003 | |
81 | ||
d3497138 AA |
82 | /* |
83 | * Status codes to return to client callers. Currently, callers ignore | |
84 | * exact value and only care for zero or nonzero, so no need to make this | |
85 | * public, it is only #define'd for clarity. | |
a187559e | 86 | * If/when standard negative codes are implemented in U-Boot, then these |
d3497138 AA |
87 | * #defines should be moved to, or replaced by ones from, the common list |
88 | * of status codes. | |
89 | */ | |
90 | ||
91 | #define MVSATA_STATUS_OK 0 | |
92 | #define MVSATA_STATUS_TIMEOUT -1 | |
93 | ||
e863f7f0 AS |
94 | /* |
95 | * Registers for SATA MBUS memory windows | |
96 | */ | |
97 | ||
98 | #define MVSATA_WIN_CONTROL(w) (MVEBU_AXP_SATA_BASE + 0x30 + ((w) << 4)) | |
99 | #define MVSATA_WIN_BASE(w) (MVEBU_AXP_SATA_BASE + 0x34 + ((w) << 4)) | |
100 | ||
101 | /* | |
102 | * Initialize SATA memory windows for Armada XP | |
103 | */ | |
104 | ||
81e33f4b | 105 | #ifdef CONFIG_ARCH_MVEBU |
e863f7f0 AS |
106 | static void mvsata_ide_conf_mbus_windows(void) |
107 | { | |
108 | const struct mbus_dram_target_info *dram; | |
109 | int i; | |
110 | ||
111 | dram = mvebu_mbus_dram_info(); | |
112 | ||
113 | /* Disable windows, Set Size/Base to 0 */ | |
114 | for (i = 0; i < 4; i++) { | |
115 | writel(0, MVSATA_WIN_CONTROL(i)); | |
116 | writel(0, MVSATA_WIN_BASE(i)); | |
117 | } | |
118 | ||
119 | for (i = 0; i < dram->num_cs; i++) { | |
120 | const struct mbus_dram_window *cs = dram->cs + i; | |
121 | writel(((cs->size - 1) & 0xffff0000) | (cs->mbus_attr << 8) | | |
122 | (dram->mbus_dram_target_id << 4) | 1, | |
123 | MVSATA_WIN_CONTROL(i)); | |
124 | writel(cs->base & 0xffff0000, MVSATA_WIN_BASE(i)); | |
125 | } | |
126 | } | |
127 | #endif | |
128 | ||
39419ce5 AA |
129 | /* |
130 | * Initialize one MVSATAHC port: set SControl's IPM to "always active" | |
131 | * and DET to "reset", then wait for SStatus's DET to become "device and | |
132 | * comm ok" (or time out after 50 us if no device), then set SControl's | |
133 | * DET back to "no action". | |
134 | */ | |
135 | ||
d3497138 | 136 | static int mvsata_ide_initialize_port(struct mvsata_port_registers *port) |
39419ce5 AA |
137 | { |
138 | u32 control; | |
139 | u32 status; | |
d3497138 | 140 | u32 timeleft = 10000; /* wait at most 10 ms for SATA reset to complete */ |
39419ce5 | 141 | |
70c55f5a MW |
142 | /* Hard reset */ |
143 | writel(MVSATA_EDMA_CMD_ATA_RST, &port->edma_cmd); | |
144 | udelay(25); /* taken from original marvell port */ | |
145 | writel(0, &port->edma_cmd); | |
146 | ||
d3497138 | 147 | /* Set control IPM to 3 (no low power) and DET to 1 (initialize) */ |
39419ce5 AA |
148 | control = readl(&port->scontrol); |
149 | control = (control & ~MVSATA_SCONTROL_MASK) | MVSATA_PORT_INIT; | |
150 | writel(control, &port->scontrol); | |
d3497138 AA |
151 | /* Toggle control DET back to 0 (normal operation) */ |
152 | control = (control & ~MVSATA_SCONTROL_MASK) | MVSATA_PORT_USE; | |
153 | writel(control, &port->scontrol); | |
154 | /* wait for status DET to become 3 (device and communication OK) */ | |
155 | while (--timeleft) { | |
39419ce5 AA |
156 | status = readl(&port->sstatus) & MVSATA_SSTATUS_DET_MASK; |
157 | if (status == MVSATA_SSTATUS_DET_DEVCOMM) | |
158 | break; | |
159 | udelay(1); | |
160 | } | |
d3497138 AA |
161 | /* return success or time-out error depending on time left */ |
162 | if (!timeleft) | |
163 | return MVSATA_STATUS_TIMEOUT; | |
164 | return MVSATA_STATUS_OK; | |
39419ce5 AA |
165 | } |
166 | ||
167 | /* | |
168 | * ide_preinit() will be called by ide_init in cmd_ide.c and will | |
169 | * reset the MVSTATHC ports needed by the board. | |
170 | */ | |
171 | ||
172 | int ide_preinit(void) | |
173 | { | |
2cb4fade | 174 | int ret = MVSATA_STATUS_TIMEOUT; |
d3497138 | 175 | int status; |
2cb4fade | 176 | |
81e33f4b | 177 | #ifdef CONFIG_ARCH_MVEBU |
e863f7f0 AS |
178 | mvsata_ide_conf_mbus_windows(); |
179 | #endif | |
180 | ||
39419ce5 AA |
181 | /* Enable ATA port 0 (could be SATA port 0 or 1) if declared */ |
182 | #if defined(CONFIG_SYS_ATA_IDE0_OFFSET) | |
d3497138 | 183 | status = mvsata_ide_initialize_port( |
39419ce5 AA |
184 | (struct mvsata_port_registers *) |
185 | (CONFIG_SYS_ATA_BASE_ADDR + CONFIG_SYS_ATA_IDE0_OFFSET)); | |
2cb4fade SG |
186 | if (status == MVSATA_STATUS_OK) |
187 | ret = MVSATA_STATUS_OK; | |
39419ce5 AA |
188 | #endif |
189 | /* Enable ATA port 1 (could be SATA port 0 or 1) if declared */ | |
190 | #if defined(CONFIG_SYS_ATA_IDE1_OFFSET) | |
d3497138 | 191 | status = mvsata_ide_initialize_port( |
39419ce5 AA |
192 | (struct mvsata_port_registers *) |
193 | (CONFIG_SYS_ATA_BASE_ADDR + CONFIG_SYS_ATA_IDE1_OFFSET)); | |
2cb4fade SG |
194 | if (status == MVSATA_STATUS_OK) |
195 | ret = MVSATA_STATUS_OK; | |
39419ce5 | 196 | #endif |
2cb4fade SG |
197 | /* Return success if at least one port initialization succeeded */ |
198 | return ret; | |
39419ce5 | 199 | } |