Blame view

drivers/mtd/maps/l440gx.c 3.98 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
6
7
8
9
10
11
12
13
   * BIOS Flash chip on Intel 440GX board.
   *
   * Bugs this currently does not work under linuxBIOS.
   */
  
  #include <linux/module.h>
  #include <linux/pci.h>
  #include <linux/kernel.h>
  #include <linux/init.h>
  #include <asm/io.h>
  #include <linux/mtd/mtd.h>
  #include <linux/mtd/map.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
  
  #define PIIXE_IOBASE_RESOURCE	11
  
  #define WINDOW_ADDR 0xfff00000
  #define WINDOW_SIZE 0x00100000
  #define BUSWIDTH 1
  
  static u32 iobase;
  #define IOBASE iobase
  #define TRIBUF_PORT (IOBASE+0x37)
  #define VPP_PORT (IOBASE+0x28)
  
  static struct mtd_info *mymtd;
  
  
  /* Is this really the vpp port? */
5fbabf3f4   Paul Parsons   mtd: maps: l440gx...
30
31
  static DEFINE_SPINLOCK(l440gx_vpp_lock);
  static int l440gx_vpp_refcnt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32
33
  static void l440gx_set_vpp(struct map_info *map, int vpp)
  {
5fbabf3f4   Paul Parsons   mtd: maps: l440gx...
34
  	unsigned long flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35

5fbabf3f4   Paul Parsons   mtd: maps: l440gx...
36
  	spin_lock_irqsave(&l440gx_vpp_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37
  	if (vpp) {
5fbabf3f4   Paul Parsons   mtd: maps: l440gx...
38
39
  		if (++l440gx_vpp_refcnt == 1)   /* first nested 'on' */
  			outl(inl(VPP_PORT) | 1, VPP_PORT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
40
  	} else {
5fbabf3f4   Paul Parsons   mtd: maps: l440gx...
41
42
  		if (--l440gx_vpp_refcnt == 0)   /* last nested 'off' */
  			outl(inl(VPP_PORT) & ~1, VPP_PORT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43
  	}
5fbabf3f4   Paul Parsons   mtd: maps: l440gx...
44
  	spin_unlock_irqrestore(&l440gx_vpp_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45
46
47
48
49
50
51
52
  }
  
  static struct map_info l440gx_map = {
  	.name = "L440GX BIOS",
  	.size = WINDOW_SIZE,
  	.bankwidth = BUSWIDTH,
  	.phys = WINDOW_ADDR,
  #if 0
69f34c98c   Thomas Gleixner   [MTD] maps: Clean...
53
  	/* FIXME verify that this is the
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54
55
56
57
58
59
60
61
62
63
64
  	 * appripriate code for vpp enable/disable
  	 */
  	.set_vpp = l440gx_set_vpp
  #endif
  };
  
  static int __init init_l440gx(void)
  {
  	struct pci_dev *dev, *pm_dev;
  	struct resource *pm_iobase;
  	__u16 word;
dd8e9ed6e   Alan Cox   [MTD] Switch to p...
65
  	dev = pci_get_device(PCI_VENDOR_ID_INTEL,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
66
  		PCI_DEVICE_ID_INTEL_82371AB_0, NULL);
dd8e9ed6e   Alan Cox   [MTD] Switch to p...
67
  	pm_dev = pci_get_device(PCI_VENDOR_ID_INTEL,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
68
  		PCI_DEVICE_ID_INTEL_82371AB_3, NULL);
dd8e9ed6e   Alan Cox   [MTD] Switch to p...
69
  	pci_dev_put(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
70
71
72
  	if (!dev || !pm_dev) {
  		printk(KERN_NOTICE "L440GX flash mapping: failed to find PIIX4 ISA bridge, cannot continue
  ");
dd8e9ed6e   Alan Cox   [MTD] Switch to p...
73
  		pci_dev_put(pm_dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
74
75
76
77
78
79
80
81
  		return -ENODEV;
  	}
  
  	l440gx_map.virt = ioremap_nocache(WINDOW_ADDR, WINDOW_SIZE);
  
  	if (!l440gx_map.virt) {
  		printk(KERN_WARNING "Failed to ioremap L440GX flash region
  ");
dd8e9ed6e   Alan Cox   [MTD] Switch to p...
82
  		pci_dev_put(pm_dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
83
84
85
86
87
  		return -ENOMEM;
  	}
  	simple_map_init(&l440gx_map);
  	printk(KERN_NOTICE "window_addr = 0x%08lx
  ", (unsigned long)l440gx_map.virt);
69f34c98c   Thomas Gleixner   [MTD] maps: Clean...
88
  	/* Setup the pm iobase resource
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
89
90
  	 * This code should move into some kind of generic bridge
  	 * driver but for the moment I'm content with getting the
69f34c98c   Thomas Gleixner   [MTD] maps: Clean...
91
  	 * allocation correct.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
92
93
94
95
96
97
98
99
100
101
102
103
104
  	 */
  	pm_iobase = &pm_dev->resource[PIIXE_IOBASE_RESOURCE];
  	if (!(pm_iobase->flags & IORESOURCE_IO)) {
  		pm_iobase->name = "pm iobase";
  		pm_iobase->start = 0;
  		pm_iobase->end = 63;
  		pm_iobase->flags = IORESOURCE_IO;
  
  		/* Put the current value in the resource */
  		pci_read_config_dword(pm_dev, 0x40, &iobase);
  		iobase &= ~1;
  		pm_iobase->start += iobase & ~1;
  		pm_iobase->end += iobase & ~1;
dd8e9ed6e   Alan Cox   [MTD] Switch to p...
105
  		pci_dev_put(pm_dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
106
107
  		/* Allocate the resource region */
  		if (pci_assign_resource(pm_dev, PIIXE_IOBASE_RESOURCE) != 0) {
dd8e9ed6e   Alan Cox   [MTD] Switch to p...
108
109
  			pci_dev_put(dev);
  			pci_dev_put(pm_dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
110
111
112
113
114
115
116
117
118
  			printk(KERN_WARNING "Could not allocate pm iobase resource
  ");
  			iounmap(l440gx_map.virt);
  			return -ENXIO;
  		}
  	}
  	/* Set the iobase */
  	iobase = pm_iobase->start;
  	pci_write_config_dword(pm_dev, 0x40, iobase | 1);
69f34c98c   Thomas Gleixner   [MTD] maps: Clean...
119

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
120
121
122
123
124
125
126
127
128
129
130
  
  	/* Set XBCS# */
  	pci_read_config_word(dev, 0x4e, &word);
  	word |= 0x4;
          pci_write_config_word(dev, 0x4e, word);
  
  	/* Supply write voltage to the chip */
  	l440gx_set_vpp(&l440gx_map, 1);
  
  	/* Enable the gate on the WE line */
  	outb(inb(TRIBUF_PORT) & ~1, TRIBUF_PORT);
69f34c98c   Thomas Gleixner   [MTD] maps: Clean...
131

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
132
133
134
135
136
137
138
139
140
141
142
         	printk(KERN_NOTICE "Enabled WE line to L440GX BIOS flash chip.
  ");
  
  	mymtd = do_map_probe("jedec_probe", &l440gx_map);
  	if (!mymtd) {
  		printk(KERN_NOTICE "JEDEC probe on BIOS chip failed. Using ROM
  ");
  		mymtd = do_map_probe("map_rom", &l440gx_map);
  	}
  	if (mymtd) {
  		mymtd->owner = THIS_MODULE;
ee0e87b17   Jamie Iles   mtd: convert rema...
143
  		mtd_device_register(mymtd, NULL, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
144
145
146
147
148
149
150
151
152
  		return 0;
  	}
  
  	iounmap(l440gx_map.virt);
  	return -ENXIO;
  }
  
  static void __exit cleanup_l440gx(void)
  {
ee0e87b17   Jamie Iles   mtd: convert rema...
153
  	mtd_device_unregister(mymtd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
154
  	map_destroy(mymtd);
69f34c98c   Thomas Gleixner   [MTD] maps: Clean...
155

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
156
157
158
159
160
161
162
163
164
  	iounmap(l440gx_map.virt);
  }
  
  module_init(init_l440gx);
  module_exit(cleanup_l440gx);
  
  MODULE_LICENSE("GPL");
  MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
  MODULE_DESCRIPTION("MTD map driver for BIOS chips on Intel L440GX motherboards");