1c82ee6d3SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2c6fd2807SJeff Garzik /*
3c6fd2807SJeff Garzik * sata_sx4.c - Promise SATA
4c6fd2807SJeff Garzik *
58c3d3d4bSTejun Heo * Maintained by: Tejun Heo <tj@kernel.org>
6c6fd2807SJeff Garzik * Please ALWAYS copy linux-ide@vger.kernel.org
7c6fd2807SJeff Garzik * on emails.
8c6fd2807SJeff Garzik *
9c6fd2807SJeff Garzik * Copyright 2003-2004 Red Hat, Inc.
10c6fd2807SJeff Garzik *
11c6fd2807SJeff Garzik * libata documentation is available via 'make {ps|pdf}docs',
1219285f3cSMauro Carvalho Chehab * as Documentation/driver-api/libata.rst
13c6fd2807SJeff Garzik *
14c6fd2807SJeff Garzik * Hardware documentation available under NDA.
15c6fd2807SJeff Garzik */
16c6fd2807SJeff Garzik
17a09060ffSJeff Garzik /*
18a09060ffSJeff Garzik Theory of operation
19a09060ffSJeff Garzik -------------------
20a09060ffSJeff Garzik
21a09060ffSJeff Garzik The SX4 (PDC20621) chip features a single Host DMA (HDMA) copy
22a09060ffSJeff Garzik engine, DIMM memory, and four ATA engines (one per SATA port).
23a09060ffSJeff Garzik Data is copied to/from DIMM memory by the HDMA engine, before
24a09060ffSJeff Garzik handing off to one (or more) of the ATA engines. The ATA
25a09060ffSJeff Garzik engines operate solely on DIMM memory.
26a09060ffSJeff Garzik
27a09060ffSJeff Garzik The SX4 behaves like a PATA chip, with no SATA controls or
28a09060ffSJeff Garzik knowledge whatsoever, leading to the presumption that
29a09060ffSJeff Garzik PATA<->SATA bridges exist on SX4 boards, external to the
30a09060ffSJeff Garzik PDC20621 chip itself.
31a09060ffSJeff Garzik
32a09060ffSJeff Garzik The chip is quite capable, supporting an XOR engine and linked
33a09060ffSJeff Garzik hardware commands (permits a string to transactions to be
34a09060ffSJeff Garzik submitted and waited-on as a single unit), and an optional
35a09060ffSJeff Garzik microprocessor.
36a09060ffSJeff Garzik
37a09060ffSJeff Garzik The limiting factor is largely software. This Linux driver was
38a09060ffSJeff Garzik written to multiplex the single HDMA engine to copy disk
39a09060ffSJeff Garzik transactions into a fixed DIMM memory space, from where an ATA
40a09060ffSJeff Garzik engine takes over. As a result, each WRITE looks like this:
41a09060ffSJeff Garzik
42a09060ffSJeff Garzik submit HDMA packet to hardware
43a09060ffSJeff Garzik hardware copies data from system memory to DIMM
44a09060ffSJeff Garzik hardware raises interrupt
45a09060ffSJeff Garzik
46a09060ffSJeff Garzik submit ATA packet to hardware
47a09060ffSJeff Garzik hardware executes ATA WRITE command, w/ data in DIMM
48a09060ffSJeff Garzik hardware raises interrupt
49a09060ffSJeff Garzik
50a09060ffSJeff Garzik and each READ looks like this:
51a09060ffSJeff Garzik
52a09060ffSJeff Garzik submit ATA packet to hardware
53a09060ffSJeff Garzik hardware executes ATA READ command, w/ data in DIMM
54a09060ffSJeff Garzik hardware raises interrupt
55a09060ffSJeff Garzik
56a09060ffSJeff Garzik submit HDMA packet to hardware
57a09060ffSJeff Garzik hardware copies data from DIMM to system memory
58a09060ffSJeff Garzik hardware raises interrupt
59a09060ffSJeff Garzik
60a09060ffSJeff Garzik This is a very slow, lock-step way of doing things that can
61a09060ffSJeff Garzik certainly be improved by motivated kernel hackers.
62a09060ffSJeff Garzik
63a09060ffSJeff Garzik */
64a09060ffSJeff Garzik
65c6fd2807SJeff Garzik #include <linux/kernel.h>
66c6fd2807SJeff Garzik #include <linux/module.h>
67c6fd2807SJeff Garzik #include <linux/pci.h>
685a0e3ad6STejun Heo #include <linux/slab.h>
69c6fd2807SJeff Garzik #include <linux/blkdev.h>
70c6fd2807SJeff Garzik #include <linux/delay.h>
71c6fd2807SJeff Garzik #include <linux/interrupt.h>
72c6fd2807SJeff Garzik #include <linux/device.h>
73c6fd2807SJeff Garzik #include <scsi/scsi_host.h>
74c6fd2807SJeff Garzik #include <scsi/scsi_cmnd.h>
75c6fd2807SJeff Garzik #include <linux/libata.h>
76c6fd2807SJeff Garzik #include "sata_promise.h"
77c6fd2807SJeff Garzik
78c6fd2807SJeff Garzik #define DRV_NAME "sata_sx4"
792a3103ceSJeff Garzik #define DRV_VERSION "0.12"
80c6fd2807SJeff Garzik
81f11c5403SHannes Reinecke static int dimm_test;
82f11c5403SHannes Reinecke module_param(dimm_test, int, 0644);
83f11c5403SHannes Reinecke MODULE_PARM_DESC(dimm_test, "Enable DIMM test during startup (1 = enabled)");
84c6fd2807SJeff Garzik
85c6fd2807SJeff Garzik enum {
860d5ff566STejun Heo PDC_MMIO_BAR = 3,
870d5ff566STejun Heo PDC_DIMM_BAR = 4,
880d5ff566STejun Heo
89c6fd2807SJeff Garzik PDC_PRD_TBL = 0x44, /* Direct command DMA table addr */
90c6fd2807SJeff Garzik
91c6fd2807SJeff Garzik PDC_PKT_SUBMIT = 0x40, /* Command packet pointer addr */
92c6fd2807SJeff Garzik PDC_HDMA_PKT_SUBMIT = 0x100, /* Host DMA packet pointer addr */
93c6fd2807SJeff Garzik PDC_INT_SEQMASK = 0x40, /* Mask of asserted SEQ INTs */
94c6fd2807SJeff Garzik PDC_HDMA_CTLSTAT = 0x12C, /* Host DMA control / status */
95c6fd2807SJeff Garzik
96a09060ffSJeff Garzik PDC_CTLSTAT = 0x60, /* IDEn control / status */
97a09060ffSJeff Garzik
98c6fd2807SJeff Garzik PDC_20621_SEQCTL = 0x400,
99c6fd2807SJeff Garzik PDC_20621_SEQMASK = 0x480,
100c6fd2807SJeff Garzik PDC_20621_GENERAL_CTL = 0x484,
101c6fd2807SJeff Garzik PDC_20621_PAGE_SIZE = (32 * 1024),
102c6fd2807SJeff Garzik
103c6fd2807SJeff Garzik /* chosen, not constant, values; we design our own DIMM mem map */
104c6fd2807SJeff Garzik PDC_20621_DIMM_WINDOW = 0x0C, /* page# for 32K DIMM window */
105c6fd2807SJeff Garzik PDC_20621_DIMM_BASE = 0x00200000,
106c6fd2807SJeff Garzik PDC_20621_DIMM_DATA = (64 * 1024),
107c6fd2807SJeff Garzik PDC_DIMM_DATA_STEP = (256 * 1024),
108c6fd2807SJeff Garzik PDC_DIMM_WINDOW_STEP = (8 * 1024),
109c6fd2807SJeff Garzik PDC_DIMM_HOST_PRD = (6 * 1024),
110c6fd2807SJeff Garzik PDC_DIMM_HOST_PKT = (128 * 0),
111c6fd2807SJeff Garzik PDC_DIMM_HPKT_PRD = (128 * 1),
112c6fd2807SJeff Garzik PDC_DIMM_ATA_PKT = (128 * 2),
113c6fd2807SJeff Garzik PDC_DIMM_APKT_PRD = (128 * 3),
114c6fd2807SJeff Garzik PDC_DIMM_HEADER_SZ = PDC_DIMM_APKT_PRD + 128,
115c6fd2807SJeff Garzik PDC_PAGE_WINDOW = 0x40,
116c6fd2807SJeff Garzik PDC_PAGE_DATA = PDC_PAGE_WINDOW +
117c6fd2807SJeff Garzik (PDC_20621_DIMM_DATA / PDC_20621_PAGE_SIZE),
118c6fd2807SJeff Garzik PDC_PAGE_SET = PDC_DIMM_DATA_STEP / PDC_20621_PAGE_SIZE,
119c6fd2807SJeff Garzik
120c6fd2807SJeff Garzik PDC_CHIP0_OFS = 0xC0000, /* offset of chip #0 */
121c6fd2807SJeff Garzik
122c6fd2807SJeff Garzik PDC_20621_ERR_MASK = (1<<19) | (1<<20) | (1<<21) | (1<<22) |
123c6fd2807SJeff Garzik (1<<23),
124c6fd2807SJeff Garzik
125c6fd2807SJeff Garzik board_20621 = 0, /* FastTrak S150 SX4 */
126c6fd2807SJeff Garzik
127b2d46b61SJeff Garzik PDC_MASK_INT = (1 << 10), /* HDMA/ATA mask int */
128b2d46b61SJeff Garzik PDC_RESET = (1 << 11), /* HDMA/ATA reset */
129a09060ffSJeff Garzik PDC_DMA_ENABLE = (1 << 7), /* DMA start/stop */
130c6fd2807SJeff Garzik
131c6fd2807SJeff Garzik PDC_MAX_HDMA = 32,
132c6fd2807SJeff Garzik PDC_HDMA_Q_MASK = (PDC_MAX_HDMA - 1),
133c6fd2807SJeff Garzik
134c6fd2807SJeff Garzik PDC_DIMM0_SPD_DEV_ADDRESS = 0x50,
135c6fd2807SJeff Garzik PDC_DIMM1_SPD_DEV_ADDRESS = 0x51,
136b2d46b61SJeff Garzik PDC_I2C_CONTROL = 0x48,
137b2d46b61SJeff Garzik PDC_I2C_ADDR_DATA = 0x4C,
138b2d46b61SJeff Garzik PDC_DIMM0_CONTROL = 0x80,
139b2d46b61SJeff Garzik PDC_DIMM1_CONTROL = 0x84,
140b2d46b61SJeff Garzik PDC_SDRAM_CONTROL = 0x88,
141b2d46b61SJeff Garzik PDC_I2C_WRITE = 0, /* master -> slave */
142b2d46b61SJeff Garzik PDC_I2C_READ = (1 << 6), /* master <- slave */
143b2d46b61SJeff Garzik PDC_I2C_START = (1 << 7), /* start I2C proto */
144b2d46b61SJeff Garzik PDC_I2C_MASK_INT = (1 << 5), /* mask I2C interrupt */
145b2d46b61SJeff Garzik PDC_I2C_COMPLETE = (1 << 16), /* I2C normal compl. */
146b2d46b61SJeff Garzik PDC_I2C_NO_ACK = (1 << 20), /* slave no-ack addr */
147c6fd2807SJeff Garzik PDC_DIMM_SPD_SUBADDRESS_START = 0x00,
148c6fd2807SJeff Garzik PDC_DIMM_SPD_SUBADDRESS_END = 0x7F,
149c6fd2807SJeff Garzik PDC_DIMM_SPD_ROW_NUM = 3,
150c6fd2807SJeff Garzik PDC_DIMM_SPD_COLUMN_NUM = 4,
151c6fd2807SJeff Garzik PDC_DIMM_SPD_MODULE_ROW = 5,
152c6fd2807SJeff Garzik PDC_DIMM_SPD_TYPE = 11,
153c6fd2807SJeff Garzik PDC_DIMM_SPD_FRESH_RATE = 12,
154c6fd2807SJeff Garzik PDC_DIMM_SPD_BANK_NUM = 17,
155c6fd2807SJeff Garzik PDC_DIMM_SPD_CAS_LATENCY = 18,
156c6fd2807SJeff Garzik PDC_DIMM_SPD_ATTRIBUTE = 21,
157c6fd2807SJeff Garzik PDC_DIMM_SPD_ROW_PRE_CHARGE = 27,
158c6fd2807SJeff Garzik PDC_DIMM_SPD_ROW_ACTIVE_DELAY = 28,
159c6fd2807SJeff Garzik PDC_DIMM_SPD_RAS_CAS_DELAY = 29,
160c6fd2807SJeff Garzik PDC_DIMM_SPD_ACTIVE_PRECHARGE = 30,
161c6fd2807SJeff Garzik PDC_DIMM_SPD_SYSTEM_FREQ = 126,
162c6fd2807SJeff Garzik PDC_CTL_STATUS = 0x08,
163c6fd2807SJeff Garzik PDC_DIMM_WINDOW_CTLR = 0x0C,
164c6fd2807SJeff Garzik PDC_TIME_CONTROL = 0x3C,
165c6fd2807SJeff Garzik PDC_TIME_PERIOD = 0x40,
166c6fd2807SJeff Garzik PDC_TIME_COUNTER = 0x44,
167c6fd2807SJeff Garzik PDC_GENERAL_CTLR = 0x484,
168c6fd2807SJeff Garzik PCI_PLL_INIT = 0x8A531824,
169b2d46b61SJeff Garzik PCI_X_TCOUNT = 0xEE1E5CFF,
170b2d46b61SJeff Garzik
171b2d46b61SJeff Garzik /* PDC_TIME_CONTROL bits */
172b2d46b61SJeff Garzik PDC_TIMER_BUZZER = (1 << 10),
173b2d46b61SJeff Garzik PDC_TIMER_MODE_PERIODIC = 0, /* bits 9:8 == 00 */
174b2d46b61SJeff Garzik PDC_TIMER_MODE_ONCE = (1 << 8), /* bits 9:8 == 01 */
175b2d46b61SJeff Garzik PDC_TIMER_ENABLE = (1 << 7),
176b2d46b61SJeff Garzik PDC_TIMER_MASK_INT = (1 << 5),
177b2d46b61SJeff Garzik PDC_TIMER_SEQ_MASK = 0x1f, /* SEQ ID for timer */
178b2d46b61SJeff Garzik PDC_TIMER_DEFAULT = PDC_TIMER_MODE_ONCE |
179b2d46b61SJeff Garzik PDC_TIMER_ENABLE |
180b2d46b61SJeff Garzik PDC_TIMER_MASK_INT,
181c6fd2807SJeff Garzik };
182c6fd2807SJeff Garzik
183f35b5e7cSAlexander Beregalov #define ECC_ERASE_BUF_SZ (128 * 1024)
184c6fd2807SJeff Garzik
185c6fd2807SJeff Garzik struct pdc_port_priv {
186c6fd2807SJeff Garzik u8 dimm_buf[(ATA_PRD_SZ * ATA_MAX_PRD) + 512];
187c6fd2807SJeff Garzik u8 *pkt;
188c6fd2807SJeff Garzik dma_addr_t pkt_dma;
189c6fd2807SJeff Garzik };
190c6fd2807SJeff Garzik
191c6fd2807SJeff Garzik struct pdc_host_priv {
192c6fd2807SJeff Garzik unsigned int doing_hdma;
193c6fd2807SJeff Garzik unsigned int hdma_prod;
194c6fd2807SJeff Garzik unsigned int hdma_cons;
195c6fd2807SJeff Garzik struct {
196c6fd2807SJeff Garzik struct ata_queued_cmd *qc;
197c6fd2807SJeff Garzik unsigned int seq;
198c6fd2807SJeff Garzik unsigned long pkt_ofs;
199c6fd2807SJeff Garzik } hdma[32];
200c6fd2807SJeff Garzik };
201c6fd2807SJeff Garzik
202c6fd2807SJeff Garzik
203c6fd2807SJeff Garzik static int pdc_sata_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
20467651ee5SJeff Garzik static void pdc_error_handler(struct ata_port *ap);
20567651ee5SJeff Garzik static void pdc_freeze(struct ata_port *ap);
20667651ee5SJeff Garzik static void pdc_thaw(struct ata_port *ap);
207c6fd2807SJeff Garzik static int pdc_port_start(struct ata_port *ap);
20895364f36SJiri Slaby static enum ata_completion_errors pdc20621_qc_prep(struct ata_queued_cmd *qc);
209c6fd2807SJeff Garzik static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf);
210c6fd2807SJeff Garzik static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf);
2114447d351STejun Heo static unsigned int pdc20621_dimm_init(struct ata_host *host);
2124447d351STejun Heo static int pdc20621_detect_dimm(struct ata_host *host);
2134447d351STejun Heo static unsigned int pdc20621_i2c_read(struct ata_host *host,
214c6fd2807SJeff Garzik u32 device, u32 subaddr, u32 *pdata);
2154447d351STejun Heo static int pdc20621_prog_dimm0(struct ata_host *host);
2164447d351STejun Heo static unsigned int pdc20621_prog_dimm_global(struct ata_host *host);
2174447d351STejun Heo static void pdc20621_get_from_dimm(struct ata_host *host,
218c6fd2807SJeff Garzik void *psource, u32 offset, u32 size);
2194447d351STejun Heo static void pdc20621_put_to_dimm(struct ata_host *host,
220c6fd2807SJeff Garzik void *psource, u32 offset, u32 size);
221c6fd2807SJeff Garzik static void pdc20621_irq_clear(struct ata_port *ap);
2229363c382STejun Heo static unsigned int pdc20621_qc_issue(struct ata_queued_cmd *qc);
22367651ee5SJeff Garzik static int pdc_softreset(struct ata_link *link, unsigned int *class,
22467651ee5SJeff Garzik unsigned long deadline);
22567651ee5SJeff Garzik static void pdc_post_internal_cmd(struct ata_queued_cmd *qc);
22667651ee5SJeff Garzik static int pdc_check_atapi_dma(struct ata_queued_cmd *qc);
227c6fd2807SJeff Garzik
228c6fd2807SJeff Garzik
22925df73d9SBart Van Assche static const struct scsi_host_template pdc_sata_sht = {
23068d1d07bSTejun Heo ATA_BASE_SHT(DRV_NAME),
231c6fd2807SJeff Garzik .sg_tablesize = LIBATA_MAX_PRD,
232c6fd2807SJeff Garzik .dma_boundary = ATA_DMA_BOUNDARY,
233c6fd2807SJeff Garzik };
234c6fd2807SJeff Garzik
235029cfd6bSTejun Heo static struct ata_port_operations pdc_20621_ops = {
23667651ee5SJeff Garzik .inherits = &ata_sff_port_ops,
23767651ee5SJeff Garzik
23867651ee5SJeff Garzik .check_atapi_dma = pdc_check_atapi_dma,
239c6fd2807SJeff Garzik .qc_prep = pdc20621_qc_prep,
2409363c382STejun Heo .qc_issue = pdc20621_qc_issue,
24167651ee5SJeff Garzik
24267651ee5SJeff Garzik .freeze = pdc_freeze,
24367651ee5SJeff Garzik .thaw = pdc_thaw,
24467651ee5SJeff Garzik .softreset = pdc_softreset,
24567651ee5SJeff Garzik .error_handler = pdc_error_handler,
24667651ee5SJeff Garzik .lost_interrupt = ATA_OP_NULL,
24767651ee5SJeff Garzik .post_internal_cmd = pdc_post_internal_cmd,
24867651ee5SJeff Garzik
249c6fd2807SJeff Garzik .port_start = pdc_port_start,
25067651ee5SJeff Garzik
25167651ee5SJeff Garzik .sff_tf_load = pdc_tf_load_mmio,
25267651ee5SJeff Garzik .sff_exec_command = pdc_exec_command_mmio,
25367651ee5SJeff Garzik .sff_irq_clear = pdc20621_irq_clear,
254c6fd2807SJeff Garzik };
255c6fd2807SJeff Garzik
256c6fd2807SJeff Garzik static const struct ata_port_info pdc_port_info[] = {
257c6fd2807SJeff Garzik /* board_20621 */
258c6fd2807SJeff Garzik {
2599cbe056fSSergei Shtylyov .flags = ATA_FLAG_SATA | ATA_FLAG_NO_ATAPI |
2609cbe056fSSergei Shtylyov ATA_FLAG_PIO_POLLING,
26114bdef98SErik Inge Bolsø .pio_mask = ATA_PIO4,
26214bdef98SErik Inge Bolsø .mwdma_mask = ATA_MWDMA2,
263469248abSJeff Garzik .udma_mask = ATA_UDMA6,
264c6fd2807SJeff Garzik .port_ops = &pdc_20621_ops,
265c6fd2807SJeff Garzik },
266c6fd2807SJeff Garzik
267c6fd2807SJeff Garzik };
268c6fd2807SJeff Garzik
269c6fd2807SJeff Garzik static const struct pci_device_id pdc_sata_pci_tbl[] = {
27054bb3a94SJeff Garzik { PCI_VDEVICE(PROMISE, 0x6622), board_20621 },
27154bb3a94SJeff Garzik
272c6fd2807SJeff Garzik { } /* terminate list */
273c6fd2807SJeff Garzik };
274c6fd2807SJeff Garzik
275c6fd2807SJeff Garzik static struct pci_driver pdc_sata_pci_driver = {
276c6fd2807SJeff Garzik .name = DRV_NAME,
277c6fd2807SJeff Garzik .id_table = pdc_sata_pci_tbl,
278c6fd2807SJeff Garzik .probe = pdc_sata_init_one,
279c6fd2807SJeff Garzik .remove = ata_pci_remove_one,
280c6fd2807SJeff Garzik };
281c6fd2807SJeff Garzik
282c6fd2807SJeff Garzik
pdc_port_start(struct ata_port * ap)283c6fd2807SJeff Garzik static int pdc_port_start(struct ata_port *ap)
284c6fd2807SJeff Garzik {
285cca3974eSJeff Garzik struct device *dev = ap->host->dev;
286c6fd2807SJeff Garzik struct pdc_port_priv *pp;
287c6fd2807SJeff Garzik
28824dc5f33STejun Heo pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
28924dc5f33STejun Heo if (!pp)
29024dc5f33STejun Heo return -ENOMEM;
291c6fd2807SJeff Garzik
29224dc5f33STejun Heo pp->pkt = dmam_alloc_coherent(dev, 128, &pp->pkt_dma, GFP_KERNEL);
29324dc5f33STejun Heo if (!pp->pkt)
29424dc5f33STejun Heo return -ENOMEM;
295c6fd2807SJeff Garzik
296c6fd2807SJeff Garzik ap->private_data = pp;
297c6fd2807SJeff Garzik
298c6fd2807SJeff Garzik return 0;
299c6fd2807SJeff Garzik }
300c6fd2807SJeff Garzik
pdc20621_ata_sg(u8 * buf,unsigned int portno,unsigned int total_len)3017c26deabSSergei Shtylyov static inline void pdc20621_ata_sg(u8 *buf, unsigned int portno,
302c6fd2807SJeff Garzik unsigned int total_len)
303c6fd2807SJeff Garzik {
304c6fd2807SJeff Garzik u32 addr;
305c6fd2807SJeff Garzik unsigned int dw = PDC_DIMM_APKT_PRD >> 2;
3064ca4e439SAl Viro __le32 *buf32 = (__le32 *) buf;
307c6fd2807SJeff Garzik
308c6fd2807SJeff Garzik /* output ATA packet S/G table */
309c6fd2807SJeff Garzik addr = PDC_20621_DIMM_BASE + PDC_20621_DIMM_DATA +
310c6fd2807SJeff Garzik (PDC_DIMM_DATA_STEP * portno);
311bc21c105SHannes Reinecke
312c6fd2807SJeff Garzik buf32[dw] = cpu_to_le32(addr);
313c6fd2807SJeff Garzik buf32[dw + 1] = cpu_to_le32(total_len | ATA_PRD_EOT);
314c6fd2807SJeff Garzik }
315c6fd2807SJeff Garzik
pdc20621_host_sg(u8 * buf,unsigned int portno,unsigned int total_len)3167c26deabSSergei Shtylyov static inline void pdc20621_host_sg(u8 *buf, unsigned int portno,
317c6fd2807SJeff Garzik unsigned int total_len)
318c6fd2807SJeff Garzik {
319c6fd2807SJeff Garzik u32 addr;
320c6fd2807SJeff Garzik unsigned int dw = PDC_DIMM_HPKT_PRD >> 2;
3214ca4e439SAl Viro __le32 *buf32 = (__le32 *) buf;
322c6fd2807SJeff Garzik
323c6fd2807SJeff Garzik /* output Host DMA packet S/G table */
324c6fd2807SJeff Garzik addr = PDC_20621_DIMM_BASE + PDC_20621_DIMM_DATA +
325c6fd2807SJeff Garzik (PDC_DIMM_DATA_STEP * portno);
326c6fd2807SJeff Garzik
327c6fd2807SJeff Garzik buf32[dw] = cpu_to_le32(addr);
328c6fd2807SJeff Garzik buf32[dw + 1] = cpu_to_le32(total_len | ATA_PRD_EOT);
329c6fd2807SJeff Garzik }
330c6fd2807SJeff Garzik
pdc20621_ata_pkt(struct ata_taskfile * tf,unsigned int devno,u8 * buf,unsigned int portno)331c6fd2807SJeff Garzik static inline unsigned int pdc20621_ata_pkt(struct ata_taskfile *tf,
332c6fd2807SJeff Garzik unsigned int devno, u8 *buf,
333c6fd2807SJeff Garzik unsigned int portno)
334c6fd2807SJeff Garzik {
335c6fd2807SJeff Garzik unsigned int i, dw;
3364ca4e439SAl Viro __le32 *buf32 = (__le32 *) buf;
337c6fd2807SJeff Garzik u8 dev_reg;
338c6fd2807SJeff Garzik
339c6fd2807SJeff Garzik unsigned int dimm_sg = PDC_20621_DIMM_BASE +
340c6fd2807SJeff Garzik (PDC_DIMM_WINDOW_STEP * portno) +
341c6fd2807SJeff Garzik PDC_DIMM_APKT_PRD;
342c6fd2807SJeff Garzik
343c6fd2807SJeff Garzik i = PDC_DIMM_ATA_PKT;
344c6fd2807SJeff Garzik
345c6fd2807SJeff Garzik /*
346c6fd2807SJeff Garzik * Set up ATA packet
347c6fd2807SJeff Garzik */
348c6fd2807SJeff Garzik if ((tf->protocol == ATA_PROT_DMA) && (!(tf->flags & ATA_TFLAG_WRITE)))
349c6fd2807SJeff Garzik buf[i++] = PDC_PKT_READ;
350c6fd2807SJeff Garzik else if (tf->protocol == ATA_PROT_NODATA)
351c6fd2807SJeff Garzik buf[i++] = PDC_PKT_NODATA;
352c6fd2807SJeff Garzik else
353c6fd2807SJeff Garzik buf[i++] = 0;
354c6fd2807SJeff Garzik buf[i++] = 0; /* reserved */
355c6fd2807SJeff Garzik buf[i++] = portno + 1; /* seq. id */
356c6fd2807SJeff Garzik buf[i++] = 0xff; /* delay seq. id */
357c6fd2807SJeff Garzik
358c6fd2807SJeff Garzik /* dimm dma S/G, and next-pkt */
359c6fd2807SJeff Garzik dw = i >> 2;
360c6fd2807SJeff Garzik if (tf->protocol == ATA_PROT_NODATA)
361c6fd2807SJeff Garzik buf32[dw] = 0;
362c6fd2807SJeff Garzik else
363c6fd2807SJeff Garzik buf32[dw] = cpu_to_le32(dimm_sg);
364c6fd2807SJeff Garzik buf32[dw + 1] = 0;
365c6fd2807SJeff Garzik i += 8;
366c6fd2807SJeff Garzik
367c6fd2807SJeff Garzik if (devno == 0)
368c6fd2807SJeff Garzik dev_reg = ATA_DEVICE_OBS;
369c6fd2807SJeff Garzik else
370c6fd2807SJeff Garzik dev_reg = ATA_DEVICE_OBS | ATA_DEV1;
371c6fd2807SJeff Garzik
372c6fd2807SJeff Garzik /* select device */
373c6fd2807SJeff Garzik buf[i++] = (1 << 5) | PDC_PKT_CLEAR_BSY | ATA_REG_DEVICE;
374c6fd2807SJeff Garzik buf[i++] = dev_reg;
375c6fd2807SJeff Garzik
376c6fd2807SJeff Garzik /* device control register */
377c6fd2807SJeff Garzik buf[i++] = (1 << 5) | PDC_REG_DEVCTL;
378c6fd2807SJeff Garzik buf[i++] = tf->ctl;
379c6fd2807SJeff Garzik
380c6fd2807SJeff Garzik return i;
381c6fd2807SJeff Garzik }
382c6fd2807SJeff Garzik
pdc20621_host_pkt(struct ata_taskfile * tf,u8 * buf,unsigned int portno)383c6fd2807SJeff Garzik static inline void pdc20621_host_pkt(struct ata_taskfile *tf, u8 *buf,
384c6fd2807SJeff Garzik unsigned int portno)
385c6fd2807SJeff Garzik {
386c6fd2807SJeff Garzik unsigned int dw;
3874ca4e439SAl Viro u32 tmp;
3884ca4e439SAl Viro __le32 *buf32 = (__le32 *) buf;
389c6fd2807SJeff Garzik
390c6fd2807SJeff Garzik unsigned int host_sg = PDC_20621_DIMM_BASE +
391c6fd2807SJeff Garzik (PDC_DIMM_WINDOW_STEP * portno) +
392c6fd2807SJeff Garzik PDC_DIMM_HOST_PRD;
393c6fd2807SJeff Garzik unsigned int dimm_sg = PDC_20621_DIMM_BASE +
394c6fd2807SJeff Garzik (PDC_DIMM_WINDOW_STEP * portno) +
395c6fd2807SJeff Garzik PDC_DIMM_HPKT_PRD;
396c6fd2807SJeff Garzik
397c6fd2807SJeff Garzik dw = PDC_DIMM_HOST_PKT >> 2;
398c6fd2807SJeff Garzik
399c6fd2807SJeff Garzik /*
400c6fd2807SJeff Garzik * Set up Host DMA packet
401c6fd2807SJeff Garzik */
402c6fd2807SJeff Garzik if ((tf->protocol == ATA_PROT_DMA) && (!(tf->flags & ATA_TFLAG_WRITE)))
403c6fd2807SJeff Garzik tmp = PDC_PKT_READ;
404c6fd2807SJeff Garzik else
405c6fd2807SJeff Garzik tmp = 0;
406c6fd2807SJeff Garzik tmp |= ((portno + 1 + 4) << 16); /* seq. id */
407c6fd2807SJeff Garzik tmp |= (0xff << 24); /* delay seq. id */
408c6fd2807SJeff Garzik buf32[dw + 0] = cpu_to_le32(tmp);
409c6fd2807SJeff Garzik buf32[dw + 1] = cpu_to_le32(host_sg);
410c6fd2807SJeff Garzik buf32[dw + 2] = cpu_to_le32(dimm_sg);
411c6fd2807SJeff Garzik buf32[dw + 3] = 0;
412c6fd2807SJeff Garzik }
413c6fd2807SJeff Garzik
pdc20621_dma_prep(struct ata_queued_cmd * qc)414c6fd2807SJeff Garzik static void pdc20621_dma_prep(struct ata_queued_cmd *qc)
415c6fd2807SJeff Garzik {
416c6fd2807SJeff Garzik struct scatterlist *sg;
417c6fd2807SJeff Garzik struct ata_port *ap = qc->ap;
418c6fd2807SJeff Garzik struct pdc_port_priv *pp = ap->private_data;
4190d5ff566STejun Heo void __iomem *mmio = ap->host->iomap[PDC_MMIO_BAR];
4200d5ff566STejun Heo void __iomem *dimm_mmio = ap->host->iomap[PDC_DIMM_BAR];
421c6fd2807SJeff Garzik unsigned int portno = ap->port_no;
422ff2aeb1eSTejun Heo unsigned int i, si, idx, total_len = 0, sgt_len;
423826cd156SAl Viro __le32 *buf = (__le32 *) &pp->dimm_buf[PDC_DIMM_HEADER_SZ];
424c6fd2807SJeff Garzik
425c6fd2807SJeff Garzik WARN_ON(!(qc->flags & ATA_QCFLAG_DMAMAP));
426c6fd2807SJeff Garzik
427c6fd2807SJeff Garzik /* hard-code chip #0 */
428c6fd2807SJeff Garzik mmio += PDC_CHIP0_OFS;
429c6fd2807SJeff Garzik
430c6fd2807SJeff Garzik /*
431c6fd2807SJeff Garzik * Build S/G table
432c6fd2807SJeff Garzik */
433c6fd2807SJeff Garzik idx = 0;
434ff2aeb1eSTejun Heo for_each_sg(qc->sg, sg, qc->n_elem, si) {
435c6fd2807SJeff Garzik buf[idx++] = cpu_to_le32(sg_dma_address(sg));
436c6fd2807SJeff Garzik buf[idx++] = cpu_to_le32(sg_dma_len(sg));
437c6fd2807SJeff Garzik total_len += sg_dma_len(sg);
438c6fd2807SJeff Garzik }
439c6fd2807SJeff Garzik buf[idx - 1] |= cpu_to_le32(ATA_PRD_EOT);
440c6fd2807SJeff Garzik sgt_len = idx * 4;
441c6fd2807SJeff Garzik
442c6fd2807SJeff Garzik /*
443c6fd2807SJeff Garzik * Build ATA, host DMA packets
444c6fd2807SJeff Garzik */
4457c26deabSSergei Shtylyov pdc20621_host_sg(&pp->dimm_buf[0], portno, total_len);
446c6fd2807SJeff Garzik pdc20621_host_pkt(&qc->tf, &pp->dimm_buf[0], portno);
447c6fd2807SJeff Garzik
4487c26deabSSergei Shtylyov pdc20621_ata_sg(&pp->dimm_buf[0], portno, total_len);
449c6fd2807SJeff Garzik i = pdc20621_ata_pkt(&qc->tf, qc->dev->devno, &pp->dimm_buf[0], portno);
450c6fd2807SJeff Garzik
451c6fd2807SJeff Garzik if (qc->tf.flags & ATA_TFLAG_LBA48)
452c6fd2807SJeff Garzik i = pdc_prep_lba48(&qc->tf, &pp->dimm_buf[0], i);
453c6fd2807SJeff Garzik else
454c6fd2807SJeff Garzik i = pdc_prep_lba28(&qc->tf, &pp->dimm_buf[0], i);
455c6fd2807SJeff Garzik
456c6fd2807SJeff Garzik pdc_pkt_footer(&qc->tf, &pp->dimm_buf[0], i);
457c6fd2807SJeff Garzik
458c6fd2807SJeff Garzik /* copy three S/G tables and two packets to DIMM MMIO window */
459c6fd2807SJeff Garzik memcpy_toio(dimm_mmio + (portno * PDC_DIMM_WINDOW_STEP),
460c6fd2807SJeff Garzik &pp->dimm_buf, PDC_DIMM_HEADER_SZ);
461c6fd2807SJeff Garzik memcpy_toio(dimm_mmio + (portno * PDC_DIMM_WINDOW_STEP) +
462c6fd2807SJeff Garzik PDC_DIMM_HOST_PRD,
463c6fd2807SJeff Garzik &pp->dimm_buf[PDC_DIMM_HEADER_SZ], sgt_len);
464c6fd2807SJeff Garzik
465c6fd2807SJeff Garzik /* force host FIFO dump */
466c6fd2807SJeff Garzik writel(0x00000001, mmio + PDC_20621_GENERAL_CTL);
467c6fd2807SJeff Garzik
468c6fd2807SJeff Garzik readl(dimm_mmio); /* MMIO PCI posting flush */
469c6fd2807SJeff Garzik
470bc21c105SHannes Reinecke ata_port_dbg(ap, "ata pkt buf ofs %u, prd size %u, mmio copied\n",
471bc21c105SHannes Reinecke i, sgt_len);
472c6fd2807SJeff Garzik }
473c6fd2807SJeff Garzik
pdc20621_nodata_prep(struct ata_queued_cmd * qc)474c6fd2807SJeff Garzik static void pdc20621_nodata_prep(struct ata_queued_cmd *qc)
475c6fd2807SJeff Garzik {
476c6fd2807SJeff Garzik struct ata_port *ap = qc->ap;
477c6fd2807SJeff Garzik struct pdc_port_priv *pp = ap->private_data;
4780d5ff566STejun Heo void __iomem *mmio = ap->host->iomap[PDC_MMIO_BAR];
4790d5ff566STejun Heo void __iomem *dimm_mmio = ap->host->iomap[PDC_DIMM_BAR];
480c6fd2807SJeff Garzik unsigned int portno = ap->port_no;
481c6fd2807SJeff Garzik unsigned int i;
482c6fd2807SJeff Garzik
483c6fd2807SJeff Garzik /* hard-code chip #0 */
484c6fd2807SJeff Garzik mmio += PDC_CHIP0_OFS;
485c6fd2807SJeff Garzik
486c6fd2807SJeff Garzik i = pdc20621_ata_pkt(&qc->tf, qc->dev->devno, &pp->dimm_buf[0], portno);
487c6fd2807SJeff Garzik
488c6fd2807SJeff Garzik if (qc->tf.flags & ATA_TFLAG_LBA48)
489c6fd2807SJeff Garzik i = pdc_prep_lba48(&qc->tf, &pp->dimm_buf[0], i);
490c6fd2807SJeff Garzik else
491c6fd2807SJeff Garzik i = pdc_prep_lba28(&qc->tf, &pp->dimm_buf[0], i);
492c6fd2807SJeff Garzik
493c6fd2807SJeff Garzik pdc_pkt_footer(&qc->tf, &pp->dimm_buf[0], i);
494c6fd2807SJeff Garzik
495c6fd2807SJeff Garzik /* copy three S/G tables and two packets to DIMM MMIO window */
496c6fd2807SJeff Garzik memcpy_toio(dimm_mmio + (portno * PDC_DIMM_WINDOW_STEP),
497c6fd2807SJeff Garzik &pp->dimm_buf, PDC_DIMM_HEADER_SZ);
498c6fd2807SJeff Garzik
499c6fd2807SJeff Garzik /* force host FIFO dump */
500c6fd2807SJeff Garzik writel(0x00000001, mmio + PDC_20621_GENERAL_CTL);
501c6fd2807SJeff Garzik
502c6fd2807SJeff Garzik readl(dimm_mmio); /* MMIO PCI posting flush */
503c6fd2807SJeff Garzik
504bc21c105SHannes Reinecke ata_port_dbg(ap, "ata pkt buf ofs %u, mmio copied\n", i);
505c6fd2807SJeff Garzik }
506c6fd2807SJeff Garzik
pdc20621_qc_prep(struct ata_queued_cmd * qc)50795364f36SJiri Slaby static enum ata_completion_errors pdc20621_qc_prep(struct ata_queued_cmd *qc)
508c6fd2807SJeff Garzik {
509c6fd2807SJeff Garzik switch (qc->tf.protocol) {
510c6fd2807SJeff Garzik case ATA_PROT_DMA:
511c6fd2807SJeff Garzik pdc20621_dma_prep(qc);
512c6fd2807SJeff Garzik break;
513c6fd2807SJeff Garzik case ATA_PROT_NODATA:
514c6fd2807SJeff Garzik pdc20621_nodata_prep(qc);
515c6fd2807SJeff Garzik break;
516c6fd2807SJeff Garzik default:
517c6fd2807SJeff Garzik break;
518c6fd2807SJeff Garzik }
51995364f36SJiri Slaby
52095364f36SJiri Slaby return AC_ERR_OK;
521c6fd2807SJeff Garzik }
522c6fd2807SJeff Garzik
__pdc20621_push_hdma(struct ata_queued_cmd * qc,unsigned int seq,u32 pkt_ofs)523c6fd2807SJeff Garzik static void __pdc20621_push_hdma(struct ata_queued_cmd *qc,
524c6fd2807SJeff Garzik unsigned int seq,
525c6fd2807SJeff Garzik u32 pkt_ofs)
526c6fd2807SJeff Garzik {
527c6fd2807SJeff Garzik struct ata_port *ap = qc->ap;
528cca3974eSJeff Garzik struct ata_host *host = ap->host;
5290d5ff566STejun Heo void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
530c6fd2807SJeff Garzik
531c6fd2807SJeff Garzik /* hard-code chip #0 */
532c6fd2807SJeff Garzik mmio += PDC_CHIP0_OFS;
533c6fd2807SJeff Garzik
534c6fd2807SJeff Garzik writel(0x00000001, mmio + PDC_20621_SEQCTL + (seq * 4));
535c6fd2807SJeff Garzik readl(mmio + PDC_20621_SEQCTL + (seq * 4)); /* flush */
536c6fd2807SJeff Garzik
537c6fd2807SJeff Garzik writel(pkt_ofs, mmio + PDC_HDMA_PKT_SUBMIT);
538c6fd2807SJeff Garzik readl(mmio + PDC_HDMA_PKT_SUBMIT); /* flush */
539c6fd2807SJeff Garzik }
540c6fd2807SJeff Garzik
pdc20621_push_hdma(struct ata_queued_cmd * qc,unsigned int seq,u32 pkt_ofs)541c6fd2807SJeff Garzik static void pdc20621_push_hdma(struct ata_queued_cmd *qc,
542c6fd2807SJeff Garzik unsigned int seq,
543c6fd2807SJeff Garzik u32 pkt_ofs)
544c6fd2807SJeff Garzik {
545c6fd2807SJeff Garzik struct ata_port *ap = qc->ap;
546cca3974eSJeff Garzik struct pdc_host_priv *pp = ap->host->private_data;
547c6fd2807SJeff Garzik unsigned int idx = pp->hdma_prod & PDC_HDMA_Q_MASK;
548c6fd2807SJeff Garzik
549c6fd2807SJeff Garzik if (!pp->doing_hdma) {
550c6fd2807SJeff Garzik __pdc20621_push_hdma(qc, seq, pkt_ofs);
551c6fd2807SJeff Garzik pp->doing_hdma = 1;
552c6fd2807SJeff Garzik return;
553c6fd2807SJeff Garzik }
554c6fd2807SJeff Garzik
555c6fd2807SJeff Garzik pp->hdma[idx].qc = qc;
556c6fd2807SJeff Garzik pp->hdma[idx].seq = seq;
557c6fd2807SJeff Garzik pp->hdma[idx].pkt_ofs = pkt_ofs;
558c6fd2807SJeff Garzik pp->hdma_prod++;
559c6fd2807SJeff Garzik }
560c6fd2807SJeff Garzik
pdc20621_pop_hdma(struct ata_queued_cmd * qc)561c6fd2807SJeff Garzik static void pdc20621_pop_hdma(struct ata_queued_cmd *qc)
562c6fd2807SJeff Garzik {
563c6fd2807SJeff Garzik struct ata_port *ap = qc->ap;
564cca3974eSJeff Garzik struct pdc_host_priv *pp = ap->host->private_data;
565c6fd2807SJeff Garzik unsigned int idx = pp->hdma_cons & PDC_HDMA_Q_MASK;
566c6fd2807SJeff Garzik
567c6fd2807SJeff Garzik /* if nothing on queue, we're done */
568c6fd2807SJeff Garzik if (pp->hdma_prod == pp->hdma_cons) {
569c6fd2807SJeff Garzik pp->doing_hdma = 0;
570c6fd2807SJeff Garzik return;
571c6fd2807SJeff Garzik }
572c6fd2807SJeff Garzik
573c6fd2807SJeff Garzik __pdc20621_push_hdma(pp->hdma[idx].qc, pp->hdma[idx].seq,
574c6fd2807SJeff Garzik pp->hdma[idx].pkt_ofs);
575c6fd2807SJeff Garzik pp->hdma_cons++;
576c6fd2807SJeff Garzik }
577c6fd2807SJeff Garzik
pdc20621_dump_hdma(struct ata_queued_cmd * qc)578c6fd2807SJeff Garzik static void pdc20621_dump_hdma(struct ata_queued_cmd *qc)
579c6fd2807SJeff Garzik {
580c6fd2807SJeff Garzik struct ata_port *ap = qc->ap;
581c6fd2807SJeff Garzik unsigned int port_no = ap->port_no;
5820d5ff566STejun Heo void __iomem *dimm_mmio = ap->host->iomap[PDC_DIMM_BAR];
583c6fd2807SJeff Garzik
584c6fd2807SJeff Garzik dimm_mmio += (port_no * PDC_DIMM_WINDOW_STEP);
585c6fd2807SJeff Garzik dimm_mmio += PDC_DIMM_HOST_PKT;
586c6fd2807SJeff Garzik
587f11c5403SHannes Reinecke ata_port_dbg(ap, "HDMA 0x%08X 0x%08X 0x%08X 0x%08X\n",
588f11c5403SHannes Reinecke readl(dimm_mmio), readl(dimm_mmio + 4),
589f11c5403SHannes Reinecke readl(dimm_mmio + 8), readl(dimm_mmio + 12));
590c6fd2807SJeff Garzik }
591c6fd2807SJeff Garzik
pdc20621_packet_start(struct ata_queued_cmd * qc)592c6fd2807SJeff Garzik static void pdc20621_packet_start(struct ata_queued_cmd *qc)
593c6fd2807SJeff Garzik {
594c6fd2807SJeff Garzik struct ata_port *ap = qc->ap;
595cca3974eSJeff Garzik struct ata_host *host = ap->host;
596c6fd2807SJeff Garzik unsigned int port_no = ap->port_no;
5970d5ff566STejun Heo void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
598c6fd2807SJeff Garzik unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
599c6fd2807SJeff Garzik u8 seq = (u8) (port_no + 1);
600c6fd2807SJeff Garzik unsigned int port_ofs;
601c6fd2807SJeff Garzik
602c6fd2807SJeff Garzik /* hard-code chip #0 */
603c6fd2807SJeff Garzik mmio += PDC_CHIP0_OFS;
604c6fd2807SJeff Garzik
605c6fd2807SJeff Garzik wmb(); /* flush PRD, pkt writes */
606c6fd2807SJeff Garzik
607c6fd2807SJeff Garzik port_ofs = PDC_20621_DIMM_BASE + (PDC_DIMM_WINDOW_STEP * port_no);
608c6fd2807SJeff Garzik
609c6fd2807SJeff Garzik /* if writing, we (1) DMA to DIMM, then (2) do ATA command */
610c6fd2807SJeff Garzik if (rw && qc->tf.protocol == ATA_PROT_DMA) {
611c6fd2807SJeff Garzik seq += 4;
612c6fd2807SJeff Garzik
613c6fd2807SJeff Garzik pdc20621_dump_hdma(qc);
614c6fd2807SJeff Garzik pdc20621_push_hdma(qc, seq, port_ofs + PDC_DIMM_HOST_PKT);
615bc21c105SHannes Reinecke ata_port_dbg(ap, "queued ofs 0x%x (%u), seq %u\n",
616c6fd2807SJeff Garzik port_ofs + PDC_DIMM_HOST_PKT,
617c6fd2807SJeff Garzik port_ofs + PDC_DIMM_HOST_PKT,
618c6fd2807SJeff Garzik seq);
619c6fd2807SJeff Garzik } else {
620c6fd2807SJeff Garzik writel(0x00000001, mmio + PDC_20621_SEQCTL + (seq * 4));
621c6fd2807SJeff Garzik readl(mmio + PDC_20621_SEQCTL + (seq * 4)); /* flush */
622c6fd2807SJeff Garzik
623c6fd2807SJeff Garzik writel(port_ofs + PDC_DIMM_ATA_PKT,
6240d5ff566STejun Heo ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
6250d5ff566STejun Heo readl(ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
626bc21c105SHannes Reinecke ata_port_dbg(ap, "submitted ofs 0x%x (%u), seq %u\n",
627c6fd2807SJeff Garzik port_ofs + PDC_DIMM_ATA_PKT,
628c6fd2807SJeff Garzik port_ofs + PDC_DIMM_ATA_PKT,
629c6fd2807SJeff Garzik seq);
630c6fd2807SJeff Garzik }
631c6fd2807SJeff Garzik }
632c6fd2807SJeff Garzik
pdc20621_qc_issue(struct ata_queued_cmd * qc)6339363c382STejun Heo static unsigned int pdc20621_qc_issue(struct ata_queued_cmd *qc)
634c6fd2807SJeff Garzik {
635c6fd2807SJeff Garzik switch (qc->tf.protocol) {
636c6fd2807SJeff Garzik case ATA_PROT_NODATA:
63719799bfcSDavid Milburn if (qc->tf.flags & ATA_TFLAG_POLLING)
63819799bfcSDavid Milburn break;
639df561f66SGustavo A. R. Silva fallthrough;
64019799bfcSDavid Milburn case ATA_PROT_DMA:
641c6fd2807SJeff Garzik pdc20621_packet_start(qc);
642c6fd2807SJeff Garzik return 0;
643c6fd2807SJeff Garzik
6440dc36888STejun Heo case ATAPI_PROT_DMA:
645c6fd2807SJeff Garzik BUG();
646c6fd2807SJeff Garzik break;
647c6fd2807SJeff Garzik
648c6fd2807SJeff Garzik default:
649c6fd2807SJeff Garzik break;
650c6fd2807SJeff Garzik }
651c6fd2807SJeff Garzik
6529363c382STejun Heo return ata_sff_qc_issue(qc);
653c6fd2807SJeff Garzik }
654c6fd2807SJeff Garzik
pdc20621_host_intr(struct ata_port * ap,struct ata_queued_cmd * qc,unsigned int doing_hdma,void __iomem * mmio)655c6fd2807SJeff Garzik static inline unsigned int pdc20621_host_intr(struct ata_port *ap,
656c6fd2807SJeff Garzik struct ata_queued_cmd *qc,
657c6fd2807SJeff Garzik unsigned int doing_hdma,
658c6fd2807SJeff Garzik void __iomem *mmio)
659c6fd2807SJeff Garzik {
660c6fd2807SJeff Garzik unsigned int port_no = ap->port_no;
661c6fd2807SJeff Garzik unsigned int port_ofs =
662c6fd2807SJeff Garzik PDC_20621_DIMM_BASE + (PDC_DIMM_WINDOW_STEP * port_no);
663c6fd2807SJeff Garzik u8 status;
664c6fd2807SJeff Garzik unsigned int handled = 0;
665c6fd2807SJeff Garzik
666c6fd2807SJeff Garzik if ((qc->tf.protocol == ATA_PROT_DMA) && /* read */
667c6fd2807SJeff Garzik (!(qc->tf.flags & ATA_TFLAG_WRITE))) {
668c6fd2807SJeff Garzik
669c6fd2807SJeff Garzik /* step two - DMA from DIMM to host */
670c6fd2807SJeff Garzik if (doing_hdma) {
671bc21c105SHannes Reinecke ata_port_dbg(ap, "read hdma, 0x%x 0x%x\n",
672c6fd2807SJeff Garzik readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT));
673c6fd2807SJeff Garzik /* get drive status; clear intr; complete txn */
674c6fd2807SJeff Garzik qc->err_mask |= ac_err_mask(ata_wait_idle(ap));
675c6fd2807SJeff Garzik ata_qc_complete(qc);
676c6fd2807SJeff Garzik pdc20621_pop_hdma(qc);
677c6fd2807SJeff Garzik }
678c6fd2807SJeff Garzik
679c6fd2807SJeff Garzik /* step one - exec ATA command */
680c6fd2807SJeff Garzik else {
681c6fd2807SJeff Garzik u8 seq = (u8) (port_no + 1 + 4);
682bc21c105SHannes Reinecke ata_port_dbg(ap, "read ata, 0x%x 0x%x\n",
683c6fd2807SJeff Garzik readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT));
684c6fd2807SJeff Garzik
685c6fd2807SJeff Garzik /* submit hdma pkt */
686c6fd2807SJeff Garzik pdc20621_dump_hdma(qc);
687c6fd2807SJeff Garzik pdc20621_push_hdma(qc, seq,
688c6fd2807SJeff Garzik port_ofs + PDC_DIMM_HOST_PKT);
689c6fd2807SJeff Garzik }
690c6fd2807SJeff Garzik handled = 1;
691c6fd2807SJeff Garzik
692c6fd2807SJeff Garzik } else if (qc->tf.protocol == ATA_PROT_DMA) { /* write */
693c6fd2807SJeff Garzik
694c6fd2807SJeff Garzik /* step one - DMA from host to DIMM */
695c6fd2807SJeff Garzik if (doing_hdma) {
696c6fd2807SJeff Garzik u8 seq = (u8) (port_no + 1);
697bc21c105SHannes Reinecke ata_port_dbg(ap, "write hdma, 0x%x 0x%x\n",
698c6fd2807SJeff Garzik readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT));
699c6fd2807SJeff Garzik
700c6fd2807SJeff Garzik /* submit ata pkt */
701c6fd2807SJeff Garzik writel(0x00000001, mmio + PDC_20621_SEQCTL + (seq * 4));
702c6fd2807SJeff Garzik readl(mmio + PDC_20621_SEQCTL + (seq * 4));
703c6fd2807SJeff Garzik writel(port_ofs + PDC_DIMM_ATA_PKT,
7040d5ff566STejun Heo ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
7050d5ff566STejun Heo readl(ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
706c6fd2807SJeff Garzik }
707c6fd2807SJeff Garzik
708c6fd2807SJeff Garzik /* step two - execute ATA command */
709c6fd2807SJeff Garzik else {
710bc21c105SHannes Reinecke ata_port_dbg(ap, "write ata, 0x%x 0x%x\n",
711c6fd2807SJeff Garzik readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT));
712c6fd2807SJeff Garzik /* get drive status; clear intr; complete txn */
713c6fd2807SJeff Garzik qc->err_mask |= ac_err_mask(ata_wait_idle(ap));
714c6fd2807SJeff Garzik ata_qc_complete(qc);
715c6fd2807SJeff Garzik pdc20621_pop_hdma(qc);
716c6fd2807SJeff Garzik }
717c6fd2807SJeff Garzik handled = 1;
718c6fd2807SJeff Garzik
719c6fd2807SJeff Garzik /* command completion, but no data xfer */
720c6fd2807SJeff Garzik } else if (qc->tf.protocol == ATA_PROT_NODATA) {
721c6fd2807SJeff Garzik
7229363c382STejun Heo status = ata_sff_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
723bc21c105SHannes Reinecke ata_port_dbg(ap, "BUS_NODATA (drv_stat 0x%X)\n", status);
724c6fd2807SJeff Garzik qc->err_mask |= ac_err_mask(status);
725c6fd2807SJeff Garzik ata_qc_complete(qc);
726c6fd2807SJeff Garzik handled = 1;
727c6fd2807SJeff Garzik
728c6fd2807SJeff Garzik } else {
729c6fd2807SJeff Garzik ap->stats.idle_irq++;
730c6fd2807SJeff Garzik }
731c6fd2807SJeff Garzik
732c6fd2807SJeff Garzik return handled;
733c6fd2807SJeff Garzik }
734c6fd2807SJeff Garzik
pdc20621_irq_clear(struct ata_port * ap)735c6fd2807SJeff Garzik static void pdc20621_irq_clear(struct ata_port *ap)
736c6fd2807SJeff Garzik {
73719799bfcSDavid Milburn ioread8(ap->ioaddr.status_addr);
738c6fd2807SJeff Garzik }
739c6fd2807SJeff Garzik
pdc20621_interrupt(int irq,void * dev_instance)7407d12e780SDavid Howells static irqreturn_t pdc20621_interrupt(int irq, void *dev_instance)
741c6fd2807SJeff Garzik {
742cca3974eSJeff Garzik struct ata_host *host = dev_instance;
743c6fd2807SJeff Garzik struct ata_port *ap;
744c6fd2807SJeff Garzik u32 mask = 0;
745c6fd2807SJeff Garzik unsigned int i, tmp, port_no;
746c6fd2807SJeff Garzik unsigned int handled = 0;
747c6fd2807SJeff Garzik void __iomem *mmio_base;
748c6fd2807SJeff Garzik
749bc21c105SHannes Reinecke if (!host || !host->iomap[PDC_MMIO_BAR])
750c6fd2807SJeff Garzik return IRQ_NONE;
751c6fd2807SJeff Garzik
7520d5ff566STejun Heo mmio_base = host->iomap[PDC_MMIO_BAR];
753c6fd2807SJeff Garzik
754c6fd2807SJeff Garzik /* reading should also clear interrupts */
755c6fd2807SJeff Garzik mmio_base += PDC_CHIP0_OFS;
756c6fd2807SJeff Garzik mask = readl(mmio_base + PDC_20621_SEQMASK);
757c6fd2807SJeff Garzik
758bc21c105SHannes Reinecke if (mask == 0xffffffff)
759c6fd2807SJeff Garzik return IRQ_NONE;
760bc21c105SHannes Reinecke
761c6fd2807SJeff Garzik mask &= 0xffff; /* only 16 tags possible */
762bc21c105SHannes Reinecke if (!mask)
763c6fd2807SJeff Garzik return IRQ_NONE;
764c6fd2807SJeff Garzik
765cca3974eSJeff Garzik spin_lock(&host->lock);
766c6fd2807SJeff Garzik
767c6fd2807SJeff Garzik for (i = 1; i < 9; i++) {
768c6fd2807SJeff Garzik port_no = i - 1;
769c6fd2807SJeff Garzik if (port_no > 3)
770c6fd2807SJeff Garzik port_no -= 4;
771cca3974eSJeff Garzik if (port_no >= host->n_ports)
772c6fd2807SJeff Garzik ap = NULL;
773c6fd2807SJeff Garzik else
774cca3974eSJeff Garzik ap = host->ports[port_no];
775c6fd2807SJeff Garzik tmp = mask & (1 << i);
776bc21c105SHannes Reinecke if (ap)
777bc21c105SHannes Reinecke ata_port_dbg(ap, "seq %u, tmp %x\n", i, tmp);
7783e4ec344STejun Heo if (tmp && ap) {
779c6fd2807SJeff Garzik struct ata_queued_cmd *qc;
780c6fd2807SJeff Garzik
7819af5c9c9STejun Heo qc = ata_qc_from_tag(ap, ap->link.active_tag);
782c6fd2807SJeff Garzik if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))
783c6fd2807SJeff Garzik handled += pdc20621_host_intr(ap, qc, (i > 4),
784c6fd2807SJeff Garzik mmio_base);
785c6fd2807SJeff Garzik }
786c6fd2807SJeff Garzik }
787c6fd2807SJeff Garzik
788cca3974eSJeff Garzik spin_unlock(&host->lock);
789c6fd2807SJeff Garzik
790c6fd2807SJeff Garzik return IRQ_RETVAL(handled);
791c6fd2807SJeff Garzik }
792c6fd2807SJeff Garzik
pdc_freeze(struct ata_port * ap)79367651ee5SJeff Garzik static void pdc_freeze(struct ata_port *ap)
794c6fd2807SJeff Garzik {
79567651ee5SJeff Garzik void __iomem *mmio = ap->ioaddr.cmd_addr;
79667651ee5SJeff Garzik u32 tmp;
797c6fd2807SJeff Garzik
79867651ee5SJeff Garzik /* FIXME: if all 4 ATA engines are stopped, also stop HDMA engine */
799c6fd2807SJeff Garzik
80067651ee5SJeff Garzik tmp = readl(mmio + PDC_CTLSTAT);
80167651ee5SJeff Garzik tmp |= PDC_MASK_INT;
80267651ee5SJeff Garzik tmp &= ~PDC_DMA_ENABLE;
80367651ee5SJeff Garzik writel(tmp, mmio + PDC_CTLSTAT);
80467651ee5SJeff Garzik readl(mmio + PDC_CTLSTAT); /* flush */
805c6fd2807SJeff Garzik }
806c6fd2807SJeff Garzik
pdc_thaw(struct ata_port * ap)80767651ee5SJeff Garzik static void pdc_thaw(struct ata_port *ap)
80867651ee5SJeff Garzik {
80967651ee5SJeff Garzik void __iomem *mmio = ap->ioaddr.cmd_addr;
81067651ee5SJeff Garzik u32 tmp;
81167651ee5SJeff Garzik
81267651ee5SJeff Garzik /* FIXME: start HDMA engine, if zero ATA engines running */
81367651ee5SJeff Garzik
81419799bfcSDavid Milburn /* clear IRQ */
81519799bfcSDavid Milburn ioread8(ap->ioaddr.status_addr);
81667651ee5SJeff Garzik
81767651ee5SJeff Garzik /* turn IRQ back on */
81867651ee5SJeff Garzik tmp = readl(mmio + PDC_CTLSTAT);
81967651ee5SJeff Garzik tmp &= ~PDC_MASK_INT;
82067651ee5SJeff Garzik writel(tmp, mmio + PDC_CTLSTAT);
82167651ee5SJeff Garzik readl(mmio + PDC_CTLSTAT); /* flush */
82267651ee5SJeff Garzik }
82367651ee5SJeff Garzik
pdc_reset_port(struct ata_port * ap)82467651ee5SJeff Garzik static void pdc_reset_port(struct ata_port *ap)
82567651ee5SJeff Garzik {
82667651ee5SJeff Garzik void __iomem *mmio = ap->ioaddr.cmd_addr + PDC_CTLSTAT;
82767651ee5SJeff Garzik unsigned int i;
82867651ee5SJeff Garzik u32 tmp;
82967651ee5SJeff Garzik
83067651ee5SJeff Garzik /* FIXME: handle HDMA copy engine */
83167651ee5SJeff Garzik
83267651ee5SJeff Garzik for (i = 11; i > 0; i--) {
83367651ee5SJeff Garzik tmp = readl(mmio);
83467651ee5SJeff Garzik if (tmp & PDC_RESET)
83567651ee5SJeff Garzik break;
83667651ee5SJeff Garzik
83767651ee5SJeff Garzik udelay(100);
83867651ee5SJeff Garzik
83967651ee5SJeff Garzik tmp |= PDC_RESET;
84067651ee5SJeff Garzik writel(tmp, mmio);
84167651ee5SJeff Garzik }
84267651ee5SJeff Garzik
84367651ee5SJeff Garzik tmp &= ~PDC_RESET;
84467651ee5SJeff Garzik writel(tmp, mmio);
84567651ee5SJeff Garzik readl(mmio); /* flush */
84667651ee5SJeff Garzik }
84767651ee5SJeff Garzik
pdc_softreset(struct ata_link * link,unsigned int * class,unsigned long deadline)84867651ee5SJeff Garzik static int pdc_softreset(struct ata_link *link, unsigned int *class,
84967651ee5SJeff Garzik unsigned long deadline)
85067651ee5SJeff Garzik {
85167651ee5SJeff Garzik pdc_reset_port(link->ap);
85267651ee5SJeff Garzik return ata_sff_softreset(link, class, deadline);
85367651ee5SJeff Garzik }
85467651ee5SJeff Garzik
pdc_error_handler(struct ata_port * ap)85567651ee5SJeff Garzik static void pdc_error_handler(struct ata_port *ap)
85667651ee5SJeff Garzik {
8574cb7c6f1SNiklas Cassel if (!ata_port_is_frozen(ap))
85867651ee5SJeff Garzik pdc_reset_port(ap);
85967651ee5SJeff Garzik
860fe06e5f9STejun Heo ata_sff_error_handler(ap);
86167651ee5SJeff Garzik }
86267651ee5SJeff Garzik
pdc_post_internal_cmd(struct ata_queued_cmd * qc)86367651ee5SJeff Garzik static void pdc_post_internal_cmd(struct ata_queued_cmd *qc)
86467651ee5SJeff Garzik {
86567651ee5SJeff Garzik struct ata_port *ap = qc->ap;
86667651ee5SJeff Garzik
86767651ee5SJeff Garzik /* make DMA engine forget about the failed command */
86887629312SNiklas Cassel if (qc->flags & ATA_QCFLAG_EH)
86967651ee5SJeff Garzik pdc_reset_port(ap);
87067651ee5SJeff Garzik }
87167651ee5SJeff Garzik
pdc_check_atapi_dma(struct ata_queued_cmd * qc)87267651ee5SJeff Garzik static int pdc_check_atapi_dma(struct ata_queued_cmd *qc)
87367651ee5SJeff Garzik {
87467651ee5SJeff Garzik u8 *scsicmd = qc->scsicmd->cmnd;
87567651ee5SJeff Garzik int pio = 1; /* atapi dma off by default */
87667651ee5SJeff Garzik
87767651ee5SJeff Garzik /* Whitelist commands that may use DMA. */
87867651ee5SJeff Garzik switch (scsicmd[0]) {
87967651ee5SJeff Garzik case WRITE_12:
88067651ee5SJeff Garzik case WRITE_10:
88167651ee5SJeff Garzik case WRITE_6:
88267651ee5SJeff Garzik case READ_12:
88367651ee5SJeff Garzik case READ_10:
88467651ee5SJeff Garzik case READ_6:
88567651ee5SJeff Garzik case 0xad: /* READ_DVD_STRUCTURE */
88667651ee5SJeff Garzik case 0xbe: /* READ_CD */
88767651ee5SJeff Garzik pio = 0;
88867651ee5SJeff Garzik }
88967651ee5SJeff Garzik /* -45150 (FFFF4FA2) to -1 (FFFFFFFF) shall use PIO mode */
89067651ee5SJeff Garzik if (scsicmd[0] == WRITE_10) {
89167651ee5SJeff Garzik unsigned int lba =
89267651ee5SJeff Garzik (scsicmd[2] << 24) |
89367651ee5SJeff Garzik (scsicmd[3] << 16) |
89467651ee5SJeff Garzik (scsicmd[4] << 8) |
89567651ee5SJeff Garzik scsicmd[5];
89667651ee5SJeff Garzik if (lba >= 0xFFFF4FA2)
89767651ee5SJeff Garzik pio = 1;
89867651ee5SJeff Garzik }
89967651ee5SJeff Garzik return pio;
900c6fd2807SJeff Garzik }
901c6fd2807SJeff Garzik
pdc_tf_load_mmio(struct ata_port * ap,const struct ata_taskfile * tf)902c6fd2807SJeff Garzik static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
903c6fd2807SJeff Garzik {
904c6fd2807SJeff Garzik WARN_ON(tf->protocol == ATA_PROT_DMA ||
90519799bfcSDavid Milburn tf->protocol == ATAPI_PROT_DMA);
9069363c382STejun Heo ata_sff_tf_load(ap, tf);
907c6fd2807SJeff Garzik }
908c6fd2807SJeff Garzik
909c6fd2807SJeff Garzik
pdc_exec_command_mmio(struct ata_port * ap,const struct ata_taskfile * tf)910c6fd2807SJeff Garzik static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
911c6fd2807SJeff Garzik {
912c6fd2807SJeff Garzik WARN_ON(tf->protocol == ATA_PROT_DMA ||
91319799bfcSDavid Milburn tf->protocol == ATAPI_PROT_DMA);
9149363c382STejun Heo ata_sff_exec_command(ap, tf);
915c6fd2807SJeff Garzik }
916c6fd2807SJeff Garzik
917c6fd2807SJeff Garzik
pdc_sata_setup_port(struct ata_ioports * port,void __iomem * base)9180d5ff566STejun Heo static void pdc_sata_setup_port(struct ata_ioports *port, void __iomem *base)
919c6fd2807SJeff Garzik {
920c6fd2807SJeff Garzik port->cmd_addr = base;
921c6fd2807SJeff Garzik port->data_addr = base;
922c6fd2807SJeff Garzik port->feature_addr =
923c6fd2807SJeff Garzik port->error_addr = base + 0x4;
924c6fd2807SJeff Garzik port->nsect_addr = base + 0x8;
925c6fd2807SJeff Garzik port->lbal_addr = base + 0xc;
926c6fd2807SJeff Garzik port->lbam_addr = base + 0x10;
927c6fd2807SJeff Garzik port->lbah_addr = base + 0x14;
928c6fd2807SJeff Garzik port->device_addr = base + 0x18;
929c6fd2807SJeff Garzik port->command_addr =
930c6fd2807SJeff Garzik port->status_addr = base + 0x1c;
931c6fd2807SJeff Garzik port->altstatus_addr =
932c6fd2807SJeff Garzik port->ctl_addr = base + 0x38;
933c6fd2807SJeff Garzik }
934c6fd2807SJeff Garzik
935c6fd2807SJeff Garzik
pdc20621_get_from_dimm(struct ata_host * host,void * psource,u32 offset,u32 size)9364447d351STejun Heo static void pdc20621_get_from_dimm(struct ata_host *host, void *psource,
937c6fd2807SJeff Garzik u32 offset, u32 size)
938c6fd2807SJeff Garzik {
939c6fd2807SJeff Garzik u32 window_size;
940c6fd2807SJeff Garzik u16 idx;
941c6fd2807SJeff Garzik u8 page_mask;
942c6fd2807SJeff Garzik long dist;
9434447d351STejun Heo void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
9444447d351STejun Heo void __iomem *dimm_mmio = host->iomap[PDC_DIMM_BAR];
945c6fd2807SJeff Garzik
946c6fd2807SJeff Garzik /* hard-code chip #0 */
947c6fd2807SJeff Garzik mmio += PDC_CHIP0_OFS;
948c6fd2807SJeff Garzik
949c6fd2807SJeff Garzik page_mask = 0x00;
950c6fd2807SJeff Garzik window_size = 0x2000 * 4; /* 32K byte uchar size */
951c6fd2807SJeff Garzik idx = (u16) (offset / window_size);
952c6fd2807SJeff Garzik
953c6fd2807SJeff Garzik writel(0x01, mmio + PDC_GENERAL_CTLR);
954c6fd2807SJeff Garzik readl(mmio + PDC_GENERAL_CTLR);
955c6fd2807SJeff Garzik writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
956c6fd2807SJeff Garzik readl(mmio + PDC_DIMM_WINDOW_CTLR);
957c6fd2807SJeff Garzik
958c6fd2807SJeff Garzik offset -= (idx * window_size);
959c6fd2807SJeff Garzik idx++;
960*4cad40d9SArnd Bergmann dist = min(size, window_size - offset);
961d5185d65SJoe Perches memcpy_fromio(psource, dimm_mmio + offset / 4, dist);
962c6fd2807SJeff Garzik
963c6fd2807SJeff Garzik psource += dist;
964c6fd2807SJeff Garzik size -= dist;
965c6fd2807SJeff Garzik for (; (long) size >= (long) window_size ;) {
966c6fd2807SJeff Garzik writel(0x01, mmio + PDC_GENERAL_CTLR);
967c6fd2807SJeff Garzik readl(mmio + PDC_GENERAL_CTLR);
968c6fd2807SJeff Garzik writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
969c6fd2807SJeff Garzik readl(mmio + PDC_DIMM_WINDOW_CTLR);
970d5185d65SJoe Perches memcpy_fromio(psource, dimm_mmio, window_size / 4);
971c6fd2807SJeff Garzik psource += window_size;
972c6fd2807SJeff Garzik size -= window_size;
973c6fd2807SJeff Garzik idx++;
974c6fd2807SJeff Garzik }
975c6fd2807SJeff Garzik
976c6fd2807SJeff Garzik if (size) {
977c6fd2807SJeff Garzik writel(0x01, mmio + PDC_GENERAL_CTLR);
978c6fd2807SJeff Garzik readl(mmio + PDC_GENERAL_CTLR);
979c6fd2807SJeff Garzik writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
980c6fd2807SJeff Garzik readl(mmio + PDC_DIMM_WINDOW_CTLR);
981d5185d65SJoe Perches memcpy_fromio(psource, dimm_mmio, size / 4);
982c6fd2807SJeff Garzik }
983c6fd2807SJeff Garzik }
984c6fd2807SJeff Garzik
985c6fd2807SJeff Garzik
pdc20621_put_to_dimm(struct ata_host * host,void * psource,u32 offset,u32 size)9864447d351STejun Heo static void pdc20621_put_to_dimm(struct ata_host *host, void *psource,
987c6fd2807SJeff Garzik u32 offset, u32 size)
988c6fd2807SJeff Garzik {
989c6fd2807SJeff Garzik u32 window_size;
990c6fd2807SJeff Garzik u16 idx;
991c6fd2807SJeff Garzik u8 page_mask;
992c6fd2807SJeff Garzik long dist;
9934447d351STejun Heo void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
9944447d351STejun Heo void __iomem *dimm_mmio = host->iomap[PDC_DIMM_BAR];
995c6fd2807SJeff Garzik
996c6fd2807SJeff Garzik /* hard-code chip #0 */
997c6fd2807SJeff Garzik mmio += PDC_CHIP0_OFS;
998c6fd2807SJeff Garzik
999c6fd2807SJeff Garzik page_mask = 0x00;
1000c6fd2807SJeff Garzik window_size = 0x2000 * 4; /* 32K byte uchar size */
1001c6fd2807SJeff Garzik idx = (u16) (offset / window_size);
1002c6fd2807SJeff Garzik
1003c6fd2807SJeff Garzik writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
1004c6fd2807SJeff Garzik readl(mmio + PDC_DIMM_WINDOW_CTLR);
1005c6fd2807SJeff Garzik offset -= (idx * window_size);
1006c6fd2807SJeff Garzik idx++;
1007*4cad40d9SArnd Bergmann dist = min(size, window_size - offset);
1008c6fd2807SJeff Garzik memcpy_toio(dimm_mmio + offset / 4, psource, dist);
1009c6fd2807SJeff Garzik writel(0x01, mmio + PDC_GENERAL_CTLR);
1010c6fd2807SJeff Garzik readl(mmio + PDC_GENERAL_CTLR);
1011c6fd2807SJeff Garzik
1012c6fd2807SJeff Garzik psource += dist;
1013c6fd2807SJeff Garzik size -= dist;
1014c6fd2807SJeff Garzik for (; (long) size >= (long) window_size ;) {
1015c6fd2807SJeff Garzik writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
1016c6fd2807SJeff Garzik readl(mmio + PDC_DIMM_WINDOW_CTLR);
1017c6fd2807SJeff Garzik memcpy_toio(dimm_mmio, psource, window_size / 4);
1018c6fd2807SJeff Garzik writel(0x01, mmio + PDC_GENERAL_CTLR);
1019c6fd2807SJeff Garzik readl(mmio + PDC_GENERAL_CTLR);
1020c6fd2807SJeff Garzik psource += window_size;
1021c6fd2807SJeff Garzik size -= window_size;
1022c6fd2807SJeff Garzik idx++;
1023c6fd2807SJeff Garzik }
1024c6fd2807SJeff Garzik
1025c6fd2807SJeff Garzik if (size) {
1026c6fd2807SJeff Garzik writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
1027c6fd2807SJeff Garzik readl(mmio + PDC_DIMM_WINDOW_CTLR);
1028c6fd2807SJeff Garzik memcpy_toio(dimm_mmio, psource, size / 4);
1029c6fd2807SJeff Garzik writel(0x01, mmio + PDC_GENERAL_CTLR);
1030c6fd2807SJeff Garzik readl(mmio + PDC_GENERAL_CTLR);
1031c6fd2807SJeff Garzik }
1032c6fd2807SJeff Garzik }
1033c6fd2807SJeff Garzik
1034c6fd2807SJeff Garzik
pdc20621_i2c_read(struct ata_host * host,u32 device,u32 subaddr,u32 * pdata)10354447d351STejun Heo static unsigned int pdc20621_i2c_read(struct ata_host *host, u32 device,
1036c6fd2807SJeff Garzik u32 subaddr, u32 *pdata)
1037c6fd2807SJeff Garzik {
10384447d351STejun Heo void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
1039c6fd2807SJeff Garzik u32 i2creg = 0;
1040c6fd2807SJeff Garzik u32 status;
1041c6fd2807SJeff Garzik u32 count = 0;
1042c6fd2807SJeff Garzik
1043c6fd2807SJeff Garzik /* hard-code chip #0 */
1044c6fd2807SJeff Garzik mmio += PDC_CHIP0_OFS;
1045c6fd2807SJeff Garzik
1046c6fd2807SJeff Garzik i2creg |= device << 24;
1047c6fd2807SJeff Garzik i2creg |= subaddr << 16;
1048c6fd2807SJeff Garzik
1049c6fd2807SJeff Garzik /* Set the device and subaddress */
1050b2d46b61SJeff Garzik writel(i2creg, mmio + PDC_I2C_ADDR_DATA);
1051b2d46b61SJeff Garzik readl(mmio + PDC_I2C_ADDR_DATA);
1052c6fd2807SJeff Garzik
1053c6fd2807SJeff Garzik /* Write Control to perform read operation, mask int */
1054c6fd2807SJeff Garzik writel(PDC_I2C_READ | PDC_I2C_START | PDC_I2C_MASK_INT,
1055b2d46b61SJeff Garzik mmio + PDC_I2C_CONTROL);
1056c6fd2807SJeff Garzik
1057c6fd2807SJeff Garzik for (count = 0; count <= 1000; count ++) {
1058b2d46b61SJeff Garzik status = readl(mmio + PDC_I2C_CONTROL);
1059c6fd2807SJeff Garzik if (status & PDC_I2C_COMPLETE) {
1060b2d46b61SJeff Garzik status = readl(mmio + PDC_I2C_ADDR_DATA);
1061c6fd2807SJeff Garzik break;
1062c6fd2807SJeff Garzik } else if (count == 1000)
1063c6fd2807SJeff Garzik return 0;
1064c6fd2807SJeff Garzik }
1065c6fd2807SJeff Garzik
1066c6fd2807SJeff Garzik *pdata = (status >> 8) & 0x000000ff;
1067c6fd2807SJeff Garzik return 1;
1068c6fd2807SJeff Garzik }
1069c6fd2807SJeff Garzik
1070c6fd2807SJeff Garzik
pdc20621_detect_dimm(struct ata_host * host)10714447d351STejun Heo static int pdc20621_detect_dimm(struct ata_host *host)
1072c6fd2807SJeff Garzik {
1073c6fd2807SJeff Garzik u32 data = 0;
10744447d351STejun Heo if (pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS,
1075c6fd2807SJeff Garzik PDC_DIMM_SPD_SYSTEM_FREQ, &data)) {
1076c6fd2807SJeff Garzik if (data == 100)
1077c6fd2807SJeff Garzik return 100;
1078c6fd2807SJeff Garzik } else
1079c6fd2807SJeff Garzik return 0;
1080c6fd2807SJeff Garzik
10814447d351STejun Heo if (pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS, 9, &data)) {
1082c6fd2807SJeff Garzik if (data <= 0x75)
1083c6fd2807SJeff Garzik return 133;
1084c6fd2807SJeff Garzik } else
1085c6fd2807SJeff Garzik return 0;
1086c6fd2807SJeff Garzik
1087c6fd2807SJeff Garzik return 0;
1088c6fd2807SJeff Garzik }
1089c6fd2807SJeff Garzik
1090c6fd2807SJeff Garzik
pdc20621_prog_dimm0(struct ata_host * host)10914447d351STejun Heo static int pdc20621_prog_dimm0(struct ata_host *host)
1092c6fd2807SJeff Garzik {
1093c6fd2807SJeff Garzik u32 spd0[50];
1094c6fd2807SJeff Garzik u32 data = 0;
1095c6fd2807SJeff Garzik int size, i;
1096c6fd2807SJeff Garzik u8 bdimmsize;
10974447d351STejun Heo void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
1098c6fd2807SJeff Garzik static const struct {
1099c6fd2807SJeff Garzik unsigned int reg;
1100c6fd2807SJeff Garzik unsigned int ofs;
1101c6fd2807SJeff Garzik } pdc_i2c_read_data [] = {
1102c6fd2807SJeff Garzik { PDC_DIMM_SPD_TYPE, 11 },
1103c6fd2807SJeff Garzik { PDC_DIMM_SPD_FRESH_RATE, 12 },
1104c6fd2807SJeff Garzik { PDC_DIMM_SPD_COLUMN_NUM, 4 },
1105c6fd2807SJeff Garzik { PDC_DIMM_SPD_ATTRIBUTE, 21 },
1106c6fd2807SJeff Garzik { PDC_DIMM_SPD_ROW_NUM, 3 },
1107c6fd2807SJeff Garzik { PDC_DIMM_SPD_BANK_NUM, 17 },
1108c6fd2807SJeff Garzik { PDC_DIMM_SPD_MODULE_ROW, 5 },
1109c6fd2807SJeff Garzik { PDC_DIMM_SPD_ROW_PRE_CHARGE, 27 },
1110c6fd2807SJeff Garzik { PDC_DIMM_SPD_ROW_ACTIVE_DELAY, 28 },
1111c6fd2807SJeff Garzik { PDC_DIMM_SPD_RAS_CAS_DELAY, 29 },
1112c6fd2807SJeff Garzik { PDC_DIMM_SPD_ACTIVE_PRECHARGE, 30 },
1113c6fd2807SJeff Garzik { PDC_DIMM_SPD_CAS_LATENCY, 18 },
1114c6fd2807SJeff Garzik };
1115c6fd2807SJeff Garzik
1116c6fd2807SJeff Garzik /* hard-code chip #0 */
1117c6fd2807SJeff Garzik mmio += PDC_CHIP0_OFS;
1118c6fd2807SJeff Garzik
1119c6fd2807SJeff Garzik for (i = 0; i < ARRAY_SIZE(pdc_i2c_read_data); i++)
11204447d351STejun Heo pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS,
1121c6fd2807SJeff Garzik pdc_i2c_read_data[i].reg,
1122c6fd2807SJeff Garzik &spd0[pdc_i2c_read_data[i].ofs]);
1123c6fd2807SJeff Garzik
1124c6fd2807SJeff Garzik data |= (spd0[4] - 8) | ((spd0[21] != 0) << 3) | ((spd0[3]-11) << 4);
1125c6fd2807SJeff Garzik data |= ((spd0[17] / 4) << 6) | ((spd0[5] / 2) << 7) |
1126c6fd2807SJeff Garzik ((((spd0[27] + 9) / 10) - 1) << 8) ;
1127c6fd2807SJeff Garzik data |= (((((spd0[29] > spd0[28])
1128c6fd2807SJeff Garzik ? spd0[29] : spd0[28]) + 9) / 10) - 1) << 10;
1129c6fd2807SJeff Garzik data |= ((spd0[30] - spd0[29] + 9) / 10 - 2) << 12;
1130c6fd2807SJeff Garzik
1131c6fd2807SJeff Garzik if (spd0[18] & 0x08)
1132c6fd2807SJeff Garzik data |= ((0x03) << 14);
1133c6fd2807SJeff Garzik else if (spd0[18] & 0x04)
1134c6fd2807SJeff Garzik data |= ((0x02) << 14);
1135c6fd2807SJeff Garzik else if (spd0[18] & 0x01)
1136c6fd2807SJeff Garzik data |= ((0x01) << 14);
1137c6fd2807SJeff Garzik else
1138c6fd2807SJeff Garzik data |= (0 << 14);
1139c6fd2807SJeff Garzik
1140c6fd2807SJeff Garzik /*
1141c6fd2807SJeff Garzik Calculate the size of bDIMMSize (power of 2) and
1142c6fd2807SJeff Garzik merge the DIMM size by program start/end address.
1143c6fd2807SJeff Garzik */
1144c6fd2807SJeff Garzik
1145c6fd2807SJeff Garzik bdimmsize = spd0[4] + (spd0[5] / 2) + spd0[3] + (spd0[17] / 2) + 3;
1146c6fd2807SJeff Garzik size = (1 << bdimmsize) >> 20; /* size = xxx(MB) */
1147c6fd2807SJeff Garzik data |= (((size / 16) - 1) << 16);
1148c6fd2807SJeff Garzik data |= (0 << 23);
1149c6fd2807SJeff Garzik data |= 8;
1150b2d46b61SJeff Garzik writel(data, mmio + PDC_DIMM0_CONTROL);
1151b2d46b61SJeff Garzik readl(mmio + PDC_DIMM0_CONTROL);
1152c6fd2807SJeff Garzik return size;
1153c6fd2807SJeff Garzik }
1154c6fd2807SJeff Garzik
1155c6fd2807SJeff Garzik
pdc20621_prog_dimm_global(struct ata_host * host)11564447d351STejun Heo static unsigned int pdc20621_prog_dimm_global(struct ata_host *host)
1157c6fd2807SJeff Garzik {
1158c6fd2807SJeff Garzik u32 data, spd0;
1159c6fd2807SJeff Garzik int error, i;
11604447d351STejun Heo void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
1161c6fd2807SJeff Garzik
1162c6fd2807SJeff Garzik /* hard-code chip #0 */
1163c6fd2807SJeff Garzik mmio += PDC_CHIP0_OFS;
1164c6fd2807SJeff Garzik
1165c6fd2807SJeff Garzik /*
1166c6fd2807SJeff Garzik Set To Default : DIMM Module Global Control Register (0x022259F1)
1167c6fd2807SJeff Garzik DIMM Arbitration Disable (bit 20)
1168c6fd2807SJeff Garzik DIMM Data/Control Output Driving Selection (bit12 - bit15)
1169c6fd2807SJeff Garzik Refresh Enable (bit 17)
1170c6fd2807SJeff Garzik */
1171c6fd2807SJeff Garzik
1172c6fd2807SJeff Garzik data = 0x022259F1;
1173b2d46b61SJeff Garzik writel(data, mmio + PDC_SDRAM_CONTROL);
1174b2d46b61SJeff Garzik readl(mmio + PDC_SDRAM_CONTROL);
1175c6fd2807SJeff Garzik
1176c6fd2807SJeff Garzik /* Turn on for ECC */
1177bb44e154STomer Barletz if (!pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS,
1178bb44e154STomer Barletz PDC_DIMM_SPD_TYPE, &spd0)) {
117916d6623fSHannes Reinecke dev_err(host->dev,
118016d6623fSHannes Reinecke "Failed in i2c read: device=%#x, subaddr=%#x\n",
1181bb44e154STomer Barletz PDC_DIMM0_SPD_DEV_ADDRESS, PDC_DIMM_SPD_TYPE);
1182bb44e154STomer Barletz return 1;
1183bb44e154STomer Barletz }
1184c6fd2807SJeff Garzik if (spd0 == 0x02) {
1185c6fd2807SJeff Garzik data |= (0x01 << 16);
1186b2d46b61SJeff Garzik writel(data, mmio + PDC_SDRAM_CONTROL);
1187b2d46b61SJeff Garzik readl(mmio + PDC_SDRAM_CONTROL);
118816d6623fSHannes Reinecke dev_err(host->dev, "Local DIMM ECC Enabled\n");
1189c6fd2807SJeff Garzik }
1190c6fd2807SJeff Garzik
1191c6fd2807SJeff Garzik /* DIMM Initialization Select/Enable (bit 18/19) */
1192c6fd2807SJeff Garzik data &= (~(1<<18));
1193c6fd2807SJeff Garzik data |= (1<<19);
1194b2d46b61SJeff Garzik writel(data, mmio + PDC_SDRAM_CONTROL);
1195c6fd2807SJeff Garzik
1196c6fd2807SJeff Garzik error = 1;
1197c6fd2807SJeff Garzik for (i = 1; i <= 10; i++) { /* polling ~5 secs */
1198b2d46b61SJeff Garzik data = readl(mmio + PDC_SDRAM_CONTROL);
1199c6fd2807SJeff Garzik if (!(data & (1<<19))) {
1200c6fd2807SJeff Garzik error = 0;
1201c6fd2807SJeff Garzik break;
1202c6fd2807SJeff Garzik }
1203c6fd2807SJeff Garzik msleep(i*100);
1204c6fd2807SJeff Garzik }
1205c6fd2807SJeff Garzik return error;
1206c6fd2807SJeff Garzik }
1207c6fd2807SJeff Garzik
1208c6fd2807SJeff Garzik
pdc20621_dimm_init(struct ata_host * host)12094447d351STejun Heo static unsigned int pdc20621_dimm_init(struct ata_host *host)
1210c6fd2807SJeff Garzik {
1211c6fd2807SJeff Garzik int speed, size, length;
1212c6fd2807SJeff Garzik u32 addr, spd0, pci_status;
1213c6fd2807SJeff Garzik u32 time_period = 0;
1214c6fd2807SJeff Garzik u32 tcount = 0;
1215c6fd2807SJeff Garzik u32 ticks = 0;
1216c6fd2807SJeff Garzik u32 clock = 0;
1217c6fd2807SJeff Garzik u32 fparam = 0;
12184447d351STejun Heo void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
1219c6fd2807SJeff Garzik
1220c6fd2807SJeff Garzik /* hard-code chip #0 */
1221c6fd2807SJeff Garzik mmio += PDC_CHIP0_OFS;
1222c6fd2807SJeff Garzik
1223c6fd2807SJeff Garzik /* Initialize PLL based upon PCI Bus Frequency */
1224c6fd2807SJeff Garzik
1225c6fd2807SJeff Garzik /* Initialize Time Period Register */
1226c6fd2807SJeff Garzik writel(0xffffffff, mmio + PDC_TIME_PERIOD);
1227c6fd2807SJeff Garzik time_period = readl(mmio + PDC_TIME_PERIOD);
1228bc21c105SHannes Reinecke dev_dbg(host->dev, "Time Period Register (0x40): 0x%x\n", time_period);
1229c6fd2807SJeff Garzik
1230c6fd2807SJeff Garzik /* Enable timer */
1231b2d46b61SJeff Garzik writel(PDC_TIMER_DEFAULT, mmio + PDC_TIME_CONTROL);
1232c6fd2807SJeff Garzik readl(mmio + PDC_TIME_CONTROL);
1233c6fd2807SJeff Garzik
1234c6fd2807SJeff Garzik /* Wait 3 seconds */
1235c6fd2807SJeff Garzik msleep(3000);
1236c6fd2807SJeff Garzik
1237c6fd2807SJeff Garzik /*
1238c6fd2807SJeff Garzik When timer is enabled, counter is decreased every internal
1239c6fd2807SJeff Garzik clock cycle.
1240c6fd2807SJeff Garzik */
1241c6fd2807SJeff Garzik
1242c6fd2807SJeff Garzik tcount = readl(mmio + PDC_TIME_COUNTER);
1243bc21c105SHannes Reinecke dev_dbg(host->dev, "Time Counter Register (0x44): 0x%x\n", tcount);
1244c6fd2807SJeff Garzik
1245c6fd2807SJeff Garzik /*
1246c6fd2807SJeff Garzik If SX4 is on PCI-X bus, after 3 seconds, the timer counter
1247c6fd2807SJeff Garzik register should be >= (0xffffffff - 3x10^8).
1248c6fd2807SJeff Garzik */
1249c6fd2807SJeff Garzik if (tcount >= PCI_X_TCOUNT) {
1250c6fd2807SJeff Garzik ticks = (time_period - tcount);
1251bc21c105SHannes Reinecke dev_dbg(host->dev, "Num counters 0x%x (%d)\n", ticks, ticks);
1252c6fd2807SJeff Garzik
1253c6fd2807SJeff Garzik clock = (ticks / 300000);
1254bc21c105SHannes Reinecke dev_dbg(host->dev, "10 * Internal clk = 0x%x (%d)\n",
1255bc21c105SHannes Reinecke clock, clock);
1256c6fd2807SJeff Garzik
1257c6fd2807SJeff Garzik clock = (clock * 33);
1258bc21c105SHannes Reinecke dev_dbg(host->dev, "10 * Internal clk * 33 = 0x%x (%d)\n",
1259bc21c105SHannes Reinecke clock, clock);
1260c6fd2807SJeff Garzik
1261c6fd2807SJeff Garzik /* PLL F Param (bit 22:16) */
1262c6fd2807SJeff Garzik fparam = (1400000 / clock) - 2;
1263bc21c105SHannes Reinecke dev_dbg(host->dev, "PLL F Param: 0x%x (%d)\n", fparam, fparam);
1264c6fd2807SJeff Garzik
1265c6fd2807SJeff Garzik /* OD param = 0x2 (bit 31:30), R param = 0x5 (bit 29:25) */
1266c6fd2807SJeff Garzik pci_status = (0x8a001824 | (fparam << 16));
1267c6fd2807SJeff Garzik } else
1268c6fd2807SJeff Garzik pci_status = PCI_PLL_INIT;
1269c6fd2807SJeff Garzik
1270c6fd2807SJeff Garzik /* Initialize PLL. */
1271bc21c105SHannes Reinecke dev_dbg(host->dev, "pci_status: 0x%x\n", pci_status);
1272c6fd2807SJeff Garzik writel(pci_status, mmio + PDC_CTL_STATUS);
1273c6fd2807SJeff Garzik readl(mmio + PDC_CTL_STATUS);
1274c6fd2807SJeff Garzik
1275c6fd2807SJeff Garzik /*
1276c6fd2807SJeff Garzik Read SPD of DIMM by I2C interface,
1277c6fd2807SJeff Garzik and program the DIMM Module Controller.
1278c6fd2807SJeff Garzik */
12794447d351STejun Heo if (!(speed = pdc20621_detect_dimm(host))) {
128016d6623fSHannes Reinecke dev_err(host->dev, "Detect Local DIMM Fail\n");
1281c6fd2807SJeff Garzik return 1; /* DIMM error */
1282c6fd2807SJeff Garzik }
1283bc21c105SHannes Reinecke dev_dbg(host->dev, "Local DIMM Speed = %d\n", speed);
1284c6fd2807SJeff Garzik
1285c6fd2807SJeff Garzik /* Programming DIMM0 Module Control Register (index_CID0:80h) */
12864447d351STejun Heo size = pdc20621_prog_dimm0(host);
1287bc21c105SHannes Reinecke dev_dbg(host->dev, "Local DIMM Size = %dMB\n", size);
1288c6fd2807SJeff Garzik
1289c6fd2807SJeff Garzik /* Programming DIMM Module Global Control Register (index_CID0:88h) */
12904447d351STejun Heo if (pdc20621_prog_dimm_global(host)) {
1291bc21c105SHannes Reinecke dev_err(host->dev,
1292bc21c105SHannes Reinecke "Programming DIMM Module Global Control Register Fail\n");
1293c6fd2807SJeff Garzik return 1;
1294c6fd2807SJeff Garzik }
1295c6fd2807SJeff Garzik
1296f11c5403SHannes Reinecke if (dimm_test) {
12975796d1c4SJeff Garzik u8 test_parttern1[40] =
12985796d1c4SJeff Garzik {0x55,0xAA,'P','r','o','m','i','s','e',' ',
12995796d1c4SJeff Garzik 'N','o','t',' ','Y','e','t',' ',
13005796d1c4SJeff Garzik 'D','e','f','i','n','e','d',' ',
1301c6fd2807SJeff Garzik '1','.','1','0',
1302c6fd2807SJeff Garzik '9','8','0','3','1','6','1','2',0,0};
1303c6fd2807SJeff Garzik u8 test_parttern2[40] = {0};
1304c6fd2807SJeff Garzik
13055796d1c4SJeff Garzik pdc20621_put_to_dimm(host, test_parttern2, 0x10040, 40);
13065796d1c4SJeff Garzik pdc20621_put_to_dimm(host, test_parttern2, 0x40, 40);
1307c6fd2807SJeff Garzik
13085796d1c4SJeff Garzik pdc20621_put_to_dimm(host, test_parttern1, 0x10040, 40);
13095796d1c4SJeff Garzik pdc20621_get_from_dimm(host, test_parttern2, 0x40, 40);
1310f11c5403SHannes Reinecke dev_info(host->dev, "DIMM test pattern 1: %x, %x, %s\n", test_parttern2[0],
1311c6fd2807SJeff Garzik test_parttern2[1], &(test_parttern2[2]));
13125796d1c4SJeff Garzik pdc20621_get_from_dimm(host, test_parttern2, 0x10040,
1313c6fd2807SJeff Garzik 40);
1314f11c5403SHannes Reinecke dev_info(host->dev, "DIMM test pattern 2: %x, %x, %s\n",
1315f11c5403SHannes Reinecke test_parttern2[0],
1316c6fd2807SJeff Garzik test_parttern2[1], &(test_parttern2[2]));
1317c6fd2807SJeff Garzik
13185796d1c4SJeff Garzik pdc20621_put_to_dimm(host, test_parttern1, 0x40, 40);
13195796d1c4SJeff Garzik pdc20621_get_from_dimm(host, test_parttern2, 0x40, 40);
1320f11c5403SHannes Reinecke dev_info(host->dev, "DIMM test pattern 3: %x, %x, %s\n",
1321f11c5403SHannes Reinecke test_parttern2[0],
1322c6fd2807SJeff Garzik test_parttern2[1], &(test_parttern2[2]));
1323c6fd2807SJeff Garzik }
1324c6fd2807SJeff Garzik
1325c6fd2807SJeff Garzik /* ECC initiliazation. */
1326c6fd2807SJeff Garzik
1327bb44e154STomer Barletz if (!pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS,
1328bb44e154STomer Barletz PDC_DIMM_SPD_TYPE, &spd0)) {
1329bc21c105SHannes Reinecke dev_err(host->dev,
1330bc21c105SHannes Reinecke "Failed in i2c read: device=%#x, subaddr=%#x\n",
1331bb44e154STomer Barletz PDC_DIMM0_SPD_DEV_ADDRESS, PDC_DIMM_SPD_TYPE);
1332bb44e154STomer Barletz return 1;
1333bb44e154STomer Barletz }
1334c6fd2807SJeff Garzik if (spd0 == 0x02) {
1335f35b5e7cSAlexander Beregalov void *buf;
1336bc21c105SHannes Reinecke dev_dbg(host->dev, "Start ECC initialization\n");
1337c6fd2807SJeff Garzik addr = 0;
1338c6fd2807SJeff Garzik length = size * 1024 * 1024;
1339f35b5e7cSAlexander Beregalov buf = kzalloc(ECC_ERASE_BUF_SZ, GFP_KERNEL);
1340427cc61aSInsu Yun if (!buf)
1341427cc61aSInsu Yun return 1;
1342c6fd2807SJeff Garzik while (addr < length) {
1343f35b5e7cSAlexander Beregalov pdc20621_put_to_dimm(host, buf, addr,
1344f35b5e7cSAlexander Beregalov ECC_ERASE_BUF_SZ);
1345f35b5e7cSAlexander Beregalov addr += ECC_ERASE_BUF_SZ;
1346c6fd2807SJeff Garzik }
1347f35b5e7cSAlexander Beregalov kfree(buf);
1348bc21c105SHannes Reinecke dev_dbg(host->dev, "Finish ECC initialization\n");
1349c6fd2807SJeff Garzik }
1350c6fd2807SJeff Garzik return 0;
1351c6fd2807SJeff Garzik }
1352c6fd2807SJeff Garzik
1353c6fd2807SJeff Garzik
pdc_20621_init(struct ata_host * host)13544447d351STejun Heo static void pdc_20621_init(struct ata_host *host)
1355c6fd2807SJeff Garzik {
1356c6fd2807SJeff Garzik u32 tmp;
13574447d351STejun Heo void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
1358c6fd2807SJeff Garzik
1359c6fd2807SJeff Garzik /* hard-code chip #0 */
1360c6fd2807SJeff Garzik mmio += PDC_CHIP0_OFS;
1361c6fd2807SJeff Garzik
1362c6fd2807SJeff Garzik /*
1363c6fd2807SJeff Garzik * Select page 0x40 for our 32k DIMM window
1364c6fd2807SJeff Garzik */
1365c6fd2807SJeff Garzik tmp = readl(mmio + PDC_20621_DIMM_WINDOW) & 0xffff0000;
1366c6fd2807SJeff Garzik tmp |= PDC_PAGE_WINDOW; /* page 40h; arbitrarily selected */
1367c6fd2807SJeff Garzik writel(tmp, mmio + PDC_20621_DIMM_WINDOW);
1368c6fd2807SJeff Garzik
1369c6fd2807SJeff Garzik /*
1370c6fd2807SJeff Garzik * Reset Host DMA
1371c6fd2807SJeff Garzik */
1372c6fd2807SJeff Garzik tmp = readl(mmio + PDC_HDMA_CTLSTAT);
1373c6fd2807SJeff Garzik tmp |= PDC_RESET;
1374c6fd2807SJeff Garzik writel(tmp, mmio + PDC_HDMA_CTLSTAT);
1375c6fd2807SJeff Garzik readl(mmio + PDC_HDMA_CTLSTAT); /* flush */
1376c6fd2807SJeff Garzik
1377c6fd2807SJeff Garzik udelay(10);
1378c6fd2807SJeff Garzik
1379c6fd2807SJeff Garzik tmp = readl(mmio + PDC_HDMA_CTLSTAT);
1380c6fd2807SJeff Garzik tmp &= ~PDC_RESET;
1381c6fd2807SJeff Garzik writel(tmp, mmio + PDC_HDMA_CTLSTAT);
1382c6fd2807SJeff Garzik readl(mmio + PDC_HDMA_CTLSTAT); /* flush */
1383c6fd2807SJeff Garzik }
1384c6fd2807SJeff Garzik
pdc_sata_init_one(struct pci_dev * pdev,const struct pci_device_id * ent)13855796d1c4SJeff Garzik static int pdc_sata_init_one(struct pci_dev *pdev,
13865796d1c4SJeff Garzik const struct pci_device_id *ent)
1387c6fd2807SJeff Garzik {
13884447d351STejun Heo const struct ata_port_info *ppi[] =
13894447d351STejun Heo { &pdc_port_info[ent->driver_data], NULL };
13904447d351STejun Heo struct ata_host *host;
139124dc5f33STejun Heo struct pdc_host_priv *hpriv;
1392cbcdd875STejun Heo int i, rc;
1393c6fd2807SJeff Garzik
139406296a1eSJoe Perches ata_print_version_once(&pdev->dev, DRV_VERSION);
1395c6fd2807SJeff Garzik
13964447d351STejun Heo /* allocate host */
13974447d351STejun Heo host = ata_host_alloc_pinfo(&pdev->dev, ppi, 4);
13984447d351STejun Heo hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL);
13994447d351STejun Heo if (!host || !hpriv)
14004447d351STejun Heo return -ENOMEM;
14014447d351STejun Heo
14024447d351STejun Heo host->private_data = hpriv;
14034447d351STejun Heo
14044447d351STejun Heo /* acquire resources and fill host */
140524dc5f33STejun Heo rc = pcim_enable_device(pdev);
1406c6fd2807SJeff Garzik if (rc)
1407c6fd2807SJeff Garzik return rc;
1408c6fd2807SJeff Garzik
14090d5ff566STejun Heo rc = pcim_iomap_regions(pdev, (1 << PDC_MMIO_BAR) | (1 << PDC_DIMM_BAR),
14100d5ff566STejun Heo DRV_NAME);
14110d5ff566STejun Heo if (rc == -EBUSY)
141224dc5f33STejun Heo pcim_pin_device(pdev);
14130d5ff566STejun Heo if (rc)
141424dc5f33STejun Heo return rc;
14154447d351STejun Heo host->iomap = pcim_iomap_table(pdev);
1416c6fd2807SJeff Garzik
1417cbcdd875STejun Heo for (i = 0; i < 4; i++) {
1418cbcdd875STejun Heo struct ata_port *ap = host->ports[i];
1419cbcdd875STejun Heo void __iomem *base = host->iomap[PDC_MMIO_BAR] + PDC_CHIP0_OFS;
1420cbcdd875STejun Heo unsigned int offset = 0x200 + i * 0x80;
1421cbcdd875STejun Heo
1422cbcdd875STejun Heo pdc_sata_setup_port(&ap->ioaddr, base + offset);
1423cbcdd875STejun Heo
1424cbcdd875STejun Heo ata_port_pbar_desc(ap, PDC_MMIO_BAR, -1, "mmio");
1425cbcdd875STejun Heo ata_port_pbar_desc(ap, PDC_DIMM_BAR, -1, "dimm");
1426cbcdd875STejun Heo ata_port_pbar_desc(ap, PDC_MMIO_BAR, offset, "port");
1427cbcdd875STejun Heo }
14284447d351STejun Heo
14294447d351STejun Heo /* configure and activate */
1430b5e55556SChristoph Hellwig rc = dma_set_mask_and_coherent(&pdev->dev, ATA_DMA_MASK);
1431c6fd2807SJeff Garzik if (rc)
143224dc5f33STejun Heo return rc;
1433c6fd2807SJeff Garzik
14344447d351STejun Heo if (pdc20621_dimm_init(host))
143524dc5f33STejun Heo return -ENOMEM;
14364447d351STejun Heo pdc_20621_init(host);
1437c6fd2807SJeff Garzik
1438c6fd2807SJeff Garzik pci_set_master(pdev);
14394447d351STejun Heo return ata_host_activate(host, pdev->irq, pdc20621_interrupt,
14404447d351STejun Heo IRQF_SHARED, &pdc_sata_sht);
1441c6fd2807SJeff Garzik }
1442c6fd2807SJeff Garzik
14432fc75da0SAxel Lin module_pci_driver(pdc_sata_pci_driver);
1444c6fd2807SJeff Garzik
1445c6fd2807SJeff Garzik MODULE_AUTHOR("Jeff Garzik");
1446c6fd2807SJeff Garzik MODULE_DESCRIPTION("Promise SATA low-level driver");
1447c6fd2807SJeff Garzik MODULE_LICENSE("GPL");
1448c6fd2807SJeff Garzik MODULE_DEVICE_TABLE(pci, pdc_sata_pci_tbl);
1449c6fd2807SJeff Garzik MODULE_VERSION(DRV_VERSION);
1450