1 // #========================================================================
5 // # Linux driver for Intel(R) StrongARM(R) PCI-based coprocessor boards.
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.
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.
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
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.
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.
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.
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####
43 // # Author(s): msalter
44 // # Contributors: msalter
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.
55 // #####DESCRIPTIONEND####
57 // #========================================================================
59 static char *version =
60 "safl.c:v0.01H 04/02/99 Mark Salter, Red Hat.\n";
62 #include <linux/module.h>
63 #include <linux/config.h>
64 #include <linux/version.h>
66 #include <linux/modversions.h>
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>
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>
80 #include <linux/sched.h>
81 #include <asm/segment.h>
83 #include <linux/proc_fs.h>
87 #include <asm/system.h>
89 #if LINUX_VERSION_CODE >= 0x020100
90 #include <linux/init.h>
91 #include <linux/vmalloc.h>
93 #include <linux/bios32.h>
94 #define __initfunc(x) x
97 #if LINUX_VERSION_CODE < 0x20155
98 #define PCI_SUPPORT_VER1
100 #define PCI_SUPPORT_VER2
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");
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
113 #ifndef PCI_DEVICE_ID_DEC_21285
114 #define PCI_DEVICE_ID_DEC_21285 0x1065
118 /* somewhat arbitrary minor number. Major number is 10 (misc). */
119 #define SAFL_MINOR 178
120 #define FLASH_SZ (4 * 1024 * 1024)
122 static int safl_open( struct inode *inode, struct file *file );
123 static int safl_close( struct inode *inode, struct file *file );
125 #if LINUX_VERSION_CODE >= 0x020100
126 static int safl_mmap(struct file * file, struct vm_area_struct * vma);
128 static int safl_mmap(struct inode * inode, struct file * file, struct vm_area_struct * vma);
132 static int safl_debug = 0;
134 static unsigned long csr_ioaddr;
135 static unsigned long flash_addr;
137 static struct file_operations safl_fops = {
144 safl_mmap, /* mmap */
145 safl_open, /* open */
147 safl_close /* close */
150 static struct miscdevice safl_dev = {
156 /* PCI configuration space information. */
157 static u8 safl_pci_bus, safl_pci_devfn;
158 static int safl_devid;
160 #ifdef PCI_SUPPORT_VER2
161 static struct pci_dev *safl_pdev;
164 static int safl_open_cnt = 0; /* #times opened */
166 __initfunc(int safl_scan(void))
168 if (pcibios_present()) {
172 * Search for an EBSA-285 board or an IOP board. Stop at
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;
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;
191 #ifdef PCI_SUPPORT_VER2
192 safl_pdev = pci_find_slot(safl_pci_bus, safl_pci_devfn);
194 misc_register(&safl_dev);
199 printk(KERN_INFO "Can't find device.\n");
208 printk(KERN_INFO "%s", version);
214 * Dword read from configuration space of secondary PCI bus.
217 sconfig_read(int addr)
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 */
231 * Dword write to configuration space of secondary PCI bus.
234 sconfig_write(int addr, int val)
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 */
244 * Dword read from configuration space of primary PCI bus.
247 pconfig_read(int addr)
251 #ifdef PCI_SUPPORT_VER2
252 pci_read_config_dword(safl_pdev, addr, &val);
254 pcibios_read_config_dword(safl_pci_bus, safl_pci_devfn, addr, &val);
262 * Dword write to configuration space of primary PCI bus.
265 pconfig_write(int addr, int val)
267 #ifdef PCI_SUPPORT_VER2
268 pci_write_config_dword(safl_pdev, addr, val);
270 pcibios_write_config_dword(safl_pci_bus, safl_pci_devfn, addr, val);
277 safl_open( struct inode *inode, struct file *file )
281 printk(KERN_INFO "SA-Flash already open.\n");
285 if (safl_devid == PCI_DEVICE_ID_DEC_21554) {
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;
291 printk(KERN_INFO "IOP: csr_io[%lx].\n", csr_ioaddr);
292 printk(KERN_INFO "IOP: flash_add[%lx].\n", flash_addr);
296 * Need to configure downstream side of 21554.
297 * These addresses are pretty arbitrary.
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 */
305 /* set downstream mem2 xlate base */
306 pconfig_write(0x9c, 0xA0000000);
308 /* set 21285 ROM address to same */
309 sconfig_write(0x30, 0xA0000001);
311 /* set 21285 ROM write byte address */
312 sconfig_write(0x68, 0);
314 } else if (safl_devid == PCI_DEVICE_ID_DEC_21285) {
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.
323 flash_addr = 0xb0000000;
324 pconfig_write(PCI_ROM_ADDRESS, flash_addr | PCI_ROM_ADDRESS_ENABLE);
335 safl_close( struct inode *inode, struct file *file )
339 if (safl_devid == PCI_DEVICE_ID_DEC_21285)
340 pconfig_write(PCI_ROM_ADDRESS, 0);
342 if (safl_devid == PCI_DEVICE_ID_DEC_21554)
343 sconfig_write(0x30, 0);
350 static inline unsigned long
351 pgprot_noncached(unsigned long prot)
353 #if LINUX_VERSION_CODE >= 0x020100
354 if (boot_cpu_data.x86 > 3)
362 #if LINUX_VERSION_CODE >= 0x020100
363 safl_mmap(struct file * file, struct vm_area_struct * vma)
365 safl_mmap(struct inode * inode, struct file * file, struct vm_area_struct * vma)
370 if (vma->vm_offset != 0)
373 size = vma->vm_end - vma->vm_start;
377 pgprot_val(vma->vm_page_prot) = pgprot_noncached(pgprot_val(vma->vm_page_prot));
379 #if LINUX_VERSION_CODE >= 0x020100
380 vma->vm_flags |= VM_IO;
383 if (remap_page_range(vma->vm_start, flash_addr, size, vma->vm_page_prot))
386 #if LINUX_VERSION_CODE < 0x020100
387 vma->vm_inode = inode;
397 misc_deregister(&safl_dev);
402 * compile-command: "cc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c safl.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"