]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/hal/arm/ebsa285/v2_0/support/linux/safl_util/safl.c
Initial revision
[karo-tx-redboot.git] / packages / hal / arm / ebsa285 / v2_0 / support / linux / safl_util / safl.c
1 // #========================================================================
2 // #
3 // #    safl.c
4 // #
5 // #    Linux driver for Intel(R) StrongARM(R) PCI-based coprocessor boards.
6 // #
7 // #========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12 //
13 // eCos is free software; you can redistribute it and/or modify it under
14 // the terms of the GNU General Public License as published by the Free
15 // Software Foundation; either version 2 or (at your option) any later version.
16 //
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
20 // for more details.
21 //
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25 //
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
32 //
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
35 //
36 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37 // at http://sources.redhat.com/ecos/ecos-license/
38 // -------------------------------------------
39 //####ECOSGPLCOPYRIGHTEND####
40 // #========================================================================
41 // ######DESCRIPTIONBEGIN####
42 // #
43 // # Author(s):     msalter
44 // # Contributors:  msalter
45 // # Date:          1999-04-02
46 // # Purpose:       Linux driver for Intel(R) StrongARM(R) PCI-based
47 // #                coprocessor boards
48 // # Description:   This module currently supports EBSA-285 and SA-IOP.
49 // #                Intel is a Registered Trademark of Intel Corporation.
50 // #                StrongARM is a Registered Trademark of Advanced RISC
51 // #                Machines Limited.
52 // #                Other Brands and Trademarks are the property of their
53 // #                respective owners.
54 // #
55 // #####DESCRIPTIONEND####
56 // #
57 // #========================================================================
58
59 static char *version =
60 "safl.c:v0.01H 04/02/99 Mark Salter, Red Hat.\n";
61
62 #include <linux/module.h>
63 #include <linux/config.h>
64 #include <linux/version.h>
65 #ifdef MODVERSIONS
66 #include <linux/modversions.h>
67 #endif
68 #include <linux/types.h>
69 #include <linux/errno.h>
70 #include <linux/kernel.h>
71 #include <linux/miscdevice.h>
72 #include <linux/malloc.h>
73 #include <linux/mm.h>
74 #include <linux/pci.h>
75 #include <linux/signal.h>
76 #include <linux/ioport.h>
77 #include <linux/fcntl.h>
78 #include <asm/pgtable.h>
79 #include <asm/page.h>
80 #include <linux/sched.h>
81 #include <asm/segment.h>
82 #ifdef CONFIG_PROC_FS
83 #include <linux/proc_fs.h>
84 #endif
85
86 #include <asm/io.h>
87 #include <asm/system.h>
88
89 #if LINUX_VERSION_CODE >= 0x020100
90 #include <linux/init.h>
91 #include <linux/vmalloc.h>
92 #else
93 #include <linux/bios32.h>
94 #define __initfunc(x) x
95 #endif
96
97 #if LINUX_VERSION_CODE < 0x20155
98 #define PCI_SUPPORT_VER1
99 #else
100 #define PCI_SUPPORT_VER2
101 #endif
102
103 #if defined(MODULE) && LINUX_VERSION_CODE > 0x20115
104 MODULE_AUTHOR("Mark Salter <msalter@redhat.com>");
105 MODULE_DESCRIPTION("Intel(R) StrongARM(R) FLASH driver for PCI EVBs");
106 #endif
107
108 /* This isn't in /usr/include/linux/pci.h */
109 #ifndef PCI_DEVICE_ID_DEC_IOP
110 #define PCI_DEVICE_ID_DEC_21554     0x46
111 #endif
112
113 #ifndef PCI_DEVICE_ID_DEC_21285
114 #define PCI_DEVICE_ID_DEC_21285     0x1065
115 #endif
116
117
118 /* somewhat arbitrary minor number. Major number is 10 (misc). */
119 #define SAFL_MINOR 178
120 #define FLASH_SZ   (4 * 1024 * 1024)
121
122 static int safl_open( struct inode *inode, struct file *file );
123 static int safl_close( struct inode *inode, struct file *file );
124
125 #if LINUX_VERSION_CODE >= 0x020100
126 static int safl_mmap(struct file * file, struct vm_area_struct * vma);
127 #else
128 static int safl_mmap(struct inode * inode, struct file * file, struct vm_area_struct * vma);
129 #endif
130
131
132 static int safl_debug = 0;
133
134 static unsigned long csr_ioaddr;
135 static unsigned long flash_addr;
136
137 static struct file_operations safl_fops = {
138     NULL,                       /* lseek */
139     NULL,                       /* read  */
140     NULL,                       /* write */
141     NULL,                       /* readdir */
142     NULL,                       /* poll */
143     NULL,                       /* ioctl */
144     safl_mmap,                  /* mmap */
145     safl_open,                  /* open */
146     NULL,                       /* flush */
147     safl_close                  /* close */
148 };
149
150 static struct miscdevice safl_dev = {
151         SAFL_MINOR,
152         "SA-FLASH",
153         &safl_fops
154 };
155
156 /* PCI configuration space information. */
157 static u8 safl_pci_bus, safl_pci_devfn;
158 static int safl_devid;
159
160 #ifdef PCI_SUPPORT_VER2
161 static struct pci_dev *safl_pdev;
162 #endif
163
164 static int safl_open_cnt = 0;   /* #times opened */
165
166 __initfunc(int safl_scan(void))
167 {
168     if (pcibios_present()) {
169         int index;
170
171         /*
172          * Search for an EBSA-285 board or an IOP board. Stop at
173          * first one found.
174          */
175         for (index = 0; index < 8; index++) {
176             if (pcibios_find_device (PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21554,
177                                      index, &safl_pci_bus, &safl_pci_devfn)
178                 == PCIBIOS_SUCCESSFUL) {
179                 safl_devid = PCI_DEVICE_ID_DEC_21554;
180                 break;
181             }
182             if (pcibios_find_device (PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21285,
183                                      index, &safl_pci_bus, &safl_pci_devfn)
184                 == PCIBIOS_SUCCESSFUL) {
185                 safl_devid = PCI_DEVICE_ID_DEC_21285;
186                 break;
187             }
188         }
189
190         if (index < 8) {
191 #ifdef PCI_SUPPORT_VER2
192             safl_pdev = pci_find_slot(safl_pci_bus, safl_pci_devfn);
193 #endif
194             misc_register(&safl_dev);
195             return 0;
196         }
197     }
198     if (safl_debug)
199         printk(KERN_INFO "Can't find device.\n");
200     return -ENODEV;
201 }
202
203
204 int
205 init_module(void)
206 {
207     if (safl_debug)
208         printk(KERN_INFO "%s", version);
209     return safl_scan();
210 }
211
212
213 /*
214  * Dword read from configuration space of secondary PCI bus.
215  */
216 static unsigned int
217 sconfig_read(int addr)
218 {
219     unsigned int val;
220
221     outw(2, csr_ioaddr + 0x12);  /* enable downstream config */
222     outl(addr | (1<<24), csr_ioaddr + 0x00);
223     val = inl(csr_ioaddr + 4);
224     outw(0, csr_ioaddr + 0x12);  /* disable downstream config */
225
226     return val;
227 }
228
229
230 /*
231  * Dword write to configuration space of secondary PCI bus.
232  */
233 static void
234 sconfig_write(int addr, int val)
235 {
236     outw(2, csr_ioaddr + 0x12);  /* enable downstream config */
237     outl(addr | (1<<24), csr_ioaddr + 0x00);
238     outl(val, csr_ioaddr + 4);
239     outw(0, csr_ioaddr + 0x12);  /* disable downstream config */
240 }
241
242
243 /*
244  * Dword read from configuration space of primary PCI bus.
245  */
246 static unsigned int
247 pconfig_read(int addr)
248 {
249     unsigned int val;
250
251 #ifdef PCI_SUPPORT_VER2
252     pci_read_config_dword(safl_pdev, addr, &val);
253 #else
254     pcibios_read_config_dword(safl_pci_bus, safl_pci_devfn, addr, &val);
255 #endif
256
257     return val;
258 }
259
260
261 /*
262  * Dword write to configuration space of primary PCI bus.
263  */
264 static void
265 pconfig_write(int addr, int val)
266 {
267 #ifdef PCI_SUPPORT_VER2
268     pci_write_config_dword(safl_pdev, addr, val);
269 #else
270     pcibios_write_config_dword(safl_pci_bus, safl_pci_devfn, addr, val);
271 #endif
272 }
273
274
275
276 static int
277 safl_open( struct inode *inode, struct file *file )
278 {
279     if (safl_open_cnt) {
280         if (safl_debug)
281             printk(KERN_INFO "SA-Flash already open.\n");
282         return( -EBUSY );
283     }
284
285     if (safl_devid == PCI_DEVICE_ID_DEC_21554) {
286
287         csr_ioaddr = pconfig_read(PCI_BASE_ADDRESS_1) & PCI_BASE_ADDRESS_IO_MASK;
288         flash_addr = pconfig_read(PCI_BASE_ADDRESS_3) & PCI_BASE_ADDRESS_MEM_MASK;
289
290         if (safl_debug) {
291             printk(KERN_INFO "IOP: csr_io[%lx].\n", csr_ioaddr);
292             printk(KERN_INFO "IOP: flash_add[%lx].\n", flash_addr);
293         }
294
295         /*
296          * Need to configure downstream side of 21554.
297          * These addresses are pretty arbitrary.
298          */
299         pconfig_write(0x50, 0xf0000000);  /* secondary CSR memory */
300         pconfig_write(0x54, 0xf201);      /* secondary CSR I/O    */
301         pconfig_write(0x58, 0xf401);      /* Upstream I/O         */
302         pconfig_write(0x5c, 0xf1000008);  /* Upstream memory 1    */
303         pconfig_write(0x44, 0x29000017);  /* enable mem an I/O    */
304
305         /* set downstream mem2 xlate base */
306         pconfig_write(0x9c, 0xA0000000);
307
308         /* set 21285 ROM address to same */
309         sconfig_write(0x30, 0xA0000001);
310
311         /* set 21285 ROM write byte address */
312         sconfig_write(0x68, 0);
313
314     } else if (safl_devid == PCI_DEVICE_ID_DEC_21285) {
315         /*
316          * I'm not sure how best to handle this. Basically, you want
317          * to assign a physical address for the expansion ROM space
318          * of the 21285. There doesn't appear to be a good way to
319          * find an unused physical space for the PCI bus. This seems
320          * to work for the limited number of motherboards that this
321          * code has been tested on. YMMV.
322          */
323         flash_addr = 0xb0000000;
324         pconfig_write(PCI_ROM_ADDRESS, flash_addr | PCI_ROM_ADDRESS_ENABLE);
325     }
326
327     safl_open_cnt++;
328
329     MOD_INC_USE_COUNT;
330     return 0;
331 }
332
333
334 static int
335 safl_close( struct inode *inode, struct file *file )
336 {
337     safl_open_cnt--;
338
339     if (safl_devid == PCI_DEVICE_ID_DEC_21285)
340         pconfig_write(PCI_ROM_ADDRESS, 0);
341
342     if (safl_devid == PCI_DEVICE_ID_DEC_21554)
343         sconfig_write(0x30, 0);
344
345     MOD_DEC_USE_COUNT;
346     return 0;
347 }
348
349
350 static inline unsigned long
351 pgprot_noncached(unsigned long prot)
352 {
353 #if LINUX_VERSION_CODE >= 0x020100
354     if (boot_cpu_data.x86 > 3)
355         prot |= _PAGE_PCD;
356 #endif
357     return prot;
358 }
359
360
361 static int
362 #if LINUX_VERSION_CODE >= 0x020100
363 safl_mmap(struct file * file, struct vm_area_struct * vma)
364 #else
365 safl_mmap(struct inode * inode, struct file * file, struct vm_area_struct * vma)
366 #endif
367 {
368     unsigned long size;
369
370     if (vma->vm_offset != 0)
371         return -EINVAL;
372
373     size = vma->vm_end - vma->vm_start;
374     if (size > FLASH_SZ)
375         return -EINVAL;
376
377     pgprot_val(vma->vm_page_prot) = pgprot_noncached(pgprot_val(vma->vm_page_prot));
378
379 #if LINUX_VERSION_CODE >= 0x020100
380     vma->vm_flags |= VM_IO;
381 #endif
382
383     if (remap_page_range(vma->vm_start, flash_addr, size, vma->vm_page_prot))
384         return -EAGAIN;
385
386 #if LINUX_VERSION_CODE < 0x020100
387     vma->vm_inode = inode;
388     inode->i_count++;
389 #endif
390
391     return 0;
392 }
393
394 void
395 cleanup_module(void)
396 {
397     misc_deregister(&safl_dev);
398 }
399 \f
400 /*
401  * Local variables:
402  *  compile-command: "cc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c safl.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
403  * End:
404  */