aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ata/sata_sx4.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.linux-foundation.org>2007-07-10 17:50:16 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-07-10 17:50:16 -0400
commit64b853aa328f34dd58e4e617cded91e2ddbcac13 (patch)
tree34b201d952bc93ead6ca91ed18dab5fb87dacf03 /drivers/ata/sata_sx4.c
parent0f166396e7e8931bb4acfd1a6ea1bd4f0b43f1dd (diff)
parentc1e4fe711a410a139095e6b3e3ce3f07f466063c (diff)
Merge branch 'upstream-linus' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik/libata-dev
* 'upstream-linus' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik/libata-dev: (32 commits) [libata] sata_mv: print out additional chip info during probe [libata] Use ATA_UDMAx standard masks when filling driver's udma_mask info [libata] AHCI: Add support for Marvell AHCI-like chips (initially 6145) [libata] Clean up driver udma_mask initializers libata: Support chips with 64K PRD quirk Add a PCI ID for santa rosa's PATA controller. sata_sil24: sil24_interrupt() micro-optimisation Add irq_flags to struct pata_platform_info sata_promise: cleanups [libata] pata_ixp4xx: kill unused var ata_piix: fix pio/mwdma programming [libata] ahci: minor internal cleanups [ATA] Add named constant for ATAPI command DEVICE RESET [libata] sata_sx4, sata_via: minor documentation updates [libata] ahci: minor internal cleanups [libata] ahci: Factor out SATA port init into a separate function [libata] pata_sil680: minor cleanups from benh [libata] sata_sx4: named constant cleanup [libata] pata_ixp4xx: convert to new EH [libata] pdc_adma: Reorder initializers with a couple structs ...
Diffstat (limited to 'drivers/ata/sata_sx4.c')
-rw-r--r--drivers/ata/sata_sx4.c168
1 files changed, 115 insertions, 53 deletions
diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c
index 2d14f3d56d92..5193bd8647ba 100644
--- a/drivers/ata/sata_sx4.c
+++ b/drivers/ata/sata_sx4.c
@@ -30,6 +30,54 @@
30 * 30 *
31 */ 31 */
32 32
33/*
34 Theory of operation
35 -------------------
36
37 The SX4 (PDC20621) chip features a single Host DMA (HDMA) copy
38 engine, DIMM memory, and four ATA engines (one per SATA port).
39 Data is copied to/from DIMM memory by the HDMA engine, before
40 handing off to one (or more) of the ATA engines. The ATA
41 engines operate solely on DIMM memory.
42
43 The SX4 behaves like a PATA chip, with no SATA controls or
44 knowledge whatsoever, leading to the presumption that
45 PATA<->SATA bridges exist on SX4 boards, external to the
46 PDC20621 chip itself.
47
48 The chip is quite capable, supporting an XOR engine and linked
49 hardware commands (permits a string to transactions to be
50 submitted and waited-on as a single unit), and an optional
51 microprocessor.
52
53 The limiting factor is largely software. This Linux driver was
54 written to multiplex the single HDMA engine to copy disk
55 transactions into a fixed DIMM memory space, from where an ATA
56 engine takes over. As a result, each WRITE looks like this:
57
58 submit HDMA packet to hardware
59 hardware copies data from system memory to DIMM
60 hardware raises interrupt
61
62 submit ATA packet to hardware
63 hardware executes ATA WRITE command, w/ data in DIMM
64 hardware raises interrupt
65
66 and each READ looks like this:
67
68 submit ATA packet to hardware
69 hardware executes ATA READ command, w/ data in DIMM
70 hardware raises interrupt
71
72 submit HDMA packet to hardware
73 hardware copies data from DIMM to system memory
74 hardware raises interrupt
75
76 This is a very slow, lock-step way of doing things that can
77 certainly be improved by motivated kernel hackers.
78
79 */
80
33#include <linux/kernel.h> 81#include <linux/kernel.h>
34#include <linux/module.h> 82#include <linux/module.h>
35#include <linux/pci.h> 83#include <linux/pci.h>
@@ -58,6 +106,8 @@ enum {
58 PDC_INT_SEQMASK = 0x40, /* Mask of asserted SEQ INTs */ 106 PDC_INT_SEQMASK = 0x40, /* Mask of asserted SEQ INTs */
59 PDC_HDMA_CTLSTAT = 0x12C, /* Host DMA control / status */ 107 PDC_HDMA_CTLSTAT = 0x12C, /* Host DMA control / status */
60 108
109 PDC_CTLSTAT = 0x60, /* IDEn control / status */
110
61 PDC_20621_SEQCTL = 0x400, 111 PDC_20621_SEQCTL = 0x400,
62 PDC_20621_SEQMASK = 0x480, 112 PDC_20621_SEQMASK = 0x480,
63 PDC_20621_GENERAL_CTL = 0x484, 113 PDC_20621_GENERAL_CTL = 0x484,
@@ -87,48 +137,60 @@ enum {
87 137
88 board_20621 = 0, /* FastTrak S150 SX4 */ 138 board_20621 = 0, /* FastTrak S150 SX4 */
89 139
90 PDC_RESET = (1 << 11), /* HDMA reset */ 140 PDC_MASK_INT = (1 << 10), /* HDMA/ATA mask int */
141 PDC_RESET = (1 << 11), /* HDMA/ATA reset */
142 PDC_DMA_ENABLE = (1 << 7), /* DMA start/stop */
91 143
92 PDC_MAX_HDMA = 32, 144 PDC_MAX_HDMA = 32,
93 PDC_HDMA_Q_MASK = (PDC_MAX_HDMA - 1), 145 PDC_HDMA_Q_MASK = (PDC_MAX_HDMA - 1),
94 146
95 PDC_DIMM0_SPD_DEV_ADDRESS = 0x50, 147 PDC_DIMM0_SPD_DEV_ADDRESS = 0x50,
96 PDC_DIMM1_SPD_DEV_ADDRESS = 0x51, 148 PDC_DIMM1_SPD_DEV_ADDRESS = 0x51,
97 PDC_MAX_DIMM_MODULE = 0x02, 149 PDC_I2C_CONTROL = 0x48,
98 PDC_I2C_CONTROL_OFFSET = 0x48, 150 PDC_I2C_ADDR_DATA = 0x4C,
99 PDC_I2C_ADDR_DATA_OFFSET = 0x4C, 151 PDC_DIMM0_CONTROL = 0x80,
100 PDC_DIMM0_CONTROL_OFFSET = 0x80, 152 PDC_DIMM1_CONTROL = 0x84,
101 PDC_DIMM1_CONTROL_OFFSET = 0x84, 153 PDC_SDRAM_CONTROL = 0x88,
102 PDC_SDRAM_CONTROL_OFFSET = 0x88, 154 PDC_I2C_WRITE = 0, /* master -> slave */
103 PDC_I2C_WRITE = 0x00000000, 155 PDC_I2C_READ = (1 << 6), /* master <- slave */
104 PDC_I2C_READ = 0x00000040, 156 PDC_I2C_START = (1 << 7), /* start I2C proto */
105 PDC_I2C_START = 0x00000080, 157 PDC_I2C_MASK_INT = (1 << 5), /* mask I2C interrupt */
106 PDC_I2C_MASK_INT = 0x00000020, 158 PDC_I2C_COMPLETE = (1 << 16), /* I2C normal compl. */
107 PDC_I2C_COMPLETE = 0x00010000, 159 PDC_I2C_NO_ACK = (1 << 20), /* slave no-ack addr */
108 PDC_I2C_NO_ACK = 0x00100000, 160 PDC_DIMM_SPD_SUBADDRESS_START = 0x00,
109 PDC_DIMM_SPD_SUBADDRESS_START = 0x00, 161 PDC_DIMM_SPD_SUBADDRESS_END = 0x7F,
110 PDC_DIMM_SPD_SUBADDRESS_END = 0x7F, 162 PDC_DIMM_SPD_ROW_NUM = 3,
111 PDC_DIMM_SPD_ROW_NUM = 3, 163 PDC_DIMM_SPD_COLUMN_NUM = 4,
112 PDC_DIMM_SPD_COLUMN_NUM = 4, 164 PDC_DIMM_SPD_MODULE_ROW = 5,
113 PDC_DIMM_SPD_MODULE_ROW = 5, 165 PDC_DIMM_SPD_TYPE = 11,
114 PDC_DIMM_SPD_TYPE = 11, 166 PDC_DIMM_SPD_FRESH_RATE = 12,
115 PDC_DIMM_SPD_FRESH_RATE = 12, 167 PDC_DIMM_SPD_BANK_NUM = 17,
116 PDC_DIMM_SPD_BANK_NUM = 17, 168 PDC_DIMM_SPD_CAS_LATENCY = 18,
117 PDC_DIMM_SPD_CAS_LATENCY = 18, 169 PDC_DIMM_SPD_ATTRIBUTE = 21,
118 PDC_DIMM_SPD_ATTRIBUTE = 21, 170 PDC_DIMM_SPD_ROW_PRE_CHARGE = 27,
119 PDC_DIMM_SPD_ROW_PRE_CHARGE = 27, 171 PDC_DIMM_SPD_ROW_ACTIVE_DELAY = 28,
120 PDC_DIMM_SPD_ROW_ACTIVE_DELAY = 28, 172 PDC_DIMM_SPD_RAS_CAS_DELAY = 29,
121 PDC_DIMM_SPD_RAS_CAS_DELAY = 29, 173 PDC_DIMM_SPD_ACTIVE_PRECHARGE = 30,
122 PDC_DIMM_SPD_ACTIVE_PRECHARGE = 30, 174 PDC_DIMM_SPD_SYSTEM_FREQ = 126,
123 PDC_DIMM_SPD_SYSTEM_FREQ = 126, 175 PDC_CTL_STATUS = 0x08,
124 PDC_CTL_STATUS = 0x08, 176 PDC_DIMM_WINDOW_CTLR = 0x0C,
125 PDC_DIMM_WINDOW_CTLR = 0x0C, 177 PDC_TIME_CONTROL = 0x3C,
126 PDC_TIME_CONTROL = 0x3C, 178 PDC_TIME_PERIOD = 0x40,
127 PDC_TIME_PERIOD = 0x40, 179 PDC_TIME_COUNTER = 0x44,
128 PDC_TIME_COUNTER = 0x44, 180 PDC_GENERAL_CTLR = 0x484,
129 PDC_GENERAL_CTLR = 0x484, 181 PCI_PLL_INIT = 0x8A531824,
130 PCI_PLL_INIT = 0x8A531824, 182 PCI_X_TCOUNT = 0xEE1E5CFF,
131 PCI_X_TCOUNT = 0xEE1E5CFF 183
184 /* PDC_TIME_CONTROL bits */
185 PDC_TIMER_BUZZER = (1 << 10),
186 PDC_TIMER_MODE_PERIODIC = 0, /* bits 9:8 == 00 */
187 PDC_TIMER_MODE_ONCE = (1 << 8), /* bits 9:8 == 01 */
188 PDC_TIMER_ENABLE = (1 << 7),
189 PDC_TIMER_MASK_INT = (1 << 5),
190 PDC_TIMER_SEQ_MASK = 0x1f, /* SEQ ID for timer */
191 PDC_TIMER_DEFAULT = PDC_TIMER_MODE_ONCE |
192 PDC_TIMER_ENABLE |
193 PDC_TIMER_MASK_INT,
132}; 194};
133 195
134 196
@@ -217,7 +279,7 @@ static const struct ata_port_info pdc_port_info[] = {
217 ATA_FLAG_NO_ATAPI | ATA_FLAG_PIO_POLLING, 279 ATA_FLAG_NO_ATAPI | ATA_FLAG_PIO_POLLING,
218 .pio_mask = 0x1f, /* pio0-4 */ 280 .pio_mask = 0x1f, /* pio0-4 */
219 .mwdma_mask = 0x07, /* mwdma0-2 */ 281 .mwdma_mask = 0x07, /* mwdma0-2 */
220 .udma_mask = 0x7f, /* udma0-6 ; FIXME */ 282 .udma_mask = ATA_UDMA6,
221 .port_ops = &pdc_20621_ops, 283 .port_ops = &pdc_20621_ops,
222 }, 284 },
223 285
@@ -999,17 +1061,17 @@ static unsigned int pdc20621_i2c_read(struct ata_host *host, u32 device,
999 i2creg |= subaddr << 16; 1061 i2creg |= subaddr << 16;
1000 1062
1001 /* Set the device and subaddress */ 1063 /* Set the device and subaddress */
1002 writel(i2creg, mmio + PDC_I2C_ADDR_DATA_OFFSET); 1064 writel(i2creg, mmio + PDC_I2C_ADDR_DATA);
1003 readl(mmio + PDC_I2C_ADDR_DATA_OFFSET); 1065 readl(mmio + PDC_I2C_ADDR_DATA);
1004 1066
1005 /* Write Control to perform read operation, mask int */ 1067 /* Write Control to perform read operation, mask int */
1006 writel(PDC_I2C_READ | PDC_I2C_START | PDC_I2C_MASK_INT, 1068 writel(PDC_I2C_READ | PDC_I2C_START | PDC_I2C_MASK_INT,
1007 mmio + PDC_I2C_CONTROL_OFFSET); 1069 mmio + PDC_I2C_CONTROL);
1008 1070
1009 for (count = 0; count <= 1000; count ++) { 1071 for (count = 0; count <= 1000; count ++) {
1010 status = readl(mmio + PDC_I2C_CONTROL_OFFSET); 1072 status = readl(mmio + PDC_I2C_CONTROL);
1011 if (status & PDC_I2C_COMPLETE) { 1073 if (status & PDC_I2C_COMPLETE) {
1012 status = readl(mmio + PDC_I2C_ADDR_DATA_OFFSET); 1074 status = readl(mmio + PDC_I2C_ADDR_DATA);
1013 break; 1075 break;
1014 } else if (count == 1000) 1076 } else if (count == 1000)
1015 return 0; 1077 return 0;
@@ -1099,8 +1161,8 @@ static int pdc20621_prog_dimm0(struct ata_host *host)
1099 data |= (((size / 16) - 1) << 16); 1161 data |= (((size / 16) - 1) << 16);
1100 data |= (0 << 23); 1162 data |= (0 << 23);
1101 data |= 8; 1163 data |= 8;
1102 writel(data, mmio + PDC_DIMM0_CONTROL_OFFSET); 1164 writel(data, mmio + PDC_DIMM0_CONTROL);
1103 readl(mmio + PDC_DIMM0_CONTROL_OFFSET); 1165 readl(mmio + PDC_DIMM0_CONTROL);
1104 return size; 1166 return size;
1105} 1167}
1106 1168
@@ -1122,27 +1184,27 @@ static unsigned int pdc20621_prog_dimm_global(struct ata_host *host)
1122 */ 1184 */
1123 1185
1124 data = 0x022259F1; 1186 data = 0x022259F1;
1125 writel(data, mmio + PDC_SDRAM_CONTROL_OFFSET); 1187 writel(data, mmio + PDC_SDRAM_CONTROL);
1126 readl(mmio + PDC_SDRAM_CONTROL_OFFSET); 1188 readl(mmio + PDC_SDRAM_CONTROL);
1127 1189
1128 /* Turn on for ECC */ 1190 /* Turn on for ECC */
1129 pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS, 1191 pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS,
1130 PDC_DIMM_SPD_TYPE, &spd0); 1192 PDC_DIMM_SPD_TYPE, &spd0);
1131 if (spd0 == 0x02) { 1193 if (spd0 == 0x02) {
1132 data |= (0x01 << 16); 1194 data |= (0x01 << 16);
1133 writel(data, mmio + PDC_SDRAM_CONTROL_OFFSET); 1195 writel(data, mmio + PDC_SDRAM_CONTROL);
1134 readl(mmio + PDC_SDRAM_CONTROL_OFFSET); 1196 readl(mmio + PDC_SDRAM_CONTROL);
1135 printk(KERN_ERR "Local DIMM ECC Enabled\n"); 1197 printk(KERN_ERR "Local DIMM ECC Enabled\n");
1136 } 1198 }
1137 1199
1138 /* DIMM Initialization Select/Enable (bit 18/19) */ 1200 /* DIMM Initialization Select/Enable (bit 18/19) */
1139 data &= (~(1<<18)); 1201 data &= (~(1<<18));
1140 data |= (1<<19); 1202 data |= (1<<19);
1141 writel(data, mmio + PDC_SDRAM_CONTROL_OFFSET); 1203 writel(data, mmio + PDC_SDRAM_CONTROL);
1142 1204
1143 error = 1; 1205 error = 1;
1144 for (i = 1; i <= 10; i++) { /* polling ~5 secs */ 1206 for (i = 1; i <= 10; i++) { /* polling ~5 secs */
1145 data = readl(mmio + PDC_SDRAM_CONTROL_OFFSET); 1207 data = readl(mmio + PDC_SDRAM_CONTROL);
1146 if (!(data & (1<<19))) { 1208 if (!(data & (1<<19))) {
1147 error = 0; 1209 error = 0;
1148 break; 1210 break;
@@ -1176,7 +1238,7 @@ static unsigned int pdc20621_dimm_init(struct ata_host *host)
1176 VPRINTK("Time Period Register (0x40): 0x%x\n", time_period); 1238 VPRINTK("Time Period Register (0x40): 0x%x\n", time_period);
1177 1239
1178 /* Enable timer */ 1240 /* Enable timer */
1179 writel(0x00001a0, mmio + PDC_TIME_CONTROL); 1241 writel(PDC_TIMER_DEFAULT, mmio + PDC_TIME_CONTROL);
1180 readl(mmio + PDC_TIME_CONTROL); 1242 readl(mmio + PDC_TIME_CONTROL);
1181 1243
1182 /* Wait 3 seconds */ 1244 /* Wait 3 seconds */