~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/drivers/mtd/pmc551.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.