blob: da91060c320fd2a196b88fbbf46c66bdc07b38e4 [file] [log] [blame]
Pete Popov26a940e2005-09-15 08:03:12 +00001/*
Pete Popov26a940e2005-09-15 08:03:12 +00002 * BRIEF MODULE DESCRIPTION
3 * AMD Alchemy Au1xxx IDE interface routines over the Static Bus
4 *
5 * Copyright (c) 2003-2005 AMD, Personal Connectivity Solutions
6 *
7 * This program is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option) any later
10 * version.
11 *
12 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
13 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
14 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR
15 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
16 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
17 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
18 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
19 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
20 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
21 * POSSIBILITY OF SUCH DAMAGE.
22 *
23 * You should have received a copy of the GNU General Public License along with
24 * this program; if not, write to the Free Software Foundation, Inc.,
25 * 675 Mass Ave, Cambridge, MA 02139, USA.
26 *
27 * Note: for more information, please refer "AMD Alchemy Au1200/Au1550 IDE
28 * Interface and Linux Device Driver" Application Note.
29 */
Pete Popov26a940e2005-09-15 08:03:12 +000030#include <linux/types.h>
31#include <linux/module.h>
32#include <linux/kernel.h>
33#include <linux/delay.h>
Jordan Crouse8f29e652005-12-15 02:17:46 +010034#include <linux/platform_device.h>
35
Pete Popov26a940e2005-09-15 08:03:12 +000036#include <linux/init.h>
37#include <linux/ide.h>
38#include <linux/sysdev.h>
39
40#include <linux/dma-mapping.h>
41
Jordan Crouse8f29e652005-12-15 02:17:46 +010042#include "ide-timing.h"
43
Pete Popov26a940e2005-09-15 08:03:12 +000044#include <asm/io.h>
45#include <asm/mach-au1x00/au1xxx.h>
46#include <asm/mach-au1x00/au1xxx_dbdma.h>
47
Pete Popov26a940e2005-09-15 08:03:12 +000048#include <asm/mach-au1x00/au1xxx_ide.h>
49
50#define DRV_NAME "au1200-ide"
Jordan Crouse8f29e652005-12-15 02:17:46 +010051#define DRV_AUTHOR "Enrico Walther <enrico.walther@amd.com> / Pete Popov <ppopov@embeddedalley.com>"
52
53/* enable the burstmode in the dbdma */
54#define IDE_AU1XXX_BURSTMODE 1
Pete Popov26a940e2005-09-15 08:03:12 +000055
56static _auide_hwif auide_hwif;
Jordan Crouse8f29e652005-12-15 02:17:46 +010057static int dbdma_init_done;
Pete Popov26a940e2005-09-15 08:03:12 +000058
Sergei Shtylyov09a77442008-04-17 01:14:33 +020059static int auide_ddma_init(_auide_hwif *auide);
60
Jordan Crouse8f29e652005-12-15 02:17:46 +010061#if defined(CONFIG_BLK_DEV_IDE_AU1XXX_PIO_DBDMA)
Pete Popov26a940e2005-09-15 08:03:12 +000062
63void auide_insw(unsigned long port, void *addr, u32 count)
64{
Jordan Crouse8f29e652005-12-15 02:17:46 +010065 _auide_hwif *ahwif = &auide_hwif;
66 chan_tab_t *ctp;
67 au1x_ddma_desc_t *dp;
Pete Popov26a940e2005-09-15 08:03:12 +000068
Jordan Crouse8f29e652005-12-15 02:17:46 +010069 if(!put_dest_flags(ahwif->rx_chan, (void*)addr, count << 1,
70 DDMA_FLAGS_NOIE)) {
71 printk(KERN_ERR "%s failed %d\n", __FUNCTION__, __LINE__);
72 return;
73 }
74 ctp = *((chan_tab_t **)ahwif->rx_chan);
75 dp = ctp->cur_ptr;
76 while (dp->dscr_cmd0 & DSCR_CMD0_V)
77 ;
78 ctp->cur_ptr = au1xxx_ddma_get_nextptr_virt(dp);
Pete Popov26a940e2005-09-15 08:03:12 +000079}
80
81void auide_outsw(unsigned long port, void *addr, u32 count)
82{
Jordan Crouse8f29e652005-12-15 02:17:46 +010083 _auide_hwif *ahwif = &auide_hwif;
84 chan_tab_t *ctp;
85 au1x_ddma_desc_t *dp;
Pete Popov26a940e2005-09-15 08:03:12 +000086
Jordan Crouse8f29e652005-12-15 02:17:46 +010087 if(!put_source_flags(ahwif->tx_chan, (void*)addr,
88 count << 1, DDMA_FLAGS_NOIE)) {
89 printk(KERN_ERR "%s failed %d\n", __FUNCTION__, __LINE__);
90 return;
91 }
92 ctp = *((chan_tab_t **)ahwif->tx_chan);
93 dp = ctp->cur_ptr;
94 while (dp->dscr_cmd0 & DSCR_CMD0_V)
95 ;
96 ctp->cur_ptr = au1xxx_ddma_get_nextptr_virt(dp);
97}
98
Pete Popov26a940e2005-09-15 08:03:12 +000099#endif
Pete Popov26a940e2005-09-15 08:03:12 +0000100
Bartlomiej Zolnierkiewicz26bcb872007-10-11 23:54:00 +0200101static void au1xxx_set_pio_mode(ide_drive_t *drive, const u8 pio)
Pete Popov26a940e2005-09-15 08:03:12 +0000102{
Bartlomiej Zolnierkiewicz88b2b322007-10-13 17:47:51 +0200103 int mem_sttime = 0, mem_stcfg = au_readl(MEM_STCFG2);
Pete Popov26a940e2005-09-15 08:03:12 +0000104
Jordan Crouse8f29e652005-12-15 02:17:46 +0100105 /* set pio mode! */
106 switch(pio) {
107 case 0:
108 mem_sttime = SBC_IDE_TIMING(PIO0);
Pete Popov26a940e2005-09-15 08:03:12 +0000109
Jordan Crouse8f29e652005-12-15 02:17:46 +0100110 /* set configuration for RCS2# */
111 mem_stcfg |= TS_MASK;
112 mem_stcfg &= ~TCSOE_MASK;
113 mem_stcfg &= ~TOECS_MASK;
114 mem_stcfg |= SBC_IDE_PIO0_TCSOE | SBC_IDE_PIO0_TOECS;
115 break;
Pete Popov26a940e2005-09-15 08:03:12 +0000116
Jordan Crouse8f29e652005-12-15 02:17:46 +0100117 case 1:
118 mem_sttime = SBC_IDE_TIMING(PIO1);
Pete Popov26a940e2005-09-15 08:03:12 +0000119
Jordan Crouse8f29e652005-12-15 02:17:46 +0100120 /* set configuration for RCS2# */
121 mem_stcfg |= TS_MASK;
122 mem_stcfg &= ~TCSOE_MASK;
123 mem_stcfg &= ~TOECS_MASK;
124 mem_stcfg |= SBC_IDE_PIO1_TCSOE | SBC_IDE_PIO1_TOECS;
125 break;
Pete Popov26a940e2005-09-15 08:03:12 +0000126
Jordan Crouse8f29e652005-12-15 02:17:46 +0100127 case 2:
128 mem_sttime = SBC_IDE_TIMING(PIO2);
Pete Popov26a940e2005-09-15 08:03:12 +0000129
Jordan Crouse8f29e652005-12-15 02:17:46 +0100130 /* set configuration for RCS2# */
131 mem_stcfg &= ~TS_MASK;
132 mem_stcfg &= ~TCSOE_MASK;
133 mem_stcfg &= ~TOECS_MASK;
134 mem_stcfg |= SBC_IDE_PIO2_TCSOE | SBC_IDE_PIO2_TOECS;
135 break;
Pete Popov26a940e2005-09-15 08:03:12 +0000136
Jordan Crouse8f29e652005-12-15 02:17:46 +0100137 case 3:
138 mem_sttime = SBC_IDE_TIMING(PIO3);
Pete Popov26a940e2005-09-15 08:03:12 +0000139
Jordan Crouse8f29e652005-12-15 02:17:46 +0100140 /* set configuration for RCS2# */
141 mem_stcfg &= ~TS_MASK;
142 mem_stcfg &= ~TCSOE_MASK;
143 mem_stcfg &= ~TOECS_MASK;
144 mem_stcfg |= SBC_IDE_PIO3_TCSOE | SBC_IDE_PIO3_TOECS;
Pete Popov26a940e2005-09-15 08:03:12 +0000145
Jordan Crouse8f29e652005-12-15 02:17:46 +0100146 break;
Pete Popov26a940e2005-09-15 08:03:12 +0000147
Jordan Crouse8f29e652005-12-15 02:17:46 +0100148 case 4:
149 mem_sttime = SBC_IDE_TIMING(PIO4);
Pete Popov26a940e2005-09-15 08:03:12 +0000150
Jordan Crouse8f29e652005-12-15 02:17:46 +0100151 /* set configuration for RCS2# */
152 mem_stcfg &= ~TS_MASK;
153 mem_stcfg &= ~TCSOE_MASK;
154 mem_stcfg &= ~TOECS_MASK;
155 mem_stcfg |= SBC_IDE_PIO4_TCSOE | SBC_IDE_PIO4_TOECS;
156 break;
157 }
158
159 au_writel(mem_sttime,MEM_STTIME2);
160 au_writel(mem_stcfg,MEM_STCFG2);
Pete Popov26a940e2005-09-15 08:03:12 +0000161}
162
Bartlomiej Zolnierkiewicz88b2b322007-10-13 17:47:51 +0200163static void auide_set_dma_mode(ide_drive_t *drive, const u8 speed)
Pete Popov26a940e2005-09-15 08:03:12 +0000164{
Bartlomiej Zolnierkiewicz88b2b322007-10-13 17:47:51 +0200165 int mem_sttime = 0, mem_stcfg = au_readl(MEM_STCFG2);
Pete Popov26a940e2005-09-15 08:03:12 +0000166
Jordan Crouse8f29e652005-12-15 02:17:46 +0100167 switch(speed) {
Pete Popov26a940e2005-09-15 08:03:12 +0000168#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
Jordan Crouse8f29e652005-12-15 02:17:46 +0100169 case XFER_MW_DMA_2:
170 mem_sttime = SBC_IDE_TIMING(MDMA2);
Pete Popov26a940e2005-09-15 08:03:12 +0000171
Jordan Crouse8f29e652005-12-15 02:17:46 +0100172 /* set configuration for RCS2# */
173 mem_stcfg &= ~TS_MASK;
174 mem_stcfg &= ~TCSOE_MASK;
175 mem_stcfg &= ~TOECS_MASK;
176 mem_stcfg |= SBC_IDE_MDMA2_TCSOE | SBC_IDE_MDMA2_TOECS;
Pete Popov26a940e2005-09-15 08:03:12 +0000177
Jordan Crouse8f29e652005-12-15 02:17:46 +0100178 break;
179 case XFER_MW_DMA_1:
180 mem_sttime = SBC_IDE_TIMING(MDMA1);
Pete Popov26a940e2005-09-15 08:03:12 +0000181
Jordan Crouse8f29e652005-12-15 02:17:46 +0100182 /* set configuration for RCS2# */
183 mem_stcfg &= ~TS_MASK;
184 mem_stcfg &= ~TCSOE_MASK;
185 mem_stcfg &= ~TOECS_MASK;
186 mem_stcfg |= SBC_IDE_MDMA1_TCSOE | SBC_IDE_MDMA1_TOECS;
187
Jordan Crouse8f29e652005-12-15 02:17:46 +0100188 break;
189 case XFER_MW_DMA_0:
190 mem_sttime = SBC_IDE_TIMING(MDMA0);
191
192 /* set configuration for RCS2# */
193 mem_stcfg |= TS_MASK;
194 mem_stcfg &= ~TCSOE_MASK;
195 mem_stcfg &= ~TOECS_MASK;
196 mem_stcfg |= SBC_IDE_MDMA0_TCSOE | SBC_IDE_MDMA0_TOECS;
197
Jordan Crouse8f29e652005-12-15 02:17:46 +0100198 break;
Pete Popov26a940e2005-09-15 08:03:12 +0000199#endif
Jordan Crouse8f29e652005-12-15 02:17:46 +0100200 }
Bartlomiej Zolnierkiewicza523a172007-02-17 02:40:23 +0100201
Jordan Crouse8f29e652005-12-15 02:17:46 +0100202 au_writel(mem_sttime,MEM_STTIME2);
203 au_writel(mem_stcfg,MEM_STCFG2);
Pete Popov26a940e2005-09-15 08:03:12 +0000204}
205
206/*
207 * Multi-Word DMA + DbDMA functions
208 */
Pete Popov26a940e2005-09-15 08:03:12 +0000209
Jordan Crouse8f29e652005-12-15 02:17:46 +0100210#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
Pete Popov26a940e2005-09-15 08:03:12 +0000211static int auide_build_dmatable(ide_drive_t *drive)
212{
Jordan Crouse8f29e652005-12-15 02:17:46 +0100213 int i, iswrite, count = 0;
214 ide_hwif_t *hwif = HWIF(drive);
Pete Popov26a940e2005-09-15 08:03:12 +0000215
Jordan Crouse8f29e652005-12-15 02:17:46 +0100216 struct request *rq = HWGROUP(drive)->rq;
Pete Popov26a940e2005-09-15 08:03:12 +0000217
Jordan Crouse8f29e652005-12-15 02:17:46 +0100218 _auide_hwif *ahwif = (_auide_hwif*)hwif->hwif_data;
219 struct scatterlist *sg;
Pete Popov26a940e2005-09-15 08:03:12 +0000220
Jordan Crouse8f29e652005-12-15 02:17:46 +0100221 iswrite = (rq_data_dir(rq) == WRITE);
222 /* Save for interrupt context */
223 ahwif->drive = drive;
Pete Popov26a940e2005-09-15 08:03:12 +0000224
Bartlomiej Zolnierkiewicz062f9f02008-02-01 23:09:32 +0100225 hwif->sg_nents = i = ide_build_sglist(drive, rq);
Pete Popov26a940e2005-09-15 08:03:12 +0000226
Jordan Crouse8f29e652005-12-15 02:17:46 +0100227 if (!i)
228 return 0;
Pete Popov26a940e2005-09-15 08:03:12 +0000229
Jordan Crouse8f29e652005-12-15 02:17:46 +0100230 /* fill the descriptors */
231 sg = hwif->sg_table;
232 while (i && sg_dma_len(sg)) {
233 u32 cur_addr;
234 u32 cur_len;
Pete Popov26a940e2005-09-15 08:03:12 +0000235
Jordan Crouse8f29e652005-12-15 02:17:46 +0100236 cur_addr = sg_dma_address(sg);
237 cur_len = sg_dma_len(sg);
Pete Popov26a940e2005-09-15 08:03:12 +0000238
Jordan Crouse8f29e652005-12-15 02:17:46 +0100239 while (cur_len) {
240 u32 flags = DDMA_FLAGS_NOIE;
241 unsigned int tc = (cur_len < 0xfe00)? cur_len: 0xfe00;
Pete Popov26a940e2005-09-15 08:03:12 +0000242
Jordan Crouse8f29e652005-12-15 02:17:46 +0100243 if (++count >= PRD_ENTRIES) {
244 printk(KERN_WARNING "%s: DMA table too small\n",
245 drive->name);
246 goto use_pio_instead;
247 }
Pete Popov26a940e2005-09-15 08:03:12 +0000248
Jordan Crouse8f29e652005-12-15 02:17:46 +0100249 /* Lets enable intr for the last descriptor only */
250 if (1==i)
251 flags = DDMA_FLAGS_IE;
252 else
253 flags = DDMA_FLAGS_NOIE;
Pete Popov26a940e2005-09-15 08:03:12 +0000254
Jordan Crouse8f29e652005-12-15 02:17:46 +0100255 if (iswrite) {
256 if(!put_source_flags(ahwif->tx_chan,
Jens Axboe45711f12007-10-22 21:19:53 +0200257 (void*) sg_virt(sg),
Jordan Crouse8f29e652005-12-15 02:17:46 +0100258 tc, flags)) {
259 printk(KERN_ERR "%s failed %d\n",
260 __FUNCTION__, __LINE__);
Pete Popov26a940e2005-09-15 08:03:12 +0000261 }
Jordan Crouse8f29e652005-12-15 02:17:46 +0100262 } else
Pete Popov26a940e2005-09-15 08:03:12 +0000263 {
Jordan Crouse8f29e652005-12-15 02:17:46 +0100264 if(!put_dest_flags(ahwif->rx_chan,
Jens Axboe45711f12007-10-22 21:19:53 +0200265 (void*) sg_virt(sg),
Jordan Crouse8f29e652005-12-15 02:17:46 +0100266 tc, flags)) {
267 printk(KERN_ERR "%s failed %d\n",
268 __FUNCTION__, __LINE__);
Pete Popov26a940e2005-09-15 08:03:12 +0000269 }
Jordan Crouse8f29e652005-12-15 02:17:46 +0100270 }
Pete Popov26a940e2005-09-15 08:03:12 +0000271
Jordan Crouse8f29e652005-12-15 02:17:46 +0100272 cur_addr += tc;
273 cur_len -= tc;
274 }
Jens Axboe55c16a72007-07-25 08:13:56 +0200275 sg = sg_next(sg);
Jordan Crouse8f29e652005-12-15 02:17:46 +0100276 i--;
277 }
Pete Popov26a940e2005-09-15 08:03:12 +0000278
Jordan Crouse8f29e652005-12-15 02:17:46 +0100279 if (count)
280 return 1;
Pete Popov26a940e2005-09-15 08:03:12 +0000281
Jordan Crouse8f29e652005-12-15 02:17:46 +0100282 use_pio_instead:
Bartlomiej Zolnierkiewicz062f9f02008-02-01 23:09:32 +0100283 ide_destroy_dmatable(drive);
Pete Popov26a940e2005-09-15 08:03:12 +0000284
Jordan Crouse8f29e652005-12-15 02:17:46 +0100285 return 0; /* revert to PIO for this request */
Pete Popov26a940e2005-09-15 08:03:12 +0000286}
287
288static int auide_dma_end(ide_drive_t *drive)
289{
Jordan Crouse8f29e652005-12-15 02:17:46 +0100290 ide_hwif_t *hwif = HWIF(drive);
Pete Popov26a940e2005-09-15 08:03:12 +0000291
Jordan Crouse8f29e652005-12-15 02:17:46 +0100292 if (hwif->sg_nents) {
Bartlomiej Zolnierkiewicz062f9f02008-02-01 23:09:32 +0100293 ide_destroy_dmatable(drive);
Jordan Crouse8f29e652005-12-15 02:17:46 +0100294 hwif->sg_nents = 0;
295 }
Pete Popov26a940e2005-09-15 08:03:12 +0000296
Jordan Crouse8f29e652005-12-15 02:17:46 +0100297 return 0;
Pete Popov26a940e2005-09-15 08:03:12 +0000298}
299
300static void auide_dma_start(ide_drive_t *drive )
301{
Pete Popov26a940e2005-09-15 08:03:12 +0000302}
303
Pete Popov26a940e2005-09-15 08:03:12 +0000304
305static void auide_dma_exec_cmd(ide_drive_t *drive, u8 command)
306{
Jordan Crouse8f29e652005-12-15 02:17:46 +0100307 /* issue cmd to drive */
308 ide_execute_command(drive, command, &ide_dma_intr,
309 (2*WAIT_CMD), NULL);
Pete Popov26a940e2005-09-15 08:03:12 +0000310}
311
312static int auide_dma_setup(ide_drive_t *drive)
Jordan Crouse8f29e652005-12-15 02:17:46 +0100313{
314 struct request *rq = HWGROUP(drive)->rq;
Pete Popov26a940e2005-09-15 08:03:12 +0000315
Jordan Crouse8f29e652005-12-15 02:17:46 +0100316 if (!auide_build_dmatable(drive)) {
317 ide_map_sg(drive, rq);
318 return 1;
319 }
Pete Popov26a940e2005-09-15 08:03:12 +0000320
Jordan Crouse8f29e652005-12-15 02:17:46 +0100321 drive->waiting_for_dma = 1;
322 return 0;
Pete Popov26a940e2005-09-15 08:03:12 +0000323}
324
Bartlomiej Zolnierkiewicz8446f652007-10-16 22:29:54 +0200325static u8 auide_mdma_filter(ide_drive_t *drive)
Pete Popov26a940e2005-09-15 08:03:12 +0000326{
Bartlomiej Zolnierkiewicz8446f652007-10-16 22:29:54 +0200327 /*
328 * FIXME: ->white_list and ->black_list are based on completely bogus
329 * ->ide_dma_check implementation which didn't set neither the host
330 * controller timings nor the device for the desired transfer mode.
331 *
332 * They should be either removed or 0x00 MWDMA mask should be
333 * returned for devices on the ->black_list.
334 */
Jordan Crouse8f29e652005-12-15 02:17:46 +0100335
Bartlomiej Zolnierkiewicz8446f652007-10-16 22:29:54 +0200336 if (dbdma_init_done == 0) {
Jordan Crouse8f29e652005-12-15 02:17:46 +0100337 auide_hwif.white_list = ide_in_drive_list(drive->id,
338 dma_white_list);
339 auide_hwif.black_list = ide_in_drive_list(drive->id,
340 dma_black_list);
341 auide_hwif.drive = drive;
342 auide_ddma_init(&auide_hwif);
343 dbdma_init_done = 1;
344 }
Pete Popov26a940e2005-09-15 08:03:12 +0000345
Jordan Crouse8f29e652005-12-15 02:17:46 +0100346 /* Is the drive in our DMA black list? */
Bartlomiej Zolnierkiewicz8446f652007-10-16 22:29:54 +0200347 if (auide_hwif.black_list)
Jordan Crouse8f29e652005-12-15 02:17:46 +0100348 printk(KERN_WARNING "%s: Disabling DMA for %s (blacklisted)\n",
Bartlomiej Zolnierkiewicz8446f652007-10-16 22:29:54 +0200349 drive->name, drive->id->model);
Jordan Crouse8f29e652005-12-15 02:17:46 +0100350
Bartlomiej Zolnierkiewicz8446f652007-10-16 22:29:54 +0200351 return drive->hwif->mwdma_mask;
352}
353
Pete Popov26a940e2005-09-15 08:03:12 +0000354static int auide_dma_test_irq(ide_drive_t *drive)
Jordan Crouse8f29e652005-12-15 02:17:46 +0100355{
356 if (drive->waiting_for_dma == 0)
357 printk(KERN_WARNING "%s: ide_dma_test_irq \
Pete Popov26a940e2005-09-15 08:03:12 +0000358 called while not waiting\n", drive->name);
359
Jordan Crouse8f29e652005-12-15 02:17:46 +0100360 /* If dbdma didn't execute the STOP command yet, the
361 * active bit is still set
Pete Popov26a940e2005-09-15 08:03:12 +0000362 */
Jordan Crouse8f29e652005-12-15 02:17:46 +0100363 drive->waiting_for_dma++;
364 if (drive->waiting_for_dma >= DMA_WAIT_TIMEOUT) {
365 printk(KERN_WARNING "%s: timeout waiting for ddma to \
Pete Popov26a940e2005-09-15 08:03:12 +0000366 complete\n", drive->name);
Jordan Crouse8f29e652005-12-15 02:17:46 +0100367 return 1;
368 }
369 udelay(10);
370 return 0;
Pete Popov26a940e2005-09-15 08:03:12 +0000371}
372
Bartlomiej Zolnierkiewicz15ce9262008-01-26 20:13:03 +0100373static void auide_dma_host_set(ide_drive_t *drive, int on)
Pete Popov26a940e2005-09-15 08:03:12 +0000374{
Pete Popov26a940e2005-09-15 08:03:12 +0000375}
376
Sergei Shtylyov841d2a92007-07-09 23:17:54 +0200377static void auide_dma_lost_irq(ide_drive_t *drive)
Pete Popov26a940e2005-09-15 08:03:12 +0000378{
Jordan Crouse8f29e652005-12-15 02:17:46 +0100379 printk(KERN_ERR "%s: IRQ lost\n", drive->name);
Pete Popov26a940e2005-09-15 08:03:12 +0000380}
381
Ralf Baechle53e62d32006-09-25 23:32:10 -0700382static void auide_ddma_tx_callback(int irq, void *param)
Pete Popov26a940e2005-09-15 08:03:12 +0000383{
Jordan Crouse8f29e652005-12-15 02:17:46 +0100384 _auide_hwif *ahwif = (_auide_hwif*)param;
385 ahwif->drive->waiting_for_dma = 0;
Pete Popov26a940e2005-09-15 08:03:12 +0000386}
387
Ralf Baechle53e62d32006-09-25 23:32:10 -0700388static void auide_ddma_rx_callback(int irq, void *param)
Pete Popov26a940e2005-09-15 08:03:12 +0000389{
Jordan Crouse8f29e652005-12-15 02:17:46 +0100390 _auide_hwif *ahwif = (_auide_hwif*)param;
391 ahwif->drive->waiting_for_dma = 0;
Pete Popov26a940e2005-09-15 08:03:12 +0000392}
393
Jordan Crouse8f29e652005-12-15 02:17:46 +0100394#endif /* end CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA */
395
396static void auide_init_dbdma_dev(dbdev_tab_t *dev, u32 dev_id, u32 tsize, u32 devwidth, u32 flags)
397{
398 dev->dev_id = dev_id;
399 dev->dev_physaddr = (u32)AU1XXX_ATA_PHYS_ADDR;
400 dev->dev_intlevel = 0;
401 dev->dev_intpolarity = 0;
402 dev->dev_tsize = tsize;
403 dev->dev_devwidth = devwidth;
404 dev->dev_flags = flags;
405}
406
407#if defined(CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA)
408
Sergei Shtylyovc283f5d2007-07-09 23:17:54 +0200409static void auide_dma_timeout(ide_drive_t *drive)
Pete Popov26a940e2005-09-15 08:03:12 +0000410{
Sergei Shtylyovc283f5d2007-07-09 23:17:54 +0200411 ide_hwif_t *hwif = HWIF(drive);
Pete Popov26a940e2005-09-15 08:03:12 +0000412
Jordan Crouse8f29e652005-12-15 02:17:46 +0100413 printk(KERN_ERR "%s: DMA timeout occurred: ", drive->name);
Pete Popov26a940e2005-09-15 08:03:12 +0000414
Sergei Shtylyovc283f5d2007-07-09 23:17:54 +0200415 if (hwif->ide_dma_test_irq(drive))
416 return;
Pete Popov26a940e2005-09-15 08:03:12 +0000417
Sergei Shtylyovc283f5d2007-07-09 23:17:54 +0200418 hwif->ide_dma_end(drive);
Pete Popov26a940e2005-09-15 08:03:12 +0000419}
Jordan Crouse8f29e652005-12-15 02:17:46 +0100420
Pete Popov26a940e2005-09-15 08:03:12 +0000421
Jordan Crouse8f29e652005-12-15 02:17:46 +0100422static int auide_ddma_init(_auide_hwif *auide) {
423
424 dbdev_tab_t source_dev_tab, target_dev_tab;
425 u32 dev_id, tsize, devwidth, flags;
426 ide_hwif_t *hwif = auide->hwif;
Pete Popov26a940e2005-09-15 08:03:12 +0000427
Jordan Crouse8f29e652005-12-15 02:17:46 +0100428 dev_id = AU1XXX_ATA_DDMA_REQ;
429
430 if (auide->white_list || auide->black_list) {
431 tsize = 8;
432 devwidth = 32;
433 }
434 else {
435 tsize = 1;
436 devwidth = 16;
437
438 printk(KERN_ERR "au1xxx-ide: %s is not on ide driver whitelist.\n",auide_hwif.drive->id->model);
439 printk(KERN_ERR " please read 'Documentation/mips/AU1xxx_IDE.README'");
440 }
441
442#ifdef IDE_AU1XXX_BURSTMODE
443 flags = DEV_FLAGS_SYNC | DEV_FLAGS_BURSTABLE;
444#else
445 flags = DEV_FLAGS_SYNC;
446#endif
447
448 /* setup dev_tab for tx channel */
449 auide_init_dbdma_dev( &source_dev_tab,
450 dev_id,
451 tsize, devwidth, DEV_FLAGS_OUT | flags);
452 auide->tx_dev_id = au1xxx_ddma_add_device( &source_dev_tab );
453
454 auide_init_dbdma_dev( &source_dev_tab,
455 dev_id,
456 tsize, devwidth, DEV_FLAGS_IN | flags);
457 auide->rx_dev_id = au1xxx_ddma_add_device( &source_dev_tab );
458
459 /* We also need to add a target device for the DMA */
460 auide_init_dbdma_dev( &target_dev_tab,
461 (u32)DSCR_CMD0_ALWAYS,
462 tsize, devwidth, DEV_FLAGS_ANYUSE);
463 auide->target_dev_id = au1xxx_ddma_add_device(&target_dev_tab);
464
465 /* Get a channel for TX */
466 auide->tx_chan = au1xxx_dbdma_chan_alloc(auide->target_dev_id,
467 auide->tx_dev_id,
468 auide_ddma_tx_callback,
469 (void*)auide);
470
471 /* Get a channel for RX */
472 auide->rx_chan = au1xxx_dbdma_chan_alloc(auide->rx_dev_id,
473 auide->target_dev_id,
474 auide_ddma_rx_callback,
475 (void*)auide);
476
477 auide->tx_desc_head = (void*)au1xxx_dbdma_ring_alloc(auide->tx_chan,
478 NUM_DESCRIPTORS);
479 auide->rx_desc_head = (void*)au1xxx_dbdma_ring_alloc(auide->rx_chan,
480 NUM_DESCRIPTORS);
481
Bartlomiej Zolnierkiewicz5df37c32008-02-01 23:09:31 +0100482 hwif->dmatable_cpu = dma_alloc_coherent(hwif->dev,
Jordan Crouse8f29e652005-12-15 02:17:46 +0100483 PRD_ENTRIES * PRD_BYTES, /* 1 Page */
484 &hwif->dmatable_dma, GFP_KERNEL);
485
486 au1xxx_dbdma_start( auide->tx_chan );
487 au1xxx_dbdma_start( auide->rx_chan );
488
489 return 0;
490}
491#else
492
Pete Popov26a940e2005-09-15 08:03:12 +0000493static int auide_ddma_init( _auide_hwif *auide )
494{
Jordan Crouse8f29e652005-12-15 02:17:46 +0100495 dbdev_tab_t source_dev_tab;
496 int flags;
Pete Popov26a940e2005-09-15 08:03:12 +0000497
Jordan Crouse8f29e652005-12-15 02:17:46 +0100498#ifdef IDE_AU1XXX_BURSTMODE
499 flags = DEV_FLAGS_SYNC | DEV_FLAGS_BURSTABLE;
Pete Popov26a940e2005-09-15 08:03:12 +0000500#else
Jordan Crouse8f29e652005-12-15 02:17:46 +0100501 flags = DEV_FLAGS_SYNC;
Pete Popov26a940e2005-09-15 08:03:12 +0000502#endif
503
Jordan Crouse8f29e652005-12-15 02:17:46 +0100504 /* setup dev_tab for tx channel */
505 auide_init_dbdma_dev( &source_dev_tab,
506 (u32)DSCR_CMD0_ALWAYS,
507 8, 32, DEV_FLAGS_OUT | flags);
508 auide->tx_dev_id = au1xxx_ddma_add_device( &source_dev_tab );
Pete Popov26a940e2005-09-15 08:03:12 +0000509
Jordan Crouse8f29e652005-12-15 02:17:46 +0100510 auide_init_dbdma_dev( &source_dev_tab,
511 (u32)DSCR_CMD0_ALWAYS,
512 8, 32, DEV_FLAGS_IN | flags);
513 auide->rx_dev_id = au1xxx_ddma_add_device( &source_dev_tab );
514
515 /* Get a channel for TX */
516 auide->tx_chan = au1xxx_dbdma_chan_alloc(DSCR_CMD0_ALWAYS,
517 auide->tx_dev_id,
518 NULL,
519 (void*)auide);
520
521 /* Get a channel for RX */
522 auide->rx_chan = au1xxx_dbdma_chan_alloc(auide->rx_dev_id,
523 DSCR_CMD0_ALWAYS,
524 NULL,
525 (void*)auide);
526
527 auide->tx_desc_head = (void*)au1xxx_dbdma_ring_alloc(auide->tx_chan,
528 NUM_DESCRIPTORS);
529 auide->rx_desc_head = (void*)au1xxx_dbdma_ring_alloc(auide->rx_chan,
530 NUM_DESCRIPTORS);
531
532 au1xxx_dbdma_start( auide->tx_chan );
533 au1xxx_dbdma_start( auide->rx_chan );
534
535 return 0;
Pete Popov26a940e2005-09-15 08:03:12 +0000536}
Jordan Crouse8f29e652005-12-15 02:17:46 +0100537#endif
Pete Popov26a940e2005-09-15 08:03:12 +0000538
539static void auide_setup_ports(hw_regs_t *hw, _auide_hwif *ahwif)
540{
Jordan Crouse8f29e652005-12-15 02:17:46 +0100541 int i;
542 unsigned long *ata_regs = hw->io_ports;
Pete Popov26a940e2005-09-15 08:03:12 +0000543
Jordan Crouse8f29e652005-12-15 02:17:46 +0100544 /* FIXME? */
545 for (i = 0; i < IDE_CONTROL_OFFSET; i++) {
546 *ata_regs++ = ahwif->regbase + (i << AU1XXX_ATA_REG_OFFSET);
547 }
Pete Popov26a940e2005-09-15 08:03:12 +0000548
Jordan Crouse8f29e652005-12-15 02:17:46 +0100549 /* set the Alternative Status register */
550 *ata_regs = ahwif->regbase + (14 << AU1XXX_ATA_REG_OFFSET);
Pete Popov26a940e2005-09-15 08:03:12 +0000551}
552
Bartlomiej Zolnierkiewiczc413b9b2008-02-02 19:56:31 +0100553static const struct ide_port_info au1xxx_port_info = {
554 .host_flags = IDE_HFLAG_POST_SET_MODE |
555 IDE_HFLAG_NO_DMA | /* no SFF-style DMA */
Bartlomiej Zolnierkiewicz807b90d2008-02-02 19:56:40 +0100556 IDE_HFLAG_NO_IO_32BIT |
Bartlomiej Zolnierkiewiczc413b9b2008-02-02 19:56:31 +0100557 IDE_HFLAG_UNMASK_IRQS,
558 .pio_mask = ATA_PIO4,
559#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
560 .mwdma_mask = ATA_MWDMA2,
561#endif
562};
563
Pete Popov26a940e2005-09-15 08:03:12 +0000564static int au_ide_probe(struct device *dev)
565{
566 struct platform_device *pdev = to_platform_device(dev);
Jordan Crouse8f29e652005-12-15 02:17:46 +0100567 _auide_hwif *ahwif = &auide_hwif;
568 ide_hwif_t *hwif;
Pete Popov26a940e2005-09-15 08:03:12 +0000569 struct resource *res;
570 int ret = 0;
Bartlomiej Zolnierkiewicz8447d9d2007-10-20 00:32:31 +0200571 u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
Bartlomiej Zolnierkiewicz9239b332007-10-20 00:32:33 +0200572 hw_regs_t hw;
Pete Popov26a940e2005-09-15 08:03:12 +0000573
574#if defined(CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA)
Jordan Crouse8f29e652005-12-15 02:17:46 +0100575 char *mode = "MWDMA2";
Pete Popov26a940e2005-09-15 08:03:12 +0000576#elif defined(CONFIG_BLK_DEV_IDE_AU1XXX_PIO_DBDMA)
Jordan Crouse8f29e652005-12-15 02:17:46 +0100577 char *mode = "PIO+DDMA(offload)";
Pete Popov26a940e2005-09-15 08:03:12 +0000578#endif
579
Jordan Crouse8f29e652005-12-15 02:17:46 +0100580 memset(&auide_hwif, 0, sizeof(_auide_hwif));
Pete Popov26a940e2005-09-15 08:03:12 +0000581 ahwif->irq = platform_get_irq(pdev, 0);
582
583 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
584
585 if (res == NULL) {
586 pr_debug("%s %d: no base address\n", DRV_NAME, pdev->id);
587 ret = -ENODEV;
588 goto out;
589 }
David Vrabel48944732006-01-19 17:56:29 +0000590 if (ahwif->irq < 0) {
591 pr_debug("%s %d: no IRQ\n", DRV_NAME, pdev->id);
592 ret = -ENODEV;
593 goto out;
594 }
Pete Popov26a940e2005-09-15 08:03:12 +0000595
Jordan Crouse8f29e652005-12-15 02:17:46 +0100596 if (!request_mem_region (res->start, res->end-res->start, pdev->name)) {
Pete Popov26a940e2005-09-15 08:03:12 +0000597 pr_debug("%s: request_mem_region failed\n", DRV_NAME);
Jordan Crouse8f29e652005-12-15 02:17:46 +0100598 ret = -EBUSY;
Pete Popov26a940e2005-09-15 08:03:12 +0000599 goto out;
Jordan Crouse8f29e652005-12-15 02:17:46 +0100600 }
Pete Popov26a940e2005-09-15 08:03:12 +0000601
602 ahwif->regbase = (u32)ioremap(res->start, res->end-res->start);
603 if (ahwif->regbase == 0) {
604 ret = -ENOMEM;
605 goto out;
606 }
607
Jordan Crouse8f29e652005-12-15 02:17:46 +0100608 /* FIXME: This might possibly break PCMCIA IDE devices */
Pete Popov26a940e2005-09-15 08:03:12 +0000609
Jordan Crouse8f29e652005-12-15 02:17:46 +0100610 hwif = &ide_hwifs[pdev->id];
Jordan Crouse8f29e652005-12-15 02:17:46 +0100611
Bartlomiej Zolnierkiewicz9239b332007-10-20 00:32:33 +0200612 memset(&hw, 0, sizeof(hw));
613 auide_setup_ports(&hw, ahwif);
Bartlomiej Zolnierkiewiczaa79a2f2008-01-26 20:13:08 +0100614 hw.irq = ahwif->irq;
Bartlomiej Zolnierkiewiczed1f7882008-02-01 23:09:32 +0100615 hw.dev = dev;
Bartlomiej Zolnierkiewiczaa79a2f2008-01-26 20:13:08 +0100616 hw.chipset = ide_au1xxx;
617
618 ide_init_port_hw(hwif, &hw);
Pete Popov26a940e2005-09-15 08:03:12 +0000619
Bartlomiej Zolnierkiewicz5df37c32008-02-01 23:09:31 +0100620 hwif->dev = dev;
621
Jordan Crouse8f29e652005-12-15 02:17:46 +0100622 /* hold should be on in all cases */
623 hwif->hold = 1;
Bartlomiej Zolnierkiewicz2ad1e552007-02-17 02:40:25 +0100624
625 hwif->mmio = 1;
Pete Popov26a940e2005-09-15 08:03:12 +0000626
Jordan Crouse8f29e652005-12-15 02:17:46 +0100627 /* If the user has selected DDMA assisted copies,
628 then set up a few local I/O function entry points
629 */
630
631#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_PIO_DBDMA
632 hwif->INSW = auide_insw;
633 hwif->OUTSW = auide_outsw;
634#endif
635
Bartlomiej Zolnierkiewicz26bcb872007-10-11 23:54:00 +0200636 hwif->set_pio_mode = &au1xxx_set_pio_mode;
Bartlomiej Zolnierkiewicz88b2b322007-10-13 17:47:51 +0200637 hwif->set_dma_mode = &auide_set_dma_mode;
Pete Popov26a940e2005-09-15 08:03:12 +0000638
639#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
Sergei Shtylyovc283f5d2007-07-09 23:17:54 +0200640 hwif->dma_timeout = &auide_dma_timeout;
Pete Popov26a940e2005-09-15 08:03:12 +0000641
Bartlomiej Zolnierkiewicz8446f652007-10-16 22:29:54 +0200642 hwif->mdma_filter = &auide_mdma_filter;
643
Bartlomiej Zolnierkiewicz15ce9262008-01-26 20:13:03 +0100644 hwif->dma_host_set = &auide_dma_host_set;
Jordan Crouse8f29e652005-12-15 02:17:46 +0100645 hwif->dma_exec_cmd = &auide_dma_exec_cmd;
646 hwif->dma_start = &auide_dma_start;
647 hwif->ide_dma_end = &auide_dma_end;
648 hwif->dma_setup = &auide_dma_setup;
649 hwif->ide_dma_test_irq = &auide_dma_test_irq;
Sergei Shtylyov841d2a92007-07-09 23:17:54 +0200650 hwif->dma_lost_irq = &auide_dma_lost_irq;
Bartlomiej Zolnierkiewicza42bcc02008-01-26 20:13:07 +0100651#endif
Jordan Crouse8f29e652005-12-15 02:17:46 +0100652 hwif->select_data = 0; /* no chipset-specific code */
653 hwif->config_data = 0; /* no chipset-specific code */
Pete Popov26a940e2005-09-15 08:03:12 +0000654
Jordan Crouse8f29e652005-12-15 02:17:46 +0100655 auide_hwif.hwif = hwif;
656 hwif->hwif_data = &auide_hwif;
Pete Popov26a940e2005-09-15 08:03:12 +0000657
Jordan Crouse8f29e652005-12-15 02:17:46 +0100658#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_PIO_DBDMA
659 auide_ddma_init(&auide_hwif);
660 dbdma_init_done = 1;
Pete Popov26a940e2005-09-15 08:03:12 +0000661#endif
662
Bartlomiej Zolnierkiewicz8447d9d2007-10-20 00:32:31 +0200663 idx[0] = hwif->index;
Bartlomiej Zolnierkiewicz5cbf79c2007-05-10 00:01:11 +0200664
Bartlomiej Zolnierkiewiczc413b9b2008-02-02 19:56:31 +0100665 ide_device_add(idx, &au1xxx_port_info);
Bartlomiej Zolnierkiewicz5cbf79c2007-05-10 00:01:11 +0200666
Pete Popov26a940e2005-09-15 08:03:12 +0000667 dev_set_drvdata(dev, hwif);
668
Jordan Crouse8f29e652005-12-15 02:17:46 +0100669 printk(KERN_INFO "Au1xxx IDE(builtin) configured for %s\n", mode );
Pete Popov26a940e2005-09-15 08:03:12 +0000670
Jordan Crouse8f29e652005-12-15 02:17:46 +0100671 out:
672 return ret;
Pete Popov26a940e2005-09-15 08:03:12 +0000673}
674
675static int au_ide_remove(struct device *dev)
676{
677 struct platform_device *pdev = to_platform_device(dev);
678 struct resource *res;
679 ide_hwif_t *hwif = dev_get_drvdata(dev);
Jordan Crouse8f29e652005-12-15 02:17:46 +0100680 _auide_hwif *ahwif = &auide_hwif;
Pete Popov26a940e2005-09-15 08:03:12 +0000681
Bartlomiej Zolnierkiewicz909f4362008-02-02 19:56:39 +0100682 ide_unregister(hwif->index, 0, 0);
Pete Popov26a940e2005-09-15 08:03:12 +0000683
684 iounmap((void *)ahwif->regbase);
685
686 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
687 release_mem_region(res->start, res->end - res->start);
688
689 return 0;
690}
691
692static struct device_driver au1200_ide_driver = {
693 .name = "au1200-ide",
694 .bus = &platform_bus_type,
695 .probe = au_ide_probe,
696 .remove = au_ide_remove,
697};
698
699static int __init au_ide_init(void)
700{
701 return driver_register(&au1200_ide_driver);
702}
703
Jordan Crouse8f29e652005-12-15 02:17:46 +0100704static void __exit au_ide_exit(void)
Pete Popov26a940e2005-09-15 08:03:12 +0000705{
706 driver_unregister(&au1200_ide_driver);
707}
708
Pete Popov26a940e2005-09-15 08:03:12 +0000709MODULE_LICENSE("GPL");
710MODULE_DESCRIPTION("AU1200 IDE driver");
711
712module_init(au_ide_init);
713module_exit(au_ide_exit);