Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.16-rc5 527 lines 13 kB view raw
1/* 2 * copyright (c) 2013 Freescale Semiconductor, Inc. 3 * Freescale IMX AHCI SATA platform driver 4 * 5 * based on the AHCI SATA platform driver by Jeff Garzik and Anton Vorontsov 6 * 7 * This program is free software; you can redistribute it and/or modify it 8 * under the terms and conditions of the GNU General Public License, 9 * version 2, as published by the Free Software Foundation. 10 * 11 * This program is distributed in the hope it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 14 * more details. 15 * 16 * You should have received a copy of the GNU General Public License along with 17 * this program. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20#include <linux/kernel.h> 21#include <linux/module.h> 22#include <linux/platform_device.h> 23#include <linux/regmap.h> 24#include <linux/ahci_platform.h> 25#include <linux/of_device.h> 26#include <linux/mfd/syscon.h> 27#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h> 28#include <linux/libata.h> 29#include "ahci.h" 30 31enum { 32 /* Timer 1-ms Register */ 33 IMX_TIMER1MS = 0x00e0, 34 /* Port0 PHY Control Register */ 35 IMX_P0PHYCR = 0x0178, 36 IMX_P0PHYCR_TEST_PDDQ = 1 << 20, 37 IMX_P0PHYCR_CR_READ = 1 << 19, 38 IMX_P0PHYCR_CR_WRITE = 1 << 18, 39 IMX_P0PHYCR_CR_CAP_DATA = 1 << 17, 40 IMX_P0PHYCR_CR_CAP_ADDR = 1 << 16, 41 /* Port0 PHY Status Register */ 42 IMX_P0PHYSR = 0x017c, 43 IMX_P0PHYSR_CR_ACK = 1 << 18, 44 IMX_P0PHYSR_CR_DATA_OUT = 0xffff << 0, 45 /* Lane0 Output Status Register */ 46 IMX_LANE0_OUT_STAT = 0x2003, 47 IMX_LANE0_OUT_STAT_RX_PLL_STATE = 1 << 1, 48 /* Clock Reset Register */ 49 IMX_CLOCK_RESET = 0x7f3f, 50 IMX_CLOCK_RESET_RESET = 1 << 0, 51}; 52 53enum ahci_imx_type { 54 AHCI_IMX53, 55 AHCI_IMX6Q, 56}; 57 58struct imx_ahci_priv { 59 struct platform_device *ahci_pdev; 60 enum ahci_imx_type type; 61 struct clk *sata_clk; 62 struct clk *sata_ref_clk; 63 struct clk *ahb_clk; 64 struct regmap *gpr; 65 bool no_device; 66 bool first_time; 67}; 68 69static int ahci_imx_hotplug; 70module_param_named(hotplug, ahci_imx_hotplug, int, 0644); 71MODULE_PARM_DESC(hotplug, "AHCI IMX hot-plug support (0=Don't support, 1=support)"); 72 73static void ahci_imx_host_stop(struct ata_host *host); 74 75static int imx_phy_crbit_assert(void __iomem *mmio, u32 bit, bool assert) 76{ 77 int timeout = 10; 78 u32 crval; 79 u32 srval; 80 81 /* Assert or deassert the bit */ 82 crval = readl(mmio + IMX_P0PHYCR); 83 if (assert) 84 crval |= bit; 85 else 86 crval &= ~bit; 87 writel(crval, mmio + IMX_P0PHYCR); 88 89 /* Wait for the cr_ack signal */ 90 do { 91 srval = readl(mmio + IMX_P0PHYSR); 92 if ((assert ? srval : ~srval) & IMX_P0PHYSR_CR_ACK) 93 break; 94 usleep_range(100, 200); 95 } while (--timeout); 96 97 return timeout ? 0 : -ETIMEDOUT; 98} 99 100static int imx_phy_reg_addressing(u16 addr, void __iomem *mmio) 101{ 102 u32 crval = addr; 103 int ret; 104 105 /* Supply the address on cr_data_in */ 106 writel(crval, mmio + IMX_P0PHYCR); 107 108 /* Assert the cr_cap_addr signal */ 109 ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_CAP_ADDR, true); 110 if (ret) 111 return ret; 112 113 /* Deassert cr_cap_addr */ 114 ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_CAP_ADDR, false); 115 if (ret) 116 return ret; 117 118 return 0; 119} 120 121static int imx_phy_reg_write(u16 val, void __iomem *mmio) 122{ 123 u32 crval = val; 124 int ret; 125 126 /* Supply the data on cr_data_in */ 127 writel(crval, mmio + IMX_P0PHYCR); 128 129 /* Assert the cr_cap_data signal */ 130 ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_CAP_DATA, true); 131 if (ret) 132 return ret; 133 134 /* Deassert cr_cap_data */ 135 ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_CAP_DATA, false); 136 if (ret) 137 return ret; 138 139 if (val & IMX_CLOCK_RESET_RESET) { 140 /* 141 * In case we're resetting the phy, it's unable to acknowledge, 142 * so we return immediately here. 143 */ 144 crval |= IMX_P0PHYCR_CR_WRITE; 145 writel(crval, mmio + IMX_P0PHYCR); 146 goto out; 147 } 148 149 /* Assert the cr_write signal */ 150 ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_WRITE, true); 151 if (ret) 152 return ret; 153 154 /* Deassert cr_write */ 155 ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_WRITE, false); 156 if (ret) 157 return ret; 158 159out: 160 return 0; 161} 162 163static int imx_phy_reg_read(u16 *val, void __iomem *mmio) 164{ 165 int ret; 166 167 /* Assert the cr_read signal */ 168 ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_READ, true); 169 if (ret) 170 return ret; 171 172 /* Capture the data from cr_data_out[] */ 173 *val = readl(mmio + IMX_P0PHYSR) & IMX_P0PHYSR_CR_DATA_OUT; 174 175 /* Deassert cr_read */ 176 ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_READ, false); 177 if (ret) 178 return ret; 179 180 return 0; 181} 182 183static int imx_sata_phy_reset(struct ahci_host_priv *hpriv) 184{ 185 void __iomem *mmio = hpriv->mmio; 186 int timeout = 10; 187 u16 val; 188 int ret; 189 190 /* Reset SATA PHY by setting RESET bit of PHY register CLOCK_RESET */ 191 ret = imx_phy_reg_addressing(IMX_CLOCK_RESET, mmio); 192 if (ret) 193 return ret; 194 ret = imx_phy_reg_write(IMX_CLOCK_RESET_RESET, mmio); 195 if (ret) 196 return ret; 197 198 /* Wait for PHY RX_PLL to be stable */ 199 do { 200 usleep_range(100, 200); 201 ret = imx_phy_reg_addressing(IMX_LANE0_OUT_STAT, mmio); 202 if (ret) 203 return ret; 204 ret = imx_phy_reg_read(&val, mmio); 205 if (ret) 206 return ret; 207 if (val & IMX_LANE0_OUT_STAT_RX_PLL_STATE) 208 break; 209 } while (--timeout); 210 211 return timeout ? 0 : -ETIMEDOUT; 212} 213 214static int imx_sata_enable(struct ahci_host_priv *hpriv) 215{ 216 struct imx_ahci_priv *imxpriv = hpriv->plat_data; 217 struct device *dev = &imxpriv->ahci_pdev->dev; 218 int ret; 219 220 if (imxpriv->no_device) 221 return 0; 222 223 if (hpriv->target_pwr) { 224 ret = regulator_enable(hpriv->target_pwr); 225 if (ret) 226 return ret; 227 } 228 229 ret = clk_prepare_enable(imxpriv->sata_ref_clk); 230 if (ret < 0) 231 goto disable_regulator; 232 233 if (imxpriv->type == AHCI_IMX6Q) { 234 /* 235 * set PHY Paremeters, two steps to configure the GPR13, 236 * one write for rest of parameters, mask of first write 237 * is 0x07ffffff, and the other one write for setting 238 * the mpll_clk_en. 239 */ 240 regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13, 241 IMX6Q_GPR13_SATA_RX_EQ_VAL_MASK | 242 IMX6Q_GPR13_SATA_RX_LOS_LVL_MASK | 243 IMX6Q_GPR13_SATA_RX_DPLL_MODE_MASK | 244 IMX6Q_GPR13_SATA_SPD_MODE_MASK | 245 IMX6Q_GPR13_SATA_MPLL_SS_EN | 246 IMX6Q_GPR13_SATA_TX_ATTEN_MASK | 247 IMX6Q_GPR13_SATA_TX_BOOST_MASK | 248 IMX6Q_GPR13_SATA_TX_LVL_MASK | 249 IMX6Q_GPR13_SATA_MPLL_CLK_EN | 250 IMX6Q_GPR13_SATA_TX_EDGE_RATE, 251 IMX6Q_GPR13_SATA_RX_EQ_VAL_3_0_DB | 252 IMX6Q_GPR13_SATA_RX_LOS_LVL_SATA2M | 253 IMX6Q_GPR13_SATA_RX_DPLL_MODE_2P_4F | 254 IMX6Q_GPR13_SATA_SPD_MODE_3P0G | 255 IMX6Q_GPR13_SATA_MPLL_SS_EN | 256 IMX6Q_GPR13_SATA_TX_ATTEN_9_16 | 257 IMX6Q_GPR13_SATA_TX_BOOST_3_33_DB | 258 IMX6Q_GPR13_SATA_TX_LVL_1_025_V); 259 regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13, 260 IMX6Q_GPR13_SATA_MPLL_CLK_EN, 261 IMX6Q_GPR13_SATA_MPLL_CLK_EN); 262 263 usleep_range(100, 200); 264 265 ret = imx_sata_phy_reset(hpriv); 266 if (ret) { 267 dev_err(dev, "failed to reset phy: %d\n", ret); 268 goto disable_regulator; 269 } 270 } 271 272 usleep_range(1000, 2000); 273 274 return 0; 275 276disable_regulator: 277 if (hpriv->target_pwr) 278 regulator_disable(hpriv->target_pwr); 279 280 return ret; 281} 282 283static void imx_sata_disable(struct ahci_host_priv *hpriv) 284{ 285 struct imx_ahci_priv *imxpriv = hpriv->plat_data; 286 287 if (imxpriv->no_device) 288 return; 289 290 if (imxpriv->type == AHCI_IMX6Q) { 291 regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13, 292 IMX6Q_GPR13_SATA_MPLL_CLK_EN, 293 !IMX6Q_GPR13_SATA_MPLL_CLK_EN); 294 } 295 296 clk_disable_unprepare(imxpriv->sata_ref_clk); 297 298 if (hpriv->target_pwr) 299 regulator_disable(hpriv->target_pwr); 300} 301 302static void ahci_imx_error_handler(struct ata_port *ap) 303{ 304 u32 reg_val; 305 struct ata_device *dev; 306 struct ata_host *host = dev_get_drvdata(ap->dev); 307 struct ahci_host_priv *hpriv = host->private_data; 308 void __iomem *mmio = hpriv->mmio; 309 struct imx_ahci_priv *imxpriv = hpriv->plat_data; 310 311 ahci_error_handler(ap); 312 313 if (!(imxpriv->first_time) || ahci_imx_hotplug) 314 return; 315 316 imxpriv->first_time = false; 317 318 ata_for_each_dev(dev, &ap->link, ENABLED) 319 return; 320 /* 321 * Disable link to save power. An imx ahci port can't be recovered 322 * without full reset once the pddq mode is enabled making it 323 * impossible to use as part of libata LPM. 324 */ 325 reg_val = readl(mmio + IMX_P0PHYCR); 326 writel(reg_val | IMX_P0PHYCR_TEST_PDDQ, mmio + IMX_P0PHYCR); 327 imx_sata_disable(hpriv); 328 imxpriv->no_device = true; 329 330 dev_info(ap->dev, "no device found, disabling link.\n"); 331 dev_info(ap->dev, "pass " MODULE_PARAM_PREFIX ".hotplug=1 to enable hotplug\n"); 332} 333 334static int ahci_imx_softreset(struct ata_link *link, unsigned int *class, 335 unsigned long deadline) 336{ 337 struct ata_port *ap = link->ap; 338 struct ata_host *host = dev_get_drvdata(ap->dev); 339 struct ahci_host_priv *hpriv = host->private_data; 340 struct imx_ahci_priv *imxpriv = hpriv->plat_data; 341 int ret = -EIO; 342 343 if (imxpriv->type == AHCI_IMX53) 344 ret = ahci_pmp_retry_srst_ops.softreset(link, class, deadline); 345 else if (imxpriv->type == AHCI_IMX6Q) 346 ret = ahci_ops.softreset(link, class, deadline); 347 348 return ret; 349} 350 351static struct ata_port_operations ahci_imx_ops = { 352 .inherits = &ahci_ops, 353 .host_stop = ahci_imx_host_stop, 354 .error_handler = ahci_imx_error_handler, 355 .softreset = ahci_imx_softreset, 356}; 357 358static const struct ata_port_info ahci_imx_port_info = { 359 .flags = AHCI_FLAG_COMMON, 360 .pio_mask = ATA_PIO4, 361 .udma_mask = ATA_UDMA6, 362 .port_ops = &ahci_imx_ops, 363}; 364 365static const struct of_device_id imx_ahci_of_match[] = { 366 { .compatible = "fsl,imx53-ahci", .data = (void *)AHCI_IMX53 }, 367 { .compatible = "fsl,imx6q-ahci", .data = (void *)AHCI_IMX6Q }, 368 {}, 369}; 370MODULE_DEVICE_TABLE(of, imx_ahci_of_match); 371 372static int imx_ahci_probe(struct platform_device *pdev) 373{ 374 struct device *dev = &pdev->dev; 375 const struct of_device_id *of_id; 376 struct ahci_host_priv *hpriv; 377 struct imx_ahci_priv *imxpriv; 378 unsigned int reg_val; 379 int ret; 380 381 of_id = of_match_device(imx_ahci_of_match, dev); 382 if (!of_id) 383 return -EINVAL; 384 385 imxpriv = devm_kzalloc(dev, sizeof(*imxpriv), GFP_KERNEL); 386 if (!imxpriv) 387 return -ENOMEM; 388 389 imxpriv->ahci_pdev = pdev; 390 imxpriv->no_device = false; 391 imxpriv->first_time = true; 392 imxpriv->type = (enum ahci_imx_type)of_id->data; 393 394 imxpriv->sata_clk = devm_clk_get(dev, "sata"); 395 if (IS_ERR(imxpriv->sata_clk)) { 396 dev_err(dev, "can't get sata clock.\n"); 397 return PTR_ERR(imxpriv->sata_clk); 398 } 399 400 imxpriv->sata_ref_clk = devm_clk_get(dev, "sata_ref"); 401 if (IS_ERR(imxpriv->sata_ref_clk)) { 402 dev_err(dev, "can't get sata_ref clock.\n"); 403 return PTR_ERR(imxpriv->sata_ref_clk); 404 } 405 406 imxpriv->ahb_clk = devm_clk_get(dev, "ahb"); 407 if (IS_ERR(imxpriv->ahb_clk)) { 408 dev_err(dev, "can't get ahb clock.\n"); 409 return PTR_ERR(imxpriv->ahb_clk); 410 } 411 412 if (imxpriv->type == AHCI_IMX6Q) { 413 imxpriv->gpr = syscon_regmap_lookup_by_compatible( 414 "fsl,imx6q-iomuxc-gpr"); 415 if (IS_ERR(imxpriv->gpr)) { 416 dev_err(dev, 417 "failed to find fsl,imx6q-iomux-gpr regmap\n"); 418 return PTR_ERR(imxpriv->gpr); 419 } 420 } 421 422 hpriv = ahci_platform_get_resources(pdev); 423 if (IS_ERR(hpriv)) 424 return PTR_ERR(hpriv); 425 426 hpriv->plat_data = imxpriv; 427 428 ret = clk_prepare_enable(imxpriv->sata_clk); 429 if (ret) 430 return ret; 431 432 ret = imx_sata_enable(hpriv); 433 if (ret) 434 goto disable_clk; 435 436 /* 437 * Configure the HWINIT bits of the HOST_CAP and HOST_PORTS_IMPL, 438 * and IP vendor specific register IMX_TIMER1MS. 439 * Configure CAP_SSS (support stagered spin up). 440 * Implement the port0. 441 * Get the ahb clock rate, and configure the TIMER1MS register. 442 */ 443 reg_val = readl(hpriv->mmio + HOST_CAP); 444 if (!(reg_val & HOST_CAP_SSS)) { 445 reg_val |= HOST_CAP_SSS; 446 writel(reg_val, hpriv->mmio + HOST_CAP); 447 } 448 reg_val = readl(hpriv->mmio + HOST_PORTS_IMPL); 449 if (!(reg_val & 0x1)) { 450 reg_val |= 0x1; 451 writel(reg_val, hpriv->mmio + HOST_PORTS_IMPL); 452 } 453 454 reg_val = clk_get_rate(imxpriv->ahb_clk) / 1000; 455 writel(reg_val, hpriv->mmio + IMX_TIMER1MS); 456 457 ret = ahci_platform_init_host(pdev, hpriv, &ahci_imx_port_info, 458 0, 0, 0); 459 if (ret) 460 goto disable_sata; 461 462 return 0; 463 464disable_sata: 465 imx_sata_disable(hpriv); 466disable_clk: 467 clk_disable_unprepare(imxpriv->sata_clk); 468 return ret; 469} 470 471static void ahci_imx_host_stop(struct ata_host *host) 472{ 473 struct ahci_host_priv *hpriv = host->private_data; 474 struct imx_ahci_priv *imxpriv = hpriv->plat_data; 475 476 imx_sata_disable(hpriv); 477 clk_disable_unprepare(imxpriv->sata_clk); 478} 479 480#ifdef CONFIG_PM_SLEEP 481static int imx_ahci_suspend(struct device *dev) 482{ 483 struct ata_host *host = dev_get_drvdata(dev); 484 struct ahci_host_priv *hpriv = host->private_data; 485 int ret; 486 487 ret = ahci_platform_suspend_host(dev); 488 if (ret) 489 return ret; 490 491 imx_sata_disable(hpriv); 492 493 return 0; 494} 495 496static int imx_ahci_resume(struct device *dev) 497{ 498 struct ata_host *host = dev_get_drvdata(dev); 499 struct ahci_host_priv *hpriv = host->private_data; 500 int ret; 501 502 ret = imx_sata_enable(hpriv); 503 if (ret) 504 return ret; 505 506 return ahci_platform_resume_host(dev); 507} 508#endif 509 510static SIMPLE_DEV_PM_OPS(ahci_imx_pm_ops, imx_ahci_suspend, imx_ahci_resume); 511 512static struct platform_driver imx_ahci_driver = { 513 .probe = imx_ahci_probe, 514 .remove = ata_platform_remove_one, 515 .driver = { 516 .name = "ahci-imx", 517 .owner = THIS_MODULE, 518 .of_match_table = imx_ahci_of_match, 519 .pm = &ahci_imx_pm_ops, 520 }, 521}; 522module_platform_driver(imx_ahci_driver); 523 524MODULE_DESCRIPTION("Freescale i.MX AHCI SATA platform driver"); 525MODULE_AUTHOR("Richard Zhu <Hong-Xing.Zhu@freescale.com>"); 526MODULE_LICENSE("GPL"); 527MODULE_ALIAS("ahci:imx");