xref: /openbmc/linux/drivers/ata/sata_sx4.c (revision 86aa961bb4619a68077ebeba21c52e9ba0eab43d)
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