c909f4bda5eeb754323c035ebaa21b02befeb041
[linux-2.6.git] / drivers / mtd / maps / scx200_docflash.c
1 /* linux/drivers/mtd/maps/scx200_docflash.c 
2
3    Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
4
5    $Id: scx200_docflash.c,v 1.5 2003/05/21 12:45:20 dwmw2 Exp $ 
6
7    National Semiconductor SCx200 flash mapped with DOCCS
8 */
9
10 #include <linux/module.h>
11 #include <linux/config.h>
12 #include <linux/types.h>
13 #include <linux/kernel.h>
14 #include <linux/init.h>
15 #include <asm/io.h>
16 #include <linux/mtd/mtd.h>
17 #include <linux/mtd/map.h>
18 #include <linux/mtd/partitions.h>
19
20 #include <linux/pci.h>
21 #include <linux/scx200.h>
22
23 #define NAME "scx200_docflash"
24
25 MODULE_AUTHOR("Christer Weinigel <wingel@hack.org>");
26 MODULE_DESCRIPTION("NatSemi SCx200 DOCCS Flash Driver");
27 MODULE_LICENSE("GPL");
28
29 /* Set this to one if you want to partition the flash */
30 #define PARTITION 1
31
32 MODULE_PARM(probe, "i");
33 MODULE_PARM_DESC(probe, "Probe for a BIOS mapping");
34 MODULE_PARM(size, "i");
35 MODULE_PARM_DESC(size, "Size of the flash mapping");
36 MODULE_PARM(width, "i");
37 MODULE_PARM_DESC(width, "Data width of the flash mapping (8/16)");
38 MODULE_PARM(flashtype, "s");
39 MODULE_PARM_DESC(flashtype, "Type of MTD probe to do");
40
41 static int probe = 0;           /* Don't autoprobe */
42 static unsigned size = 0x1000000; /* 16 MiB the whole ISA address space */
43 static unsigned width = 8;      /* Default to 8 bits wide */
44 static char *flashtype = "cfi_probe";
45
46 static struct resource docmem = {
47         .flags = IORESOURCE_MEM,
48         .name  = "NatSemi SCx200 DOCCS Flash",
49 };
50
51 static struct mtd_info *mymtd;
52
53 #if PARTITION
54 static struct mtd_partition partition_info[] = {
55         { 
56                 .name   = "DOCCS Boot kernel", 
57                 .offset = 0, 
58                 .size   = 0xc0000
59         },
60         { 
61                 .name   = "DOCCS Low BIOS", 
62                 .offset = 0xc0000, 
63                 .size   = 0x40000
64         },
65         { 
66                 .name   = "DOCCS File system", 
67                 .offset = 0x100000, 
68                 .size   = ~0    /* calculate from flash size */
69         },
70         { 
71                 .name   = "DOCCS High BIOS", 
72                 .offset = ~0,   /* calculate from flash size */
73                 .size   = 0x80000
74         },
75 };
76 #define NUM_PARTITIONS (sizeof(partition_info)/sizeof(partition_info[0]))
77 #endif
78
79
80 static struct map_info scx200_docflash_map = {
81         .name      = "NatSemi SCx200 DOCCS Flash",
82 };
83
84 int __init init_scx200_docflash(void)
85 {
86         unsigned u;
87         unsigned base;
88         unsigned ctrl;
89         unsigned pmr;
90         struct pci_dev *bridge;
91
92         printk(KERN_DEBUG NAME ": NatSemi SCx200 DOCCS Flash Driver\n");
93
94         if ((bridge = pci_find_device(PCI_VENDOR_ID_NS, 
95                                       PCI_DEVICE_ID_NS_SCx200_BRIDGE,
96                                       NULL)) == NULL)
97                 return -ENODEV;
98         
99         if (!scx200_cb_probe(SCx200_CB_BASE)) {
100                 printk(KERN_WARNING NAME ": no configuration block found\n");
101                 return -ENODEV;
102         }
103
104         if (probe) {
105                 /* Try to use the present flash mapping if any */
106                 pci_read_config_dword(bridge, SCx200_DOCCS_BASE, &base);
107                 pci_read_config_dword(bridge, SCx200_DOCCS_CTRL, &ctrl);
108                 pmr = inl(SCx200_CB_BASE + SCx200_PMR);
109
110                 if (base == 0
111                     || (ctrl & 0x07000000) != 0x07000000
112                     || (ctrl & 0x0007ffff) == 0)
113                         return -ENODEV;
114
115                 size = ((ctrl&0x1fff)<<13) + (1<<13);
116
117                 for (u = size; u > 1; u >>= 1)
118                         ;
119                 if (u != 1)
120                         return -ENODEV;
121
122                 if (pmr & (1<<6))
123                         width = 16;
124                 else
125                         width = 8;
126
127                 docmem.start = base;
128                 docmem.end = base + size;
129
130                 if (request_resource(&iomem_resource, &docmem)) {
131                         printk(KERN_ERR NAME ": unable to allocate memory for flash mapping\n");
132                         return -ENOMEM;
133                 }
134         } else {
135                 for (u = size; u > 1; u >>= 1)
136                         ;
137                 if (u != 1) {
138                         printk(KERN_ERR NAME ": invalid size for flash mapping\n");
139                         return -EINVAL;
140                 }
141                 
142                 if (width != 8 && width != 16) {
143                         printk(KERN_ERR NAME ": invalid bus width for flash mapping\n");
144                         return -EINVAL;
145                 }
146                 
147                 if (allocate_resource(&iomem_resource, &docmem, 
148                                       size,
149                                       0xc0000000, 0xffffffff, 
150                                       size, NULL, NULL)) {
151                         printk(KERN_ERR NAME ": unable to allocate memory for flash mapping\n");
152                         return -ENOMEM;
153                 }
154                 
155                 ctrl = 0x07000000 | ((size-1) >> 13);
156
157                 printk(KERN_INFO "DOCCS BASE=0x%08lx, CTRL=0x%08lx\n", (long)docmem.start, (long)ctrl);
158                 
159                 pci_write_config_dword(bridge, SCx200_DOCCS_BASE, docmem.start);
160                 pci_write_config_dword(bridge, SCx200_DOCCS_CTRL, ctrl);
161                 pmr = inl(SCx200_CB_BASE + SCx200_PMR);
162                 
163                 if (width == 8) {
164                         pmr &= ~(1<<6);
165                 } else {
166                         pmr |= (1<<6);
167                 }
168                 outl(pmr, SCx200_CB_BASE + SCx200_PMR);
169         }
170         
171         printk(KERN_INFO NAME ": DOCCS mapped at 0x%lx-0x%lx, width %d\n", 
172                docmem.start, docmem.end, width);
173
174         scx200_docflash_map.size = size;
175         if (width == 8)
176                 scx200_docflash_map.buswidth = 1;
177         else
178                 scx200_docflash_map.buswidth = 2;
179
180         simple_map_init(&scx200_docflash_map);
181
182         scx200_docflash_map.phys = docmem.start;
183         scx200_docflash_map.virt = (unsigned long)ioremap(docmem.start, scx200_docflash_map.size);
184         if (!scx200_docflash_map.virt) {
185                 printk(KERN_ERR NAME ": failed to ioremap the flash\n");
186                 release_resource(&docmem);
187                 return -EIO;
188         }
189
190         mymtd = do_map_probe(flashtype, &scx200_docflash_map);
191         if (!mymtd) {
192                 printk(KERN_ERR NAME ": unable to detect flash\n");
193                 iounmap((void *)scx200_docflash_map.virt);
194                 release_resource(&docmem);
195                 return -ENXIO;
196         }
197
198         if (size < mymtd->size)
199                 printk(KERN_WARNING NAME ": warning, flash mapping is smaller than flash size\n");
200
201         mymtd->owner = THIS_MODULE;
202
203 #if PARTITION
204         partition_info[3].offset = mymtd->size-partition_info[3].size;
205         partition_info[2].size = partition_info[3].offset-partition_info[2].offset;
206         add_mtd_partitions(mymtd, partition_info, NUM_PARTITIONS);
207 #else
208         add_mtd_device(mymtd);
209 #endif
210         return 0;
211 }
212
213 static void __exit cleanup_scx200_docflash(void)
214 {
215         if (mymtd) {
216 #if PARTITION
217                 del_mtd_partitions(mymtd);
218 #else
219                 del_mtd_device(mymtd);
220 #endif
221                 map_destroy(mymtd);
222         }
223         if (scx200_docflash_map.virt) {
224                 iounmap((void *)scx200_docflash_map.virt);
225                 release_resource(&docmem);
226         }
227 }
228
229 module_init(init_scx200_docflash);
230 module_exit(cleanup_scx200_docflash);
231
232 /*
233     Local variables:
234         compile-command: "make -k -C ../../.. SUBDIRS=drivers/mtd/maps modules"
235         c-basic-offset: 8
236     End:
237 */