Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/arm/freescale/imx/imx6_ahci.c
39537 views
1
/*-
2
* Copyright (c) 2017 Rogiel Sulzbach <[email protected]>
3
* All rights reserved.
4
*
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
7
* are met:
8
* 1. Redistributions of source code must retain the above copyright
9
* notice, this list of conditions and the following disclaimer.
10
* 2. Redistributions in binary form must reproduce the above copyright
11
* notice, this list of conditions and the following disclaimer in the
12
* documentation and/or other materials provided with the distribution.
13
*
14
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24
* SUCH DAMAGE.
25
*/
26
27
28
#include <sys/param.h>
29
#include <sys/systm.h>
30
#include <sys/bus.h>
31
#include <sys/rman.h>
32
#include <sys/kernel.h>
33
#include <sys/module.h>
34
35
#include <machine/bus.h>
36
#include <dev/ofw/ofw_bus.h>
37
#include <dev/ofw/ofw_bus_subr.h>
38
39
#include <dev/ahci/ahci.h>
40
#include <arm/freescale/imx/imx_iomuxreg.h>
41
#include <arm/freescale/imx/imx_iomuxvar.h>
42
#include <arm/freescale/imx/imx_ccmvar.h>
43
44
#define SATA_TIMER1MS 0x000000e0
45
46
#define SATA_P0PHYCR 0x00000178
47
#define SATA_P0PHYCR_CR_READ (1 << 19)
48
#define SATA_P0PHYCR_CR_WRITE (1 << 18)
49
#define SATA_P0PHYCR_CR_CAP_DATA (1 << 17)
50
#define SATA_P0PHYCR_CR_CAP_ADDR (1 << 16)
51
#define SATA_P0PHYCR_CR_DATA_IN(v) ((v) & 0xffff)
52
53
#define SATA_P0PHYSR 0x0000017c
54
#define SATA_P0PHYSR_CR_ACK (1 << 18)
55
#define SATA_P0PHYSR_CR_DATA_OUT(v) ((v) & 0xffff)
56
57
/* phy registers */
58
#define SATA_PHY_CLOCK_RESET 0x7f3f
59
#define SATA_PHY_CLOCK_RESET_RST (1 << 0)
60
61
#define SATA_PHY_LANE0_OUT_STAT 0x2003
62
#define SATA_PHY_LANE0_OUT_STAT_RX_PLL_STATE (1 << 1)
63
64
static struct ofw_compat_data compat_data[] = {
65
{"fsl,imx6q-ahci", true},
66
{NULL, false}
67
};
68
69
static int
70
imx6_ahci_phy_ctrl(struct ahci_controller* sc, uint32_t bitmask, bool on)
71
{
72
uint32_t v;
73
int timeout;
74
bool state;
75
76
v = ATA_INL(sc->r_mem, SATA_P0PHYCR);
77
if (on) {
78
v |= bitmask;
79
} else {
80
v &= ~bitmask;
81
}
82
ATA_OUTL(sc->r_mem, SATA_P0PHYCR, v);
83
84
for (timeout = 5000; timeout > 0; --timeout) {
85
v = ATA_INL(sc->r_mem, SATA_P0PHYSR);
86
state = (v & SATA_P0PHYSR_CR_ACK) == SATA_P0PHYSR_CR_ACK;
87
if(state == on) {
88
break;
89
}
90
DELAY(100);
91
}
92
93
if (timeout > 0) {
94
return (0);
95
}
96
97
return (ETIMEDOUT);
98
}
99
100
static int
101
imx6_ahci_phy_addr(struct ahci_controller* sc, uint32_t addr)
102
{
103
int error;
104
105
DELAY(100);
106
107
ATA_OUTL(sc->r_mem, SATA_P0PHYCR, addr);
108
109
error = imx6_ahci_phy_ctrl(sc, SATA_P0PHYCR_CR_CAP_ADDR, true);
110
if (error != 0) {
111
device_printf(sc->dev,
112
"%s: timeout on SATA_P0PHYCR_CR_CAP_ADDR=1\n",
113
__FUNCTION__);
114
return (error);
115
}
116
117
error = imx6_ahci_phy_ctrl(sc, SATA_P0PHYCR_CR_CAP_ADDR, false);
118
if (error != 0) {
119
device_printf(sc->dev,
120
"%s: timeout on SATA_P0PHYCR_CR_CAP_ADDR=0\n",
121
__FUNCTION__);
122
return (error);
123
}
124
125
return (0);
126
}
127
128
static int
129
imx6_ahci_phy_write(struct ahci_controller* sc, uint32_t addr,
130
uint16_t data)
131
{
132
int error;
133
134
error = imx6_ahci_phy_addr(sc, addr);
135
if (error != 0) {
136
device_printf(sc->dev, "%s: error on imx6_ahci_phy_addr\n",
137
__FUNCTION__);
138
return (error);
139
}
140
141
ATA_OUTL(sc->r_mem, SATA_P0PHYCR, data);
142
143
error = imx6_ahci_phy_ctrl(sc, SATA_P0PHYCR_CR_CAP_DATA, true);
144
if (error != 0) {
145
device_printf(sc->dev,
146
"%s: error on SATA_P0PHYCR_CR_CAP_DATA=1\n", __FUNCTION__);
147
return (error);
148
}
149
if (imx6_ahci_phy_ctrl(sc, SATA_P0PHYCR_CR_CAP_DATA, false) != 0) {
150
device_printf(sc->dev,
151
"%s: error on SATA_P0PHYCR_CR_CAP_DATA=0\n", __FUNCTION__);
152
return (error);
153
}
154
155
if ((addr == SATA_PHY_CLOCK_RESET) && data) {
156
/* we can't check ACK after RESET */
157
ATA_OUTL(sc->r_mem, SATA_P0PHYCR,
158
SATA_P0PHYCR_CR_DATA_IN(data) | SATA_P0PHYCR_CR_WRITE);
159
return (0);
160
}
161
162
error = imx6_ahci_phy_ctrl(sc, SATA_P0PHYCR_CR_WRITE, true);
163
if (error != 0) {
164
device_printf(sc->dev, "%s: error on SATA_P0PHYCR_CR_WRITE=1\n",
165
__FUNCTION__);
166
return (error);
167
}
168
169
error = imx6_ahci_phy_ctrl(sc, SATA_P0PHYCR_CR_WRITE, false);
170
if (error != 0) {
171
device_printf(sc->dev, "%s: error on SATA_P0PHYCR_CR_WRITE=0\n",
172
__FUNCTION__);
173
return (error);
174
}
175
176
return (0);
177
}
178
179
static int
180
imx6_ahci_phy_read(struct ahci_controller* sc, uint32_t addr, uint16_t* val)
181
{
182
int error;
183
uint32_t v;
184
185
error = imx6_ahci_phy_addr(sc, addr);
186
if (error != 0) {
187
device_printf(sc->dev, "%s: error on imx6_ahci_phy_addr\n",
188
__FUNCTION__);
189
return (error);
190
}
191
192
error = imx6_ahci_phy_ctrl(sc, SATA_P0PHYCR_CR_READ, true);
193
if (error != 0) {
194
device_printf(sc->dev, "%s: error on SATA_P0PHYCR_CR_READ=1\n",
195
__FUNCTION__);
196
return (error);
197
}
198
199
v = ATA_INL(sc->r_mem, SATA_P0PHYSR);
200
201
error = imx6_ahci_phy_ctrl(sc, SATA_P0PHYCR_CR_READ, false);
202
if (error != 0) {
203
device_printf(sc->dev, "%s: error on SATA_P0PHYCR_CR_READ=0\n",
204
__FUNCTION__);
205
return (error);
206
}
207
208
*val = SATA_P0PHYSR_CR_DATA_OUT(v);
209
return (0);
210
}
211
212
static int
213
imx6_ahci_probe(device_t dev)
214
{
215
216
if (!ofw_bus_status_okay(dev)) {
217
return (ENXIO);
218
}
219
220
if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) {
221
return (ENXIO);
222
}
223
device_set_desc(dev, "i.MX6 Integrated AHCI controller");
224
225
return (BUS_PROBE_DEFAULT);
226
}
227
228
static int
229
imx6_ahci_attach(device_t dev)
230
{
231
struct ahci_controller* ctlr;
232
uint16_t pllstat;
233
uint32_t v;
234
int error, timeout;
235
236
ctlr = device_get_softc(dev);
237
238
/* Power up the controller and phy. */
239
error = imx6_ccm_sata_enable();
240
if (error != 0) {
241
device_printf(dev, "error enabling controller and phy\n");
242
return (error);
243
}
244
245
ctlr->vendorid = 0;
246
ctlr->deviceid = 0;
247
ctlr->subvendorid = 0;
248
ctlr->subdeviceid = 0;
249
ctlr->numirqs = 1;
250
ctlr->r_rid = 0;
251
if ((ctlr->r_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
252
&ctlr->r_rid, RF_ACTIVE)) == NULL) {
253
return (ENXIO);
254
}
255
256
v = imx_iomux_gpr_get(IOMUX_GPR13);
257
/* Clear out existing values; these numbers are bitmasks. */
258
v &= ~(IOMUX_GPR13_SATA_PHY_8(7) |
259
IOMUX_GPR13_SATA_PHY_7(0x1f) |
260
IOMUX_GPR13_SATA_PHY_6(7) |
261
IOMUX_GPR13_SATA_SPEED(1) |
262
IOMUX_GPR13_SATA_PHY_5(1) |
263
IOMUX_GPR13_SATA_PHY_4(7) |
264
IOMUX_GPR13_SATA_PHY_3(0xf) |
265
IOMUX_GPR13_SATA_PHY_2(0x1f) |
266
IOMUX_GPR13_SATA_PHY_1(1) |
267
IOMUX_GPR13_SATA_PHY_0(1));
268
/* setting */
269
v |= IOMUX_GPR13_SATA_PHY_8(5) | /* Rx 3.0db */
270
IOMUX_GPR13_SATA_PHY_7(0x12) | /* Rx SATA2m */
271
IOMUX_GPR13_SATA_PHY_6(3) | /* Rx DPLL mode */
272
IOMUX_GPR13_SATA_SPEED(1) | /* 3.0GHz */
273
IOMUX_GPR13_SATA_PHY_5(0) | /* SpreadSpectram */
274
IOMUX_GPR13_SATA_PHY_4(4) | /* Tx Attenuation 9/16 */
275
IOMUX_GPR13_SATA_PHY_3(0) | /* Tx Boost 0db */
276
IOMUX_GPR13_SATA_PHY_2(0x11) | /* Tx Level 1.104V */
277
IOMUX_GPR13_SATA_PHY_1(1); /* PLL clock enable */
278
imx_iomux_gpr_set(IOMUX_GPR13, v);
279
280
/* phy reset */
281
error = imx6_ahci_phy_write(ctlr, SATA_PHY_CLOCK_RESET,
282
SATA_PHY_CLOCK_RESET_RST);
283
if (error != 0) {
284
device_printf(dev, "cannot reset PHY\n");
285
goto fail;
286
}
287
288
for (timeout = 50; timeout > 0; --timeout) {
289
DELAY(100);
290
error = imx6_ahci_phy_read(ctlr, SATA_PHY_LANE0_OUT_STAT,
291
&pllstat);
292
if (error != 0) {
293
device_printf(dev, "cannot read LANE0 status\n");
294
goto fail;
295
}
296
if (pllstat & SATA_PHY_LANE0_OUT_STAT_RX_PLL_STATE) {
297
break;
298
}
299
}
300
if (timeout <= 0) {
301
device_printf(dev, "time out reading LANE0 status\n");
302
error = ETIMEDOUT;
303
goto fail;
304
}
305
306
/* Support Staggered Spin-up */
307
v = ATA_INL(ctlr->r_mem, AHCI_CAP);
308
ATA_OUTL(ctlr->r_mem, AHCI_CAP, v | AHCI_CAP_SSS);
309
310
/* Ports Implemented. must set 1 */
311
v = ATA_INL(ctlr->r_mem, AHCI_PI);
312
ATA_OUTL(ctlr->r_mem, AHCI_PI, v | (1 << 0));
313
314
/* set 1ms-timer = AHB clock / 1000 */
315
ATA_OUTL(ctlr->r_mem, SATA_TIMER1MS,
316
imx_ccm_ahb_hz() / 1000);
317
318
/*
319
* Note: ahci_attach will release ctlr->r_mem on errors automatically
320
*/
321
return (ahci_attach(dev));
322
323
fail:
324
bus_release_resource(dev, SYS_RES_MEMORY, ctlr->r_rid, ctlr->r_mem);
325
return (error);
326
}
327
328
static int
329
imx6_ahci_detach(device_t dev)
330
{
331
332
return (ahci_detach(dev));
333
}
334
335
static device_method_t imx6_ahci_ata_methods[] = {
336
/* device probe, attach and detach methods */
337
DEVMETHOD(device_probe, imx6_ahci_probe),
338
DEVMETHOD(device_attach, imx6_ahci_attach),
339
DEVMETHOD(device_detach, imx6_ahci_detach),
340
341
/* ahci bus methods */
342
DEVMETHOD(bus_print_child, ahci_print_child),
343
DEVMETHOD(bus_alloc_resource, ahci_alloc_resource),
344
DEVMETHOD(bus_release_resource, ahci_release_resource),
345
DEVMETHOD(bus_setup_intr, ahci_setup_intr),
346
DEVMETHOD(bus_teardown_intr, ahci_teardown_intr),
347
DEVMETHOD(bus_child_location, ahci_child_location),
348
349
DEVMETHOD_END
350
};
351
352
static driver_t ahci_ata_driver = {
353
"ahci",
354
imx6_ahci_ata_methods,
355
sizeof(struct ahci_controller)
356
};
357
358
DRIVER_MODULE(imx6_ahci, simplebus, ahci_ata_driver, 0, 0);
359
MODULE_DEPEND(imx6_ahci, ahci, 1, 1, 1);
360
SIMPLEBUS_PNP_INFO(compat_data)
361
362