ahci_qoriq.c (10452B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Freescale QorIQ AHCI SATA platform driver 4 * 5 * Copyright 2015 Freescale, Inc. 6 * Tang Yuantian <Yuantian.Tang@freescale.com> 7 */ 8 9#include <linux/acpi.h> 10#include <linux/kernel.h> 11#include <linux/module.h> 12#include <linux/pm.h> 13#include <linux/ahci_platform.h> 14#include <linux/device.h> 15#include <linux/of_address.h> 16#include <linux/of.h> 17#include <linux/of_device.h> 18#include <linux/platform_device.h> 19#include <linux/libata.h> 20#include "ahci.h" 21 22#define DRV_NAME "ahci-qoriq" 23 24/* port register definition */ 25#define PORT_PHY1 0xA8 26#define PORT_PHY2 0xAC 27#define PORT_PHY3 0xB0 28#define PORT_PHY4 0xB4 29#define PORT_PHY5 0xB8 30#define PORT_AXICC 0xBC 31#define PORT_TRANS 0xC8 32 33/* port register default value */ 34#define AHCI_PORT_PHY_1_CFG 0xa003fffe 35#define AHCI_PORT_PHY2_CFG 0x28184d1f 36#define AHCI_PORT_PHY3_CFG 0x0e081509 37#define AHCI_PORT_TRANS_CFG 0x08000029 38#define AHCI_PORT_AXICC_CFG 0x3fffffff 39 40/* for ls1021a */ 41#define LS1021A_PORT_PHY2 0x28183414 42#define LS1021A_PORT_PHY3 0x0e080e06 43#define LS1021A_PORT_PHY4 0x064a080b 44#define LS1021A_PORT_PHY5 0x2aa86470 45#define LS1021A_AXICC_ADDR 0xC0 46 47#define SATA_ECC_DISABLE 0x00020000 48#define ECC_DIS_ARMV8_CH2 0x80000000 49#define ECC_DIS_LS1088A 0x40000000 50 51enum ahci_qoriq_type { 52 AHCI_LS1021A, 53 AHCI_LS1028A, 54 AHCI_LS1043A, 55 AHCI_LS2080A, 56 AHCI_LS1046A, 57 AHCI_LS1088A, 58 AHCI_LS2088A, 59 AHCI_LX2160A, 60}; 61 62struct ahci_qoriq_priv { 63 struct ccsr_ahci *reg_base; 64 enum ahci_qoriq_type type; 65 void __iomem *ecc_addr; 66 bool is_dmacoherent; 67}; 68 69static bool ecc_initialized; 70 71static const struct of_device_id ahci_qoriq_of_match[] = { 72 { .compatible = "fsl,ls1021a-ahci", .data = (void *)AHCI_LS1021A}, 73 { .compatible = "fsl,ls1028a-ahci", .data = (void *)AHCI_LS1028A}, 74 { .compatible = "fsl,ls1043a-ahci", .data = (void *)AHCI_LS1043A}, 75 { .compatible = "fsl,ls2080a-ahci", .data = (void *)AHCI_LS2080A}, 76 { .compatible = "fsl,ls1046a-ahci", .data = (void *)AHCI_LS1046A}, 77 { .compatible = "fsl,ls1088a-ahci", .data = (void *)AHCI_LS1088A}, 78 { .compatible = "fsl,ls2088a-ahci", .data = (void *)AHCI_LS2088A}, 79 { .compatible = "fsl,lx2160a-ahci", .data = (void *)AHCI_LX2160A}, 80 { /* sentinel */ } 81}; 82MODULE_DEVICE_TABLE(of, ahci_qoriq_of_match); 83 84static const struct acpi_device_id ahci_qoriq_acpi_match[] = { 85 {"NXP0004", .driver_data = (kernel_ulong_t)AHCI_LX2160A}, 86 { } 87}; 88MODULE_DEVICE_TABLE(acpi, ahci_qoriq_acpi_match); 89 90static int ahci_qoriq_hardreset(struct ata_link *link, unsigned int *class, 91 unsigned long deadline) 92{ 93 const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context); 94 void __iomem *port_mmio = ahci_port_base(link->ap); 95 u32 px_cmd, px_is, px_val; 96 struct ata_port *ap = link->ap; 97 struct ahci_port_priv *pp = ap->private_data; 98 struct ahci_host_priv *hpriv = ap->host->private_data; 99 struct ahci_qoriq_priv *qoriq_priv = hpriv->plat_data; 100 u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; 101 struct ata_taskfile tf; 102 bool online; 103 int rc; 104 bool ls1021a_workaround = (qoriq_priv->type == AHCI_LS1021A); 105 106 hpriv->stop_engine(ap); 107 108 /* 109 * There is a errata on ls1021a Rev1.0 and Rev2.0 which is: 110 * A-009042: The device detection initialization sequence 111 * mistakenly resets some registers. 112 * 113 * Workaround for this is: 114 * The software should read and store PxCMD and PxIS values 115 * before issuing the device detection initialization sequence. 116 * After the sequence is complete, software should restore the 117 * PxCMD and PxIS with the stored values. 118 */ 119 if (ls1021a_workaround) { 120 px_cmd = readl(port_mmio + PORT_CMD); 121 px_is = readl(port_mmio + PORT_IRQ_STAT); 122 } 123 124 /* clear D2H reception area to properly wait for D2H FIS */ 125 ata_tf_init(link->device, &tf); 126 tf.status = ATA_BUSY; 127 ata_tf_to_fis(&tf, 0, 0, d2h_fis); 128 129 rc = sata_link_hardreset(link, timing, deadline, &online, 130 ahci_check_ready); 131 132 /* restore the PxCMD and PxIS on ls1021 */ 133 if (ls1021a_workaround) { 134 px_val = readl(port_mmio + PORT_CMD); 135 if (px_val != px_cmd) 136 writel(px_cmd, port_mmio + PORT_CMD); 137 138 px_val = readl(port_mmio + PORT_IRQ_STAT); 139 if (px_val != px_is) 140 writel(px_is, port_mmio + PORT_IRQ_STAT); 141 } 142 143 hpriv->start_engine(ap); 144 145 if (online) 146 *class = ahci_dev_classify(ap); 147 return rc; 148} 149 150static struct ata_port_operations ahci_qoriq_ops = { 151 .inherits = &ahci_ops, 152 .hardreset = ahci_qoriq_hardreset, 153}; 154 155static const struct ata_port_info ahci_qoriq_port_info = { 156 .flags = AHCI_FLAG_COMMON | ATA_FLAG_NCQ, 157 .pio_mask = ATA_PIO4, 158 .udma_mask = ATA_UDMA6, 159 .port_ops = &ahci_qoriq_ops, 160}; 161 162static struct scsi_host_template ahci_qoriq_sht = { 163 AHCI_SHT(DRV_NAME), 164}; 165 166static int ahci_qoriq_phy_init(struct ahci_host_priv *hpriv) 167{ 168 struct ahci_qoriq_priv *qpriv = hpriv->plat_data; 169 void __iomem *reg_base = hpriv->mmio; 170 171 switch (qpriv->type) { 172 case AHCI_LS1021A: 173 if (!(qpriv->ecc_addr || ecc_initialized)) 174 return -EINVAL; 175 else if (qpriv->ecc_addr && !ecc_initialized) 176 writel(SATA_ECC_DISABLE, qpriv->ecc_addr); 177 writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1); 178 writel(LS1021A_PORT_PHY2, reg_base + PORT_PHY2); 179 writel(LS1021A_PORT_PHY3, reg_base + PORT_PHY3); 180 writel(LS1021A_PORT_PHY4, reg_base + PORT_PHY4); 181 writel(LS1021A_PORT_PHY5, reg_base + PORT_PHY5); 182 writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS); 183 if (qpriv->is_dmacoherent) 184 writel(AHCI_PORT_AXICC_CFG, 185 reg_base + LS1021A_AXICC_ADDR); 186 break; 187 188 case AHCI_LS1043A: 189 if (!(qpriv->ecc_addr || ecc_initialized)) 190 return -EINVAL; 191 else if (qpriv->ecc_addr && !ecc_initialized) 192 writel(readl(qpriv->ecc_addr) | 193 ECC_DIS_ARMV8_CH2, 194 qpriv->ecc_addr); 195 writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1); 196 writel(AHCI_PORT_PHY2_CFG, reg_base + PORT_PHY2); 197 writel(AHCI_PORT_PHY3_CFG, reg_base + PORT_PHY3); 198 writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS); 199 if (qpriv->is_dmacoherent) 200 writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC); 201 break; 202 203 case AHCI_LS2080A: 204 writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1); 205 writel(AHCI_PORT_PHY2_CFG, reg_base + PORT_PHY2); 206 writel(AHCI_PORT_PHY3_CFG, reg_base + PORT_PHY3); 207 writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS); 208 if (qpriv->is_dmacoherent) 209 writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC); 210 break; 211 212 case AHCI_LS1046A: 213 if (!(qpriv->ecc_addr || ecc_initialized)) 214 return -EINVAL; 215 else if (qpriv->ecc_addr && !ecc_initialized) 216 writel(readl(qpriv->ecc_addr) | 217 ECC_DIS_ARMV8_CH2, 218 qpriv->ecc_addr); 219 writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1); 220 writel(AHCI_PORT_PHY2_CFG, reg_base + PORT_PHY2); 221 writel(AHCI_PORT_PHY3_CFG, reg_base + PORT_PHY3); 222 writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS); 223 if (qpriv->is_dmacoherent) 224 writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC); 225 break; 226 227 case AHCI_LS1028A: 228 case AHCI_LS1088A: 229 case AHCI_LX2160A: 230 if (!(qpriv->ecc_addr || ecc_initialized)) 231 return -EINVAL; 232 else if (qpriv->ecc_addr && !ecc_initialized) 233 writel(readl(qpriv->ecc_addr) | 234 ECC_DIS_LS1088A, 235 qpriv->ecc_addr); 236 writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1); 237 writel(AHCI_PORT_PHY2_CFG, reg_base + PORT_PHY2); 238 writel(AHCI_PORT_PHY3_CFG, reg_base + PORT_PHY3); 239 writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS); 240 if (qpriv->is_dmacoherent) 241 writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC); 242 break; 243 244 case AHCI_LS2088A: 245 writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1); 246 writel(AHCI_PORT_PHY2_CFG, reg_base + PORT_PHY2); 247 writel(AHCI_PORT_PHY3_CFG, reg_base + PORT_PHY3); 248 writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS); 249 if (qpriv->is_dmacoherent) 250 writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC); 251 break; 252 } 253 254 ecc_initialized = true; 255 return 0; 256} 257 258static int ahci_qoriq_probe(struct platform_device *pdev) 259{ 260 struct device_node *np = pdev->dev.of_node; 261 const struct acpi_device_id *acpi_id; 262 struct device *dev = &pdev->dev; 263 struct ahci_host_priv *hpriv; 264 struct ahci_qoriq_priv *qoriq_priv; 265 const struct of_device_id *of_id; 266 struct resource *res; 267 int rc; 268 269 hpriv = ahci_platform_get_resources(pdev, 0); 270 if (IS_ERR(hpriv)) 271 return PTR_ERR(hpriv); 272 273 of_id = of_match_node(ahci_qoriq_of_match, np); 274 acpi_id = acpi_match_device(ahci_qoriq_acpi_match, &pdev->dev); 275 if (!(of_id || acpi_id)) 276 return -ENODEV; 277 278 qoriq_priv = devm_kzalloc(dev, sizeof(*qoriq_priv), GFP_KERNEL); 279 if (!qoriq_priv) 280 return -ENOMEM; 281 282 if (of_id) 283 qoriq_priv->type = (enum ahci_qoriq_type)of_id->data; 284 else 285 qoriq_priv->type = (enum ahci_qoriq_type)acpi_id->driver_data; 286 287 if (unlikely(!ecc_initialized)) { 288 res = platform_get_resource_byname(pdev, 289 IORESOURCE_MEM, 290 "sata-ecc"); 291 if (res) { 292 qoriq_priv->ecc_addr = 293 devm_ioremap_resource(dev, res); 294 if (IS_ERR(qoriq_priv->ecc_addr)) 295 return PTR_ERR(qoriq_priv->ecc_addr); 296 } 297 } 298 299 if (device_get_dma_attr(&pdev->dev) == DEV_DMA_COHERENT) 300 qoriq_priv->is_dmacoherent = true; 301 302 rc = ahci_platform_enable_resources(hpriv); 303 if (rc) 304 return rc; 305 306 hpriv->plat_data = qoriq_priv; 307 rc = ahci_qoriq_phy_init(hpriv); 308 if (rc) 309 goto disable_resources; 310 311 rc = ahci_platform_init_host(pdev, hpriv, &ahci_qoriq_port_info, 312 &ahci_qoriq_sht); 313 if (rc) 314 goto disable_resources; 315 316 return 0; 317 318disable_resources: 319 ahci_platform_disable_resources(hpriv); 320 321 return rc; 322} 323 324#ifdef CONFIG_PM_SLEEP 325static int ahci_qoriq_resume(struct device *dev) 326{ 327 struct ata_host *host = dev_get_drvdata(dev); 328 struct ahci_host_priv *hpriv = host->private_data; 329 int rc; 330 331 rc = ahci_platform_enable_resources(hpriv); 332 if (rc) 333 return rc; 334 335 rc = ahci_qoriq_phy_init(hpriv); 336 if (rc) 337 goto disable_resources; 338 339 rc = ahci_platform_resume_host(dev); 340 if (rc) 341 goto disable_resources; 342 343 /* We resumed so update PM runtime state */ 344 pm_runtime_disable(dev); 345 pm_runtime_set_active(dev); 346 pm_runtime_enable(dev); 347 348 return 0; 349 350disable_resources: 351 ahci_platform_disable_resources(hpriv); 352 353 return rc; 354} 355#endif 356 357static SIMPLE_DEV_PM_OPS(ahci_qoriq_pm_ops, ahci_platform_suspend, 358 ahci_qoriq_resume); 359 360static struct platform_driver ahci_qoriq_driver = { 361 .probe = ahci_qoriq_probe, 362 .remove = ata_platform_remove_one, 363 .driver = { 364 .name = DRV_NAME, 365 .of_match_table = ahci_qoriq_of_match, 366 .acpi_match_table = ahci_qoriq_acpi_match, 367 .pm = &ahci_qoriq_pm_ops, 368 }, 369}; 370module_platform_driver(ahci_qoriq_driver); 371 372MODULE_DESCRIPTION("Freescale QorIQ AHCI SATA platform driver"); 373MODULE_AUTHOR("Tang Yuantian <Yuantian.Tang@freescale.com>"); 374MODULE_LICENSE("GPL");