| /* |
| * sata_brcmstb.c - ServerWorks / Apple K2 SATA |
| * |
| * Maintained by: Benjamin Herrenschmidt <benh@kernel.crashing.org> and |
| * Jeff Garzik <jgarzik@pobox.com> |
| * Please ALWAYS copy linux-ide@vger.kernel.org |
| * on emails. |
| * |
| * Copyright 2003 Benjamin Herrenschmidt <benh@kernel.crashing.org> |
| * |
| * Bits from Jeff Garzik, Copyright RedHat, Inc. |
| * |
| * This driver probably works with non-Apple versions of the |
| * Broadcom chipset... |
| * |
| * |
| * 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.* |
| * |
| * Hardware documentation available under NDA. |
| * |
| * BRCM NOTE: |
| * 2.6.29.1 version was ported from 2.6.18-6.6a. PMP support is disabled. |
| * remove all QDMA/NCQ and PMP support |
| */ |
| |
| #include <linux/kernel.h> |
| #include <linux/module.h> |
| #include <linux/pci.h> |
| #include <linux/init.h> |
| #include <linux/blkdev.h> |
| #include <linux/delay.h> |
| #include <linux/interrupt.h> |
| #include <linux/device.h> |
| #include <scsi/scsi_host.h> |
| #include <linux/spinlock.h> |
| #include <linux/libata.h> |
| #include <linux/pm.h> |
| #include <linux/clk.h> |
| #include <linux/version.h> |
| #include <linux/pm_runtime.h> |
| |
| #ifdef CONFIG_PPC_OF |
| #include <asm/prom.h> |
| #include <asm/pci-bridge.h> |
| #endif /* CONFIG_PPC_OF */ |
| |
| #define DRV_NAME "sata_brcmstb" |
| #define DRV_VERSION "4.0" |
| |
| #include <asm/brcmstb/brcmstb.h> |
| |
| static int ssc; /* aka: bcmssc, gSataInterpolation */ |
| static int s2; /* aka: bcmsata2, gSata2_3Gbps */ |
| |
| module_param(ssc, int, 0444); |
| module_param(s2, int, 0444); |
| |
| struct k2_host_priv { |
| spinlock_t lock; |
| int sleep_flag; |
| struct clk *clk; |
| void __iomem *mmio_base; |
| unsigned long hp_jif; |
| }; |
| |
| #define SLEEP_FLAG(host) ({ \ |
| struct ata_host *h = (host); \ |
| struct k2_host_priv *hp = h->private_data; \ |
| hp->sleep_flag; \ |
| }) |
| |
| #define SET_SLEEP_FLAG(host, val) do { \ |
| struct ata_host *h = (host); \ |
| struct k2_host_priv *hp = h->private_data; \ |
| hp->sleep_flag = (val); \ |
| } while (0) |
| |
| #define K2_AWAKE 0 |
| #define K2_SLEEPING 1 |
| #define K2_OFF 2 |
| |
| static int k2_power_on(void *arg); |
| |
| #define K2_POWER_ON(host) do { \ |
| if (SLEEP_FLAG(host) != K2_AWAKE) \ |
| k2_power_on(host); \ |
| } while (0) |
| |
| /* |
| * if bcmsata2=1, but device only support SATA I, |
| * then downgrade to SATA I and reset SATA core |
| */ |
| #define AUTO_NEG_SPEED |
| |
| static unsigned int new_speed_mask; |
| |
| enum { |
| /* ap->flags bits */ |
| K2_FLAG_SATA_8_PORTS = (1 << 24), |
| K2_FLAG_NO_ATAPI_DMA = (1 << 25), |
| K2_FLAG_BAR_POS_3 = (1 << 26), |
| K2_FLAG_BRCM_SATA2 = (1 << 27), |
| |
| /* Taskfile registers offsets */ |
| K2_SATA_TF_CMD_OFFSET = 0x00, |
| K2_SATA_TF_DATA_OFFSET = 0x00, |
| K2_SATA_TF_ERROR_OFFSET = 0x04, |
| K2_SATA_TF_NSECT_OFFSET = 0x08, |
| K2_SATA_TF_LBAL_OFFSET = 0x0c, |
| K2_SATA_TF_LBAM_OFFSET = 0x10, |
| K2_SATA_TF_LBAH_OFFSET = 0x14, |
| K2_SATA_TF_DEVICE_OFFSET = 0x18, |
| K2_SATA_TF_CMDSTAT_OFFSET = 0x1c, |
| K2_SATA_TF_CTL_OFFSET = 0x20, |
| |
| /* DMA base */ |
| K2_SATA_DMA_CMD_OFFSET = 0x30, |
| |
| /* SCRs base */ |
| K2_SATA_SCR_STATUS_OFFSET = 0x40, /* aka SCR0 */ |
| K2_SATA_SCR_ERROR_OFFSET = 0x44, /* aka SCR1 */ |
| K2_SATA_SCR_CONTROL_OFFSET = 0x48, /* aka SCR2 */ |
| K2_SATA_SCR_ACTIVE_OFFSET = 0x4c, /* aka SCR3 */ |
| |
| /* Others */ |
| K2_SATA_SICR1_OFFSET = 0x80, |
| K2_SATA_SICR2_OFFSET = 0x84, |
| K2_SATA_SIMR_OFFSET = 0x88, /* SATA intr mask register */ |
| K2_SATA_MDIO_OFFSET = 0x8c, /* SATA MDIO access register */ |
| K2_SATA_SCQR_OFFSET = 0x94, /* SATA command queue depth */ |
| K2_SATA_QAL_OFFSET = 0xa0, /* QDMA ring address lower */ |
| K2_SATA_QAU_OFFSET = 0xa4, /* QDMA ring address upper */ |
| K2_SATA_QPI_OFFSET = 0xa8, /* QDMA producer index */ |
| K2_SATA_QCI_OFFSET = 0xac, /* QDMA consumer index */ |
| K2_SATA_QCR_OFFSET = 0xb0, /* QDMA control register */ |
| K2_SATA_QDR_OFFSET = 0xb4, /* QDMA queue depth */ |
| K2_SATA_QSR_OFFSET = 0xb8, /* QDMA status register */ |
| K2_SATA_QMR_OFFSET = 0xbc, /* QDMA interrupt mask */ |
| K2_SATA_QCI2_OFFSET = 0xc0, /* QDMA internal QCI for NCQ */ |
| |
| K2_SATA_E0_OFFSET = 0xe0, |
| K2_SATA_F0_OFFSET = 0xf0, |
| |
| /* Port stride */ |
| K2_SATA_PORT_OFFSET = 0x100, |
| |
| K2_SATA_GLOBAL_STATUS = 0x1004, |
| K2_SATA_GLOBAL_MASK = 0x1018, |
| |
| chip_sata1 = 0, |
| chip_sata2 = 1, |
| }; |
| |
| #define PORT_BASE(x, y) ((x) + (K2_SATA_PORT_OFFSET * (unsigned)(y))) |
| #define PORT_MMIO(x) PORT_BASE((void __iomem *) \ |
| ((x)->host->iomap[5]), \ |
| (x)->port_no) |
| |
| /* |
| * Extra init functions for stblinux platforms |
| */ |
| |
| #define WRITE_CMD 1 |
| #define READ_CMD 2 |
| #define CMD_DONE (1 << 15) |
| #define SATA_MMIO 0x24 |
| |
| /* |
| * 1. port is SATA port ( 0 or 1) |
| * 2. reg is the address of the MDIO register ( see spec ) |
| * 3. MMIO_BASE_ADDR is MMIO base address from SATA PCI configuration |
| * registers addr 24-27 |
| */ |
| static int mdio_read_reg(void __iomem *mmio_base, int port, |
| int reg) |
| { |
| void __iomem *mdio = mmio_base + K2_SATA_MDIO_OFFSET; |
| unsigned int pSel = 1 << port; |
| uint32_t cmd = WRITE_CMD; |
| |
| if (reg > 0x13) |
| return -1; |
| |
| /* Select Port */ |
| writel(pSel<<16 | (cmd << 13) | 7, mdio); |
| while (!(readl(mdio) & CMD_DONE)) |
| udelay(1); |
| |
| writel((READ_CMD << 13) + reg, mdio); |
| while (!(readl(mdio) & CMD_DONE)) |
| udelay(1); |
| |
| return readl(mdio) >> 16; |
| } |
| |
| static void mdio_write_reg(void __iomem *mmio_base, int port, |
| int reg, uint16_t val) |
| { |
| void __iomem *mdio = mmio_base + K2_SATA_MDIO_OFFSET; |
| unsigned int pSel = 1 << port; |
| uint32_t cmd = WRITE_CMD; |
| |
| if (reg > 0x13) |
| return; |
| |
| /* Select Port */ |
| writel(pSel<<16 | (cmd << 13) | 7, mdio); |
| while (!(readl(mdio) & CMD_DONE)) |
| udelay(1); |
| |
| writel((val << 16) + (WRITE_CMD << 13) + reg, mdio); |
| while (!(readl(mdio) & CMD_DONE)) |
| udelay(1); |
| } |
| |
| static void DisablePHY(void __iomem *mmio_base, int port) |
| { |
| uint32_t *pScr2 = PORT_BASE(mmio_base, port) + |
| K2_SATA_SCR_CONTROL_OFFSET; |
| writel(1, pScr2); |
| } |
| |
| static void EnablePHY(void __iomem *mmio_base, int port) |
| { |
| uint32_t *pScr2 = PORT_BASE(mmio_base, port) + |
| K2_SATA_SCR_CONTROL_OFFSET; |
| writel(0, pScr2); |
| } |
| |
| static void bcm_sg_workaround(void __iomem *mmio_base, int port) |
| { |
| int tmp16; |
| |
| DisablePHY(mmio_base, port); |
| |
| /* |
| * Do Interpolation when |
| * spread spectrucm clocking (SSC) is NOT enabled. But, the code must |
| * be used for a system with SSC-enabled drive. |
| * ssc is not zero when the argument bcmssc=1 is specified |
| */ |
| if (ssc) { |
| tmp16 = mdio_read_reg(mmio_base, port, 9); |
| mdio_write_reg(mmio_base, port, 9, tmp16 | 1); |
| } |
| |
| /* Do analog reset */ |
| tmp16 = mdio_read_reg(mmio_base, port, 4); |
| tmp16 |= 8; |
| mdio_write_reg(mmio_base, port, 4, tmp16); |
| |
| udelay(1000); |
| tmp16 &= 0xFFF7; |
| mdio_write_reg(mmio_base, port, 4, tmp16); |
| udelay(1000); |
| |
| /* Enable PHY */ |
| EnablePHY(mmio_base, port); |
| } |
| |
| /* |
| * This routine change (lower) bandwidth of SATA PLL to lower jitter |
| * from main internal ref clk in attempt to use on chip refclock |
| */ |
| static void brcm_SetPllTxRxCtrl(void __iomem *mmio_base, int port) |
| { |
| int tmp16; |
| |
| /* Change Tx control */ |
| mdio_write_reg(mmio_base, port, 0xa, 0x0260); |
| mdio_write_reg(mmio_base, port, 0x11, 0x0a10); |
| /* Change Rx control */ |
| tmp16 = mdio_read_reg(mmio_base, port, 0xF); |
| tmp16 &= 0xc000; |
| tmp16 |= 0x1000; |
| mdio_write_reg(mmio_base, port, 0xF, tmp16); |
| } |
| |
| static void brcm_TunePLL(void __iomem *mmio_base, int port) |
| { |
| int tmp; |
| int i; |
| |
| /* program VCO step bit [12:10] start with 111 */ |
| mdio_write_reg(mmio_base, port, 0x13, 0x1c00); |
| |
| udelay(100000); |
| |
| /* start pll tuner */ |
| mdio_write_reg(mmio_base, port, 0x13, 0x1e00); |
| |
| udelay(10000); |
| |
| /* check lock bit */ |
| tmp = mdio_read_reg(mmio_base, port, 0x7); |
| |
| for (i = 0; i < 10000; i++) { |
| tmp = mdio_read_reg(mmio_base, port, 0x7); |
| if ((tmp & 0x8000) == 0x8000) |
| return; |
| udelay(1); |
| } |
| DPRINTK("PLL did not lock\n"); |
| } |
| |
| static void brcm_EnableOOBWindowFix(void __iomem *mmio_base, int port) |
| { |
| int sval; |
| |
| /* Port 0 Transmit Control Register */ |
| sval = mdio_read_reg(mmio_base, port, 0x0D); |
| sval |= 0x400; |
| mdio_write_reg(mmio_base, port, 0x0D, sval); |
| } |
| |
| static void brcm_Enable256AlignDetection(void __iomem *mmio_base, int port) |
| { |
| uint32_t tmp32; |
| void __iomem *port_mmio; |
| |
| port_mmio = PORT_BASE(mmio_base, port); |
| |
| tmp32 = readl(port_mmio + K2_SATA_SICR1_OFFSET); |
| tmp32 |= 0x08000000; |
| writel(tmp32, port_mmio + K2_SATA_SICR1_OFFSET); |
| |
| tmp32 = readl(port_mmio + K2_SATA_SICR2_OFFSET); |
| tmp32 |= 0x00800000; |
| writel(tmp32, port_mmio + K2_SATA_SICR2_OFFSET); |
| } |
| |
| static void brcm_AnalogReset(void __iomem *mmio_base, int port) |
| { |
| /* do analog reset */ |
| mdio_write_reg(mmio_base, port, 0x4, 8); |
| udelay(10000); |
| mdio_write_reg(mmio_base, port, 0x4, 0); |
| |
| bcm_sg_workaround(mmio_base, port); |
| } |
| |
| static void brcm_InitSata_1_5Gb(void __iomem *mmio_base, int port) |
| { |
| int tmp; |
| volatile uint32_t tmp32; |
| void __iomem *port_mmio; |
| |
| port_mmio = PORT_BASE(mmio_base, port); |
| |
| /* reset deskew TX FIFO */ |
| mdio_write_reg(mmio_base, port, 7, 1<<port); |
| mdio_write_reg(mmio_base, port, 0xd, 0x4800); |
| udelay(10000); |
| mdio_write_reg(mmio_base, port, 0xd, 0x0800); |
| udelay(10000); |
| |
| /* Enable low speed (1.5G) mode */ |
| tmp = mdio_read_reg(mmio_base, port, 8); |
| mdio_write_reg(mmio_base, port, 8, tmp | 0x10); |
| |
| /* Enable lock monitor.. if not set the lock bit is not updated */ |
| tmp = mdio_read_reg(mmio_base, port, 0x13); |
| |
| mdio_write_reg(mmio_base, port, 0x13, tmp|2); |
| udelay(10000); |
| |
| /* disable 3G feature */ |
| tmp32 = readl(port_mmio + K2_SATA_F0_OFFSET); |
| writel(tmp32 & 0xfffffbff, port_mmio + K2_SATA_F0_OFFSET); |
| udelay(10000); |
| |
| /* enable 4G addressing support */ |
| tmp32 = readl(port_mmio + K2_SATA_SICR2_OFFSET); |
| writel(tmp32 | 0x20009400, port_mmio + K2_SATA_SICR2_OFFSET); |
| |
| tmp32 = readl(port_mmio + K2_SATA_SICR1_OFFSET); |
| tmp32 &= 0xffff0000; |
| writel(tmp32 | 0x00000f10, port_mmio + K2_SATA_SICR1_OFFSET); |
| |
| /* Clean up the fifo */ |
| tmp32 = readl(port_mmio + K2_SATA_E0_OFFSET); |
| writel(tmp32 | 2, port_mmio + K2_SATA_E0_OFFSET); |
| |
| brcm_SetPllTxRxCtrl(mmio_base, port); |
| brcm_EnableOOBWindowFix(mmio_base, port); |
| |
| brcm_Enable256AlignDetection(mmio_base, port); |
| |
| if (!port) { |
| #ifdef CONFIG_BRCM_SATA_75MHZ_PLL |
| /* use 75Mhz PLL clock */ |
| mdio_write_reg(mmio_base, port, 0, 0x2004); |
| #else |
| /* use 100Mhz PLL clock */ |
| mdio_write_reg(mmio_base, port, 0, 0x1404); |
| #endif |
| brcm_TunePLL(mmio_base, port); |
| brcm_AnalogReset(mmio_base, port); |
| udelay(10000); |
| } |
| |
| writel(0, port_mmio + K2_SATA_SCR_CONTROL_OFFSET); |
| } |
| |
| static void brcm_InitSata2_3Gb(void __iomem *mmio_base, int port) |
| { |
| volatile uint16_t tmp; |
| volatile uint32_t tmp32; |
| void __iomem *port_base; |
| |
| port_base = PORT_BASE(mmio_base, port); |
| |
| /* reset deskew TX FIFO */ |
| mdio_write_reg(mmio_base, port, 7, 1<<port); |
| mdio_write_reg(mmio_base, port, 0xd, 0x4800); |
| udelay(10000); |
| mdio_write_reg(mmio_base, port, 0xd, 0x0800); |
| udelay(10000); |
| |
| /* run at 3G mode */ |
| tmp = mdio_read_reg(mmio_base, port, 8); |
| mdio_write_reg(mmio_base, port, 8, tmp & ~(0x10)); |
| udelay(10000); |
| |
| /* Enable lock monitor. if not set the lock bit is not updated */ |
| tmp = mdio_read_reg(mmio_base, port, 0x13); |
| mdio_write_reg(mmio_base, port, 0x13, tmp|2); |
| |
| /* Enable 3Gb interface */ |
| tmp32 = readl(port_base + K2_SATA_F0_OFFSET); |
| writel(tmp32 | 0x10500, port_base + K2_SATA_F0_OFFSET); |
| udelay(10000); |
| |
| /* enable 4G addressing support */ |
| tmp32 = readl(port_base + K2_SATA_SICR2_OFFSET); |
| writel(tmp32 | 0x20009400, port_base + K2_SATA_SICR2_OFFSET); |
| |
| tmp32 = readl(port_base + K2_SATA_SICR1_OFFSET); |
| tmp32 &= 0xffff0000; |
| writel(tmp32 | 0x00000f10, port_base + K2_SATA_SICR1_OFFSET); |
| |
| /* Clean up the fifo */ |
| tmp32 = readl(port_base + K2_SATA_E0_OFFSET); |
| writel(tmp32|2, port_base + K2_SATA_E0_OFFSET); |
| |
| /* Tweak PLL, Tx, and Rx */ |
| brcm_SetPllTxRxCtrl(mmio_base, port); |
| brcm_EnableOOBWindowFix(mmio_base, port); |
| |
| brcm_Enable256AlignDetection(mmio_base, port); |
| |
| if (!port) { |
| #ifdef CONFIG_BRCM_SATA_75MHZ_PLL |
| /* use 75Mhz PLL clock */ |
| mdio_write_reg(mmio_base, port, 0, 0x2004); |
| #else |
| /* use 100Mhz PLL clock */ |
| mdio_write_reg(mmio_base, port, 0, 0x1404); |
| #endif |
| brcm_TunePLL(mmio_base, port); |
| brcm_AnalogReset(mmio_base, port); |
| udelay(10000); |
| } |
| |
| writel(0, port_base + K2_SATA_SCR_CONTROL_OFFSET); |
| } |
| |
| /* Kernel argument bcmsata2=0|1 */ |
| static inline void brcm_initsata2(void __iomem *mmio_base, int num_ports) |
| { |
| int port; |
| unsigned int first = 1; |
| |
| retry_brcm_initsata2: |
| for (port = 0; port < num_ports; port++) |
| writel(1, (void *)(mmio_base + port*K2_SATA_PORT_OFFSET + |
| K2_SATA_SCR_CONTROL_OFFSET)); |
| |
| for (port = 0; port < num_ports; port++) { |
| /* |
| * Turn on 3Gbps if bcmsata2=1 is specified as kernel argument |
| * during bootup |
| */ |
| if (s2) { |
| if (new_speed_mask == 0) |
| brcm_InitSata2_3Gb(mmio_base, port); |
| else if (new_speed_mask & (1<<port)) |
| brcm_InitSata_1_5Gb(mmio_base, port); |
| } else |
| brcm_InitSata_1_5Gb(mmio_base, port); |
| } |
| |
| #ifdef AUTO_NEG_SPEED |
| if (s2 && first) { |
| int port; |
| msleep(10); |
| |
| for (port = 0; port < num_ports; port++) { |
| unsigned int status = readl((void *)(mmio_base + |
| port*K2_SATA_PORT_OFFSET + |
| K2_SATA_SCR_STATUS_OFFSET)); |
| if ((status & 0xf) >= 0x5 && |
| (status & 0xf0) == 0 && |
| (status & 0xf00) == 0) |
| new_speed_mask |= 1<<port; |
| } |
| |
| first = 0; |
| if (new_speed_mask) |
| goto retry_brcm_initsata2; |
| } |
| |
| new_speed_mask = 0; |
| #endif |
| } |
| |
| void k2_sata_postreset(struct ata_link *link, unsigned int *classes) |
| { |
| struct ata_port *ap = link->ap; |
| void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr; |
| unsigned int reg = readl(port + K2_SATA_SIMR_OFFSET); |
| |
| if (ap->ops->freeze) |
| ap->ops->freeze(ap); |
| |
| writel(reg | SERR_PHYRDY_CHG, port + K2_SATA_SIMR_OFFSET); |
| |
| if (ap->ops->thaw) |
| ap->ops->thaw(ap); |
| |
| return ata_std_postreset(link, classes); |
| } |
| |
| static void bcm97xxx_sata_init(struct pci_dev *dev, |
| void __iomem *mmio_base, |
| int n_ports, |
| int sata2_core) |
| { |
| int reg; |
| int port; |
| void __iomem *port_base; |
| |
| if (sata2_core) { |
| brcm_initsata2(mmio_base, n_ports); |
| /* Skip all workarounds. Those have been fixed with 65nm */ |
| return; |
| } |
| |
| /* |
| * Before accessing the MDIO registers through pci space disable |
| * external MDIO access. write MDIO register at offset 0x07 with |
| * (1 << port number) where port number starts at 0. |
| * Read MDIO register at offset 0x0D into variable reg. |
| * reg_0d = reg_0d | 0x04 |
| * Write reg_0d to MDIO register at offset 0x0D. |
| */ |
| for (port = 0; port < n_ports; port++) { |
| /* Put PHY in reset */ |
| port_base = PORT_BASE(mmio_base, 0); |
| reg = readl(port_base+K2_SATA_SCR_CONTROL_OFFSET); |
| writel((reg & ~0xf) | 1, port_base+K2_SATA_SCR_CONTROL_OFFSET); |
| |
| /* Choose the port and read reg 0xd */ |
| reg = mdio_read_reg(mmio_base, port, 0xd); |
| reg |= 0x4; |
| mdio_write_reg(mmio_base, port, 0xd, reg); |
| reg = mdio_read_reg(mmio_base, port, 0xd); |
| |
| /* Re-enable PHY */ |
| reg = readl(port_base+K2_SATA_SCR_CONTROL_OFFSET); |
| writel(reg & ~0xf, port_base+K2_SATA_SCR_CONTROL_OFFSET); |
| } |
| |
| /* PR22401: Identify Seagate drives with ST controllers */ |
| for (port = 0; port < n_ports; port++) |
| bcm_sg_workaround(mmio_base, port); |
| } |
| |
| /* |
| * Common (legacy/QDMA) functions |
| */ |
| |
| static int k2_sata_scr_read(struct ata_link *link, |
| unsigned int sc_reg, |
| u32 *val) |
| { |
| if (sc_reg > SCR_CONTROL) |
| return -EINVAL; |
| *val = readl((void *) link->ap->ioaddr.scr_addr + (sc_reg * 4)); |
| return 0; |
| } |
| |
| |
| static int k2_sata_scr_write(struct ata_link *link, |
| unsigned int sc_reg, |
| u32 val) |
| { |
| if (sc_reg > SCR_CONTROL) |
| return -EINVAL; |
| writel(val, (void *) link->ap->ioaddr.scr_addr + (sc_reg * 4)); |
| return 0; |
| } |
| |
| static u8 k2_stat_check_status(struct ata_port *ap) |
| { |
| return readl((void *) ap->ioaddr.status_addr); |
| } |
| |
| static void k2_sata_tf_read(struct ata_port *ap, struct ata_taskfile *tf) |
| { |
| struct ata_ioports *ioaddr = &ap->ioaddr; |
| u16 nsect, lbal, lbam, lbah, feature; |
| void __iomem *port_mmio = PORT_MMIO(ap); |
| u32 qcr, qsr; |
| |
| qcr = readl(port_mmio + K2_SATA_QCR_OFFSET); |
| |
| /* QDMA active, unpaused - pause the queue to read taskfile */ |
| if ((qcr & 3) == 1) { |
| int i = 0; |
| |
| writel(qcr | 2, port_mmio + K2_SATA_QCR_OFFSET); |
| do { |
| qsr = readl(port_mmio + K2_SATA_QSR_OFFSET); |
| if (qsr & 2) |
| break; |
| if (++i == 1000) { |
| ata_port_printk(ap, KERN_WARNING, |
| "error pausing queue for taskfile read\n"); |
| break; |
| } |
| udelay(1); |
| } while (1); |
| } |
| |
| tf->command = k2_stat_check_status(ap); |
| tf->device = readw((void *)ioaddr->device_addr); |
| feature = readw((void *)ioaddr->error_addr); |
| nsect = readw((void *)ioaddr->nsect_addr); |
| lbal = readw((void *)ioaddr->lbal_addr); |
| lbam = readw((void *)ioaddr->lbam_addr); |
| lbah = readw((void *)ioaddr->lbah_addr); |
| |
| tf->feature = feature; |
| tf->nsect = nsect; |
| tf->lbal = lbal; |
| tf->lbam = lbam; |
| tf->lbah = lbah; |
| |
| if (tf->flags & ATA_TFLAG_LBA48) { |
| tf->hob_feature = feature >> 8; |
| tf->hob_nsect = nsect >> 8; |
| tf->hob_lbal = lbal >> 8; |
| tf->hob_lbam = lbam >> 8; |
| tf->hob_lbah = lbah >> 8; |
| } |
| /* unpause queue */ |
| if ((qcr & 3) == 1) |
| writel(qcr, port_mmio + K2_SATA_QCR_OFFSET); |
| } |
| |
| #ifdef CONFIG_PPC_OF |
| /* |
| * k2_sata_proc_info |
| * inout : decides on the direction of the dataflow and the meaning of the |
| * variables |
| * buffer: If inout==FALSE data is being written to it else read from it |
| * *start: If inout==FALSE start of the valid data in the buffer |
| * offset: If inout==FALSE offset from the beginning of the imaginary file |
| * from which we start writing into the buffer |
| * length: If inout==FALSE max number of bytes to be written into the buffer |
| * else number of bytes in the buffer |
| */ |
| static int k2_sata_proc_info(struct Scsi_Host *shost, char *page, char **start, |
| off_t offset, int count, int inout) |
| { |
| struct ata_port *ap; |
| struct device_node *np; |
| int len, index; |
| |
| /* Find the ata_port */ |
| ap = ata_shost_to_port(shost); |
| if (ap == NULL) |
| return 0; |
| |
| /* Find the OF node for the PCI device proper */ |
| np = pci_device_to_OF_node(to_pci_dev(ap->host->dev)); |
| if (np == NULL) |
| return 0; |
| |
| /* Match it to a port node */ |
| index = (ap == ap->host->ports[0]) ? 0 : 1; |
| for (np = np->child; np != NULL; np = np->sibling) { |
| const u32 *reg = get_property(np, "reg", NULL); |
| if (!reg) |
| continue; |
| if (index == *reg) |
| break; |
| } |
| if (np == NULL) |
| return 0; |
| |
| len = sprintf(page, "devspec: %s\n", np->full_name); |
| |
| return len; |
| } |
| #endif /* CONFIG_PPC_OF */ |
| |
| /* |
| * Legacy-only functions |
| */ |
| |
| static void k2_sata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) |
| { |
| struct ata_ioports *ioaddr = &ap->ioaddr; |
| unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; |
| |
| if (tf->ctl != ap->last_ctl) { |
| writeb(tf->ctl, ioaddr->ctl_addr); |
| ap->last_ctl = tf->ctl; |
| ata_wait_idle(ap); |
| } |
| if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) { |
| writew(tf->feature | (((u16)tf->hob_feature) << 8), |
| (void *)ioaddr->feature_addr); |
| writew(tf->nsect | (((u16)tf->hob_nsect) << 8), |
| (void *)ioaddr->nsect_addr); |
| writew(tf->lbal | (((u16)tf->hob_lbal) << 8), |
| (void *)ioaddr->lbal_addr); |
| writew(tf->lbam | (((u16)tf->hob_lbam) << 8), |
| (void *)ioaddr->lbam_addr); |
| writew(tf->lbah | (((u16)tf->hob_lbah) << 8), |
| (void *)ioaddr->lbah_addr); |
| } else if (is_addr) { |
| writew(tf->feature, (void *)ioaddr->feature_addr); |
| writew(tf->nsect, (void *)ioaddr->nsect_addr); |
| writew(tf->lbal, (void *)ioaddr->lbal_addr); |
| writew(tf->lbam, (void *)ioaddr->lbam_addr); |
| writew(tf->lbah, (void *)ioaddr->lbah_addr); |
| } |
| |
| if (tf->flags & ATA_TFLAG_DEVICE) |
| writeb(tf->device, (void *)ioaddr->device_addr); |
| |
| ata_wait_idle(ap); |
| } |
| |
| /** |
| * k2_bmdma_setup_mmio - Set up PCI IDE BMDMA transaction (MMIO) |
| * @qc: Info associated with this ATA transaction. |
| * |
| * LOCKING: |
| * spin_lock_irqsave(host lock) |
| */ |
| |
| static void k2_bmdma_setup_mmio(struct ata_queued_cmd *qc) |
| { |
| struct ata_port *ap = qc->ap; |
| unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE); |
| u8 dmactl; |
| void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr; |
| /* load PRD table addr. */ |
| mb(); /* make sure PRD table writes are visible to controller */ |
| writel(ap->bmdma_prd_dma, mmio + ATA_DMA_TABLE_OFS); |
| |
| /* specify data direction, triple-check start bit is clear */ |
| dmactl = readb(mmio + ATA_DMA_CMD); |
| dmactl &= ~(ATA_DMA_WR | ATA_DMA_START); |
| if (!rw) |
| dmactl |= ATA_DMA_WR; |
| writeb(dmactl, mmio + ATA_DMA_CMD); |
| |
| /* issue r/w command if this is not a ATA DMA command*/ |
| if (qc->tf.protocol != ATA_PROT_DMA) |
| ap->ops->sff_exec_command(ap, &qc->tf); |
| } |
| |
| /** |
| * k2_bmdma_start_mmio - Start a PCI IDE BMDMA transaction (MMIO) |
| * @qc: Info associated with this ATA transaction. |
| * |
| * LOCKING: |
| * spin_lock_irqsave(host lock) |
| */ |
| |
| static void k2_bmdma_start_mmio(struct ata_queued_cmd *qc) |
| { |
| struct ata_port *ap = qc->ap; |
| void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr; |
| u8 dmactl; |
| |
| /* start host DMA transaction */ |
| dmactl = readb(mmio + ATA_DMA_CMD); |
| writeb(dmactl | ATA_DMA_START, mmio + ATA_DMA_CMD); |
| /* There is a race condition in certain SATA controllers that can |
| * be seen when the r/w command is given to the controller before the |
| * host DMA is started. On a Read command, the controller would initiate |
| * the command to the drive even before it sees the DMA start. |
| * When there are very fast drives connected to the controller, |
| * or when the data request hits in the drive cache, there is the |
| * possibility that the drive returns a part or all of the requested |
| * data to the controller before the DMA start is issued. |
| * In this case, the controller would become confused as to what to do |
| * with the data. |
| * In the worst case when all the data is returned back to |
| * the controller, the controller could hang. In other cases it could |
| * return partial data returning in data corruption. This problem has |
| * been seen in PPC systems and can also appear on an system with very |
| * fast disks, where the SATA controller is sitting behind a |
| * number of bridges, and hence there is significant latency between |
| * the r/w command and the start command. |
| */ |
| |
| /* issue r/w command if the access is to ATA */ |
| if (qc->tf.protocol == ATA_PROT_DMA) |
| ap->ops->sff_exec_command(ap, &qc->tf); |
| } |
| |
| static int k2_sata_port_start(struct ata_port *ap) |
| { |
| ata_bmdma_port_start(ap); |
| return 0; |
| } |
| |
| static void k2_sata_error_handler(struct ata_port *ap) |
| { |
| ata_sff_error_handler(ap); |
| } |
| |
| static irqreturn_t k2_sata_interrupt(int irq, void *dev_instance) |
| { |
| struct ata_host *host = dev_instance; |
| unsigned int i; |
| unsigned int handled = 0; |
| unsigned long flags; |
| struct k2_host_priv *hp = host->private_data; |
| |
| spin_lock_irqsave(&host->lock, flags); |
| |
| for (i = 0; i < host->n_ports; i++) { |
| struct ata_port *ap; |
| struct ata_link *link; |
| |
| ap = host->ports[i]; |
| |
| ata_for_each_link(link, ap, EDGE) { |
| int rc; |
| unsigned int serror; |
| |
| rc = sata_scr_read(link, SCR_ERROR, &serror); |
| |
| if (rc == 0) { |
| if (serror & (SERR_PHYRDY_CHG | SERR_DEV_XCHG)) { |
| if (time_after(jiffies, hp->hp_jif)) { |
| struct ata_eh_info *ehi = |
| &ap->link.eh_info; |
| unsigned long hp_flags; |
| |
| sata_scr_write(link, SCR_ERROR, serror); |
| |
| spin_lock_irqsave(&hp->lock, hp_flags); |
| hp->hp_jif = jiffies + 2*HZ; |
| spin_unlock_irqrestore(&hp->lock, |
| hp_flags); |
| |
| ata_ehi_hotplugged(ehi); |
| ata_ehi_push_desc(ehi, "hotplug"); |
| ata_port_freeze(ap); |
| handled |= IRQ_HANDLED; |
| } else { |
| sata_scr_write(link, SCR_ERROR, serror); |
| handled |= IRQ_HANDLED; |
| } |
| } |
| } |
| } |
| } |
| |
| spin_unlock_irqrestore(&host->lock, flags); |
| |
| if (handled & IRQ_HANDLED) |
| return handled; |
| |
| return ata_bmdma_interrupt(irq, dev_instance); |
| } |
| |
| /* |
| * Power management |
| */ |
| static void k2_sata_clk_disable(struct device *dev) |
| { |
| struct ata_host *host = dev_get_drvdata(dev); |
| struct k2_host_priv *hp = host->private_data; |
| clk_disable(hp->clk); |
| } |
| |
| static void k2_sata_clk_enable(struct device *dev) |
| { |
| struct ata_host *host = dev_get_drvdata(dev); |
| struct k2_host_priv *hp = host->private_data; |
| |
| clk_enable(hp->clk); |
| } |
| |
| static int k2_power_off(void *arg) |
| { |
| struct ata_host *host = arg; |
| struct pci_dev *pdev = to_pci_dev(host->dev); |
| struct k2_host_priv *hp = host->private_data; |
| int i, active = 0; |
| unsigned long flags; |
| unsigned int retries = 100; |
| |
| spin_lock_irqsave(&hp->lock, flags); |
| if (SLEEP_FLAG(host) == K2_SLEEPING || SLEEP_FLAG(host) == K2_OFF) { |
| spin_unlock_irqrestore(&hp->lock, flags); |
| return 0; |
| } |
| |
| do { |
| for (i = 0; i < host->n_ports; i++) { |
| struct ata_port *ap; |
| struct ata_link *link; |
| struct ata_device *dev; |
| |
| ap = host->ports[i]; |
| |
| /* |
| * dev->sdev is set to NULL in ata_scsi_slave_destroy() |
| * upon hot or warm unplug. If it is non-NULL, |
| * the device is still enabled and it is unsafe to |
| * power off the core. |
| */ |
| ata_for_each_link(link, ap, EDGE) { |
| ata_for_each_dev(dev, link, ALL) { |
| if (dev->sdev) |
| active++; |
| } |
| } |
| } |
| |
| if (!active) |
| break; |
| |
| active = 0; |
| msleep(100); |
| } while (retries--); |
| |
| if (active) { |
| spin_unlock_irqrestore(&hp->lock, flags); |
| return -EBUSY; |
| } else { |
| void __iomem *port_base; |
| |
| SET_SLEEP_FLAG(host, K2_OFF); |
| |
| /* put all ports in Slumber mode */ |
| for (i = 0; i < host->n_ports; i++) { |
| port_base = PORT_BASE(hp->mmio_base, i); |
| writel(readl(port_base + K2_SATA_SICR1_OFFSET) | |
| (1 << 25), port_base + K2_SATA_SICR1_OFFSET); |
| udelay(10); |
| writel((readl(port_base + K2_SATA_SICR2_OFFSET) & |
| ~(7 << 18)) | (2 << 18), |
| port_base + K2_SATA_SICR2_OFFSET); |
| udelay(50); |
| writel((readl(port_base + K2_SATA_SICR2_OFFSET) & |
| ~(7 << 18)) | (0 << 18), |
| port_base + K2_SATA_SICR2_OFFSET); |
| } |
| |
| disable_irq(pdev->irq); |
| k2_sata_clk_disable(host->dev); |
| spin_unlock_irqrestore(&hp->lock, flags); |
| |
| return 0; |
| } |
| } |
| |
| static int k2_power_on(void *arg) |
| { |
| struct ata_host *host = arg; |
| struct pci_dev *pdev = to_pci_dev(host->dev); |
| struct k2_host_priv *hp = host->private_data; |
| void __iomem *port_base; |
| int i; |
| unsigned long flags; |
| |
| spin_lock_irqsave(&hp->lock, flags); |
| if (SLEEP_FLAG(host) == K2_AWAKE) { |
| spin_unlock_irqrestore(&hp->lock, flags); |
| return 0; |
| } |
| |
| k2_sata_clk_enable(host->dev); |
| brcm_initsata2(hp->mmio_base, host->n_ports); |
| enable_irq(pdev->irq); |
| |
| /* wake up all ports */ |
| for (i = 0; i < host->n_ports; i++) { |
| port_base = PORT_BASE(hp->mmio_base, i); |
| writel(readl(port_base + K2_SATA_SICR1_OFFSET) & |
| ~(1 << 25), port_base + K2_SATA_SICR1_OFFSET); |
| udelay(10); |
| writel((readl(port_base + K2_SATA_SICR2_OFFSET) & |
| ~(7 << 18)) | (4 << 18), |
| port_base + K2_SATA_SICR2_OFFSET); |
| udelay(50); |
| writel((readl(port_base + K2_SATA_SICR2_OFFSET) & |
| ~(7 << 18)) | (0 << 18), |
| port_base + K2_SATA_SICR2_OFFSET); |
| } |
| |
| SET_SLEEP_FLAG(host, K2_AWAKE); |
| spin_unlock_irqrestore(&hp->lock, flags); |
| |
| return 0; |
| } |
| |
| static int k2_sata_pm_cb(int event, void *arg) |
| { |
| if (event == PM_EVENT_SUSPEND) |
| return k2_power_off(arg); |
| else if (event == PM_EVENT_RESUME) |
| return k2_power_on(arg); |
| else |
| return -EINVAL; |
| } |
| |
| static void k2_sata_remove_one(struct pci_dev *pdev) |
| { |
| struct device *dev = &pdev->dev; |
| struct ata_host *host = dev_get_drvdata(dev); |
| struct k2_host_priv *hp = host->private_data; |
| |
| brcm_pm_unregister_cb("sata"); |
| pm_runtime_get_noresume(&pdev->dev); |
| |
| K2_POWER_ON(host); |
| ata_pci_remove_one(pdev); |
| |
| clk_disable(hp->clk); |
| clk_put(hp->clk); |
| kfree(hp); |
| } |
| |
| static int k2_sata_suspend(struct device *dev) |
| { |
| struct ata_host *host = dev_get_drvdata(dev); |
| struct pci_dev *pdev = to_pci_dev(host->dev); |
| struct k2_host_priv *hp = host->private_data; |
| int i; |
| void __iomem *port_base; |
| unsigned long flags; |
| |
| spin_lock_irqsave(&hp->lock, flags); |
| |
| if (SLEEP_FLAG(host) == K2_SLEEPING || SLEEP_FLAG(host) == K2_OFF) { |
| spin_unlock_irqrestore(&hp->lock, flags); |
| return 0; |
| } |
| |
| SET_SLEEP_FLAG(host, K2_SLEEPING); |
| |
| /* put all ports in Slumber mode */ |
| for (i = 0; i < host->n_ports; i++) { |
| port_base = PORT_BASE(hp->mmio_base, i); |
| writel(readl(port_base + K2_SATA_SICR1_OFFSET) | |
| (1 << 25), port_base + K2_SATA_SICR1_OFFSET); |
| udelay(10); |
| writel((readl(port_base + K2_SATA_SICR2_OFFSET) & |
| ~(7 << 18)) | (2 << 18), |
| port_base + K2_SATA_SICR2_OFFSET); |
| udelay(50); |
| writel((readl(port_base + K2_SATA_SICR2_OFFSET) & |
| ~(7 << 18)) | (0 << 18), |
| port_base + K2_SATA_SICR2_OFFSET); |
| } |
| |
| disable_irq(pdev->irq); |
| k2_sata_clk_disable(dev); |
| spin_unlock_irqrestore(&hp->lock, flags); |
| return 0; |
| } |
| |
| static int k2_sata_resume(struct device *dev) |
| { |
| struct ata_host *host = dev_get_drvdata(dev); |
| struct pci_dev *pdev = to_pci_dev(host->dev); |
| struct k2_host_priv *hp = host->private_data; |
| void __iomem *port_base; |
| int i; |
| unsigned long flags; |
| |
| spin_lock_irqsave(&hp->lock, flags); |
| |
| if (SLEEP_FLAG(host) == K2_AWAKE || SLEEP_FLAG(host) == K2_OFF) { |
| spin_unlock_irqrestore(&hp->lock, flags); |
| return 0; |
| } |
| |
| k2_sata_clk_enable(dev); |
| brcm_initsata2(hp->mmio_base, host->n_ports); |
| enable_irq(pdev->irq); |
| |
| /* wake up all ports */ |
| for (i = 0; i < host->n_ports; i++) { |
| struct ata_port *ap; |
| struct ata_link *link; |
| |
| port_base = PORT_BASE(hp->mmio_base, i); |
| writel(readl(port_base + K2_SATA_SICR1_OFFSET) & |
| ~(1 << 25), port_base + K2_SATA_SICR1_OFFSET); |
| udelay(10); |
| writel((readl(port_base + K2_SATA_SICR2_OFFSET) & |
| ~(7 << 18)) | (4 << 18), |
| port_base + K2_SATA_SICR2_OFFSET); |
| udelay(50); |
| writel((readl(port_base + K2_SATA_SICR2_OFFSET) & |
| ~(7 << 18)) | (0 << 18), |
| port_base + K2_SATA_SICR2_OFFSET); |
| |
| ap = host->ports[i]; |
| |
| ata_for_each_link(link, ap, EDGE) { |
| spin_unlock_irqrestore(&hp->lock, flags); |
| sata_std_hardreset(link, NULL, 1000); |
| spin_lock_irqsave(&hp->lock, flags); |
| } |
| } |
| |
| SET_SLEEP_FLAG(host, K2_AWAKE); |
| spin_unlock_irqrestore(&hp->lock, flags); |
| return 0; |
| } |
| |
| static int k2_sata_runtime_suspend(struct device *dev) |
| { |
| return k2_sata_suspend(dev); |
| } |
| |
| static int k2_sata_runtime_resume(struct device *dev) |
| { |
| return k2_sata_resume(dev); |
| } |
| |
| static int k2_sata_runtime_idle(struct device *dev) |
| { |
| dev_printk(KERN_DEBUG, dev, "%s [%lu] disabling the SATA clock\n", |
| __func__, jiffies); |
| return 0; /* ignored by pm core */ |
| } |
| |
| /* |
| * Driver initialization |
| */ |
| |
| static struct scsi_host_template k2_sata_sht = { |
| .module = THIS_MODULE, |
| .name = DRV_NAME, |
| .ioctl = ata_scsi_ioctl, |
| .queuecommand = ata_scsi_queuecmd, |
| .can_queue = ATA_DEF_QUEUE, |
| .this_id = ATA_SHT_THIS_ID, |
| .sg_tablesize = LIBATA_MAX_PRD, |
| .cmd_per_lun = ATA_SHT_CMD_PER_LUN, |
| .emulated = ATA_SHT_EMULATED, |
| .use_clustering = ATA_SHT_USE_CLUSTERING, |
| .proc_name = DRV_NAME, |
| .dma_boundary = ATA_DMA_BOUNDARY, |
| .slave_configure = ata_scsi_slave_config, |
| .slave_destroy = ata_scsi_slave_destroy, |
| #ifdef CONFIG_PPC_OF |
| .proc_info = k2_sata_proc_info, |
| #endif |
| .bios_param = ata_std_bios_param, |
| }; |
| |
| |
| static struct ata_port_operations k2_sata_ops = { |
| .inherits = &ata_bmdma_port_ops, |
| .sff_tf_read = k2_sata_tf_read, |
| .sff_check_status = k2_stat_check_status, |
| .scr_read = k2_sata_scr_read, |
| .scr_write = k2_sata_scr_write, |
| .port_start = k2_sata_port_start, |
| .error_handler = k2_sata_error_handler, |
| .postreset = k2_sata_postreset, |
| |
| .bmdma_setup = k2_bmdma_setup_mmio, |
| .bmdma_start = k2_bmdma_start_mmio, |
| .sff_tf_load = k2_sata_tf_load, |
| }; |
| |
| static const struct ata_port_info k2_port_info[] = { |
| /* chip_sata1 */ |
| { |
| .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | |
| ATA_FLAG_MMIO | K2_FLAG_NO_ATAPI_DMA, |
| .pio_mask = 0x1f, |
| .mwdma_mask = 0x07, |
| .udma_mask = ATA_UDMA7, |
| .port_ops = &k2_sata_ops, |
| }, |
| /* chip_sata2 */ |
| { |
| .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | |
| ATA_FLAG_MMIO | K2_FLAG_NO_ATAPI_DMA | |
| K2_FLAG_BRCM_SATA2, |
| .pio_mask = 0x1f, |
| .mwdma_mask = 0x07, |
| .udma_mask = ATA_UDMA7, |
| .port_ops = &k2_sata_ops, |
| }, |
| }; |
| |
| static void k2_sata_setup_port(struct ata_ioports *port, void __iomem *base) |
| { |
| port->cmd_addr = base + K2_SATA_TF_CMD_OFFSET; |
| port->data_addr = base + K2_SATA_TF_DATA_OFFSET; |
| port->feature_addr = |
| port->error_addr = base + K2_SATA_TF_ERROR_OFFSET; |
| port->nsect_addr = base + K2_SATA_TF_NSECT_OFFSET; |
| port->lbal_addr = base + K2_SATA_TF_LBAL_OFFSET; |
| port->lbam_addr = base + K2_SATA_TF_LBAM_OFFSET; |
| port->lbah_addr = base + K2_SATA_TF_LBAH_OFFSET; |
| port->device_addr = base + K2_SATA_TF_DEVICE_OFFSET; |
| port->command_addr = |
| port->status_addr = base + K2_SATA_TF_CMDSTAT_OFFSET; |
| port->altstatus_addr = |
| port->ctl_addr = base + K2_SATA_TF_CTL_OFFSET; |
| port->bmdma_addr = base + K2_SATA_DMA_CMD_OFFSET; |
| port->scr_addr = base + K2_SATA_SCR_STATUS_OFFSET; |
| } |
| |
| static int k2_sata_init_one(struct pci_dev *pdev, |
| const struct pci_device_id *ent) |
| { |
| static int printed_version; |
| const struct ata_port_info *ppi[] = { |
| &k2_port_info[ent->driver_data], NULL }; |
| struct ata_host *host; |
| void __iomem *mmio_base; |
| int n_ports, i, rc, bar_pos; |
| struct k2_host_priv *hp; |
| |
| if (!printed_version++) |
| dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); |
| |
| #ifdef CONFIG_BRCM_SATA_SINGLE_PORT |
| n_ports = 1; |
| #else |
| n_ports = 2; |
| #endif |
| |
| host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports); |
| if (!host) |
| return -ENOMEM; |
| |
| host->private_data = hp = kzalloc(sizeof(*hp), GFP_KERNEL); |
| if (!hp) |
| return -ENOMEM; |
| |
| spin_lock_init(&hp->lock); |
| hp->clk = clk_get(&pdev->dev, "sata"); |
| clk_enable(hp->clk); |
| hp->sleep_flag = K2_AWAKE; |
| |
| bar_pos = 5; |
| if (ppi[0]->flags & K2_FLAG_BAR_POS_3) |
| bar_pos = 3; |
| /* |
| * If this driver happens to only be useful on Apple's K2, then |
| * we should check that here as it has a normal Serverworks ID |
| */ |
| rc = pcim_enable_device(pdev); |
| if (rc) |
| return rc; |
| |
| /* |
| * Check if we have resources mapped at all (second function may |
| * have been disabled by firmware) |
| */ |
| if (pci_resource_len(pdev, bar_pos) == 0) { |
| /* In IDE mode we need to pin the device to ensure that |
| * pcim_release does not clear the busmaster bit in config |
| * space, clearing causes busmaster DMA to fail on ports 3 & 4 |
| */ |
| pcim_pin_device(pdev); |
| return -ENODEV; |
| } |
| |
| /* Request and iomap PCI regions */ |
| rc = pcim_iomap_regions(pdev, 1 << bar_pos, DRV_NAME); |
| if (rc == -EBUSY) |
| pcim_pin_device(pdev); |
| if (rc) |
| return rc; |
| host->iomap = pcim_iomap_table(pdev); |
| hp->mmio_base = mmio_base = host->iomap[bar_pos]; |
| |
| /* different controllers have different number of ports - |
| * currently 4 or 8 |
| * All ports are on the same function. Multi-function device is no |
| * longer available. This should not be seen in any system. |
| */ |
| for (i = 0; i < host->n_ports; i++) { |
| struct ata_port *ap = host->ports[i]; |
| unsigned int offset = i * K2_SATA_PORT_OFFSET; |
| |
| k2_sata_setup_port(&ap->ioaddr, mmio_base + offset); |
| |
| ata_port_pbar_desc(ap, 5, -1, "mmio"); |
| ata_port_pbar_desc(ap, 5, offset, "port"); |
| } |
| |
| rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); |
| if (rc) |
| return rc; |
| rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK); |
| if (rc) |
| return rc; |
| |
| /* Clear a magic bit in SCR1 according to Darwin, those help |
| * some funky seagate drives (though so far, those were already |
| * set by the firmware on the machines I had access to) |
| */ |
| writel(readl(mmio_base + K2_SATA_SICR1_OFFSET) & ~0x00040000, |
| mmio_base + K2_SATA_SICR1_OFFSET); |
| |
| /* Clear SATA error & interrupts we don't use */ |
| writel(0xffffffff, mmio_base + K2_SATA_SCR_ERROR_OFFSET); |
| writel(0x0, mmio_base + K2_SATA_SIMR_OFFSET); |
| |
| pci_set_master(pdev); |
| |
| bcm97xxx_sata_init(pdev, mmio_base, n_ports, |
| ppi[0]->flags & K2_FLAG_BRCM_SATA2); |
| hp->hp_jif = jiffies; |
| |
| rc = ata_host_activate(host, pdev->irq, k2_sata_interrupt, |
| IRQF_SHARED, &k2_sata_sht); |
| if (rc) |
| return rc; |
| |
| brcm_pm_register_cb("sata", k2_sata_pm_cb, host); |
| |
| /* pci core incremented pm counter before calling probe, |
| * we are decrementing it to enable runtime pm */ |
| pm_runtime_put_noidle(&pdev->dev); |
| |
| return 0; |
| } |
| |
| static const struct pci_device_id k2_sata_pci_tbl[] = { |
| { PCI_VDEVICE(SERVERWORKS, 0x0242), chip_sata1 }, /* 7401 and older */ |
| { PCI_VDEVICE(BROADCOM, 0x8602), chip_sata2 }, /* 7400 and newer */ |
| { } |
| }; |
| |
| static const struct dev_pm_ops k2_sata_pm_ops = { |
| .suspend_noirq = k2_sata_suspend, |
| .resume_noirq = k2_sata_resume, |
| .runtime_suspend = k2_sata_runtime_suspend, |
| .runtime_resume = k2_sata_runtime_resume, |
| .runtime_idle = k2_sata_runtime_idle, |
| }; |
| |
| static struct pci_driver k2_sata_pci_driver = { |
| .name = DRV_NAME, |
| .id_table = k2_sata_pci_tbl, |
| .probe = k2_sata_init_one, |
| .remove = k2_sata_remove_one, |
| .driver.pm = &k2_sata_pm_ops, |
| }; |
| |
| static int __init k2_sata_init(void) |
| { |
| return pci_register_driver(&k2_sata_pci_driver); |
| } |
| |
| static void __exit k2_sata_exit(void) |
| { |
| pci_unregister_driver(&k2_sata_pci_driver); |
| } |
| |
| MODULE_AUTHOR("Benjamin Herrenschmidt"); |
| MODULE_DESCRIPTION("low-level driver for K2 SATA controller"); |
| MODULE_LICENSE("GPL"); |
| MODULE_DEVICE_TABLE(pci, k2_sata_pci_tbl); |
| MODULE_VERSION(DRV_VERSION); |
| |
| module_init(k2_sata_init); |
| module_exit(k2_sata_exit); |