diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-10 17:50:16 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-10 17:50:16 -0400 |
commit | 64b853aa328f34dd58e4e617cded91e2ddbcac13 (patch) | |
tree | 34b201d952bc93ead6ca91ed18dab5fb87dacf03 /drivers/ata/sata_sx4.c | |
parent | 0f166396e7e8931bb4acfd1a6ea1bd4f0b43f1dd (diff) | |
parent | c1e4fe711a410a139095e6b3e3ce3f07f466063c (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.c | 168 |
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 */ |