blob: 1802f92180e4b2525c68e20634c9b7167ec18c43 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * sata_sx4.c - Promise SATA
3 *
4 * Maintained by: Jeff Garzik <jgarzik@pobox.com>
5 * Please ALWAYS copy linux-ide@vger.kernel.org
6 * on emails.
7 *
8 * Copyright 2003-2004 Red Hat, Inc.
9 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 *
Jeff Garzikaf36d7f2005-08-28 20:18:39 -040011 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2, or (at your option)
14 * any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; see the file COPYING. If not, write to
23 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 *
26 * libata documentation is available via 'make {ps|pdf}docs',
27 * as Documentation/DocBook/libata.*
28 *
29 * Hardware documentation available under NDA.
Linus Torvalds1da177e2005-04-16 15:20:36 -070030 *
31 */
32
Jeff Garzika09060f2007-05-28 08:17:06 -040033/*
34 Theory of operation
35 -------------------
36
37 The SX4 (PDC20621) chip features a single Host DMA (HDMA) copy
38 engine, DIMM memory, and four ATA engines (one per SATA port).
39 Data is copied to/from DIMM memory by the HDMA engine, before
40 handing off to one (or more) of the ATA engines. The ATA
41 engines operate solely on DIMM memory.
42
43 The SX4 behaves like a PATA chip, with no SATA controls or
44 knowledge whatsoever, leading to the presumption that
45 PATA<->SATA bridges exist on SX4 boards, external to the
46 PDC20621 chip itself.
47
48 The chip is quite capable, supporting an XOR engine and linked
49 hardware commands (permits a string to transactions to be
50 submitted and waited-on as a single unit), and an optional
51 microprocessor.
52
53 The limiting factor is largely software. This Linux driver was
54 written to multiplex the single HDMA engine to copy disk
55 transactions into a fixed DIMM memory space, from where an ATA
56 engine takes over. As a result, each WRITE looks like this:
57
58 submit HDMA packet to hardware
59 hardware copies data from system memory to DIMM
60 hardware raises interrupt
61
62 submit ATA packet to hardware
63 hardware executes ATA WRITE command, w/ data in DIMM
64 hardware raises interrupt
Jeff Garzik2dcb4072007-10-19 06:42:56 -040065
Jeff Garzika09060f2007-05-28 08:17:06 -040066 and each READ looks like this:
67
68 submit ATA packet to hardware
69 hardware executes ATA READ command, w/ data in DIMM
70 hardware raises interrupt
Jeff Garzik2dcb4072007-10-19 06:42:56 -040071
Jeff Garzika09060f2007-05-28 08:17:06 -040072 submit HDMA packet to hardware
73 hardware copies data from DIMM to system memory
74 hardware raises interrupt
75
76 This is a very slow, lock-step way of doing things that can
77 certainly be improved by motivated kernel hackers.
78
79 */
80
Linus Torvalds1da177e2005-04-16 15:20:36 -070081#include <linux/kernel.h>
82#include <linux/module.h>
83#include <linux/pci.h>
84#include <linux/init.h>
85#include <linux/blkdev.h>
86#include <linux/delay.h>
87#include <linux/interrupt.h>
Jeff Garzika9524a72005-10-30 14:39:11 -050088#include <linux/device.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070089#include <scsi/scsi_host.h>
Jeff Garzik193515d2005-11-07 00:59:37 -050090#include <scsi/scsi_cmnd.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070091#include <linux/libata.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070092#include "sata_promise.h"
93
94#define DRV_NAME "sata_sx4"
Jeff Garzik2a3103c2007-08-31 04:54:06 -040095#define DRV_VERSION "0.12"
Linus Torvalds1da177e2005-04-16 15:20:36 -070096
97
98enum {
Tejun Heo0d5ff562007-02-01 15:06:36 +090099 PDC_MMIO_BAR = 3,
100 PDC_DIMM_BAR = 4,
101
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102 PDC_PRD_TBL = 0x44, /* Direct command DMA table addr */
103
104 PDC_PKT_SUBMIT = 0x40, /* Command packet pointer addr */
105 PDC_HDMA_PKT_SUBMIT = 0x100, /* Host DMA packet pointer addr */
106 PDC_INT_SEQMASK = 0x40, /* Mask of asserted SEQ INTs */
107 PDC_HDMA_CTLSTAT = 0x12C, /* Host DMA control / status */
108
Jeff Garzika09060f2007-05-28 08:17:06 -0400109 PDC_CTLSTAT = 0x60, /* IDEn control / status */
110
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111 PDC_20621_SEQCTL = 0x400,
112 PDC_20621_SEQMASK = 0x480,
113 PDC_20621_GENERAL_CTL = 0x484,
114 PDC_20621_PAGE_SIZE = (32 * 1024),
115
116 /* chosen, not constant, values; we design our own DIMM mem map */
117 PDC_20621_DIMM_WINDOW = 0x0C, /* page# for 32K DIMM window */
118 PDC_20621_DIMM_BASE = 0x00200000,
119 PDC_20621_DIMM_DATA = (64 * 1024),
120 PDC_DIMM_DATA_STEP = (256 * 1024),
121 PDC_DIMM_WINDOW_STEP = (8 * 1024),
122 PDC_DIMM_HOST_PRD = (6 * 1024),
123 PDC_DIMM_HOST_PKT = (128 * 0),
124 PDC_DIMM_HPKT_PRD = (128 * 1),
125 PDC_DIMM_ATA_PKT = (128 * 2),
126 PDC_DIMM_APKT_PRD = (128 * 3),
127 PDC_DIMM_HEADER_SZ = PDC_DIMM_APKT_PRD + 128,
128 PDC_PAGE_WINDOW = 0x40,
129 PDC_PAGE_DATA = PDC_PAGE_WINDOW +
130 (PDC_20621_DIMM_DATA / PDC_20621_PAGE_SIZE),
131 PDC_PAGE_SET = PDC_DIMM_DATA_STEP / PDC_20621_PAGE_SIZE,
132
133 PDC_CHIP0_OFS = 0xC0000, /* offset of chip #0 */
134
135 PDC_20621_ERR_MASK = (1<<19) | (1<<20) | (1<<21) | (1<<22) |
136 (1<<23),
137
138 board_20621 = 0, /* FastTrak S150 SX4 */
139
Jeff Garzikb2d46b62007-05-27 22:58:54 -0400140 PDC_MASK_INT = (1 << 10), /* HDMA/ATA mask int */
141 PDC_RESET = (1 << 11), /* HDMA/ATA reset */
Jeff Garzika09060f2007-05-28 08:17:06 -0400142 PDC_DMA_ENABLE = (1 << 7), /* DMA start/stop */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143
144 PDC_MAX_HDMA = 32,
145 PDC_HDMA_Q_MASK = (PDC_MAX_HDMA - 1),
146
Jeff Garzikb2d46b62007-05-27 22:58:54 -0400147 PDC_DIMM0_SPD_DEV_ADDRESS = 0x50,
148 PDC_DIMM1_SPD_DEV_ADDRESS = 0x51,
149 PDC_I2C_CONTROL = 0x48,
150 PDC_I2C_ADDR_DATA = 0x4C,
151 PDC_DIMM0_CONTROL = 0x80,
152 PDC_DIMM1_CONTROL = 0x84,
153 PDC_SDRAM_CONTROL = 0x88,
154 PDC_I2C_WRITE = 0, /* master -> slave */
155 PDC_I2C_READ = (1 << 6), /* master <- slave */
156 PDC_I2C_START = (1 << 7), /* start I2C proto */
157 PDC_I2C_MASK_INT = (1 << 5), /* mask I2C interrupt */
158 PDC_I2C_COMPLETE = (1 << 16), /* I2C normal compl. */
159 PDC_I2C_NO_ACK = (1 << 20), /* slave no-ack addr */
160 PDC_DIMM_SPD_SUBADDRESS_START = 0x00,
161 PDC_DIMM_SPD_SUBADDRESS_END = 0x7F,
162 PDC_DIMM_SPD_ROW_NUM = 3,
163 PDC_DIMM_SPD_COLUMN_NUM = 4,
164 PDC_DIMM_SPD_MODULE_ROW = 5,
165 PDC_DIMM_SPD_TYPE = 11,
166 PDC_DIMM_SPD_FRESH_RATE = 12,
167 PDC_DIMM_SPD_BANK_NUM = 17,
168 PDC_DIMM_SPD_CAS_LATENCY = 18,
169 PDC_DIMM_SPD_ATTRIBUTE = 21,
170 PDC_DIMM_SPD_ROW_PRE_CHARGE = 27,
171 PDC_DIMM_SPD_ROW_ACTIVE_DELAY = 28,
172 PDC_DIMM_SPD_RAS_CAS_DELAY = 29,
173 PDC_DIMM_SPD_ACTIVE_PRECHARGE = 30,
174 PDC_DIMM_SPD_SYSTEM_FREQ = 126,
175 PDC_CTL_STATUS = 0x08,
176 PDC_DIMM_WINDOW_CTLR = 0x0C,
177 PDC_TIME_CONTROL = 0x3C,
178 PDC_TIME_PERIOD = 0x40,
179 PDC_TIME_COUNTER = 0x44,
180 PDC_GENERAL_CTLR = 0x484,
181 PCI_PLL_INIT = 0x8A531824,
182 PCI_X_TCOUNT = 0xEE1E5CFF,
183
184 /* PDC_TIME_CONTROL bits */
185 PDC_TIMER_BUZZER = (1 << 10),
186 PDC_TIMER_MODE_PERIODIC = 0, /* bits 9:8 == 00 */
187 PDC_TIMER_MODE_ONCE = (1 << 8), /* bits 9:8 == 01 */
188 PDC_TIMER_ENABLE = (1 << 7),
189 PDC_TIMER_MASK_INT = (1 << 5),
190 PDC_TIMER_SEQ_MASK = 0x1f, /* SEQ ID for timer */
191 PDC_TIMER_DEFAULT = PDC_TIMER_MODE_ONCE |
192 PDC_TIMER_ENABLE |
193 PDC_TIMER_MASK_INT,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194};
195
196
197struct pdc_port_priv {
198 u8 dimm_buf[(ATA_PRD_SZ * ATA_MAX_PRD) + 512];
199 u8 *pkt;
200 dma_addr_t pkt_dma;
201};
202
203struct pdc_host_priv {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204 unsigned int doing_hdma;
205 unsigned int hdma_prod;
206 unsigned int hdma_cons;
207 struct {
208 struct ata_queued_cmd *qc;
209 unsigned int seq;
210 unsigned long pkt_ofs;
211 } hdma[32];
212};
213
214
Jeff Garzik5796d1c2007-10-26 00:03:37 -0400215static int pdc_sata_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216static void pdc_eng_timeout(struct ata_port *ap);
Jeff Garzik5796d1c2007-10-26 00:03:37 -0400217static void pdc_20621_phy_reset(struct ata_port *ap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218static int pdc_port_start(struct ata_port *ap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219static void pdc20621_qc_prep(struct ata_queued_cmd *qc);
Jeff Garzik057ace52005-10-22 14:27:05 -0400220static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf);
221static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf);
Tejun Heo4447d352007-04-17 23:44:08 +0900222static unsigned int pdc20621_dimm_init(struct ata_host *host);
223static int pdc20621_detect_dimm(struct ata_host *host);
224static unsigned int pdc20621_i2c_read(struct ata_host *host,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 u32 device, u32 subaddr, u32 *pdata);
Tejun Heo4447d352007-04-17 23:44:08 +0900226static int pdc20621_prog_dimm0(struct ata_host *host);
227static unsigned int pdc20621_prog_dimm_global(struct ata_host *host);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228#ifdef ATA_VERBOSE_DEBUG
Tejun Heo4447d352007-04-17 23:44:08 +0900229static void pdc20621_get_from_dimm(struct ata_host *host,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230 void *psource, u32 offset, u32 size);
231#endif
Tejun Heo4447d352007-04-17 23:44:08 +0900232static void pdc20621_put_to_dimm(struct ata_host *host,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233 void *psource, u32 offset, u32 size);
234static void pdc20621_irq_clear(struct ata_port *ap);
Tejun Heo9a3d9eb2006-01-23 13:09:36 +0900235static unsigned int pdc20621_qc_issue_prot(struct ata_queued_cmd *qc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236
237
Jeff Garzik193515d2005-11-07 00:59:37 -0500238static struct scsi_host_template pdc_sata_sht = {
Tejun Heo68d1d072008-03-25 12:22:49 +0900239 ATA_BASE_SHT(DRV_NAME),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240 .sg_tablesize = LIBATA_MAX_PRD,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241 .dma_boundary = ATA_DMA_BOUNDARY,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242};
243
Jeff Garzik057ace52005-10-22 14:27:05 -0400244static const struct ata_port_operations pdc_20621_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 .tf_load = pdc_tf_load_mmio,
246 .tf_read = ata_tf_read,
247 .check_status = ata_check_status,
248 .exec_command = pdc_exec_command_mmio,
249 .dev_select = ata_std_dev_select,
250 .phy_reset = pdc_20621_phy_reset,
251 .qc_prep = pdc20621_qc_prep,
252 .qc_issue = pdc20621_qc_issue_prot,
Tejun Heo0d5ff562007-02-01 15:06:36 +0900253 .data_xfer = ata_data_xfer,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 .eng_timeout = pdc_eng_timeout,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255 .irq_clear = pdc20621_irq_clear,
Akira Iguchi246ce3b2007-01-26 16:27:58 +0900256 .irq_on = ata_irq_on,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 .port_start = pdc_port_start,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258};
259
Arjan van de Ven98ac62d2005-11-28 10:06:23 +0100260static const struct ata_port_info pdc_port_info[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 /* board_20621 */
262 {
Jeff Garzikcca39742006-08-24 03:19:22 -0400263 .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
Jeff Garzik50630192005-12-13 02:29:45 -0500264 ATA_FLAG_SRST | ATA_FLAG_MMIO |
Albert Lee1f3461a2006-05-23 18:12:30 +0800265 ATA_FLAG_NO_ATAPI | ATA_FLAG_PIO_POLLING,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266 .pio_mask = 0x1f, /* pio0-4 */
267 .mwdma_mask = 0x07, /* mwdma0-2 */
Jeff Garzik469248a2007-07-08 01:13:16 -0400268 .udma_mask = ATA_UDMA6,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 .port_ops = &pdc_20621_ops,
270 },
271
272};
273
Jeff Garzik3b7d6972005-11-10 11:04:11 -0500274static const struct pci_device_id pdc_sata_pci_tbl[] = {
Jeff Garzik54bb3a92006-09-27 22:20:11 -0400275 { PCI_VDEVICE(PROMISE, 0x6622), board_20621 },
276
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 { } /* terminate list */
278};
279
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280static struct pci_driver pdc_sata_pci_driver = {
281 .name = DRV_NAME,
282 .id_table = pdc_sata_pci_tbl,
283 .probe = pdc_sata_init_one,
284 .remove = ata_pci_remove_one,
285};
286
287
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288static int pdc_port_start(struct ata_port *ap)
289{
Jeff Garzikcca39742006-08-24 03:19:22 -0400290 struct device *dev = ap->host->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 struct pdc_port_priv *pp;
292 int rc;
293
294 rc = ata_port_start(ap);
295 if (rc)
296 return rc;
297
Tejun Heo24dc5f32007-01-20 16:00:28 +0900298 pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
299 if (!pp)
300 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301
Tejun Heo24dc5f32007-01-20 16:00:28 +0900302 pp->pkt = dmam_alloc_coherent(dev, 128, &pp->pkt_dma, GFP_KERNEL);
303 if (!pp->pkt)
304 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305
306 ap->private_data = pp;
307
308 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309}
310
Jeff Garzik5796d1c2007-10-26 00:03:37 -0400311static void pdc_20621_phy_reset(struct ata_port *ap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312{
313 VPRINTK("ENTER\n");
Jeff Garzik5796d1c2007-10-26 00:03:37 -0400314 ap->cbl = ATA_CBL_SATA;
315 ata_port_probe(ap);
316 ata_bus_reset(ap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317}
318
319static inline void pdc20621_ata_sg(struct ata_taskfile *tf, u8 *buf,
Jeff Garzik5796d1c2007-10-26 00:03:37 -0400320 unsigned int portno,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 unsigned int total_len)
322{
323 u32 addr;
324 unsigned int dw = PDC_DIMM_APKT_PRD >> 2;
Al Viro4ca4e432007-12-30 09:32:22 +0000325 __le32 *buf32 = (__le32 *) buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326
327 /* output ATA packet S/G table */
328 addr = PDC_20621_DIMM_BASE + PDC_20621_DIMM_DATA +
329 (PDC_DIMM_DATA_STEP * portno);
330 VPRINTK("ATA sg addr 0x%x, %d\n", addr, addr);
331 buf32[dw] = cpu_to_le32(addr);
332 buf32[dw + 1] = cpu_to_le32(total_len | ATA_PRD_EOT);
333
334 VPRINTK("ATA PSG @ %x == (0x%x, 0x%x)\n",
335 PDC_20621_DIMM_BASE +
336 (PDC_DIMM_WINDOW_STEP * portno) +
337 PDC_DIMM_APKT_PRD,
338 buf32[dw], buf32[dw + 1]);
339}
340
341static inline void pdc20621_host_sg(struct ata_taskfile *tf, u8 *buf,
Jeff Garzik5796d1c2007-10-26 00:03:37 -0400342 unsigned int portno,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 unsigned int total_len)
344{
345 u32 addr;
346 unsigned int dw = PDC_DIMM_HPKT_PRD >> 2;
Al Viro4ca4e432007-12-30 09:32:22 +0000347 __le32 *buf32 = (__le32 *) buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348
349 /* output Host DMA packet S/G table */
350 addr = PDC_20621_DIMM_BASE + PDC_20621_DIMM_DATA +
351 (PDC_DIMM_DATA_STEP * portno);
352
353 buf32[dw] = cpu_to_le32(addr);
354 buf32[dw + 1] = cpu_to_le32(total_len | ATA_PRD_EOT);
355
356 VPRINTK("HOST PSG @ %x == (0x%x, 0x%x)\n",
357 PDC_20621_DIMM_BASE +
358 (PDC_DIMM_WINDOW_STEP * portno) +
359 PDC_DIMM_HPKT_PRD,
360 buf32[dw], buf32[dw + 1]);
361}
362
363static inline unsigned int pdc20621_ata_pkt(struct ata_taskfile *tf,
364 unsigned int devno, u8 *buf,
365 unsigned int portno)
366{
367 unsigned int i, dw;
Al Viro4ca4e432007-12-30 09:32:22 +0000368 __le32 *buf32 = (__le32 *) buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 u8 dev_reg;
370
371 unsigned int dimm_sg = PDC_20621_DIMM_BASE +
372 (PDC_DIMM_WINDOW_STEP * portno) +
373 PDC_DIMM_APKT_PRD;
374 VPRINTK("ENTER, dimm_sg == 0x%x, %d\n", dimm_sg, dimm_sg);
375
376 i = PDC_DIMM_ATA_PKT;
377
378 /*
379 * Set up ATA packet
380 */
381 if ((tf->protocol == ATA_PROT_DMA) && (!(tf->flags & ATA_TFLAG_WRITE)))
382 buf[i++] = PDC_PKT_READ;
383 else if (tf->protocol == ATA_PROT_NODATA)
384 buf[i++] = PDC_PKT_NODATA;
385 else
386 buf[i++] = 0;
387 buf[i++] = 0; /* reserved */
388 buf[i++] = portno + 1; /* seq. id */
389 buf[i++] = 0xff; /* delay seq. id */
390
391 /* dimm dma S/G, and next-pkt */
392 dw = i >> 2;
393 if (tf->protocol == ATA_PROT_NODATA)
394 buf32[dw] = 0;
395 else
396 buf32[dw] = cpu_to_le32(dimm_sg);
397 buf32[dw + 1] = 0;
398 i += 8;
399
400 if (devno == 0)
401 dev_reg = ATA_DEVICE_OBS;
402 else
403 dev_reg = ATA_DEVICE_OBS | ATA_DEV1;
404
405 /* select device */
406 buf[i++] = (1 << 5) | PDC_PKT_CLEAR_BSY | ATA_REG_DEVICE;
407 buf[i++] = dev_reg;
408
409 /* device control register */
410 buf[i++] = (1 << 5) | PDC_REG_DEVCTL;
411 buf[i++] = tf->ctl;
412
413 return i;
414}
415
416static inline void pdc20621_host_pkt(struct ata_taskfile *tf, u8 *buf,
417 unsigned int portno)
418{
419 unsigned int dw;
Al Viro4ca4e432007-12-30 09:32:22 +0000420 u32 tmp;
421 __le32 *buf32 = (__le32 *) buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422
423 unsigned int host_sg = PDC_20621_DIMM_BASE +
424 (PDC_DIMM_WINDOW_STEP * portno) +
425 PDC_DIMM_HOST_PRD;
426 unsigned int dimm_sg = PDC_20621_DIMM_BASE +
427 (PDC_DIMM_WINDOW_STEP * portno) +
428 PDC_DIMM_HPKT_PRD;
429 VPRINTK("ENTER, dimm_sg == 0x%x, %d\n", dimm_sg, dimm_sg);
430 VPRINTK("host_sg == 0x%x, %d\n", host_sg, host_sg);
431
432 dw = PDC_DIMM_HOST_PKT >> 2;
433
434 /*
435 * Set up Host DMA packet
436 */
437 if ((tf->protocol == ATA_PROT_DMA) && (!(tf->flags & ATA_TFLAG_WRITE)))
438 tmp = PDC_PKT_READ;
439 else
440 tmp = 0;
441 tmp |= ((portno + 1 + 4) << 16); /* seq. id */
442 tmp |= (0xff << 24); /* delay seq. id */
443 buf32[dw + 0] = cpu_to_le32(tmp);
444 buf32[dw + 1] = cpu_to_le32(host_sg);
445 buf32[dw + 2] = cpu_to_le32(dimm_sg);
446 buf32[dw + 3] = 0;
447
448 VPRINTK("HOST PKT @ %x == (0x%x 0x%x 0x%x 0x%x)\n",
449 PDC_20621_DIMM_BASE + (PDC_DIMM_WINDOW_STEP * portno) +
450 PDC_DIMM_HOST_PKT,
451 buf32[dw + 0],
452 buf32[dw + 1],
453 buf32[dw + 2],
454 buf32[dw + 3]);
455}
456
457static void pdc20621_dma_prep(struct ata_queued_cmd *qc)
458{
Jeff Garzikcedc9a42005-10-05 07:13:30 -0400459 struct scatterlist *sg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 struct ata_port *ap = qc->ap;
461 struct pdc_port_priv *pp = ap->private_data;
Tejun Heo0d5ff562007-02-01 15:06:36 +0900462 void __iomem *mmio = ap->host->iomap[PDC_MMIO_BAR];
463 void __iomem *dimm_mmio = ap->host->iomap[PDC_DIMM_BAR];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 unsigned int portno = ap->port_no;
Tejun Heoff2aeb12007-12-05 16:43:11 +0900465 unsigned int i, si, idx, total_len = 0, sgt_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466 u32 *buf = (u32 *) &pp->dimm_buf[PDC_DIMM_HEADER_SZ];
467
Tejun Heobeec7db2006-02-11 19:11:13 +0900468 WARN_ON(!(qc->flags & ATA_QCFLAG_DMAMAP));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469
Tejun Heo44877b42007-02-21 01:06:51 +0900470 VPRINTK("ata%u: ENTER\n", ap->print_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471
472 /* hard-code chip #0 */
473 mmio += PDC_CHIP0_OFS;
474
475 /*
476 * Build S/G table
477 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 idx = 0;
Tejun Heoff2aeb12007-12-05 16:43:11 +0900479 for_each_sg(qc->sg, sg, qc->n_elem, si) {
Jeff Garzikcedc9a42005-10-05 07:13:30 -0400480 buf[idx++] = cpu_to_le32(sg_dma_address(sg));
481 buf[idx++] = cpu_to_le32(sg_dma_len(sg));
482 total_len += sg_dma_len(sg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 }
484 buf[idx - 1] |= cpu_to_le32(ATA_PRD_EOT);
485 sgt_len = idx * 4;
486
487 /*
488 * Build ATA, host DMA packets
489 */
490 pdc20621_host_sg(&qc->tf, &pp->dimm_buf[0], portno, total_len);
491 pdc20621_host_pkt(&qc->tf, &pp->dimm_buf[0], portno);
492
493 pdc20621_ata_sg(&qc->tf, &pp->dimm_buf[0], portno, total_len);
494 i = pdc20621_ata_pkt(&qc->tf, qc->dev->devno, &pp->dimm_buf[0], portno);
495
496 if (qc->tf.flags & ATA_TFLAG_LBA48)
497 i = pdc_prep_lba48(&qc->tf, &pp->dimm_buf[0], i);
498 else
499 i = pdc_prep_lba28(&qc->tf, &pp->dimm_buf[0], i);
500
501 pdc_pkt_footer(&qc->tf, &pp->dimm_buf[0], i);
502
503 /* copy three S/G tables and two packets to DIMM MMIO window */
504 memcpy_toio(dimm_mmio + (portno * PDC_DIMM_WINDOW_STEP),
505 &pp->dimm_buf, PDC_DIMM_HEADER_SZ);
506 memcpy_toio(dimm_mmio + (portno * PDC_DIMM_WINDOW_STEP) +
507 PDC_DIMM_HOST_PRD,
508 &pp->dimm_buf[PDC_DIMM_HEADER_SZ], sgt_len);
509
510 /* force host FIFO dump */
511 writel(0x00000001, mmio + PDC_20621_GENERAL_CTL);
512
513 readl(dimm_mmio); /* MMIO PCI posting flush */
514
515 VPRINTK("ata pkt buf ofs %u, prd size %u, mmio copied\n", i, sgt_len);
516}
517
518static void pdc20621_nodata_prep(struct ata_queued_cmd *qc)
519{
520 struct ata_port *ap = qc->ap;
521 struct pdc_port_priv *pp = ap->private_data;
Tejun Heo0d5ff562007-02-01 15:06:36 +0900522 void __iomem *mmio = ap->host->iomap[PDC_MMIO_BAR];
523 void __iomem *dimm_mmio = ap->host->iomap[PDC_DIMM_BAR];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 unsigned int portno = ap->port_no;
525 unsigned int i;
526
Tejun Heo44877b42007-02-21 01:06:51 +0900527 VPRINTK("ata%u: ENTER\n", ap->print_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528
529 /* hard-code chip #0 */
530 mmio += PDC_CHIP0_OFS;
531
532 i = pdc20621_ata_pkt(&qc->tf, qc->dev->devno, &pp->dimm_buf[0], portno);
533
534 if (qc->tf.flags & ATA_TFLAG_LBA48)
535 i = pdc_prep_lba48(&qc->tf, &pp->dimm_buf[0], i);
536 else
537 i = pdc_prep_lba28(&qc->tf, &pp->dimm_buf[0], i);
538
539 pdc_pkt_footer(&qc->tf, &pp->dimm_buf[0], i);
540
541 /* copy three S/G tables and two packets to DIMM MMIO window */
542 memcpy_toio(dimm_mmio + (portno * PDC_DIMM_WINDOW_STEP),
543 &pp->dimm_buf, PDC_DIMM_HEADER_SZ);
544
545 /* force host FIFO dump */
546 writel(0x00000001, mmio + PDC_20621_GENERAL_CTL);
547
548 readl(dimm_mmio); /* MMIO PCI posting flush */
549
550 VPRINTK("ata pkt buf ofs %u, mmio copied\n", i);
551}
552
553static void pdc20621_qc_prep(struct ata_queued_cmd *qc)
554{
555 switch (qc->tf.protocol) {
556 case ATA_PROT_DMA:
557 pdc20621_dma_prep(qc);
558 break;
559 case ATA_PROT_NODATA:
560 pdc20621_nodata_prep(qc);
561 break;
562 default:
563 break;
564 }
565}
566
567static void __pdc20621_push_hdma(struct ata_queued_cmd *qc,
568 unsigned int seq,
569 u32 pkt_ofs)
570{
571 struct ata_port *ap = qc->ap;
Jeff Garzikcca39742006-08-24 03:19:22 -0400572 struct ata_host *host = ap->host;
Tejun Heo0d5ff562007-02-01 15:06:36 +0900573 void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574
575 /* hard-code chip #0 */
576 mmio += PDC_CHIP0_OFS;
577
578 writel(0x00000001, mmio + PDC_20621_SEQCTL + (seq * 4));
579 readl(mmio + PDC_20621_SEQCTL + (seq * 4)); /* flush */
580
581 writel(pkt_ofs, mmio + PDC_HDMA_PKT_SUBMIT);
582 readl(mmio + PDC_HDMA_PKT_SUBMIT); /* flush */
583}
584
585static void pdc20621_push_hdma(struct ata_queued_cmd *qc,
586 unsigned int seq,
587 u32 pkt_ofs)
588{
589 struct ata_port *ap = qc->ap;
Jeff Garzikcca39742006-08-24 03:19:22 -0400590 struct pdc_host_priv *pp = ap->host->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591 unsigned int idx = pp->hdma_prod & PDC_HDMA_Q_MASK;
592
593 if (!pp->doing_hdma) {
594 __pdc20621_push_hdma(qc, seq, pkt_ofs);
595 pp->doing_hdma = 1;
596 return;
597 }
598
599 pp->hdma[idx].qc = qc;
600 pp->hdma[idx].seq = seq;
601 pp->hdma[idx].pkt_ofs = pkt_ofs;
602 pp->hdma_prod++;
603}
604
605static void pdc20621_pop_hdma(struct ata_queued_cmd *qc)
606{
607 struct ata_port *ap = qc->ap;
Jeff Garzikcca39742006-08-24 03:19:22 -0400608 struct pdc_host_priv *pp = ap->host->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 unsigned int idx = pp->hdma_cons & PDC_HDMA_Q_MASK;
610
611 /* if nothing on queue, we're done */
612 if (pp->hdma_prod == pp->hdma_cons) {
613 pp->doing_hdma = 0;
614 return;
615 }
616
617 __pdc20621_push_hdma(pp->hdma[idx].qc, pp->hdma[idx].seq,
618 pp->hdma[idx].pkt_ofs);
619 pp->hdma_cons++;
620}
621
622#ifdef ATA_VERBOSE_DEBUG
623static void pdc20621_dump_hdma(struct ata_queued_cmd *qc)
624{
625 struct ata_port *ap = qc->ap;
626 unsigned int port_no = ap->port_no;
Tejun Heo0d5ff562007-02-01 15:06:36 +0900627 void __iomem *dimm_mmio = ap->host->iomap[PDC_DIMM_BAR];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628
629 dimm_mmio += (port_no * PDC_DIMM_WINDOW_STEP);
630 dimm_mmio += PDC_DIMM_HOST_PKT;
631
632 printk(KERN_ERR "HDMA[0] == 0x%08X\n", readl(dimm_mmio));
633 printk(KERN_ERR "HDMA[1] == 0x%08X\n", readl(dimm_mmio + 4));
634 printk(KERN_ERR "HDMA[2] == 0x%08X\n", readl(dimm_mmio + 8));
635 printk(KERN_ERR "HDMA[3] == 0x%08X\n", readl(dimm_mmio + 12));
636}
637#else
638static inline void pdc20621_dump_hdma(struct ata_queued_cmd *qc) { }
639#endif /* ATA_VERBOSE_DEBUG */
640
641static void pdc20621_packet_start(struct ata_queued_cmd *qc)
642{
643 struct ata_port *ap = qc->ap;
Jeff Garzikcca39742006-08-24 03:19:22 -0400644 struct ata_host *host = ap->host;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 unsigned int port_no = ap->port_no;
Tejun Heo0d5ff562007-02-01 15:06:36 +0900646 void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
648 u8 seq = (u8) (port_no + 1);
649 unsigned int port_ofs;
650
651 /* hard-code chip #0 */
652 mmio += PDC_CHIP0_OFS;
653
Tejun Heo44877b42007-02-21 01:06:51 +0900654 VPRINTK("ata%u: ENTER\n", ap->print_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655
656 wmb(); /* flush PRD, pkt writes */
657
658 port_ofs = PDC_20621_DIMM_BASE + (PDC_DIMM_WINDOW_STEP * port_no);
659
660 /* if writing, we (1) DMA to DIMM, then (2) do ATA command */
661 if (rw && qc->tf.protocol == ATA_PROT_DMA) {
662 seq += 4;
663
664 pdc20621_dump_hdma(qc);
665 pdc20621_push_hdma(qc, seq, port_ofs + PDC_DIMM_HOST_PKT);
666 VPRINTK("queued ofs 0x%x (%u), seq %u\n",
667 port_ofs + PDC_DIMM_HOST_PKT,
668 port_ofs + PDC_DIMM_HOST_PKT,
669 seq);
670 } else {
671 writel(0x00000001, mmio + PDC_20621_SEQCTL + (seq * 4));
672 readl(mmio + PDC_20621_SEQCTL + (seq * 4)); /* flush */
673
674 writel(port_ofs + PDC_DIMM_ATA_PKT,
Tejun Heo0d5ff562007-02-01 15:06:36 +0900675 ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
676 readl(ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 VPRINTK("submitted ofs 0x%x (%u), seq %u\n",
678 port_ofs + PDC_DIMM_ATA_PKT,
679 port_ofs + PDC_DIMM_ATA_PKT,
680 seq);
681 }
682}
683
Tejun Heo9a3d9eb2006-01-23 13:09:36 +0900684static unsigned int pdc20621_qc_issue_prot(struct ata_queued_cmd *qc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685{
686 switch (qc->tf.protocol) {
687 case ATA_PROT_DMA:
688 case ATA_PROT_NODATA:
689 pdc20621_packet_start(qc);
690 return 0;
691
Tejun Heo0dc36882007-12-18 16:34:43 -0500692 case ATAPI_PROT_DMA:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 BUG();
694 break;
695
696 default:
697 break;
698 }
699
700 return ata_qc_issue_prot(qc);
701}
702
Jeff Garzik5796d1c2007-10-26 00:03:37 -0400703static inline unsigned int pdc20621_host_intr(struct ata_port *ap,
704 struct ata_queued_cmd *qc,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 unsigned int doing_hdma,
Jeff Garzikea6ba102005-08-30 05:18:18 -0400706 void __iomem *mmio)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707{
708 unsigned int port_no = ap->port_no;
709 unsigned int port_ofs =
710 PDC_20621_DIMM_BASE + (PDC_DIMM_WINDOW_STEP * port_no);
711 u8 status;
712 unsigned int handled = 0;
713
714 VPRINTK("ENTER\n");
715
716 if ((qc->tf.protocol == ATA_PROT_DMA) && /* read */
717 (!(qc->tf.flags & ATA_TFLAG_WRITE))) {
718
719 /* step two - DMA from DIMM to host */
720 if (doing_hdma) {
Tejun Heo44877b42007-02-21 01:06:51 +0900721 VPRINTK("ata%u: read hdma, 0x%x 0x%x\n", ap->print_id,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT));
723 /* get drive status; clear intr; complete txn */
Albert Leea22e2eb2005-12-05 15:38:02 +0800724 qc->err_mask |= ac_err_mask(ata_wait_idle(ap));
725 ata_qc_complete(qc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 pdc20621_pop_hdma(qc);
727 }
728
729 /* step one - exec ATA command */
730 else {
731 u8 seq = (u8) (port_no + 1 + 4);
Tejun Heo44877b42007-02-21 01:06:51 +0900732 VPRINTK("ata%u: read ata, 0x%x 0x%x\n", ap->print_id,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT));
734
735 /* submit hdma pkt */
736 pdc20621_dump_hdma(qc);
737 pdc20621_push_hdma(qc, seq,
738 port_ofs + PDC_DIMM_HOST_PKT);
739 }
740 handled = 1;
741
742 } else if (qc->tf.protocol == ATA_PROT_DMA) { /* write */
743
744 /* step one - DMA from host to DIMM */
745 if (doing_hdma) {
746 u8 seq = (u8) (port_no + 1);
Tejun Heo44877b42007-02-21 01:06:51 +0900747 VPRINTK("ata%u: write hdma, 0x%x 0x%x\n", ap->print_id,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT));
749
750 /* submit ata pkt */
751 writel(0x00000001, mmio + PDC_20621_SEQCTL + (seq * 4));
752 readl(mmio + PDC_20621_SEQCTL + (seq * 4));
753 writel(port_ofs + PDC_DIMM_ATA_PKT,
Tejun Heo0d5ff562007-02-01 15:06:36 +0900754 ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
755 readl(ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 }
757
758 /* step two - execute ATA command */
759 else {
Tejun Heo44877b42007-02-21 01:06:51 +0900760 VPRINTK("ata%u: write ata, 0x%x 0x%x\n", ap->print_id,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT));
762 /* get drive status; clear intr; complete txn */
Albert Leea22e2eb2005-12-05 15:38:02 +0800763 qc->err_mask |= ac_err_mask(ata_wait_idle(ap));
764 ata_qc_complete(qc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 pdc20621_pop_hdma(qc);
766 }
767 handled = 1;
768
769 /* command completion, but no data xfer */
770 } else if (qc->tf.protocol == ATA_PROT_NODATA) {
771
772 status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
773 DPRINTK("BUS_NODATA (drv_stat 0x%X)\n", status);
Albert Leea22e2eb2005-12-05 15:38:02 +0800774 qc->err_mask |= ac_err_mask(status);
775 ata_qc_complete(qc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 handled = 1;
777
778 } else {
779 ap->stats.idle_irq++;
780 }
781
782 return handled;
783}
784
785static void pdc20621_irq_clear(struct ata_port *ap)
786{
Jeff Garzikcca39742006-08-24 03:19:22 -0400787 struct ata_host *host = ap->host;
Tejun Heo0d5ff562007-02-01 15:06:36 +0900788 void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789
790 mmio += PDC_CHIP0_OFS;
791
792 readl(mmio + PDC_20621_SEQMASK);
793}
794
Jeff Garzik5796d1c2007-10-26 00:03:37 -0400795static irqreturn_t pdc20621_interrupt(int irq, void *dev_instance)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796{
Jeff Garzikcca39742006-08-24 03:19:22 -0400797 struct ata_host *host = dev_instance;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 struct ata_port *ap;
799 u32 mask = 0;
800 unsigned int i, tmp, port_no;
801 unsigned int handled = 0;
Jeff Garzikea6ba102005-08-30 05:18:18 -0400802 void __iomem *mmio_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803
804 VPRINTK("ENTER\n");
805
Tejun Heo0d5ff562007-02-01 15:06:36 +0900806 if (!host || !host->iomap[PDC_MMIO_BAR]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 VPRINTK("QUICK EXIT\n");
808 return IRQ_NONE;
809 }
810
Tejun Heo0d5ff562007-02-01 15:06:36 +0900811 mmio_base = host->iomap[PDC_MMIO_BAR];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812
813 /* reading should also clear interrupts */
814 mmio_base += PDC_CHIP0_OFS;
815 mask = readl(mmio_base + PDC_20621_SEQMASK);
816 VPRINTK("mask == 0x%x\n", mask);
817
818 if (mask == 0xffffffff) {
819 VPRINTK("QUICK EXIT 2\n");
820 return IRQ_NONE;
821 }
822 mask &= 0xffff; /* only 16 tags possible */
823 if (!mask) {
824 VPRINTK("QUICK EXIT 3\n");
825 return IRQ_NONE;
826 }
827
Jeff Garzik5796d1c2007-10-26 00:03:37 -0400828 spin_lock(&host->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829
Jeff Garzik5796d1c2007-10-26 00:03:37 -0400830 for (i = 1; i < 9; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 port_no = i - 1;
832 if (port_no > 3)
833 port_no -= 4;
Jeff Garzikcca39742006-08-24 03:19:22 -0400834 if (port_no >= host->n_ports)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 ap = NULL;
836 else
Jeff Garzikcca39742006-08-24 03:19:22 -0400837 ap = host->ports[port_no];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 tmp = mask & (1 << i);
839 VPRINTK("seq %u, port_no %u, ap %p, tmp %x\n", i, port_no, ap, tmp);
Tejun Heoc1389502005-08-22 14:59:24 +0900840 if (tmp && ap &&
Jeff Garzik029f5462006-04-02 10:30:40 -0400841 !(ap->flags & ATA_FLAG_DISABLED)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 struct ata_queued_cmd *qc;
843
Tejun Heo9af5c9c2007-08-06 18:36:22 +0900844 qc = ata_qc_from_tag(ap, ap->link.active_tag);
Albert Leee50362e2005-09-27 17:39:50 +0800845 if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 handled += pdc20621_host_intr(ap, qc, (i > 4),
847 mmio_base);
848 }
849 }
850
Jeff Garzik5796d1c2007-10-26 00:03:37 -0400851 spin_unlock(&host->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852
853 VPRINTK("mask == 0x%x\n", mask);
854
855 VPRINTK("EXIT\n");
856
857 return IRQ_RETVAL(handled);
858}
859
860static void pdc_eng_timeout(struct ata_port *ap)
861{
862 u8 drv_stat;
Jeff Garzikcca39742006-08-24 03:19:22 -0400863 struct ata_host *host = ap->host;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 struct ata_queued_cmd *qc;
Jeff Garzikb8f61532005-08-25 22:01:20 -0400865 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866
867 DPRINTK("ENTER\n");
868
Jeff Garzikcca39742006-08-24 03:19:22 -0400869 spin_lock_irqsave(&host->lock, flags);
Jeff Garzikb8f61532005-08-25 22:01:20 -0400870
Tejun Heo9af5c9c2007-08-06 18:36:22 +0900871 qc = ata_qc_from_tag(ap, ap->link.active_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 switch (qc->tf.protocol) {
874 case ATA_PROT_DMA:
875 case ATA_PROT_NODATA:
Tejun Heof15a1da2006-05-15 20:57:56 +0900876 ata_port_printk(ap, KERN_ERR, "command timeout\n");
Albert Leea22e2eb2005-12-05 15:38:02 +0800877 qc->err_mask |= __ac_err_mask(ata_wait_idle(ap));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 break;
879
880 default:
881 drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
882
Tejun Heof15a1da2006-05-15 20:57:56 +0900883 ata_port_printk(ap, KERN_ERR,
884 "unknown timeout, cmd 0x%x stat 0x%x\n",
885 qc->tf.command, drv_stat);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886
Albert Leea22e2eb2005-12-05 15:38:02 +0800887 qc->err_mask |= ac_err_mask(drv_stat);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888 break;
889 }
890
Jeff Garzikcca39742006-08-24 03:19:22 -0400891 spin_unlock_irqrestore(&host->lock, flags);
Tejun Heof6379022006-02-10 15:10:48 +0900892 ata_eh_qc_complete(qc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 DPRINTK("EXIT\n");
894}
895
Jeff Garzik057ace52005-10-22 14:27:05 -0400896static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897{
Jeff Garzik5796d1c2007-10-26 00:03:37 -0400898 WARN_ON(tf->protocol == ATA_PROT_DMA ||
899 tf->protocol == ATA_PROT_NODATA);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 ata_tf_load(ap, tf);
901}
902
903
Jeff Garzik057ace52005-10-22 14:27:05 -0400904static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905{
Jeff Garzik5796d1c2007-10-26 00:03:37 -0400906 WARN_ON(tf->protocol == ATA_PROT_DMA ||
907 tf->protocol == ATA_PROT_NODATA);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 ata_exec_command(ap, tf);
909}
910
911
Tejun Heo0d5ff562007-02-01 15:06:36 +0900912static void pdc_sata_setup_port(struct ata_ioports *port, void __iomem *base)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913{
914 port->cmd_addr = base;
915 port->data_addr = base;
916 port->feature_addr =
917 port->error_addr = base + 0x4;
918 port->nsect_addr = base + 0x8;
919 port->lbal_addr = base + 0xc;
920 port->lbam_addr = base + 0x10;
921 port->lbah_addr = base + 0x14;
922 port->device_addr = base + 0x18;
923 port->command_addr =
924 port->status_addr = base + 0x1c;
925 port->altstatus_addr =
926 port->ctl_addr = base + 0x38;
927}
928
929
930#ifdef ATA_VERBOSE_DEBUG
Tejun Heo4447d352007-04-17 23:44:08 +0900931static void pdc20621_get_from_dimm(struct ata_host *host, void *psource,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 u32 offset, u32 size)
933{
934 u32 window_size;
935 u16 idx;
936 u8 page_mask;
937 long dist;
Tejun Heo4447d352007-04-17 23:44:08 +0900938 void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
939 void __iomem *dimm_mmio = host->iomap[PDC_DIMM_BAR];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940
941 /* hard-code chip #0 */
942 mmio += PDC_CHIP0_OFS;
943
Jeff Garzik8a60a072005-07-31 13:13:24 -0400944 page_mask = 0x00;
Jeff Garzik5796d1c2007-10-26 00:03:37 -0400945 window_size = 0x2000 * 4; /* 32K byte uchar size */
Jeff Garzik8a60a072005-07-31 13:13:24 -0400946 idx = (u16) (offset / window_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947
948 writel(0x01, mmio + PDC_GENERAL_CTLR);
949 readl(mmio + PDC_GENERAL_CTLR);
950 writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
951 readl(mmio + PDC_DIMM_WINDOW_CTLR);
952
953 offset -= (idx * window_size);
954 idx++;
Jeff Garzik8a60a072005-07-31 13:13:24 -0400955 dist = ((long) (window_size - (offset + size))) >= 0 ? size :
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956 (long) (window_size - offset);
Jeff Garzik8a60a072005-07-31 13:13:24 -0400957 memcpy_fromio((char *) psource, (char *) (dimm_mmio + offset / 4),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 dist);
959
Jeff Garzik8a60a072005-07-31 13:13:24 -0400960 psource += dist;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 size -= dist;
962 for (; (long) size >= (long) window_size ;) {
963 writel(0x01, mmio + PDC_GENERAL_CTLR);
964 readl(mmio + PDC_GENERAL_CTLR);
965 writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
966 readl(mmio + PDC_DIMM_WINDOW_CTLR);
Jeff Garzik8a60a072005-07-31 13:13:24 -0400967 memcpy_fromio((char *) psource, (char *) (dimm_mmio),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 window_size / 4);
969 psource += window_size;
970 size -= window_size;
Jeff Garzik5796d1c2007-10-26 00:03:37 -0400971 idx++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972 }
973
974 if (size) {
975 writel(0x01, mmio + PDC_GENERAL_CTLR);
976 readl(mmio + PDC_GENERAL_CTLR);
977 writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
978 readl(mmio + PDC_DIMM_WINDOW_CTLR);
Jeff Garzik8a60a072005-07-31 13:13:24 -0400979 memcpy_fromio((char *) psource, (char *) (dimm_mmio),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980 size / 4);
981 }
982}
983#endif
984
985
Tejun Heo4447d352007-04-17 23:44:08 +0900986static void pdc20621_put_to_dimm(struct ata_host *host, void *psource,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 u32 offset, u32 size)
988{
989 u32 window_size;
990 u16 idx;
991 u8 page_mask;
992 long dist;
Tejun Heo4447d352007-04-17 23:44:08 +0900993 void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
994 void __iomem *dimm_mmio = host->iomap[PDC_DIMM_BAR];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995
Jeff Garzik8a60a072005-07-31 13:13:24 -0400996 /* hard-code chip #0 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 mmio += PDC_CHIP0_OFS;
998
Jeff Garzik8a60a072005-07-31 13:13:24 -0400999 page_mask = 0x00;
Jeff Garzik5796d1c2007-10-26 00:03:37 -04001000 window_size = 0x2000 * 4; /* 32K byte uchar size */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 idx = (u16) (offset / window_size);
1002
1003 writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
1004 readl(mmio + PDC_DIMM_WINDOW_CTLR);
Jeff Garzik8a60a072005-07-31 13:13:24 -04001005 offset -= (idx * window_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006 idx++;
1007 dist = ((long)(s32)(window_size - (offset + size))) >= 0 ? size :
1008 (long) (window_size - offset);
Al Viroa9afd7c2005-10-21 06:46:02 +01001009 memcpy_toio(dimm_mmio + offset / 4, psource, dist);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 writel(0x01, mmio + PDC_GENERAL_CTLR);
1011 readl(mmio + PDC_GENERAL_CTLR);
1012
Jeff Garzik8a60a072005-07-31 13:13:24 -04001013 psource += dist;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 size -= dist;
1015 for (; (long) size >= (long) window_size ;) {
1016 writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
1017 readl(mmio + PDC_DIMM_WINDOW_CTLR);
Al Viroa9afd7c2005-10-21 06:46:02 +01001018 memcpy_toio(dimm_mmio, psource, window_size / 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 writel(0x01, mmio + PDC_GENERAL_CTLR);
1020 readl(mmio + PDC_GENERAL_CTLR);
1021 psource += window_size;
1022 size -= window_size;
Jeff Garzik5796d1c2007-10-26 00:03:37 -04001023 idx++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024 }
Jeff Garzik8a60a072005-07-31 13:13:24 -04001025
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 if (size) {
1027 writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
1028 readl(mmio + PDC_DIMM_WINDOW_CTLR);
Al Viroa9afd7c2005-10-21 06:46:02 +01001029 memcpy_toio(dimm_mmio, psource, size / 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030 writel(0x01, mmio + PDC_GENERAL_CTLR);
1031 readl(mmio + PDC_GENERAL_CTLR);
1032 }
1033}
1034
1035
Tejun Heo4447d352007-04-17 23:44:08 +09001036static unsigned int pdc20621_i2c_read(struct ata_host *host, u32 device,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037 u32 subaddr, u32 *pdata)
1038{
Tejun Heo4447d352007-04-17 23:44:08 +09001039 void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040 u32 i2creg = 0;
Jeff Garzik8a60a072005-07-31 13:13:24 -04001041 u32 status;
Jeff Garzik5796d1c2007-10-26 00:03:37 -04001042 u32 count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043
1044 /* hard-code chip #0 */
1045 mmio += PDC_CHIP0_OFS;
1046
1047 i2creg |= device << 24;
1048 i2creg |= subaddr << 16;
1049
1050 /* Set the device and subaddress */
Jeff Garzikb2d46b62007-05-27 22:58:54 -04001051 writel(i2creg, mmio + PDC_I2C_ADDR_DATA);
1052 readl(mmio + PDC_I2C_ADDR_DATA);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053
1054 /* Write Control to perform read operation, mask int */
Jeff Garzik8a60a072005-07-31 13:13:24 -04001055 writel(PDC_I2C_READ | PDC_I2C_START | PDC_I2C_MASK_INT,
Jeff Garzikb2d46b62007-05-27 22:58:54 -04001056 mmio + PDC_I2C_CONTROL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057
1058 for (count = 0; count <= 1000; count ++) {
Jeff Garzikb2d46b62007-05-27 22:58:54 -04001059 status = readl(mmio + PDC_I2C_CONTROL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 if (status & PDC_I2C_COMPLETE) {
Jeff Garzikb2d46b62007-05-27 22:58:54 -04001061 status = readl(mmio + PDC_I2C_ADDR_DATA);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 break;
1063 } else if (count == 1000)
1064 return 0;
1065 }
1066
1067 *pdata = (status >> 8) & 0x000000ff;
Jeff Garzik8a60a072005-07-31 13:13:24 -04001068 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069}
1070
1071
Tejun Heo4447d352007-04-17 23:44:08 +09001072static int pdc20621_detect_dimm(struct ata_host *host)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073{
Jeff Garzik5796d1c2007-10-26 00:03:37 -04001074 u32 data = 0;
Tejun Heo4447d352007-04-17 23:44:08 +09001075 if (pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076 PDC_DIMM_SPD_SYSTEM_FREQ, &data)) {
Jeff Garzik5796d1c2007-10-26 00:03:37 -04001077 if (data == 100)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 return 100;
Jeff Garzik5796d1c2007-10-26 00:03:37 -04001079 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 return 0;
Jeff Garzik8a60a072005-07-31 13:13:24 -04001081
Tejun Heo4447d352007-04-17 23:44:08 +09001082 if (pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS, 9, &data)) {
Jeff Garzikb4479162007-10-25 20:47:30 -04001083 if (data <= 0x75)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 return 133;
Jeff Garzik5796d1c2007-10-26 00:03:37 -04001085 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086 return 0;
Jeff Garzik8a60a072005-07-31 13:13:24 -04001087
Jeff Garzik5796d1c2007-10-26 00:03:37 -04001088 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089}
1090
1091
Tejun Heo4447d352007-04-17 23:44:08 +09001092static int pdc20621_prog_dimm0(struct ata_host *host)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093{
1094 u32 spd0[50];
1095 u32 data = 0;
Jeff Garzik5796d1c2007-10-26 00:03:37 -04001096 int size, i;
1097 u8 bdimmsize;
Tejun Heo4447d352007-04-17 23:44:08 +09001098 void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 static const struct {
1100 unsigned int reg;
1101 unsigned int ofs;
1102 } pdc_i2c_read_data [] = {
Jeff Garzik8a60a072005-07-31 13:13:24 -04001103 { PDC_DIMM_SPD_TYPE, 11 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104 { PDC_DIMM_SPD_FRESH_RATE, 12 },
Jeff Garzik8a60a072005-07-31 13:13:24 -04001105 { PDC_DIMM_SPD_COLUMN_NUM, 4 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106 { PDC_DIMM_SPD_ATTRIBUTE, 21 },
1107 { PDC_DIMM_SPD_ROW_NUM, 3 },
1108 { PDC_DIMM_SPD_BANK_NUM, 17 },
1109 { PDC_DIMM_SPD_MODULE_ROW, 5 },
1110 { PDC_DIMM_SPD_ROW_PRE_CHARGE, 27 },
1111 { PDC_DIMM_SPD_ROW_ACTIVE_DELAY, 28 },
1112 { PDC_DIMM_SPD_RAS_CAS_DELAY, 29 },
1113 { PDC_DIMM_SPD_ACTIVE_PRECHARGE, 30 },
Jeff Garzik8a60a072005-07-31 13:13:24 -04001114 { PDC_DIMM_SPD_CAS_LATENCY, 18 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 };
1116
1117 /* hard-code chip #0 */
1118 mmio += PDC_CHIP0_OFS;
1119
Jeff Garzik5796d1c2007-10-26 00:03:37 -04001120 for (i = 0; i < ARRAY_SIZE(pdc_i2c_read_data); i++)
Tejun Heo4447d352007-04-17 23:44:08 +09001121 pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS,
Jeff Garzik8a60a072005-07-31 13:13:24 -04001122 pdc_i2c_read_data[i].reg,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123 &spd0[pdc_i2c_read_data[i].ofs]);
Jeff Garzik8a60a072005-07-31 13:13:24 -04001124
Jeff Garzik5796d1c2007-10-26 00:03:37 -04001125 data |= (spd0[4] - 8) | ((spd0[21] != 0) << 3) | ((spd0[3]-11) << 4);
1126 data |= ((spd0[17] / 4) << 6) | ((spd0[5] / 2) << 7) |
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127 ((((spd0[27] + 9) / 10) - 1) << 8) ;
Jeff Garzik5796d1c2007-10-26 00:03:37 -04001128 data |= (((((spd0[29] > spd0[28])
Jeff Garzik8a60a072005-07-31 13:13:24 -04001129 ? spd0[29] : spd0[28]) + 9) / 10) - 1) << 10;
Jeff Garzik5796d1c2007-10-26 00:03:37 -04001130 data |= ((spd0[30] - spd0[29] + 9) / 10 - 2) << 12;
Jeff Garzik8a60a072005-07-31 13:13:24 -04001131
Jeff Garzik5796d1c2007-10-26 00:03:37 -04001132 if (spd0[18] & 0x08)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 data |= ((0x03) << 14);
Jeff Garzik5796d1c2007-10-26 00:03:37 -04001134 else if (spd0[18] & 0x04)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135 data |= ((0x02) << 14);
Jeff Garzik5796d1c2007-10-26 00:03:37 -04001136 else if (spd0[18] & 0x01)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 data |= ((0x01) << 14);
Jeff Garzik5796d1c2007-10-26 00:03:37 -04001138 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 data |= (0 << 14);
1140
Jeff Garzik5796d1c2007-10-26 00:03:37 -04001141 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142 Calculate the size of bDIMMSize (power of 2) and
1143 merge the DIMM size by program start/end address.
1144 */
1145
Jeff Garzik5796d1c2007-10-26 00:03:37 -04001146 bdimmsize = spd0[4] + (spd0[5] / 2) + spd0[3] + (spd0[17] / 2) + 3;
1147 size = (1 << bdimmsize) >> 20; /* size = xxx(MB) */
1148 data |= (((size / 16) - 1) << 16);
1149 data |= (0 << 23);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150 data |= 8;
Jeff Garzik5796d1c2007-10-26 00:03:37 -04001151 writel(data, mmio + PDC_DIMM0_CONTROL);
Jeff Garzikb2d46b62007-05-27 22:58:54 -04001152 readl(mmio + PDC_DIMM0_CONTROL);
Jeff Garzik5796d1c2007-10-26 00:03:37 -04001153 return size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154}
1155
1156
Tejun Heo4447d352007-04-17 23:44:08 +09001157static unsigned int pdc20621_prog_dimm_global(struct ata_host *host)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158{
1159 u32 data, spd0;
Tejun Heo0d5ff562007-02-01 15:06:36 +09001160 int error, i;
Tejun Heo4447d352007-04-17 23:44:08 +09001161 void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162
1163 /* hard-code chip #0 */
Jeff Garzik5796d1c2007-10-26 00:03:37 -04001164 mmio += PDC_CHIP0_OFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165
Jeff Garzik5796d1c2007-10-26 00:03:37 -04001166 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167 Set To Default : DIMM Module Global Control Register (0x022259F1)
1168 DIMM Arbitration Disable (bit 20)
1169 DIMM Data/Control Output Driving Selection (bit12 - bit15)
1170 Refresh Enable (bit 17)
1171 */
1172
Jeff Garzik8a60a072005-07-31 13:13:24 -04001173 data = 0x022259F1;
Jeff Garzikb2d46b62007-05-27 22:58:54 -04001174 writel(data, mmio + PDC_SDRAM_CONTROL);
1175 readl(mmio + PDC_SDRAM_CONTROL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176
1177 /* Turn on for ECC */
Tejun Heo4447d352007-04-17 23:44:08 +09001178 pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179 PDC_DIMM_SPD_TYPE, &spd0);
1180 if (spd0 == 0x02) {
1181 data |= (0x01 << 16);
Jeff Garzikb2d46b62007-05-27 22:58:54 -04001182 writel(data, mmio + PDC_SDRAM_CONTROL);
1183 readl(mmio + PDC_SDRAM_CONTROL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 printk(KERN_ERR "Local DIMM ECC Enabled\n");
Jeff Garzik5796d1c2007-10-26 00:03:37 -04001185 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186
Jeff Garzik5796d1c2007-10-26 00:03:37 -04001187 /* DIMM Initialization Select/Enable (bit 18/19) */
1188 data &= (~(1<<18));
1189 data |= (1<<19);
1190 writel(data, mmio + PDC_SDRAM_CONTROL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191
Jeff Garzik5796d1c2007-10-26 00:03:37 -04001192 error = 1;
1193 for (i = 1; i <= 10; i++) { /* polling ~5 secs */
Jeff Garzikb2d46b62007-05-27 22:58:54 -04001194 data = readl(mmio + PDC_SDRAM_CONTROL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195 if (!(data & (1<<19))) {
Jeff Garzik5796d1c2007-10-26 00:03:37 -04001196 error = 0;
1197 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198 }
1199 msleep(i*100);
Jeff Garzik5796d1c2007-10-26 00:03:37 -04001200 }
1201 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202}
Jeff Garzik8a60a072005-07-31 13:13:24 -04001203
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204
Tejun Heo4447d352007-04-17 23:44:08 +09001205static unsigned int pdc20621_dimm_init(struct ata_host *host)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206{
Jeff Garzik8a60a072005-07-31 13:13:24 -04001207 int speed, size, length;
Jeff Garzik5796d1c2007-10-26 00:03:37 -04001208 u32 addr, spd0, pci_status;
1209 u32 tmp = 0;
1210 u32 time_period = 0;
1211 u32 tcount = 0;
1212 u32 ticks = 0;
1213 u32 clock = 0;
1214 u32 fparam = 0;
Tejun Heo4447d352007-04-17 23:44:08 +09001215 void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216
1217 /* hard-code chip #0 */
Jeff Garzik5796d1c2007-10-26 00:03:37 -04001218 mmio += PDC_CHIP0_OFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219
1220 /* Initialize PLL based upon PCI Bus Frequency */
1221
1222 /* Initialize Time Period Register */
1223 writel(0xffffffff, mmio + PDC_TIME_PERIOD);
1224 time_period = readl(mmio + PDC_TIME_PERIOD);
1225 VPRINTK("Time Period Register (0x40): 0x%x\n", time_period);
1226
1227 /* Enable timer */
Jeff Garzikb2d46b62007-05-27 22:58:54 -04001228 writel(PDC_TIMER_DEFAULT, mmio + PDC_TIME_CONTROL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229 readl(mmio + PDC_TIME_CONTROL);
1230
1231 /* Wait 3 seconds */
1232 msleep(3000);
1233
Jeff Garzik8a60a072005-07-31 13:13:24 -04001234 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235 When timer is enabled, counter is decreased every internal
1236 clock cycle.
1237 */
1238
1239 tcount = readl(mmio + PDC_TIME_COUNTER);
1240 VPRINTK("Time Counter Register (0x44): 0x%x\n", tcount);
1241
Jeff Garzik8a60a072005-07-31 13:13:24 -04001242 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243 If SX4 is on PCI-X bus, after 3 seconds, the timer counter
1244 register should be >= (0xffffffff - 3x10^8).
1245 */
Jeff Garzikb4479162007-10-25 20:47:30 -04001246 if (tcount >= PCI_X_TCOUNT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247 ticks = (time_period - tcount);
1248 VPRINTK("Num counters 0x%x (%d)\n", ticks, ticks);
Jeff Garzik8a60a072005-07-31 13:13:24 -04001249
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250 clock = (ticks / 300000);
1251 VPRINTK("10 * Internal clk = 0x%x (%d)\n", clock, clock);
Jeff Garzik8a60a072005-07-31 13:13:24 -04001252
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253 clock = (clock * 33);
1254 VPRINTK("10 * Internal clk * 33 = 0x%x (%d)\n", clock, clock);
1255
1256 /* PLL F Param (bit 22:16) */
1257 fparam = (1400000 / clock) - 2;
1258 VPRINTK("PLL F Param: 0x%x (%d)\n", fparam, fparam);
Jeff Garzik8a60a072005-07-31 13:13:24 -04001259
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260 /* OD param = 0x2 (bit 31:30), R param = 0x5 (bit 29:25) */
1261 pci_status = (0x8a001824 | (fparam << 16));
1262 } else
1263 pci_status = PCI_PLL_INIT;
1264
1265 /* Initialize PLL. */
1266 VPRINTK("pci_status: 0x%x\n", pci_status);
1267 writel(pci_status, mmio + PDC_CTL_STATUS);
1268 readl(mmio + PDC_CTL_STATUS);
1269
Jeff Garzik8a60a072005-07-31 13:13:24 -04001270 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271 Read SPD of DIMM by I2C interface,
1272 and program the DIMM Module Controller.
1273 */
Tejun Heo4447d352007-04-17 23:44:08 +09001274 if (!(speed = pdc20621_detect_dimm(host))) {
Jeff Garzik8a60a072005-07-31 13:13:24 -04001275 printk(KERN_ERR "Detect Local DIMM Fail\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276 return 1; /* DIMM error */
Jeff Garzik5796d1c2007-10-26 00:03:37 -04001277 }
1278 VPRINTK("Local DIMM Speed = %d\n", speed);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279
Jeff Garzik5796d1c2007-10-26 00:03:37 -04001280 /* Programming DIMM0 Module Control Register (index_CID0:80h) */
Tejun Heo4447d352007-04-17 23:44:08 +09001281 size = pdc20621_prog_dimm0(host);
Jeff Garzik5796d1c2007-10-26 00:03:37 -04001282 VPRINTK("Local DIMM Size = %dMB\n", size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283
Jeff Garzik5796d1c2007-10-26 00:03:37 -04001284 /* Programming DIMM Module Global Control Register (index_CID0:88h) */
Tejun Heo4447d352007-04-17 23:44:08 +09001285 if (pdc20621_prog_dimm_global(host)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286 printk(KERN_ERR "Programming DIMM Module Global Control Register Fail\n");
1287 return 1;
Jeff Garzik5796d1c2007-10-26 00:03:37 -04001288 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289
1290#ifdef ATA_VERBOSE_DEBUG
1291 {
Jeff Garzik5796d1c2007-10-26 00:03:37 -04001292 u8 test_parttern1[40] =
1293 {0x55,0xAA,'P','r','o','m','i','s','e',' ',
1294 'N','o','t',' ','Y','e','t',' ',
1295 'D','e','f','i','n','e','d',' ',
1296 '1','.','1','0',
1297 '9','8','0','3','1','6','1','2',0,0};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298 u8 test_parttern2[40] = {0};
1299
Jeff Garzik5796d1c2007-10-26 00:03:37 -04001300 pdc20621_put_to_dimm(host, test_parttern2, 0x10040, 40);
1301 pdc20621_put_to_dimm(host, test_parttern2, 0x40, 40);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302
Jeff Garzik5796d1c2007-10-26 00:03:37 -04001303 pdc20621_put_to_dimm(host, test_parttern1, 0x10040, 40);
1304 pdc20621_get_from_dimm(host, test_parttern2, 0x40, 40);
Jeff Garzik8a60a072005-07-31 13:13:24 -04001305 printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0],
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306 test_parttern2[1], &(test_parttern2[2]));
Jeff Garzik5796d1c2007-10-26 00:03:37 -04001307 pdc20621_get_from_dimm(host, test_parttern2, 0x10040,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308 40);
Jeff Garzik8a60a072005-07-31 13:13:24 -04001309 printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0],
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310 test_parttern2[1], &(test_parttern2[2]));
1311
Jeff Garzik5796d1c2007-10-26 00:03:37 -04001312 pdc20621_put_to_dimm(host, test_parttern1, 0x40, 40);
1313 pdc20621_get_from_dimm(host, test_parttern2, 0x40, 40);
Jeff Garzik8a60a072005-07-31 13:13:24 -04001314 printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0],
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 test_parttern2[1], &(test_parttern2[2]));
1316 }
1317#endif
1318
1319 /* ECC initiliazation. */
1320
Tejun Heo4447d352007-04-17 23:44:08 +09001321 pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 PDC_DIMM_SPD_TYPE, &spd0);
1323 if (spd0 == 0x02) {
1324 VPRINTK("Start ECC initialization\n");
1325 addr = 0;
1326 length = size * 1024 * 1024;
1327 while (addr < length) {
Tejun Heo4447d352007-04-17 23:44:08 +09001328 pdc20621_put_to_dimm(host, (void *) &tmp, addr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329 sizeof(u32));
1330 addr += sizeof(u32);
1331 }
1332 VPRINTK("Finish ECC initialization\n");
1333 }
1334 return 0;
1335}
1336
1337
Tejun Heo4447d352007-04-17 23:44:08 +09001338static void pdc_20621_init(struct ata_host *host)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339{
1340 u32 tmp;
Tejun Heo4447d352007-04-17 23:44:08 +09001341 void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342
1343 /* hard-code chip #0 */
1344 mmio += PDC_CHIP0_OFS;
1345
1346 /*
1347 * Select page 0x40 for our 32k DIMM window
1348 */
1349 tmp = readl(mmio + PDC_20621_DIMM_WINDOW) & 0xffff0000;
1350 tmp |= PDC_PAGE_WINDOW; /* page 40h; arbitrarily selected */
1351 writel(tmp, mmio + PDC_20621_DIMM_WINDOW);
1352
1353 /*
1354 * Reset Host DMA
1355 */
1356 tmp = readl(mmio + PDC_HDMA_CTLSTAT);
1357 tmp |= PDC_RESET;
1358 writel(tmp, mmio + PDC_HDMA_CTLSTAT);
1359 readl(mmio + PDC_HDMA_CTLSTAT); /* flush */
1360
1361 udelay(10);
1362
1363 tmp = readl(mmio + PDC_HDMA_CTLSTAT);
1364 tmp &= ~PDC_RESET;
1365 writel(tmp, mmio + PDC_HDMA_CTLSTAT);
1366 readl(mmio + PDC_HDMA_CTLSTAT); /* flush */
1367}
1368
Jeff Garzik5796d1c2007-10-26 00:03:37 -04001369static int pdc_sata_init_one(struct pci_dev *pdev,
1370 const struct pci_device_id *ent)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371{
1372 static int printed_version;
Tejun Heo4447d352007-04-17 23:44:08 +09001373 const struct ata_port_info *ppi[] =
1374 { &pdc_port_info[ent->driver_data], NULL };
1375 struct ata_host *host;
Tejun Heo24dc5f32007-01-20 16:00:28 +09001376 struct pdc_host_priv *hpriv;
Tejun Heocbcdd872007-08-18 13:14:55 +09001377 int i, rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378
1379 if (!printed_version++)
Jeff Garzika9524a72005-10-30 14:39:11 -05001380 dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381
Tejun Heo4447d352007-04-17 23:44:08 +09001382 /* allocate host */
1383 host = ata_host_alloc_pinfo(&pdev->dev, ppi, 4);
1384 hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL);
1385 if (!host || !hpriv)
1386 return -ENOMEM;
1387
1388 host->private_data = hpriv;
1389
1390 /* acquire resources and fill host */
Tejun Heo24dc5f32007-01-20 16:00:28 +09001391 rc = pcim_enable_device(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392 if (rc)
1393 return rc;
1394
Tejun Heo0d5ff562007-02-01 15:06:36 +09001395 rc = pcim_iomap_regions(pdev, (1 << PDC_MMIO_BAR) | (1 << PDC_DIMM_BAR),
1396 DRV_NAME);
1397 if (rc == -EBUSY)
Tejun Heo24dc5f32007-01-20 16:00:28 +09001398 pcim_pin_device(pdev);
Tejun Heo0d5ff562007-02-01 15:06:36 +09001399 if (rc)
Tejun Heo24dc5f32007-01-20 16:00:28 +09001400 return rc;
Tejun Heo4447d352007-04-17 23:44:08 +09001401 host->iomap = pcim_iomap_table(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402
Tejun Heocbcdd872007-08-18 13:14:55 +09001403 for (i = 0; i < 4; i++) {
1404 struct ata_port *ap = host->ports[i];
1405 void __iomem *base = host->iomap[PDC_MMIO_BAR] + PDC_CHIP0_OFS;
1406 unsigned int offset = 0x200 + i * 0x80;
1407
1408 pdc_sata_setup_port(&ap->ioaddr, base + offset);
1409
1410 ata_port_pbar_desc(ap, PDC_MMIO_BAR, -1, "mmio");
1411 ata_port_pbar_desc(ap, PDC_DIMM_BAR, -1, "dimm");
1412 ata_port_pbar_desc(ap, PDC_MMIO_BAR, offset, "port");
1413 }
Tejun Heo4447d352007-04-17 23:44:08 +09001414
1415 /* configure and activate */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416 rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
1417 if (rc)
Tejun Heo24dc5f32007-01-20 16:00:28 +09001418 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419 rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
1420 if (rc)
Tejun Heo24dc5f32007-01-20 16:00:28 +09001421 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422
Tejun Heo4447d352007-04-17 23:44:08 +09001423 if (pdc20621_dimm_init(host))
Tejun Heo24dc5f32007-01-20 16:00:28 +09001424 return -ENOMEM;
Tejun Heo4447d352007-04-17 23:44:08 +09001425 pdc_20621_init(host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426
1427 pci_set_master(pdev);
Tejun Heo4447d352007-04-17 23:44:08 +09001428 return ata_host_activate(host, pdev->irq, pdc20621_interrupt,
1429 IRQF_SHARED, &pdc_sata_sht);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430}
1431
1432
1433static int __init pdc_sata_init(void)
1434{
Pavel Roskinb7887192006-08-10 18:13:18 +09001435 return pci_register_driver(&pdc_sata_pci_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436}
1437
1438
1439static void __exit pdc_sata_exit(void)
1440{
1441 pci_unregister_driver(&pdc_sata_pci_driver);
1442}
1443
1444
1445MODULE_AUTHOR("Jeff Garzik");
1446MODULE_DESCRIPTION("Promise SATA low-level driver");
1447MODULE_LICENSE("GPL");
1448MODULE_DEVICE_TABLE(pci, pdc_sata_pci_tbl);
1449MODULE_VERSION(DRV_VERSION);
1450
1451module_init(pdc_sata_init);
1452module_exit(pdc_sata_exit);