ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / drivers / mtd / devices / pmc551.c
1 /*
2  * $Id: pmc551.c,v 1.24 2003/05/20 21:03:08 dwmw2 Exp $
3  *
4  * PMC551 PCI Mezzanine Ram Device
5  *
6  * Author:
7  *       Mark Ferrell <mferrell@mvista.com>
8  *       Copyright 1999,2000 Nortel Networks
9  *
10  * License:
11  *       As part of this driver was derived from the slram.c driver it
12  *       falls under the same license, which is GNU General Public
13  *       License v2
14  *
15  * Description:
16  *       This driver is intended to support the PMC551 PCI Ram device
17  *       from Ramix Inc.  The PMC551 is a PMC Mezzanine module for
18  *       cPCI embedded systems.  The device contains a single SROM
19  *       that initially programs the V370PDC chipset onboard the
20  *       device, and various banks of DRAM/SDRAM onboard.  This driver
21  *       implements this PCI Ram device as an MTD (Memory Technology
22  *       Device) so that it can be used to hold a file system, or for
23  *       added swap space in embedded systems.  Since the memory on
24  *       this board isn't as fast as main memory we do not try to hook
25  *       it into main memory as that would simply reduce performance
26  *       on the system.  Using it as a block device allows us to use
27  *       it as high speed swap or for a high speed disk device of some
28  *       sort.  Which becomes very useful on diskless systems in the
29  *       embedded market I might add.
30  *       
31  * Notes:
32  *       Due to what I assume is more buggy SROM, the 64M PMC551 I
33  *       have available claims that all 4 of it's DRAM banks have 64M
34  *       of ram configured (making a grand total of 256M onboard).
35  *       This is slightly annoying since the BAR0 size reflects the
36  *       aperture size, not the dram size, and the V370PDC supplies no
37  *       other method for memory size discovery.  This problem is
38  *       mostly only relevant when compiled as a module, as the
39  *       unloading of the module with an aperture size smaller then
40  *       the ram will cause the driver to detect the onboard memory
41  *       size to be equal to the aperture size when the module is
42  *       reloaded.  Soooo, to help, the module supports an msize
43  *       option to allow the specification of the onboard memory, and
44  *       an asize option, to allow the specification of the aperture
45  *       size.  The aperture must be equal to or less then the memory
46  *       size, the driver will correct this if you screw it up.  This
47  *       problem is not relevant for compiled in drivers as compiled
48  *       in drivers only init once.
49  *
50  * Credits:
51  *       Saeed Karamooz <saeed@ramix.com> of Ramix INC. for the
52  *       initial example code of how to initialize this device and for
53  *       help with questions I had concerning operation of the device.
54  *
55  *       Most of the MTD code for this driver was originally written
56  *       for the slram.o module in the MTD drivers package which
57  *       allows the mapping of system memory into an MTD device.
58  *       Since the PMC551 memory module is accessed in the same
59  *       fashion as system memory, the slram.c code became a very nice
60  *       fit to the needs of this driver.  All we added was PCI
61  *       detection/initialization to the driver and automatically figure
62  *       out the size via the PCI detection.o, later changes by Corey
63  *       Minyard set up the card to utilize a 1M sliding apature.
64  *
65  *       Corey Minyard <minyard@nortelnetworks.com>
66  *       * Modified driver to utilize a sliding aperture instead of 
67  *         mapping all memory into kernel space which turned out to
68  *         be very wasteful.
69  *       * Located a bug in the SROM's initialization sequence that 
70  *         made the memory unusable, added a fix to code to touch up
71  *         the DRAM some.
72  *
73  * Bugs/FIXME's:
74  *       * MUST fix the init function to not spin on a register
75  *       waiting for it to set .. this does not safely handle busted
76  *       devices that never reset the register correctly which will
77  *       cause the system to hang w/ a reboot being the only chance at
78  *       recover. [sort of fixed, could be better]
79  *       * Add I2C handling of the SROM so we can read the SROM's information
80  *       about the aperture size.  This should always accurately reflect the
81  *       onboard memory size.
82  *       * Comb the init routine.  It's still a bit cludgy on a few things.
83  */
84
85 #include <linux/version.h>
86 #include <linux/config.h>
87 #include <linux/kernel.h>
88 #include <linux/module.h>
89 #include <asm/uaccess.h>
90 #include <linux/types.h>
91 #include <linux/sched.h>
92 #include <linux/init.h>
93 #include <linux/ptrace.h>
94 #include <linux/slab.h>
95 #include <linux/string.h>
96 #include <linux/timer.h>
97 #include <linux/major.h>
98 #include <linux/fs.h>
99 #include <linux/ioctl.h>
100 #include <asm/io.h>
101 #include <asm/system.h>
102 #include <linux/pci.h>
103
104 #ifndef CONFIG_PCI
105 #error Enable PCI in your kernel config
106 #endif
107
108 #include <linux/mtd/mtd.h>
109 #include <linux/mtd/pmc551.h>
110 #include <linux/mtd/compatmac.h>
111
112 #if LINUX_VERSION_CODE > 0x20300
113 #define PCI_BASE_ADDRESS(dev) (dev->resource[0].start)
114 #else
115 #define PCI_BASE_ADDRESS(dev) (dev->base_address[0])
116 #endif
117
118 static struct mtd_info *pmc551list;
119
120 static int pmc551_erase (struct mtd_info *mtd, struct erase_info *instr)
121 {
122         struct mypriv *priv = (struct mypriv *)mtd->priv;
123         u32 soff_hi, soff_lo; /* start address offset hi/lo */
124         u32 eoff_hi, eoff_lo; /* end address offset hi/lo */
125         unsigned long end;
126         u_char *ptr;
127         size_t retlen;
128
129 #ifdef CONFIG_MTD_PMC551_DEBUG
130         printk(KERN_DEBUG "pmc551_erase(pos:%ld, len:%ld)\n", (long)instr->addr, (long)instr->len);
131 #endif
132
133         end = instr->addr + instr->len - 1;
134
135         /* Is it past the end? */
136         if ( end > mtd->size ) {
137 #ifdef CONFIG_MTD_PMC551_DEBUG
138         printk(KERN_DEBUG "pmc551_erase() out of bounds (%ld > %ld)\n", (long)end, (long)mtd->size);
139 #endif
140                 return -EINVAL;
141         }
142
143         eoff_hi = end & ~(priv->asize - 1);
144         soff_hi = instr->addr & ~(priv->asize - 1);
145         eoff_lo = end & (priv->asize - 1);
146         soff_lo = instr->addr & (priv->asize - 1);
147
148         pmc551_point (mtd, instr->addr, instr->len, &retlen, &ptr);
149
150         if ( soff_hi == eoff_hi || mtd->size == priv->asize) {
151                 /* The whole thing fits within one access, so just one shot
152                    will do it. */
153                 memset(ptr, 0xff, instr->len);
154         } else {
155                 /* We have to do multiple writes to get all the data
156                    written. */
157                 while (soff_hi != eoff_hi) {
158 #ifdef CONFIG_MTD_PMC551_DEBUG
159                         printk( KERN_DEBUG "pmc551_erase() soff_hi: %ld, eoff_hi: %ld\n", (long)soff_hi, (long)eoff_hi);
160 #endif
161                         memset(ptr, 0xff, priv->asize);
162                         if (soff_hi + priv->asize >= mtd->size) {
163                                 goto out;
164                         }
165                         soff_hi += priv->asize;
166                         pmc551_point (mtd,(priv->base_map0|soff_hi),
167                                       priv->asize, &retlen, &ptr);
168                 }
169                 memset (ptr, 0xff, eoff_lo);
170         }
171
172 out:
173         instr->state = MTD_ERASE_DONE;
174 #ifdef CONFIG_MTD_PMC551_DEBUG
175         printk(KERN_DEBUG "pmc551_erase() done\n");
176 #endif
177
178         if (instr->callback) {
179                 (*(instr->callback))(instr);
180         }
181         return 0;
182 }
183
184
185 static int pmc551_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf)
186 {
187         struct mypriv *priv = (struct mypriv *)mtd->priv;
188         u32 soff_hi;
189         u32 soff_lo;
190
191 #ifdef CONFIG_MTD_PMC551_DEBUG
192         printk(KERN_DEBUG "pmc551_point(%ld, %ld)\n", (long)from, (long)len);
193 #endif
194
195         if (from + len > mtd->size) {
196 #ifdef CONFIG_MTD_PMC551_DEBUG
197                 printk(KERN_DEBUG "pmc551_point() out of bounds (%ld > %ld)\n", (long)from+len, (long)mtd->size);
198 #endif
199                 return -EINVAL;
200         }
201
202         soff_hi = from & ~(priv->asize - 1);
203         soff_lo = from & (priv->asize - 1);
204
205         /* Cheap hack optimization */
206         if( priv->curr_map0 != from ) {
207                 pci_write_config_dword ( priv->dev, PMC551_PCI_MEM_MAP0,
208                                         (priv->base_map0 | soff_hi) );
209                 priv->curr_map0 = soff_hi;
210         }
211
212         *mtdbuf = priv->start + soff_lo;
213         *retlen = len;
214         return 0;
215 }
216
217
218 static void pmc551_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
219 {
220 #ifdef CONFIG_MTD_PMC551_DEBUG
221         printk(KERN_DEBUG "pmc551_unpoint()\n");
222 #endif
223 }
224
225
226 static int pmc551_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
227 {
228         struct mypriv *priv = (struct mypriv *)mtd->priv;
229         u32 soff_hi, soff_lo; /* start address offset hi/lo */
230         u32 eoff_hi, eoff_lo; /* end address offset hi/lo */
231         unsigned long end;
232         u_char *ptr;
233         u_char *copyto = buf;
234
235 #ifdef CONFIG_MTD_PMC551_DEBUG
236         printk(KERN_DEBUG "pmc551_read(pos:%ld, len:%ld) asize: %ld\n", (long)from, (long)len, (long)priv->asize);
237 #endif
238
239         end = from + len - 1;
240
241         /* Is it past the end? */
242         if (end > mtd->size) {
243 #ifdef CONFIG_MTD_PMC551_DEBUG
244         printk(KERN_DEBUG "pmc551_read() out of bounds (%ld > %ld)\n", (long) end, (long)mtd->size);
245 #endif
246                 return -EINVAL;
247         }
248
249         soff_hi = from & ~(priv->asize - 1);
250         eoff_hi = end & ~(priv->asize - 1);
251         soff_lo = from & (priv->asize - 1);
252         eoff_lo = end & (priv->asize - 1);
253
254         pmc551_point (mtd, from, len, retlen, &ptr);
255
256         if (soff_hi == eoff_hi) {
257                 /* The whole thing fits within one access, so just one shot
258                    will do it. */
259                 memcpy(copyto, ptr, len);
260                 copyto += len;
261         } else {
262                 /* We have to do multiple writes to get all the data
263                    written. */
264                 while (soff_hi != eoff_hi) {
265 #ifdef CONFIG_MTD_PMC551_DEBUG
266                         printk( KERN_DEBUG "pmc551_read() soff_hi: %ld, eoff_hi: %ld\n", (long)soff_hi, (long)eoff_hi);
267 #endif
268                         memcpy(copyto, ptr, priv->asize);
269                         copyto += priv->asize;
270                         if (soff_hi + priv->asize >= mtd->size) {
271                                 goto out;
272                         }
273                         soff_hi += priv->asize;
274                         pmc551_point (mtd, soff_hi, priv->asize, retlen, &ptr);
275                 }
276                 memcpy(copyto, ptr, eoff_lo);
277                 copyto += eoff_lo;
278         }
279
280 out:
281 #ifdef CONFIG_MTD_PMC551_DEBUG
282         printk(KERN_DEBUG "pmc551_read() done\n");
283 #endif
284         *retlen = copyto - buf;
285         return 0;
286 }
287
288 static int pmc551_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
289 {
290         struct mypriv *priv = (struct mypriv *)mtd->priv;
291         u32 soff_hi, soff_lo; /* start address offset hi/lo */
292         u32 eoff_hi, eoff_lo; /* end address offset hi/lo */
293         unsigned long end;
294         u_char *ptr;
295         const u_char *copyfrom = buf;
296
297
298 #ifdef CONFIG_MTD_PMC551_DEBUG
299         printk(KERN_DEBUG "pmc551_write(pos:%ld, len:%ld) asize:%ld\n", (long)to, (long)len, (long)priv->asize);
300 #endif
301
302         end = to + len - 1;
303         /* Is it past the end?  or did the u32 wrap? */
304         if (end > mtd->size ) {
305 #ifdef CONFIG_MTD_PMC551_DEBUG
306         printk(KERN_DEBUG "pmc551_write() out of bounds (end: %ld, size: %ld, to: %ld)\n", (long) end, (long)mtd->size, (long)to);
307 #endif
308                 return -EINVAL;
309         }
310
311         soff_hi = to & ~(priv->asize - 1);
312         eoff_hi = end & ~(priv->asize - 1);
313         soff_lo = to & (priv->asize - 1);
314         eoff_lo = end & (priv->asize - 1);
315
316         pmc551_point (mtd, to, len, retlen, &ptr);
317
318         if (soff_hi == eoff_hi) {
319                 /* The whole thing fits within one access, so just one shot
320                    will do it. */
321                 memcpy(ptr, copyfrom, len);
322                 copyfrom += len;
323         } else {
324                 /* We have to do multiple writes to get all the data
325                    written. */
326                 while (soff_hi != eoff_hi) {
327 #ifdef CONFIG_MTD_PMC551_DEBUG
328                         printk( KERN_DEBUG "pmc551_write() soff_hi: %ld, eoff_hi: %ld\n", (long)soff_hi, (long)eoff_hi);
329 #endif
330                         memcpy(ptr, copyfrom, priv->asize);
331                         copyfrom += priv->asize;
332                         if (soff_hi >= mtd->size) {
333                                 goto out;
334                         }
335                         soff_hi += priv->asize;
336                         pmc551_point (mtd, soff_hi, priv->asize, retlen, &ptr);
337                 }
338                 memcpy(ptr, copyfrom, eoff_lo);
339                 copyfrom += eoff_lo;
340         }
341
342 out:
343 #ifdef CONFIG_MTD_PMC551_DEBUG
344         printk(KERN_DEBUG "pmc551_write() done\n");
345 #endif
346         *retlen = copyfrom - buf;
347         return 0;
348 }
349
350 /*
351  * Fixup routines for the V370PDC
352  * PCI device ID 0x020011b0
353  *
354  * This function basicly kick starts the DRAM oboard the card and gets it
355  * ready to be used.  Before this is done the device reads VERY erratic, so
356  * much that it can crash the Linux 2.2.x series kernels when a user cat's
357  * /proc/pci .. though that is mainly a kernel bug in handling the PCI DEVSEL
358  * register.  FIXME: stop spinning on registers .. must implement a timeout
359  * mechanism
360  * returns the size of the memory region found.
361  */
362 static u32 fixup_pmc551 (struct pci_dev *dev)
363 {
364 #ifdef CONFIG_MTD_PMC551_BUGFIX
365         u32 dram_data;
366 #endif
367         u32 size, dcmd, cfg, dtmp;
368         u16 cmd, tmp, i;
369         u8 bcmd, counter;
370
371         /* Sanity Check */
372         if(!dev) {
373                 return -ENODEV;
374         }
375
376         /*
377          * Attempt to reset the card
378          * FIXME: Stop Spinning registers
379          */
380         counter=0;
381         /* unlock registers */
382         pci_write_config_byte(dev, PMC551_SYS_CTRL_REG, 0xA5 );
383         /* read in old data */
384         pci_read_config_byte(dev, PMC551_SYS_CTRL_REG, &bcmd );
385         /* bang the reset line up and down for a few */
386         for(i=0;i<10;i++) {
387                 counter=0;
388                 bcmd &= ~0x80;
389                 while(counter++ < 100) {
390                         pci_write_config_byte(dev, PMC551_SYS_CTRL_REG, bcmd);
391                 }
392                 counter=0;
393                 bcmd |= 0x80;
394                 while(counter++ < 100) {
395                         pci_write_config_byte(dev, PMC551_SYS_CTRL_REG, bcmd);
396                 }
397         }
398         bcmd |= (0x40|0x20);
399         pci_write_config_byte(dev, PMC551_SYS_CTRL_REG, bcmd);
400
401         /* 
402          * Take care and turn off the memory on the device while we
403          * tweak the configurations
404          */
405         pci_read_config_word(dev, PCI_COMMAND, &cmd);
406         tmp = cmd & ~(PCI_COMMAND_IO|PCI_COMMAND_MEMORY);
407         pci_write_config_word(dev, PCI_COMMAND, tmp);
408
409         /*
410          * Disable existing aperture before probing memory size
411          */
412         pci_read_config_dword(dev, PMC551_PCI_MEM_MAP0, &dcmd);
413         dtmp=(dcmd|PMC551_PCI_MEM_MAP_ENABLE|PMC551_PCI_MEM_MAP_REG_EN);
414         pci_write_config_dword(dev, PMC551_PCI_MEM_MAP0, dtmp);
415         /*
416          * Grab old BAR0 config so that we can figure out memory size
417          * This is another bit of kludge going on.  The reason for the
418          * redundancy is I am hoping to retain the original configuration
419          * previously assigned to the card by the BIOS or some previous 
420          * fixup routine in the kernel.  So we read the old config into cfg,
421          * then write all 1's to the memory space, read back the result into
422          * "size", and then write back all the old config.
423          */
424         pci_read_config_dword( dev, PCI_BASE_ADDRESS_0, &cfg );
425 #ifndef CONFIG_MTD_PMC551_BUGFIX
426         pci_write_config_dword( dev, PCI_BASE_ADDRESS_0, ~0 );
427         pci_read_config_dword( dev, PCI_BASE_ADDRESS_0, &size );
428         size = (size&PCI_BASE_ADDRESS_MEM_MASK);
429         size &= ~(size-1);
430         pci_write_config_dword( dev, PCI_BASE_ADDRESS_0, cfg );
431 #else
432         /*
433          * Get the size of the memory by reading all the DRAM size values
434          * and adding them up.
435          *
436          * KLUDGE ALERT: the boards we are using have invalid column and
437          * row mux values.  We fix them here, but this will break other
438          * memory configurations.
439          */
440         pci_read_config_dword(dev, PMC551_DRAM_BLK0, &dram_data);
441         size = PMC551_DRAM_BLK_GET_SIZE(dram_data);
442         dram_data = PMC551_DRAM_BLK_SET_COL_MUX(dram_data, 0x5);
443         dram_data = PMC551_DRAM_BLK_SET_ROW_MUX(dram_data, 0x9);
444         pci_write_config_dword(dev, PMC551_DRAM_BLK0, dram_data);
445
446         pci_read_config_dword(dev, PMC551_DRAM_BLK1, &dram_data);
447         size += PMC551_DRAM_BLK_GET_SIZE(dram_data);
448         dram_data = PMC551_DRAM_BLK_SET_COL_MUX(dram_data, 0x5);
449         dram_data = PMC551_DRAM_BLK_SET_ROW_MUX(dram_data, 0x9);
450         pci_write_config_dword(dev, PMC551_DRAM_BLK1, dram_data);
451
452         pci_read_config_dword(dev, PMC551_DRAM_BLK2, &dram_data);
453         size += PMC551_DRAM_BLK_GET_SIZE(dram_data);
454         dram_data = PMC551_DRAM_BLK_SET_COL_MUX(dram_data, 0x5);
455         dram_data = PMC551_DRAM_BLK_SET_ROW_MUX(dram_data, 0x9);
456         pci_write_config_dword(dev, PMC551_DRAM_BLK2, dram_data);
457
458         pci_read_config_dword(dev, PMC551_DRAM_BLK3, &dram_data);
459         size += PMC551_DRAM_BLK_GET_SIZE(dram_data);
460         dram_data = PMC551_DRAM_BLK_SET_COL_MUX(dram_data, 0x5);
461         dram_data = PMC551_DRAM_BLK_SET_ROW_MUX(dram_data, 0x9);
462         pci_write_config_dword(dev, PMC551_DRAM_BLK3, dram_data);
463
464         /*
465          * Oops .. something went wrong
466          */
467         if( (size &= PCI_BASE_ADDRESS_MEM_MASK) == 0) {
468                 return -ENODEV;
469         }
470 #endif /* CONFIG_MTD_PMC551_BUGFIX */
471
472         if ((cfg&PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_MEMORY) {
473                 return -ENODEV;
474         }
475
476         /*
477          * Precharge Dram
478          */
479         pci_write_config_word( dev, PMC551_SDRAM_MA, 0x0400 );
480         pci_write_config_word( dev, PMC551_SDRAM_CMD, 0x00bf );
481
482         /*
483          * Wait until command has gone through
484          * FIXME: register spinning issue
485          */
486         do {    pci_read_config_word( dev, PMC551_SDRAM_CMD, &cmd );
487                 if(counter++ > 100)break;
488         } while ( (PCI_COMMAND_IO) & cmd );
489
490         /*
491          * Turn on auto refresh 
492          * The loop is taken directly from Ramix's example code.  I assume that
493          * this must be held high for some duration of time, but I can find no
494          * documentation refrencing the reasons why.
495          */
496         for ( i = 1; i<=8 ; i++) {
497                 pci_write_config_word (dev, PMC551_SDRAM_CMD, 0x0df);
498
499                 /*
500                  * Make certain command has gone through
501                  * FIXME: register spinning issue
502                  */
503                 counter=0;
504                 do {    pci_read_config_word(dev, PMC551_SDRAM_CMD, &cmd);
505                         if(counter++ > 100)break;
506                 } while ( (PCI_COMMAND_IO) & cmd );
507         }
508
509         pci_write_config_word ( dev, PMC551_SDRAM_MA, 0x0020);
510         pci_write_config_word ( dev, PMC551_SDRAM_CMD, 0x0ff);
511
512         /*
513          * Wait until command completes
514          * FIXME: register spinning issue
515          */
516         counter=0;
517         do {    pci_read_config_word ( dev, PMC551_SDRAM_CMD, &cmd);
518                 if(counter++ > 100)break;
519         } while ( (PCI_COMMAND_IO) & cmd );
520
521         pci_read_config_dword ( dev, PMC551_DRAM_CFG, &dcmd);
522         dcmd |= 0x02000000;
523         pci_write_config_dword ( dev, PMC551_DRAM_CFG, dcmd);
524
525         /*
526          * Check to make certain fast back-to-back, if not
527          * then set it so
528          */
529         pci_read_config_word( dev, PCI_STATUS, &cmd);
530         if((cmd&PCI_COMMAND_FAST_BACK) == 0) {
531                 cmd |= PCI_COMMAND_FAST_BACK;
532                 pci_write_config_word( dev, PCI_STATUS, cmd);
533         }
534
535         /*
536          * Check to make certain the DEVSEL is set correctly, this device
537          * has a tendancy to assert DEVSEL and TRDY when a write is performed
538          * to the memory when memory is read-only
539          */
540         if((cmd&PCI_STATUS_DEVSEL_MASK) != 0x0) {
541                 cmd &= ~PCI_STATUS_DEVSEL_MASK;
542                 pci_write_config_word( dev, PCI_STATUS, cmd );
543         }
544         /*
545          * Set to be prefetchable and put everything back based on old cfg.
546          * it's possible that the reset of the V370PDC nuked the original
547          * setup
548          */
549         /*
550         cfg |= PCI_BASE_ADDRESS_MEM_PREFETCH;
551         pci_write_config_dword( dev, PCI_BASE_ADDRESS_0, cfg );
552         */
553
554         /*
555          * Turn PCI memory and I/O bus access back on
556          */
557         pci_write_config_word( dev, PCI_COMMAND,
558                                PCI_COMMAND_MEMORY | PCI_COMMAND_IO );
559 #ifdef CONFIG_MTD_PMC551_DEBUG
560         /*
561          * Some screen fun
562          */
563         printk(KERN_DEBUG "pmc551: %d%c (0x%x) of %sprefetchable memory at 0x%lx\n",
564                (size<1024)?size:(size<1048576)?size>>10:size>>20,
565                (size<1024)?'B':(size<1048576)?'K':'M',
566                size, ((dcmd&(0x1<<3)) == 0)?"non-":"",
567                PCI_BASE_ADDRESS(dev)&PCI_BASE_ADDRESS_MEM_MASK );
568
569         /*
570          * Check to see the state of the memory
571          */
572         pci_read_config_dword( dev, PMC551_DRAM_BLK0, &dcmd );
573         printk(KERN_DEBUG "pmc551: DRAM_BLK0 Flags: %s,%s\n"
574                           "pmc551: DRAM_BLK0 Size: %d at %d\n"
575                           "pmc551: DRAM_BLK0 Row MUX: %d, Col MUX: %d\n",
576                (((0x1<<1)&dcmd) == 0)?"RW":"RO",
577                (((0x1<<0)&dcmd) == 0)?"Off":"On",
578                PMC551_DRAM_BLK_GET_SIZE(dcmd),
579                ((dcmd>>20)&0x7FF), ((dcmd>>13)&0x7), ((dcmd>>9)&0xF) );
580
581         pci_read_config_dword( dev, PMC551_DRAM_BLK1, &dcmd );
582         printk(KERN_DEBUG "pmc551: DRAM_BLK1 Flags: %s,%s\n"
583                           "pmc551: DRAM_BLK1 Size: %d at %d\n"
584                           "pmc551: DRAM_BLK1 Row MUX: %d, Col MUX: %d\n",
585                (((0x1<<1)&dcmd) == 0)?"RW":"RO",
586                (((0x1<<0)&dcmd) == 0)?"Off":"On",
587                PMC551_DRAM_BLK_GET_SIZE(dcmd),
588                ((dcmd>>20)&0x7FF), ((dcmd>>13)&0x7), ((dcmd>>9)&0xF) );
589
590         pci_read_config_dword( dev, PMC551_DRAM_BLK2, &dcmd );
591         printk(KERN_DEBUG "pmc551: DRAM_BLK2 Flags: %s,%s\n"
592                           "pmc551: DRAM_BLK2 Size: %d at %d\n"
593                           "pmc551: DRAM_BLK2 Row MUX: %d, Col MUX: %d\n",
594                (((0x1<<1)&dcmd) == 0)?"RW":"RO",
595                (((0x1<<0)&dcmd) == 0)?"Off":"On",
596                PMC551_DRAM_BLK_GET_SIZE(dcmd),
597                ((dcmd>>20)&0x7FF), ((dcmd>>13)&0x7), ((dcmd>>9)&0xF) );
598
599         pci_read_config_dword( dev, PMC551_DRAM_BLK3, &dcmd );
600         printk(KERN_DEBUG "pmc551: DRAM_BLK3 Flags: %s,%s\n"
601                           "pmc551: DRAM_BLK3 Size: %d at %d\n"
602                           "pmc551: DRAM_BLK3 Row MUX: %d, Col MUX: %d\n",
603                (((0x1<<1)&dcmd) == 0)?"RW":"RO",
604                (((0x1<<0)&dcmd) == 0)?"Off":"On",
605                PMC551_DRAM_BLK_GET_SIZE(dcmd),
606                ((dcmd>>20)&0x7FF), ((dcmd>>13)&0x7), ((dcmd>>9)&0xF) );
607
608         pci_read_config_word( dev, PCI_COMMAND, &cmd );
609         printk( KERN_DEBUG "pmc551: Memory Access %s\n",
610                 (((0x1<<1)&cmd) == 0)?"off":"on" );
611         printk( KERN_DEBUG "pmc551: I/O Access %s\n",
612                 (((0x1<<0)&cmd) == 0)?"off":"on" );
613
614         pci_read_config_word( dev, PCI_STATUS, &cmd );
615         printk( KERN_DEBUG "pmc551: Devsel %s\n",
616                 ((PCI_STATUS_DEVSEL_MASK&cmd)==0x000)?"Fast":
617                 ((PCI_STATUS_DEVSEL_MASK&cmd)==0x200)?"Medium":
618                 ((PCI_STATUS_DEVSEL_MASK&cmd)==0x400)?"Slow":"Invalid" );
619
620         printk( KERN_DEBUG "pmc551: %sFast Back-to-Back\n",
621                 ((PCI_COMMAND_FAST_BACK&cmd) == 0)?"Not ":"" );
622
623         pci_read_config_byte(dev, PMC551_SYS_CTRL_REG, &bcmd );
624         printk( KERN_DEBUG "pmc551: EEPROM is under %s control\n"
625                            "pmc551: System Control Register is %slocked to PCI access\n"
626                            "pmc551: System Control Register is %slocked to EEPROM access\n", 
627                 (bcmd&0x1)?"software":"hardware",
628                 (bcmd&0x20)?"":"un", (bcmd&0x40)?"":"un");
629 #endif
630         return size;
631 }
632
633 /*
634  * Kernel version specific module stuffages
635  */
636
637
638 MODULE_LICENSE("GPL");
639 MODULE_AUTHOR("Mark Ferrell <mferrell@mvista.com>");
640 MODULE_DESCRIPTION(PMC551_VERSION);
641 MODULE_PARM(msize, "i");
642 MODULE_PARM_DESC(msize, "memory size in Megabytes [1 - 1024]");
643 MODULE_PARM(asize, "i");
644 MODULE_PARM_DESC(asize, "aperture size, must be <= memsize [1-1024]");
645
646 /*
647  * Stuff these outside the ifdef so as to not bust compiled in driver support
648  */
649 static int msize=0;
650 #if defined(CONFIG_MTD_PMC551_APERTURE_SIZE)
651 static int asize=CONFIG_MTD_PMC551_APERTURE_SIZE
652 #else
653 static int asize=0;
654 #endif
655
656 /*
657  * PMC551 Card Initialization
658  */
659 int __init init_pmc551(void)
660 {
661         struct pci_dev *PCI_Device = NULL;
662         struct mypriv *priv;
663         int count, found=0;
664         struct mtd_info *mtd;
665         u32 length = 0;
666
667         if(msize) {
668                 msize = (1 << (ffs(msize) - 1))<<20;
669                 if (msize > (1<<30)) {
670                         printk(KERN_NOTICE "pmc551: Invalid memory size [%d]\n", msize);
671                         return -EINVAL;
672                 }
673         }
674
675         if(asize) {
676                 asize = (1 << (ffs(asize) - 1))<<20;
677                 if (asize > (1<<30) ) {
678                         printk(KERN_NOTICE "pmc551: Invalid aperture size [%d]\n", asize);
679                         return -EINVAL;
680                 }
681         }
682
683         printk(KERN_INFO PMC551_VERSION);
684
685         /*
686          * PCU-bus chipset probe.
687          */
688         for( count = 0; count < MAX_MTD_DEVICES; count++ ) {
689
690                 if ((PCI_Device = pci_find_device(PCI_VENDOR_ID_V3_SEMI,
691                                                   PCI_DEVICE_ID_V3_SEMI_V370PDC,
692                                                   PCI_Device ) ) == NULL) {
693                         break;
694                 }
695
696                 printk(KERN_NOTICE "pmc551: Found PCI V370PDC at 0x%lX\n",
697                                     PCI_BASE_ADDRESS(PCI_Device));
698
699                 /*
700                  * The PMC551 device acts VERY weird if you don't init it
701                  * first.  i.e. it will not correctly report devsel.  If for
702                  * some reason the sdram is in a wrote-protected state the
703                  * device will DEVSEL when it is written to causing problems
704                  * with the oldproc.c driver in
705                  * some kernels (2.2.*)
706                  */
707                 if((length = fixup_pmc551(PCI_Device)) <= 0) {
708                         printk(KERN_NOTICE "pmc551: Cannot init SDRAM\n");
709                         break;
710                 }
711
712                 /*
713                  * This is needed until the driver is capable of reading the
714                  * onboard I2C SROM to discover the "real" memory size.
715                  */
716                 if(msize) {
717                         length = msize;
718                         printk(KERN_NOTICE "pmc551: Using specified memory size 0x%x\n", length);
719                 } else {
720                         msize = length;
721                 }
722
723                 mtd = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
724                 if (!mtd) {
725                         printk(KERN_NOTICE "pmc551: Cannot allocate new MTD device.\n");
726                         break;
727                 }
728
729                 memset(mtd, 0, sizeof(struct mtd_info));
730
731                 priv = kmalloc (sizeof(struct mypriv), GFP_KERNEL);
732                 if (!priv) {
733                         printk(KERN_NOTICE "pmc551: Cannot allocate new MTD device.\n");
734                         kfree(mtd);
735                         break;
736                 }
737                 memset(priv, 0, sizeof(*priv));
738                 mtd->priv = priv;
739                 priv->dev = PCI_Device;
740
741                 if(asize > length) {
742                         printk(KERN_NOTICE "pmc551: reducing aperture size to fit %dM\n",length>>20);
743                         priv->asize = asize = length;
744                 } else if (asize == 0 || asize == length) {
745                         printk(KERN_NOTICE "pmc551: Using existing aperture size %dM\n", length>>20);
746                         priv->asize = asize = length;
747                 } else {
748                         printk(KERN_NOTICE "pmc551: Using specified aperture size %dM\n", asize>>20);
749                         priv->asize = asize;
750                 }
751                 priv->start = ioremap((PCI_BASE_ADDRESS(PCI_Device)
752                                        & PCI_BASE_ADDRESS_MEM_MASK),
753                                       priv->asize);
754                 
755                 if (!priv->start) {
756                         printk(KERN_NOTICE "pmc551: Unable to map IO space\n");
757                         kfree(mtd->priv);
758                         kfree(mtd);
759                         break;
760                 }
761
762 #ifdef CONFIG_MTD_PMC551_DEBUG
763                 printk( KERN_DEBUG "pmc551: setting aperture to %d\n",
764                         ffs(priv->asize>>20)-1);
765 #endif
766
767                 priv->base_map0 = ( PMC551_PCI_MEM_MAP_REG_EN
768                                   | PMC551_PCI_MEM_MAP_ENABLE
769                                   | (ffs(priv->asize>>20)-1)<<4 );
770                 priv->curr_map0 = priv->base_map0;
771                 pci_write_config_dword ( priv->dev, PMC551_PCI_MEM_MAP0,
772                                          priv->curr_map0 );
773
774 #ifdef CONFIG_MTD_PMC551_DEBUG
775                 printk( KERN_DEBUG "pmc551: aperture set to %d\n", 
776                         (priv->base_map0 & 0xF0)>>4 );
777 #endif
778
779                 mtd->size       = msize;
780                 mtd->flags      = MTD_CAP_RAM;
781                 mtd->erase      = pmc551_erase;
782                 mtd->read       = pmc551_read;
783                 mtd->write      = pmc551_write;
784                 mtd->point      = pmc551_point;
785                 mtd->unpoint    = pmc551_unpoint;
786                 mtd->type       = MTD_RAM;
787                 mtd->name       = "PMC551 RAM board";
788                 mtd->erasesize  = 0x10000;
789                 mtd->owner = THIS_MODULE;
790
791                 if (add_mtd_device(mtd)) {
792                         printk(KERN_NOTICE "pmc551: Failed to register new device\n");
793                         iounmap(priv->start);
794                         kfree(mtd->priv);
795                         kfree(mtd);
796                         break;
797                 }
798                 printk(KERN_NOTICE "Registered pmc551 memory device.\n");
799                 printk(KERN_NOTICE "Mapped %dM of memory from 0x%p to 0x%p\n",
800                        priv->asize>>20,
801                        priv->start,
802                        priv->start + priv->asize);
803                 printk(KERN_NOTICE "Total memory is %d%c\n",
804                         (length<1024)?length:
805                                 (length<1048576)?length>>10:length>>20,
806                         (length<1024)?'B':(length<1048576)?'K':'M');
807                 priv->nextpmc551 = pmc551list;
808                 pmc551list = mtd;
809                 found++;
810         }
811
812         if( !pmc551list ) {
813                 printk(KERN_NOTICE "pmc551: not detected\n");
814                 return -ENODEV;
815         } else {
816                 printk(KERN_NOTICE "pmc551: %d pmc551 devices loaded\n", found);
817                 return 0;
818         }
819 }
820
821 /*
822  * PMC551 Card Cleanup
823  */
824 static void __exit cleanup_pmc551(void)
825 {
826         int found=0;
827         struct mtd_info *mtd;
828         struct mypriv *priv;
829
830         while((mtd=pmc551list)) {
831                 priv = (struct mypriv *)mtd->priv;
832                 pmc551list = priv->nextpmc551;
833                 
834                 if(priv->start) {
835                         printk (KERN_DEBUG "pmc551: unmapping %dM starting at 0x%p\n",
836                                 priv->asize>>20, priv->start);
837                         iounmap (priv->start);
838                 }
839                 
840                 kfree (mtd->priv);
841                 del_mtd_device (mtd);
842                 kfree (mtd);
843                 found++;
844         }
845
846         printk(KERN_NOTICE "pmc551: %d pmc551 devices unloaded\n", found);
847 }
848
849 module_init(init_pmc551);
850 module_exit(cleanup_pmc551);