/* * ahci.c - AHCI SATA support * * Maintained by: Jeff Garzik * Please ALWAYS copy linux-ide@vger.kernel.org * on emails. * * Copyright 2004-2005 Red Hat, Inc. * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * * * libata documentation is available via 'make {ps|pdf}docs', * as Documentation/DocBook/libata.* * * AHCI hardware documentation: * http://www.intel.com/technology/serialata/pdf/rev1_0.pdf * http://www.intel.com/technology/serialata/pdf/rev1_1.pdf * */ /** * Some part of this file is modified by Ikanos Communications. * * Copyright (C) 2013-2014 Ikanos Communications. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ahci.h" #if CONFIG_FUSIV_SATA_EXTERNAL_CLOCK #include #endif #define DRV_NAME "ahci_vx185" #define DRV_VERSION "IKF_S_1.1" enum { board_ahci_vx185 = 0, }; void ata_plat_init (void __iomem *base); extern void ata_plat_remove(struct ata_host *host); static int ahci_init_one(struct platform_device *pdev); static char *SATA_GEN = "GEN2"; module_param(SATA_GEN, charp, 0); MODULE_PARM_DESC(SATA_GEN, "SATA GENERATION SUPPORT (2=GEN2, 1=GEN1)"); static struct scsi_host_template ahci_sht = { ATA_NCQ_SHT(DRV_NAME), .can_queue = AHCI_MAX_CMDS - 1, .sg_tablesize = AHCI_MAX_SG, .dma_boundary = AHCI_DMA_BOUNDARY, .shost_attrs = ahci_shost_attrs, .sdev_attrs = ahci_sdev_attrs, }; static const struct ata_port_info ahci_port_info[] = { [board_ahci_vx185] = { .flags = AHCI_FLAG_COMMON, .pio_mask = ATA_PIO4, .udma_mask = ATA_UDMA6, .port_ops = &ahci_ops, }, }; /* ata_plat_init - Do platform specific init of the AHCI SATA controller. * @base - Base address of the AHCI SATA controller */ void ata_plat_init (void __iomem *base) { volatile unsigned int temp; #if CONFIG_FUSIV_SATA_EXTERNAL_CLOCK /* SN Select SATA ref clock as external source and value as 100MHz */ scu_regs->cpu_ctl_mask &= ~(1 << SATA_REF_CLK_SEL); scu_regs->cpu_ctl &= ~(1 << SATA_REF_CLK_SEL); scu_regs->cpu_ctl_mask |= (1 << SATA_REF_CLK_SEL); // Remove MASKS for clock source and prescalar ; // Write the value scu_regs->cpu_ctl_mask &= ~(0x3 << SATA_MPLL_PRESCALE); scu_regs->cpu_ctl &= ~(0x3 << SATA_MPLL_PRESCALE); // External source Bit31 - 0, Divide by 2 (bit 23:24 = 01) scu_regs->cpu_ctl |= (0x2 << SATA_MPLL_PRESCALE); // External source Bit31 - 0, Divide by 2 (bit 23:24 = 01) scu_regs->cpu_ctl_mask |= (0x3 << SATA_MPLL_PRESCALE); #endif /* Remove CLK and Reset write Mask for SATA */ *(volatile unsigned int *)0xb9000000 &= ~(1 << 13); /* Disable SATA reset */ *(volatile unsigned int *)0xb9000004 |= 1 << 13; /* Enable SATA Clock */ *(volatile unsigned int *)0xb900001c |= 1 << 13; /* Enable Byte Swap for SATA D-Bus access (Big endian to Little endian ??) */ //*(volatile unsigned int *)0xb9150178 |= 1 << 21; temp = *(volatile unsigned int *)0xb9150178; temp = (temp & 0xffdf0000 ) | 0x0020e210; *(volatile unsigned int *)0xb9150178 = temp; /* Set the address for read or write */ *(volatile unsigned int *)0xb9150178 = 0x00200014; *(volatile unsigned int *)0xb9150178 = 0x00210014; temp = *(volatile unsigned int *)0xb915017c; *(volatile unsigned int *)0xb9150178 = 0x00200014; /* The following will write with data 0xfe10 to the address we set */ *(volatile unsigned int *)0xb9150178 = 0x0020fe10; *(volatile unsigned int *)0xb9150178 = 0x0022fe10; temp = *(volatile unsigned int *)0xb915017c; *(volatile unsigned int *)0xb9150178 = 0x0020fe10; temp = *(volatile unsigned int *)0xb915017c; *(volatile unsigned int *)0xb9150178 = 0x0024fe10; temp = *(volatile unsigned int *)0xb915017c; *(volatile unsigned int *)0xb9150178 = 0x00200000; temp = *(volatile unsigned int *)0xb915017c; /* Initialize the port implement */ *(volatile unsigned int *)0xb915000c = 0x1; /* Configure the Link Layer OOB detection counters */ *(volatile unsigned int *)0xb91500bc = 0x82060b13; *(volatile unsigned int *)0xb91500bc = 0x82060b13; // Single write is not modifying the bits 30:24, hence 2 writes return; } static int ahci_init_one(struct platform_device *pdev) { unsigned int board_id = *(int *)pdev->dev.platform_data; struct ata_port_info pi = ahci_port_info[board_id]; struct resource *res; static int printed_version; const struct ata_port_info *ppi[] = { &pi, NULL }; struct device *dev = &pdev->dev; struct ahci_host_priv *hpriv; struct ata_host *host; int n_ports, i, rc,ret; const char *scc_s; printk("ENTER\n"); WARN_ON(ATA_MAX_QUEUE > AHCI_MAX_CMDS); if (!printed_version++) // printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); ata_print_version_once(&pdev->dev, DRV_VERSION); printk("version " DRV_VERSION "\n"); hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL); if (!hpriv) return -ENOMEM; hpriv->flags |= (unsigned long)pi.private_data; /* * Get the register base first */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) return -EINVAL; hpriv->mmio = devm_ioremap(&pdev->dev, res->start, res->end - res->start + 1); // hpriv->mmio = 0x19150000; res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!res) { dev_printk(KERN_INFO, &pdev->dev, ": no irq\n"); return -ENODEV; } hpriv->irq = res->start; /* Call platform specific init*/ ata_plat_init(hpriv->mmio); /* save initial config */ ahci_save_initial_config(&pdev->dev, hpriv,0,0); /* prepare host */ if (hpriv->cap & HOST_CAP_NCQ) pi.flags |= ATA_FLAG_NCQ | ATA_FLAG_FPDMA_AA; if (hpriv->cap & HOST_CAP_PMP) pi.flags |= ATA_FLAG_PMP; /* CAP.NP sometimes indicate the index of the last enabled * port, at other times, that of the last possible port, so * determining the maximum port number requires looking at * both CAP.NP and port_map. */ n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map)); host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports); if (!host) return -ENOMEM; host->iomap = hpriv->base; host->private_data = hpriv; if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss) host->flags |= ATA_HOST_PARALLEL_SCAN; else printk(KERN_INFO "ahci: SSS flag set, parallel bus scan disabled\n"); if (pi.flags & ATA_FLAG_EM) ahci_reset_em(host); for (i = 0; i < host->n_ports; i++) { struct ata_port *ap = host->ports[i]; /* disabled/not-implemented port */ if (!(hpriv->port_map & (1 << i))) ap->ops = &ata_dummy_port_ops; } rc = ahci_reset_controller(host); if (rc) return rc; ahci_init_controller(host); scc_s="SATA"; ahci_print_info(host,scc_s); host->ops = pi.port_ops; if (readl(hpriv->mmio + 0x100 + PORT_SCR_CTL) & 0x1) writel(0, hpriv->mmio + 0x100 + PORT_SCR_CTL); if(!strnicmp(SATA_GEN,"GEN1",4)) { /* * SN: Limit SATA link speed to GEN 1 in VX185 (1.5 gbps) * SN: Enable GEN 2 (3.0 gbps) when Jitter issues are get resolved and certification is through * SN: Commenting below 2 lines will enable the Auto negotiate speed (default mode) */ rc = readl(hpriv->mmio + 0x100 + PORT_SCR_CTL); writel(rc | 0x10, hpriv->mmio + 0x100 + PORT_SCR_CTL); } ret = ata_host_activate(host, hpriv->irq, ahci_interrupt, IRQF_SHARED, &ahci_sht); VPRINTK("EXIT\n"); return ret; } static struct platform_driver ahci_platform_driver = { .probe = ahci_init_one, .driver = { .name = DRV_NAME, .owner = THIS_MODULE, } }; static int __init ahci_init(void) { return platform_driver_register(&ahci_platform_driver); } static void __exit ahci_exit(void) { platform_driver_unregister(&ahci_platform_driver); } MODULE_AUTHOR("Jeff Garzik;Modified by Ikanos for BSP Support"); MODULE_DESCRIPTION("AHCI SATA low-level driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_VERSION); module_init(ahci_init); module_exit(ahci_exit);