1/* $NetBSD: imx_ahcisata.c,v 1.4 2022/02/06 20:20:19 andvar Exp $ */ 2 3/*- 4 * Copyright (c) 2019 Genetec Corporation. All rights reserved. 5 * Written by Hashimoto Kenichi for Genetec Corporation. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29#include <sys/cdefs.h> 30__KERNEL_RCSID(0, "$NetBSD: imx_ahcisata.c,v 1.4 2022/02/06 20:20:19 andvar Exp $"); 31 32#include <sys/param.h> 33#include <sys/bus.h> 34#include <sys/device.h> 35#include <sys/intr.h> 36#include <sys/systm.h> 37#include <sys/kernel.h> 38 39#include <dev/ata/atavar.h> 40#include <dev/ic/ahcisatavar.h> 41 42#include <arm/nxp/imx_ahcisatareg.h> 43#include <arm/nxp/imx6_iomuxreg.h> 44#include <arm/nxp/imx6_ccmreg.h> 45#include <arm/nxp/imx6_ccmvar.h> 46 47#include <dev/fdt/fdtvar.h> 48 49static int imx_ahcisata_match(device_t, cfdata_t, void *); 50static void imx_ahcisata_attach(device_t, device_t, void *); 51 52struct imx_ahcisata_softc { 53 struct ahci_softc sc; 54 55 device_t sc_dev; 56 bus_space_tag_t sc_iot; 57 bus_space_handle_t sc_ioh; 58 bus_space_handle_t sc_gpr_ioh; 59 void *sc_ih; 60 61 u_int sc_tx_level; 62 u_int sc_tx_boost; 63 u_int sc_tx_atten; 64 u_int sc_rx_eq; 65 u_int sc_ss; 66 67 struct clk *sc_clk_sata; 68 struct clk *sc_clk_sata_ref; 69 struct clk *sc_clk_ahb; 70}; 71 72static int imx_ahcisata_init(struct imx_ahcisata_softc *); 73static int imx_ahcisata_phy_ctrl(struct imx_ahcisata_softc *, uint32_t, int); 74static int imx_ahcisata_phy_addr(struct imx_ahcisata_softc *, uint32_t); 75static int imx_ahcisata_phy_write(struct imx_ahcisata_softc *, uint32_t, uint16_t); 76static int imx_ahcisata_phy_read(struct imx_ahcisata_softc *, uint32_t); 77static int imx_ahcisata_init_clocks(struct imx_ahcisata_softc *); 78 79CFATTACH_DECL_NEW(imx_ahcisata, sizeof(struct imx_ahcisata_softc), 80 imx_ahcisata_match, imx_ahcisata_attach, NULL, NULL); 81 82static const struct device_compatible_entry compat_data[] = { 83 { .compat = "fsl,imx6q-ahci" }, 84 DEVICE_COMPAT_EOL 85}; 86 87static int 88imx_ahcisata_match(device_t parent, cfdata_t cf, void *aux) 89{ 90 struct fdt_attach_args * const faa = aux; 91 92 return of_compatible_match(faa->faa_phandle, compat_data); 93} 94 95static void 96imx_ahcisata_attach(device_t parent, device_t self, void *aux) 97{ 98 struct imx_ahcisata_softc * const sc = device_private(self); 99 struct fdt_attach_args * const faa = aux; 100 const int phandle = faa->faa_phandle; 101 bus_addr_t ahci_addr; 102 bus_size_t ahci_size; 103 bus_addr_t addr; 104 bus_size_t size; 105 char intrstr[128]; 106 int error; 107 108 if (fdtbus_get_reg(phandle, 0, &ahci_addr, &ahci_size) != 0) { 109 aprint_error(": couldn't get ahci registers\n"); 110 return; 111 } 112 113 if (of_getprop_uint32(phandle, "fsl,transmit-level-mV", &sc->sc_tx_level) != 0) 114 sc->sc_tx_level = 1104; 115 if (of_getprop_uint32(phandle, "fsl,transmit-boost-mdB", &sc->sc_tx_boost) != 0) 116 sc->sc_tx_boost = 3330; 117 if (of_getprop_uint32(phandle, "fsl,transmit-atten-16ths", &sc->sc_tx_atten) != 0) 118 sc->sc_tx_atten = 9; 119 if (of_getprop_uint32(phandle, "fsl,receive-eq-mdB", &sc->sc_rx_eq) != 0) 120 sc->sc_rx_eq = 3000; 121 if (of_getprop_bool(phandle, "fsl,no-spread-spectrum") == false) 122 sc->sc_ss = 1; 123 else 124 sc->sc_ss = 0; 125 126 sc->sc_clk_sata = fdtbus_clock_get(phandle, "sata"); 127 if (sc->sc_clk_sata == NULL) { 128 aprint_error(": couldn't get clock sata\n"); 129 return; 130 } 131 sc->sc_clk_sata_ref = fdtbus_clock_get(phandle, "sata_ref"); 132 if (sc->sc_clk_sata_ref == NULL) { 133 aprint_error(": couldn't get clock sata_ref\n"); 134 return; 135 } 136 sc->sc_clk_ahb = fdtbus_clock_get(phandle, "ahb"); 137 if (sc->sc_clk_ahb == NULL) { 138 aprint_error(": couldn't get clock ahb\n"); 139 return; 140 } 141 142 aprint_naive("\n"); 143 aprint_normal(": AHCI Controller\n"); 144 145 aprint_debug_dev(self, "tx level %d [mV]\n", sc->sc_tx_level); 146 aprint_debug_dev(self, "tx boost %d [mdB]\n", sc->sc_tx_boost); 147 aprint_debug_dev(self, "tx atten %d [16ths]\n", sc->sc_tx_atten); 148 aprint_debug_dev(self, "rx eq %d [mdB]\n", sc->sc_rx_eq); 149 aprint_debug_dev(self, "ss %d\n", sc->sc_ss); 150 151 sc->sc_dev = self; 152 153 sc->sc.sc_atac.atac_dev = self; 154 sc->sc.sc_ahci_ports = 1; 155 sc->sc.sc_dmat = faa->faa_dmat; 156 sc->sc.sc_ahcit = faa->faa_bst; 157 sc->sc.sc_ahcis = ahci_size; 158 error = bus_space_map(sc->sc.sc_ahcit, ahci_addr, ahci_size, 0, 159 &sc->sc.sc_ahcih); 160 if (error) { 161 aprint_error(": couldn't map ahci registers: %d\n", error); 162 return; 163 } 164 165 sc->sc_iot = sc->sc.sc_ahcit; 166 sc->sc_ioh = sc->sc.sc_ahcih; 167 168 const int gpr_phandle = OF_finddevice("/soc/aips-bus/iomuxc-gpr"); 169 fdtbus_get_reg(gpr_phandle, 0, &addr, &size); 170 if (bus_space_map(sc->sc_iot, addr, size, 0, &sc->sc_gpr_ioh)) { 171 aprint_error_dev(self, "Cannot map registers\n"); 172 return; 173 } 174 175 if (imx_ahcisata_init_clocks(sc) != 0) { 176 aprint_error_dev(self, "couldn't init clocks\n"); 177 return; 178 } 179 180 if (imx_ahcisata_init(sc) != 0) { 181 aprint_error_dev(self, "couldn't init ahci\n"); 182 return; 183 } 184 185 if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) { 186 aprint_error_dev(self, "failed to decode interrupt\n"); 187 return; 188 } 189 190 sc->sc_ih = fdtbus_intr_establish_xname(phandle, 0, IPL_BIO, 0, 191 ahci_intr, &sc->sc, device_xname(self)); 192 if (sc->sc_ih == NULL) { 193 aprint_error_dev(self, "failed to establish interrupt on %s\n", 194 intrstr); 195 return; 196 } 197 aprint_normal_dev(self, "interrupting on %s\n", intrstr); 198 199 ahci_attach(&sc->sc); 200} 201 202static int 203imx_ahcisata_phy_ctrl(struct imx_ahcisata_softc *sc, uint32_t bitmask, int on) 204{ 205 uint32_t v; 206 int timeout; 207 208 v = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SATA_P0PHYCR); 209 if (on) 210 v |= bitmask; 211 else 212 v &= ~bitmask; 213 bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_P0PHYCR, v); 214 215 for (timeout = 5000; timeout > 0; --timeout) { 216 v = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SATA_P0PHYSR); 217 if (!!(v & SATA_P0PHYSR_CR_ACK) == !!on) 218 break; 219 delay(100); 220 } 221 222 if (timeout > 0) 223 return 0; 224 225 return -1; 226} 227 228static int 229imx_ahcisata_phy_addr(struct imx_ahcisata_softc *sc, uint32_t addr) 230{ 231 delay(100); 232 233 bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_P0PHYCR, addr); 234 235 if (imx_ahcisata_phy_ctrl(sc, SATA_P0PHYCR_CR_CAP_ADDR, 1) != 0) 236 return -1; 237 if (imx_ahcisata_phy_ctrl(sc, SATA_P0PHYCR_CR_CAP_ADDR, 0) != 0) 238 return -1; 239 240 return 0; 241} 242 243static int 244imx_ahcisata_phy_write(struct imx_ahcisata_softc *sc, uint32_t addr, 245 uint16_t data) 246{ 247 if (imx_ahcisata_phy_addr(sc, addr) != 0) 248 return -1; 249 250 bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_P0PHYCR, data); 251 252 if (imx_ahcisata_phy_ctrl(sc, SATA_P0PHYCR_CR_CAP_DATA, 1) != 0) 253 return -1; 254 if (imx_ahcisata_phy_ctrl(sc, SATA_P0PHYCR_CR_CAP_DATA, 0) != 0) 255 return -1; 256 257 if ((addr == SATA_PHY_CLOCK_RESET) && data) { 258 /* we can't check ACK after RESET */ 259 bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_P0PHYCR, 260 data | SATA_P0PHYCR_CR_WRITE); 261 return 0; 262 } 263 264 if (imx_ahcisata_phy_ctrl(sc, SATA_P0PHYCR_CR_WRITE, 1) != 0) 265 return -1; 266 if (imx_ahcisata_phy_ctrl(sc, SATA_P0PHYCR_CR_WRITE, 0) != 0) 267 return -1; 268 269 return 0; 270} 271 272static int 273imx_ahcisata_phy_read(struct imx_ahcisata_softc *sc, uint32_t addr) 274{ 275 uint32_t v; 276 277 if (imx_ahcisata_phy_addr(sc, addr) != 0) 278 return -1; 279 280 if (imx_ahcisata_phy_ctrl(sc, SATA_P0PHYCR_CR_READ, 1) != 0) 281 return -1; 282 283 v = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SATA_P0PHYSR); 284 285 if (imx_ahcisata_phy_ctrl(sc, SATA_P0PHYCR_CR_READ, 0) != 0) 286 return -1; 287 288 return SATA_P0PHYSR_CR_DATA_OUT(v); 289} 290 291const static int tx_level[] = { 292 937, 293 947, 294 957, 295 966, 296 976, 297 986, 298 996, 299 1005, 300 1015, 301 1025, 302 1035, 303 1045, 304 1054, 305 1064, 306 1074, 307 1084, 308 1094, 309 1104, 310 1113, 311 1123, 312 1133, 313 1143, 314 1152, 315 1162, 316 1172, 317 1182, 318 1191, 319 1201, 320 1211, 321 1221, 322 1230, 323 1240, 324}; 325 326const static int tx_boots[] = { 327 0, 328 370, 329 740, 330 1110, 331 1480, 332 1850, 333 2220, 334 2590, 335 2960, 336 3330, 337 3700, 338 4070, 339 4440, 340 4810, 341 5280, 342 5750, 343}; 344 345const static int tx_atten[] = { 346 16, 347 14, 348 12, 349 10, 350 9, 351 8, 352}; 353 354const static int rx_eq[] = { 355 500, 356 1000, 357 1500, 358 2000, 359 2500, 360 3000, 361 3500, 362 4000, 363}; 364 365static int 366imx_ahcisata_search_regval(const int *values, int count, int val) 367{ 368 for (int i = 0; i < count; i++) 369 if (values[i] == val) 370 return i; 371 372 return -1; 373} 374 375static int 376imx_ahcisata_init(struct imx_ahcisata_softc *sc) 377{ 378 uint32_t v; 379 int timeout; 380 int pllstat; 381 382 v = bus_space_read_4(sc->sc_iot, sc->sc_gpr_ioh, IOMUX_GPR13); 383 /* clear */ 384 v &= ~(IOMUX_GPR13_SATA_PHY_8 | 385 IOMUX_GPR13_SATA_PHY_7 | 386 IOMUX_GPR13_SATA_PHY_6 | 387 IOMUX_GPR13_SATA_SPEED | 388 IOMUX_GPR13_SATA_PHY_5 | 389 IOMUX_GPR13_SATA_PHY_4 | 390 IOMUX_GPR13_SATA_PHY_3 | 391 IOMUX_GPR13_SATA_PHY_2 | 392 IOMUX_GPR13_SATA_PHY_1 | 393 IOMUX_GPR13_SATA_PHY_0); 394 /* setting */ 395 struct { 396 const int *array; 397 int count; 398 int val; 399 int def_val; 400 int mask; 401 } gpr13_sata_phy_settings[] = { 402 { tx_level, __arraycount(tx_level), sc->sc_tx_level, 403 0x11, IOMUX_GPR13_SATA_PHY_2 }, 404 { tx_boots, __arraycount(tx_boots), sc->sc_tx_boost, 405 0x09, IOMUX_GPR13_SATA_PHY_3 }, 406 { tx_atten, __arraycount(tx_atten), sc->sc_tx_atten, 407 0x04, IOMUX_GPR13_SATA_PHY_4 }, 408 { rx_eq, __arraycount(rx_eq), sc->sc_rx_eq, 409 0x05, IOMUX_GPR13_SATA_PHY_8 } 410 }; 411 for (int i = 0; i < __arraycount(gpr13_sata_phy_settings); i++) { 412 int val; 413 val = imx_ahcisata_search_regval( 414 gpr13_sata_phy_settings[i].array, 415 gpr13_sata_phy_settings[i].count, 416 gpr13_sata_phy_settings[i].val); 417 if (val == -1) 418 val = gpr13_sata_phy_settings[i].def_val; 419 v |= __SHIFTIN(val, gpr13_sata_phy_settings[i].mask); 420 } 421 v |= __SHIFTIN(0x12, IOMUX_GPR13_SATA_PHY_7); /* Rx SATA2m */ 422 v |= __SHIFTIN(3, IOMUX_GPR13_SATA_PHY_6); /* Rx DPLL mode */ 423 v |= __SHIFTIN(1, IOMUX_GPR13_SATA_SPEED); /* 3.0GHz */ 424 v |= __SHIFTIN(sc->sc_ss, IOMUX_GPR13_SATA_PHY_5); 425 v |= __SHIFTIN(1, IOMUX_GPR13_SATA_PHY_1); /* PLL clock enable */ 426 bus_space_write_4(sc->sc_iot, sc->sc_gpr_ioh, IOMUX_GPR13, v); 427 428 /* phy reset */ 429 if (imx_ahcisata_phy_write(sc, SATA_PHY_CLOCK_RESET, 430 SATA_PHY_CLOCK_RESET_RST) < 0) { 431 aprint_error_dev(sc->sc_dev, "cannot reset PHY\n"); 432 return -1; 433 } 434 435 for (timeout = 50; timeout > 0; --timeout) { 436 delay(100); 437 pllstat = imx_ahcisata_phy_read(sc, SATA_PHY_LANE0_OUT_STAT); 438 if (pllstat < 0) { 439 aprint_error_dev(sc->sc_dev, 440 "cannot read LANE0 status\n"); 441 break; 442 } 443 if (pllstat & SATA_PHY_LANE0_OUT_STAT_RX_PLL_STATE) 444 break; 445 } 446 if (timeout <= 0) 447 return -1; 448 449 /* Support Staggered Spin-up */ 450 v = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SATA_CAP); 451 bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_CAP, v | SATA_CAP_SSS); 452 453 /* Ports Implemented. must set 1 */ 454 v = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SATA_PI); 455 bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_PI, v | SATA_PI_PI); 456 457 /* set 1ms-timer = AHB clock / 1000 */ 458 bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_TIMER1MS, 459 clk_get_rate(sc->sc_clk_ahb) / 1000); 460 461 return 0; 462} 463 464static int 465imx_ahcisata_init_clocks(struct imx_ahcisata_softc *sc) 466{ 467 int error; 468 469 error = clk_enable(sc->sc_clk_sata); 470 if (error) { 471 aprint_error_dev(sc->sc_dev, "couldn't enable sata: %d\n", error); 472 return error; 473 } 474 error = clk_enable(sc->sc_clk_sata_ref); 475 if (error) { 476 aprint_error_dev(sc->sc_dev, "couldn't enable sata-ref: %d\n", error); 477 return error; 478 } 479 error = clk_enable(sc->sc_clk_ahb); 480 if (error) { 481 aprint_error_dev(sc->sc_dev, "couldn't enable anb: %d\n", error); 482 return error; 483 } 484 485 return 0; 486} 487