xref: /openbmc/linux/drivers/mtd/maps/ichxrom.c (revision 4883307c)
109c434b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * ichxrom.c
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  * Normal mappings of chips in physical memory
61da177e4SLinus Torvalds  */
71da177e4SLinus Torvalds 
81da177e4SLinus Torvalds #include <linux/module.h>
91da177e4SLinus Torvalds #include <linux/types.h>
101da177e4SLinus Torvalds #include <linux/kernel.h>
111da177e4SLinus Torvalds #include <linux/init.h>
125a0e3ad6STejun Heo #include <linux/slab.h>
131da177e4SLinus Torvalds #include <asm/io.h>
141da177e4SLinus Torvalds #include <linux/mtd/mtd.h>
151da177e4SLinus Torvalds #include <linux/mtd/map.h>
161da177e4SLinus Torvalds #include <linux/mtd/cfi.h>
171da177e4SLinus Torvalds #include <linux/mtd/flashchip.h>
181da177e4SLinus Torvalds #include <linux/pci.h>
191da177e4SLinus Torvalds #include <linux/pci_ids.h>
201da177e4SLinus Torvalds #include <linux/list.h>
211da177e4SLinus Torvalds 
221da177e4SLinus Torvalds #define xstr(s) str(s)
231da177e4SLinus Torvalds #define str(s) #s
241da177e4SLinus Torvalds #define MOD_NAME xstr(KBUILD_BASENAME)
251da177e4SLinus Torvalds 
261da177e4SLinus Torvalds #define ADDRESS_NAME_LEN 18
271da177e4SLinus Torvalds 
281da177e4SLinus Torvalds #define ROM_PROBE_STEP_SIZE (64*1024) /* 64KiB */
291da177e4SLinus Torvalds 
301da177e4SLinus Torvalds #define BIOS_CNTL	0x4e
311da177e4SLinus Torvalds #define FWH_DEC_EN1	0xE3
321da177e4SLinus Torvalds #define FWH_DEC_EN2	0xF0
331da177e4SLinus Torvalds #define FWH_SEL1	0xE8
341da177e4SLinus Torvalds #define FWH_SEL2	0xEE
351da177e4SLinus Torvalds 
361da177e4SLinus Torvalds struct ichxrom_window {
371da177e4SLinus Torvalds 	void __iomem* virt;
381da177e4SLinus Torvalds 	unsigned long phys;
391da177e4SLinus Torvalds 	unsigned long size;
401da177e4SLinus Torvalds 	struct list_head maps;
411da177e4SLinus Torvalds 	struct resource rsrc;
421da177e4SLinus Torvalds 	struct pci_dev *pdev;
431da177e4SLinus Torvalds };
441da177e4SLinus Torvalds 
451da177e4SLinus Torvalds struct ichxrom_map_info {
461da177e4SLinus Torvalds 	struct list_head list;
471da177e4SLinus Torvalds 	struct map_info map;
481da177e4SLinus Torvalds 	struct mtd_info *mtd;
491da177e4SLinus Torvalds 	struct resource rsrc;
501da177e4SLinus Torvalds 	char map_name[sizeof(MOD_NAME) + 2 + ADDRESS_NAME_LEN];
511da177e4SLinus Torvalds };
521da177e4SLinus Torvalds 
531da177e4SLinus Torvalds static struct ichxrom_window ichxrom_window = {
541da177e4SLinus Torvalds 	.maps = LIST_HEAD_INIT(ichxrom_window.maps),
551da177e4SLinus Torvalds };
561da177e4SLinus Torvalds 
ichxrom_cleanup(struct ichxrom_window * window)571da177e4SLinus Torvalds static void ichxrom_cleanup(struct ichxrom_window *window)
581da177e4SLinus Torvalds {
591da177e4SLinus Torvalds 	struct ichxrom_map_info *map, *scratch;
601da177e4SLinus Torvalds 	u16 word;
61e70dda08SArnd Bergmann 	int ret;
621da177e4SLinus Torvalds 
631da177e4SLinus Torvalds 	/* Disable writes through the rom window */
64e70dda08SArnd Bergmann 	ret = pci_read_config_word(window->pdev, BIOS_CNTL, &word);
65e70dda08SArnd Bergmann 	if (!ret)
661da177e4SLinus Torvalds 		pci_write_config_word(window->pdev, BIOS_CNTL, word & ~1);
67dd8e9ed6SAlan Cox 	pci_dev_put(window->pdev);
681da177e4SLinus Torvalds 
691da177e4SLinus Torvalds 	/* Free all of the mtd devices */
701da177e4SLinus Torvalds 	list_for_each_entry_safe(map, scratch, &window->maps, list) {
711da177e4SLinus Torvalds 		if (map->rsrc.parent)
721da177e4SLinus Torvalds 			release_resource(&map->rsrc);
73ee0e87b1SJamie Iles 		mtd_device_unregister(map->mtd);
741da177e4SLinus Torvalds 		map_destroy(map->mtd);
751da177e4SLinus Torvalds 		list_del(&map->list);
761da177e4SLinus Torvalds 		kfree(map);
771da177e4SLinus Torvalds 	}
781da177e4SLinus Torvalds 	if (window->rsrc.parent)
791da177e4SLinus Torvalds 		release_resource(&window->rsrc);
801da177e4SLinus Torvalds 	if (window->virt) {
811da177e4SLinus Torvalds 		iounmap(window->virt);
821da177e4SLinus Torvalds 		window->virt = NULL;
831da177e4SLinus Torvalds 		window->phys = 0;
841da177e4SLinus Torvalds 		window->size = 0;
851da177e4SLinus Torvalds 		window->pdev = NULL;
861da177e4SLinus Torvalds 	}
871da177e4SLinus Torvalds }
881da177e4SLinus Torvalds 
891da177e4SLinus Torvalds 
ichxrom_init_one(struct pci_dev * pdev,const struct pci_device_id * ent)90e4106a7cSJulia Lawall static int __init ichxrom_init_one(struct pci_dev *pdev,
911da177e4SLinus Torvalds 				   const struct pci_device_id *ent)
921da177e4SLinus Torvalds {
931da177e4SLinus Torvalds 	static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL };
941da177e4SLinus Torvalds 	struct ichxrom_window *window = &ichxrom_window;
951da177e4SLinus Torvalds 	struct ichxrom_map_info *map = NULL;
961da177e4SLinus Torvalds 	unsigned long map_top;
971da177e4SLinus Torvalds 	u8 byte;
981da177e4SLinus Torvalds 	u16 word;
991da177e4SLinus Torvalds 
1001da177e4SLinus Torvalds 	/* For now I just handle the ichx and I assume there
1011da177e4SLinus Torvalds 	 * are not a lot of resources up at the top of the address
1021da177e4SLinus Torvalds 	 * space.  It is possible to handle other devices in the
1031da177e4SLinus Torvalds 	 * top 16MB but it is very painful.  Also since
1041da177e4SLinus Torvalds 	 * you can only really attach a FWH to an ICHX there
1051da177e4SLinus Torvalds 	 * a number of simplifications you can make.
1061da177e4SLinus Torvalds 	 *
1071da177e4SLinus Torvalds 	 * Also you can page firmware hubs if an 8MB window isn't enough
1081da177e4SLinus Torvalds 	 * but don't currently handle that case either.
1091da177e4SLinus Torvalds 	 */
1101da177e4SLinus Torvalds 	window->pdev = pdev;
1111da177e4SLinus Torvalds 
1121da177e4SLinus Torvalds 	/* Find a region continuous to the end of the ROM window  */
1131da177e4SLinus Torvalds 	window->phys = 0;
1141da177e4SLinus Torvalds 	pci_read_config_byte(pdev, FWH_DEC_EN1, &byte);
1151da177e4SLinus Torvalds 	if (byte == 0xff) {
1161da177e4SLinus Torvalds 		window->phys = 0xffc00000;
1171da177e4SLinus Torvalds 		pci_read_config_byte(pdev, FWH_DEC_EN2, &byte);
1181da177e4SLinus Torvalds 		if ((byte & 0x0f) == 0x0f) {
1191da177e4SLinus Torvalds 			window->phys = 0xff400000;
1201da177e4SLinus Torvalds 		}
1211da177e4SLinus Torvalds 		else if ((byte & 0x0e) == 0x0e) {
1221da177e4SLinus Torvalds 			window->phys = 0xff500000;
1231da177e4SLinus Torvalds 		}
1241da177e4SLinus Torvalds 		else if ((byte & 0x0c) == 0x0c) {
1251da177e4SLinus Torvalds 			window->phys = 0xff600000;
1261da177e4SLinus Torvalds 		}
1271da177e4SLinus Torvalds 		else if ((byte & 0x08) == 0x08) {
1281da177e4SLinus Torvalds 			window->phys = 0xff700000;
1291da177e4SLinus Torvalds 		}
1301da177e4SLinus Torvalds 	}
1311da177e4SLinus Torvalds 	else if ((byte & 0xfe) == 0xfe) {
1321da177e4SLinus Torvalds 		window->phys = 0xffc80000;
1331da177e4SLinus Torvalds 	}
1341da177e4SLinus Torvalds 	else if ((byte & 0xfc) == 0xfc) {
1351da177e4SLinus Torvalds 		window->phys = 0xffd00000;
1361da177e4SLinus Torvalds 	}
1371da177e4SLinus Torvalds 	else if ((byte & 0xf8) == 0xf8) {
1381da177e4SLinus Torvalds 		window->phys = 0xffd80000;
1391da177e4SLinus Torvalds 	}
1401da177e4SLinus Torvalds 	else if ((byte & 0xf0) == 0xf0) {
1411da177e4SLinus Torvalds 		window->phys = 0xffe00000;
1421da177e4SLinus Torvalds 	}
1431da177e4SLinus Torvalds 	else if ((byte & 0xe0) == 0xe0) {
1441da177e4SLinus Torvalds 		window->phys = 0xffe80000;
1451da177e4SLinus Torvalds 	}
1461da177e4SLinus Torvalds 	else if ((byte & 0xc0) == 0xc0) {
1471da177e4SLinus Torvalds 		window->phys = 0xfff00000;
1481da177e4SLinus Torvalds 	}
1491da177e4SLinus Torvalds 	else if ((byte & 0x80) == 0x80) {
1501da177e4SLinus Torvalds 		window->phys = 0xfff80000;
1511da177e4SLinus Torvalds 	}
1521da177e4SLinus Torvalds 
1531da177e4SLinus Torvalds 	if (window->phys == 0) {
1541da177e4SLinus Torvalds 		printk(KERN_ERR MOD_NAME ": Rom window is closed\n");
1551da177e4SLinus Torvalds 		goto out;
1561da177e4SLinus Torvalds 	}
1571da177e4SLinus Torvalds 	window->phys -= 0x400000UL;
1581da177e4SLinus Torvalds 	window->size = (0xffffffffUL - window->phys) + 1UL;
1591da177e4SLinus Torvalds 
1601da177e4SLinus Torvalds 	/* Enable writes through the rom window */
1611da177e4SLinus Torvalds 	pci_read_config_word(pdev, BIOS_CNTL, &word);
1621da177e4SLinus Torvalds 	if (!(word & 1)  && (word & (1<<1))) {
1631da177e4SLinus Torvalds 		/* The BIOS will generate an error if I enable
1641da177e4SLinus Torvalds 		 * this device, so don't even try.
1651da177e4SLinus Torvalds 		 */
1661da177e4SLinus Torvalds 		printk(KERN_ERR MOD_NAME ": firmware access control, I can't enable writes\n");
1671da177e4SLinus Torvalds 		goto out;
1681da177e4SLinus Torvalds 	}
1691da177e4SLinus Torvalds 	pci_write_config_word(pdev, BIOS_CNTL, word | 1);
1701da177e4SLinus Torvalds 
1711da177e4SLinus Torvalds 	/*
1721da177e4SLinus Torvalds 	 * Try to reserve the window mem region.  If this fails then
17301d0afddSGeert Uytterhoeven 	 * it is likely due to the window being "reserved" by the BIOS.
1741da177e4SLinus Torvalds 	 */
1751da177e4SLinus Torvalds 	window->rsrc.name = MOD_NAME;
1761da177e4SLinus Torvalds 	window->rsrc.start = window->phys;
1771da177e4SLinus Torvalds 	window->rsrc.end   = window->phys + window->size - 1;
1781da177e4SLinus Torvalds 	window->rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
1791da177e4SLinus Torvalds 	if (request_resource(&iomem_resource, &window->rsrc)) {
1801da177e4SLinus Torvalds 		window->rsrc.parent = NULL;
181f9a5279cSJoe Perches 		printk(KERN_DEBUG MOD_NAME ": "
182f9a5279cSJoe Perches 		       "%s(): Unable to register resource %pR - kernel bug?\n",
183f9a5279cSJoe Perches 		       __func__, &window->rsrc);
1841da177e4SLinus Torvalds 	}
1851da177e4SLinus Torvalds 
1861da177e4SLinus Torvalds 	/* Map the firmware hub into my address space. */
1874bdc0d67SChristoph Hellwig 	window->virt = ioremap(window->phys, window->size);
1881da177e4SLinus Torvalds 	if (!window->virt) {
1891da177e4SLinus Torvalds 		printk(KERN_ERR MOD_NAME ": ioremap(%08lx, %08lx) failed\n",
1901da177e4SLinus Torvalds 			window->phys, window->size);
1911da177e4SLinus Torvalds 		goto out;
1921da177e4SLinus Torvalds 	}
1931da177e4SLinus Torvalds 
1941da177e4SLinus Torvalds 	/* Get the first address to look for an rom chip at */
1951da177e4SLinus Torvalds 	map_top = window->phys;
1961da177e4SLinus Torvalds 	if ((window->phys & 0x3fffff) != 0) {
1971da177e4SLinus Torvalds 		map_top = window->phys + 0x400000;
1981da177e4SLinus Torvalds 	}
1991da177e4SLinus Torvalds #if 1
2001da177e4SLinus Torvalds 	/* The probe sequence run over the firmware hub lock
2011da177e4SLinus Torvalds 	 * registers sets them to 0x7 (no access).
2021da177e4SLinus Torvalds 	 * Probe at most the last 4M of the address space.
2031da177e4SLinus Torvalds 	 */
2041da177e4SLinus Torvalds 	if (map_top < 0xffc00000) {
2051da177e4SLinus Torvalds 		map_top = 0xffc00000;
2061da177e4SLinus Torvalds 	}
2071da177e4SLinus Torvalds #endif
2081da177e4SLinus Torvalds 	/* Loop through and look for rom chips */
2091da177e4SLinus Torvalds 	while((map_top - 1) < 0xffffffffUL) {
2101da177e4SLinus Torvalds 		struct cfi_private *cfi;
2111da177e4SLinus Torvalds 		unsigned long offset;
2121da177e4SLinus Torvalds 		int i;
2131da177e4SLinus Torvalds 
2141da177e4SLinus Torvalds 		if (!map) {
2151da177e4SLinus Torvalds 			map = kmalloc(sizeof(*map), GFP_KERNEL);
216*4883307cSZhen Lei 			if (!map)
2171da177e4SLinus Torvalds 				goto out;
2181da177e4SLinus Torvalds 		}
2191da177e4SLinus Torvalds 		memset(map, 0, sizeof(*map));
2201da177e4SLinus Torvalds 		INIT_LIST_HEAD(&map->list);
2211da177e4SLinus Torvalds 		map->map.name = map->map_name;
2221da177e4SLinus Torvalds 		map->map.phys = map_top;
2231da177e4SLinus Torvalds 		offset = map_top - window->phys;
2241da177e4SLinus Torvalds 		map->map.virt = (void __iomem *)
2251da177e4SLinus Torvalds 			(((unsigned long)(window->virt)) + offset);
2261da177e4SLinus Torvalds 		map->map.size = 0xffffffffUL - map_top + 1UL;
2271da177e4SLinus Torvalds 		/* Set the name of the map to the address I am trying */
2283a38d3afSAndrew Morton 		sprintf(map->map_name, "%s @%08Lx",
2293a38d3afSAndrew Morton 			MOD_NAME, (unsigned long long)map->map.phys);
2301da177e4SLinus Torvalds 
2311da177e4SLinus Torvalds 		/* Firmware hubs only use vpp when being programmed
2321da177e4SLinus Torvalds 		 * in a factory setting.  So in-place programming
2331da177e4SLinus Torvalds 		 * needs to use a different method.
2341da177e4SLinus Torvalds 		 */
2351da177e4SLinus Torvalds 		for(map->map.bankwidth = 32; map->map.bankwidth;
2361da177e4SLinus Torvalds 			map->map.bankwidth >>= 1)
2371da177e4SLinus Torvalds 		{
2381da177e4SLinus Torvalds 			char **probe_type;
2391da177e4SLinus Torvalds 			/* Skip bankwidths that are not supported */
2401da177e4SLinus Torvalds 			if (!map_bankwidth_supported(map->map.bankwidth))
2411da177e4SLinus Torvalds 				continue;
2421da177e4SLinus Torvalds 
2431da177e4SLinus Torvalds 			/* Setup the map methods */
2441da177e4SLinus Torvalds 			simple_map_init(&map->map);
2451da177e4SLinus Torvalds 
2461da177e4SLinus Torvalds 			/* Try all of the probe methods */
2471da177e4SLinus Torvalds 			probe_type = rom_probe_types;
2481da177e4SLinus Torvalds 			for(; *probe_type; probe_type++) {
2491da177e4SLinus Torvalds 				map->mtd = do_map_probe(*probe_type, &map->map);
2501da177e4SLinus Torvalds 				if (map->mtd)
2511da177e4SLinus Torvalds 					goto found;
2521da177e4SLinus Torvalds 			}
2531da177e4SLinus Torvalds 		}
2541da177e4SLinus Torvalds 		map_top += ROM_PROBE_STEP_SIZE;
2551da177e4SLinus Torvalds 		continue;
2561da177e4SLinus Torvalds 	found:
2571da177e4SLinus Torvalds 		/* Trim the size if we are larger than the map */
2581da177e4SLinus Torvalds 		if (map->mtd->size > map->map.size) {
2591da177e4SLinus Torvalds 			printk(KERN_WARNING MOD_NAME
26069423d99SAdrian Hunter 				" rom(%llu) larger than window(%lu). fixing...\n",
26169423d99SAdrian Hunter 				(unsigned long long)map->mtd->size, map->map.size);
2621da177e4SLinus Torvalds 			map->mtd->size = map->map.size;
2631da177e4SLinus Torvalds 		}
2641da177e4SLinus Torvalds 		if (window->rsrc.parent) {
2651da177e4SLinus Torvalds 			/*
2661da177e4SLinus Torvalds 			 * Registering the MTD device in iomem may not be possible
2671da177e4SLinus Torvalds 			 * if there is a BIOS "reserved" and BUSY range.  If this
2681da177e4SLinus Torvalds 			 * fails then continue anyway.
2691da177e4SLinus Torvalds 			 */
2701da177e4SLinus Torvalds 			map->rsrc.name  = map->map_name;
2711da177e4SLinus Torvalds 			map->rsrc.start = map->map.phys;
2721da177e4SLinus Torvalds 			map->rsrc.end   = map->map.phys + map->mtd->size - 1;
2731da177e4SLinus Torvalds 			map->rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
2741da177e4SLinus Torvalds 			if (request_resource(&window->rsrc, &map->rsrc)) {
2751da177e4SLinus Torvalds 				printk(KERN_ERR MOD_NAME
2761da177e4SLinus Torvalds 					": cannot reserve MTD resource\n");
2771da177e4SLinus Torvalds 				map->rsrc.parent = NULL;
2781da177e4SLinus Torvalds 			}
2791da177e4SLinus Torvalds 		}
2801da177e4SLinus Torvalds 
2811da177e4SLinus Torvalds 		/* Make the whole region visible in the map */
2821da177e4SLinus Torvalds 		map->map.virt = window->virt;
2831da177e4SLinus Torvalds 		map->map.phys = window->phys;
2841da177e4SLinus Torvalds 		cfi = map->map.fldrv_priv;
2851da177e4SLinus Torvalds 		for(i = 0; i < cfi->numchips; i++) {
2861da177e4SLinus Torvalds 			cfi->chips[i].start += offset;
2871da177e4SLinus Torvalds 		}
2881da177e4SLinus Torvalds 
2891da177e4SLinus Torvalds 		/* Now that the mtd devices is complete claim and export it */
2901da177e4SLinus Torvalds 		map->mtd->owner = THIS_MODULE;
291ee0e87b1SJamie Iles 		if (mtd_device_register(map->mtd, NULL, 0)) {
2921da177e4SLinus Torvalds 			map_destroy(map->mtd);
2931da177e4SLinus Torvalds 			map->mtd = NULL;
2941da177e4SLinus Torvalds 			goto out;
2951da177e4SLinus Torvalds 		}
2961da177e4SLinus Torvalds 
2971da177e4SLinus Torvalds 
2981da177e4SLinus Torvalds 		/* Calculate the new value of map_top */
2991da177e4SLinus Torvalds 		map_top += map->mtd->size;
3001da177e4SLinus Torvalds 
3011da177e4SLinus Torvalds 		/* File away the map structure */
3021da177e4SLinus Torvalds 		list_add(&map->list, &window->maps);
3031da177e4SLinus Torvalds 		map = NULL;
3041da177e4SLinus Torvalds 	}
3051da177e4SLinus Torvalds 
3061da177e4SLinus Torvalds  out:
3071da177e4SLinus Torvalds 	/* Free any left over map structures */
3081da177e4SLinus Torvalds 	kfree(map);
309fa671646SJesper Juhl 
3101da177e4SLinus Torvalds 	/* See if I have any map structures */
3111da177e4SLinus Torvalds 	if (list_empty(&window->maps)) {
3121da177e4SLinus Torvalds 		ichxrom_cleanup(window);
3131da177e4SLinus Torvalds 		return -ENODEV;
3141da177e4SLinus Torvalds 	}
3151da177e4SLinus Torvalds 	return 0;
3161da177e4SLinus Torvalds }
3171da177e4SLinus Torvalds 
3181da177e4SLinus Torvalds 
ichxrom_remove_one(struct pci_dev * pdev)319810b7e06SBill Pemberton static void ichxrom_remove_one(struct pci_dev *pdev)
3201da177e4SLinus Torvalds {
3211da177e4SLinus Torvalds 	struct ichxrom_window *window = &ichxrom_window;
3221da177e4SLinus Torvalds 	ichxrom_cleanup(window);
3231da177e4SLinus Torvalds }
3241da177e4SLinus Torvalds 
32568002593SArvind Yadav static const struct pci_device_id ichxrom_pci_tbl[] = {
3261da177e4SLinus Torvalds 	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0,
3271da177e4SLinus Torvalds 	  PCI_ANY_ID, PCI_ANY_ID, },
3281da177e4SLinus Torvalds 	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0,
3291da177e4SLinus Torvalds 	  PCI_ANY_ID, PCI_ANY_ID, },
3301da177e4SLinus Torvalds 	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0,
3311da177e4SLinus Torvalds 	  PCI_ANY_ID, PCI_ANY_ID, },
3321da177e4SLinus Torvalds 	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0,
3331da177e4SLinus Torvalds 	  PCI_ANY_ID, PCI_ANY_ID, },
3341da177e4SLinus Torvalds 	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_1,
3351da177e4SLinus Torvalds 	  PCI_ANY_ID, PCI_ANY_ID, },
3361da177e4SLinus Torvalds 	{ 0, },
3371da177e4SLinus Torvalds };
3381da177e4SLinus Torvalds 
339b9c86d59SDavid Woodhouse #if 0
3401da177e4SLinus Torvalds MODULE_DEVICE_TABLE(pci, ichxrom_pci_tbl);
3411da177e4SLinus Torvalds 
3421da177e4SLinus Torvalds static struct pci_driver ichxrom_driver = {
3431da177e4SLinus Torvalds 	.name =		MOD_NAME,
3441da177e4SLinus Torvalds 	.id_table =	ichxrom_pci_tbl,
3451da177e4SLinus Torvalds 	.probe =	ichxrom_init_one,
3461da177e4SLinus Torvalds 	.remove =	ichxrom_remove_one,
3471da177e4SLinus Torvalds };
3481da177e4SLinus Torvalds #endif
3491da177e4SLinus Torvalds 
init_ichxrom(void)3501da177e4SLinus Torvalds static int __init init_ichxrom(void)
3511da177e4SLinus Torvalds {
3521da177e4SLinus Torvalds 	struct pci_dev *pdev;
35368002593SArvind Yadav 	const struct pci_device_id *id;
3541da177e4SLinus Torvalds 
3551da177e4SLinus Torvalds 	pdev = NULL;
3561da177e4SLinus Torvalds 	for (id = ichxrom_pci_tbl; id->vendor; id++) {
357dd8e9ed6SAlan Cox 		pdev = pci_get_device(id->vendor, id->device, NULL);
3581da177e4SLinus Torvalds 		if (pdev) {
3591da177e4SLinus Torvalds 			break;
3601da177e4SLinus Torvalds 		}
3611da177e4SLinus Torvalds 	}
3621da177e4SLinus Torvalds 	if (pdev) {
3631da177e4SLinus Torvalds 		return ichxrom_init_one(pdev, &ichxrom_pci_tbl[0]);
3641da177e4SLinus Torvalds 	}
3651da177e4SLinus Torvalds 	return -ENXIO;
3661da177e4SLinus Torvalds #if 0
367ff3bc4ebSDomen Puncer 	return pci_register_driver(&ichxrom_driver);
3681da177e4SLinus Torvalds #endif
3691da177e4SLinus Torvalds }
3701da177e4SLinus Torvalds 
cleanup_ichxrom(void)3711da177e4SLinus Torvalds static void __exit cleanup_ichxrom(void)
3721da177e4SLinus Torvalds {
3731da177e4SLinus Torvalds 	ichxrom_remove_one(ichxrom_window.pdev);
3741da177e4SLinus Torvalds }
3751da177e4SLinus Torvalds 
3761da177e4SLinus Torvalds module_init(init_ichxrom);
3771da177e4SLinus Torvalds module_exit(cleanup_ichxrom);
3781da177e4SLinus Torvalds 
3791da177e4SLinus Torvalds MODULE_LICENSE("GPL");
3801da177e4SLinus Torvalds MODULE_AUTHOR("Eric Biederman <ebiederman@lnxi.com>");
3811da177e4SLinus Torvalds MODULE_DESCRIPTION("MTD map driver for BIOS chips on the ICHX southbridge");
382