Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * amd76xrom.c
0004  *
0005  * Normal mappings of chips in physical memory
0006  */
0007 
0008 #include <linux/module.h>
0009 #include <linux/types.h>
0010 #include <linux/kernel.h>
0011 #include <linux/init.h>
0012 #include <linux/slab.h>
0013 #include <asm/io.h>
0014 #include <linux/mtd/mtd.h>
0015 #include <linux/mtd/map.h>
0016 #include <linux/mtd/cfi.h>
0017 #include <linux/mtd/flashchip.h>
0018 #include <linux/pci.h>
0019 #include <linux/pci_ids.h>
0020 #include <linux/list.h>
0021 
0022 
0023 #define xstr(s) str(s)
0024 #define str(s) #s
0025 #define MOD_NAME xstr(KBUILD_BASENAME)
0026 
0027 #define ADDRESS_NAME_LEN 18
0028 
0029 #define ROM_PROBE_STEP_SIZE (64*1024) /* 64KiB */
0030 
0031 struct amd76xrom_window {
0032     void __iomem *virt;
0033     unsigned long phys;
0034     unsigned long size;
0035     struct list_head maps;
0036     struct resource rsrc;
0037     struct pci_dev *pdev;
0038 };
0039 
0040 struct amd76xrom_map_info {
0041     struct list_head list;
0042     struct map_info map;
0043     struct mtd_info *mtd;
0044     struct resource rsrc;
0045     char map_name[sizeof(MOD_NAME) + 2 + ADDRESS_NAME_LEN];
0046 };
0047 
0048 /* The 2 bits controlling the window size are often set to allow reading
0049  * the BIOS, but too small to allow writing, since the lock registers are
0050  * 4MiB lower in the address space than the data.
0051  *
0052  * This is intended to prevent flashing the bios, perhaps accidentally.
0053  *
0054  * This parameter allows the normal driver to over-ride the BIOS settings.
0055  *
0056  * The bits are 6 and 7.  If both bits are set, it is a 5MiB window.
0057  * If only the 7 Bit is set, it is a 4MiB window.  Otherwise, a
0058  * 64KiB window.
0059  *
0060  */
0061 static uint win_size_bits;
0062 module_param(win_size_bits, uint, 0);
0063 MODULE_PARM_DESC(win_size_bits, "ROM window size bits override for 0x43 byte, normally set by BIOS.");
0064 
0065 static struct amd76xrom_window amd76xrom_window = {
0066     .maps = LIST_HEAD_INIT(amd76xrom_window.maps),
0067 };
0068 
0069 static void amd76xrom_cleanup(struct amd76xrom_window *window)
0070 {
0071     struct amd76xrom_map_info *map, *scratch;
0072     u8 byte;
0073 
0074     if (window->pdev) {
0075         /* Disable writes through the rom window */
0076         pci_read_config_byte(window->pdev, 0x40, &byte);
0077         pci_write_config_byte(window->pdev, 0x40, byte & ~1);
0078         pci_dev_put(window->pdev);
0079     }
0080 
0081     /* Free all of the mtd devices */
0082     list_for_each_entry_safe(map, scratch, &window->maps, list) {
0083         if (map->rsrc.parent) {
0084             release_resource(&map->rsrc);
0085         }
0086         mtd_device_unregister(map->mtd);
0087         map_destroy(map->mtd);
0088         list_del(&map->list);
0089         kfree(map);
0090     }
0091     if (window->rsrc.parent)
0092         release_resource(&window->rsrc);
0093 
0094     if (window->virt) {
0095         iounmap(window->virt);
0096         window->virt = NULL;
0097         window->phys = 0;
0098         window->size = 0;
0099         window->pdev = NULL;
0100     }
0101 }
0102 
0103 
0104 static int amd76xrom_init_one(struct pci_dev *pdev,
0105                   const struct pci_device_id *ent)
0106 {
0107     static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL };
0108     u8 byte;
0109     struct amd76xrom_window *window = &amd76xrom_window;
0110     struct amd76xrom_map_info *map = NULL;
0111     unsigned long map_top;
0112 
0113     /* Remember the pci dev I find the window in - already have a ref */
0114     window->pdev = pdev;
0115 
0116     /* Enable the selected rom window.  This is often incorrectly
0117      * set up by the BIOS, and the 4MiB offset for the lock registers
0118      * requires the full 5MiB of window space.
0119      *
0120      * This 'write, then read' approach leaves the bits for
0121      * other uses of the hardware info.
0122      */
0123     pci_read_config_byte(pdev, 0x43, &byte);
0124     pci_write_config_byte(pdev, 0x43, byte | win_size_bits );
0125 
0126     /* Assume the rom window is properly setup, and find it's size */
0127     pci_read_config_byte(pdev, 0x43, &byte);
0128     if ((byte & ((1<<7)|(1<<6))) == ((1<<7)|(1<<6))) {
0129         window->phys = 0xffb00000; /* 5MiB */
0130     }
0131     else if ((byte & (1<<7)) == (1<<7)) {
0132         window->phys = 0xffc00000; /* 4MiB */
0133     }
0134     else {
0135         window->phys = 0xffff0000; /* 64KiB */
0136     }
0137     window->size = 0xffffffffUL - window->phys + 1UL;
0138 
0139     /*
0140      * Try to reserve the window mem region.  If this fails then
0141      * it is likely due to a fragment of the window being
0142      * "reserved" by the BIOS.  In the case that the
0143      * request_mem_region() fails then once the rom size is
0144      * discovered we will try to reserve the unreserved fragment.
0145      */
0146     window->rsrc.name = MOD_NAME;
0147     window->rsrc.start = window->phys;
0148     window->rsrc.end   = window->phys + window->size - 1;
0149     window->rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
0150     if (request_resource(&iomem_resource, &window->rsrc)) {
0151         window->rsrc.parent = NULL;
0152         printk(KERN_ERR MOD_NAME
0153                " %s(): Unable to register resource %pR - kernel bug?\n",
0154                __func__, &window->rsrc);
0155         return -EBUSY;
0156     }
0157 
0158 
0159     /* Enable writes through the rom window */
0160     pci_read_config_byte(pdev, 0x40, &byte);
0161     pci_write_config_byte(pdev, 0x40, byte | 1);
0162 
0163     /* FIXME handle registers 0x80 - 0x8C the bios region locks */
0164 
0165     /* For write accesses caches are useless */
0166     window->virt = ioremap(window->phys, window->size);
0167     if (!window->virt) {
0168         printk(KERN_ERR MOD_NAME ": ioremap(%08lx, %08lx) failed\n",
0169             window->phys, window->size);
0170         goto out;
0171     }
0172 
0173     /* Get the first address to look for an rom chip at */
0174     map_top = window->phys;
0175 #if 1
0176     /* The probe sequence run over the firmware hub lock
0177      * registers sets them to 0x7 (no access).
0178      * Probe at most the last 4M of the address space.
0179      */
0180     if (map_top < 0xffc00000) {
0181         map_top = 0xffc00000;
0182     }
0183 #endif
0184     /* Loop  through and look for rom chips */
0185     while((map_top - 1) < 0xffffffffUL) {
0186         struct cfi_private *cfi;
0187         unsigned long offset;
0188         int i;
0189 
0190         if (!map) {
0191             map = kmalloc(sizeof(*map), GFP_KERNEL);
0192             if (!map)
0193                 goto out;
0194         }
0195         memset(map, 0, sizeof(*map));
0196         INIT_LIST_HEAD(&map->list);
0197         map->map.name = map->map_name;
0198         map->map.phys = map_top;
0199         offset = map_top - window->phys;
0200         map->map.virt = (void __iomem *)
0201             (((unsigned long)(window->virt)) + offset);
0202         map->map.size = 0xffffffffUL - map_top + 1UL;
0203         /* Set the name of the map to the address I am trying */
0204         sprintf(map->map_name, "%s @%08Lx",
0205             MOD_NAME, (unsigned long long)map->map.phys);
0206 
0207         /* There is no generic VPP support */
0208         for(map->map.bankwidth = 32; map->map.bankwidth;
0209             map->map.bankwidth >>= 1)
0210         {
0211             char **probe_type;
0212             /* Skip bankwidths that are not supported */
0213             if (!map_bankwidth_supported(map->map.bankwidth))
0214                 continue;
0215 
0216             /* Setup the map methods */
0217             simple_map_init(&map->map);
0218 
0219             /* Try all of the probe methods */
0220             probe_type = rom_probe_types;
0221             for(; *probe_type; probe_type++) {
0222                 map->mtd = do_map_probe(*probe_type, &map->map);
0223                 if (map->mtd)
0224                     goto found;
0225             }
0226         }
0227         map_top += ROM_PROBE_STEP_SIZE;
0228         continue;
0229     found:
0230         /* Trim the size if we are larger than the map */
0231         if (map->mtd->size > map->map.size) {
0232             printk(KERN_WARNING MOD_NAME
0233                 " rom(%llu) larger than window(%lu). fixing...\n",
0234                 (unsigned long long)map->mtd->size, map->map.size);
0235             map->mtd->size = map->map.size;
0236         }
0237         if (window->rsrc.parent) {
0238             /*
0239              * Registering the MTD device in iomem may not be possible
0240              * if there is a BIOS "reserved" and BUSY range.  If this
0241              * fails then continue anyway.
0242              */
0243             map->rsrc.name  = map->map_name;
0244             map->rsrc.start = map->map.phys;
0245             map->rsrc.end   = map->map.phys + map->mtd->size - 1;
0246             map->rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
0247             if (request_resource(&window->rsrc, &map->rsrc)) {
0248                 printk(KERN_ERR MOD_NAME
0249                     ": cannot reserve MTD resource\n");
0250                 map->rsrc.parent = NULL;
0251             }
0252         }
0253 
0254         /* Make the whole region visible in the map */
0255         map->map.virt = window->virt;
0256         map->map.phys = window->phys;
0257         cfi = map->map.fldrv_priv;
0258         for(i = 0; i < cfi->numchips; i++) {
0259             cfi->chips[i].start += offset;
0260         }
0261 
0262         /* Now that the mtd devices is complete claim and export it */
0263         map->mtd->owner = THIS_MODULE;
0264         if (mtd_device_register(map->mtd, NULL, 0)) {
0265             map_destroy(map->mtd);
0266             map->mtd = NULL;
0267             goto out;
0268         }
0269 
0270 
0271         /* Calculate the new value of map_top */
0272         map_top += map->mtd->size;
0273 
0274         /* File away the map structure */
0275         list_add(&map->list, &window->maps);
0276         map = NULL;
0277     }
0278 
0279  out:
0280     /* Free any left over map structures */
0281     kfree(map);
0282     /* See if I have any map structures */
0283     if (list_empty(&window->maps)) {
0284         amd76xrom_cleanup(window);
0285         return -ENODEV;
0286     }
0287     return 0;
0288 }
0289 
0290 
0291 static void amd76xrom_remove_one(struct pci_dev *pdev)
0292 {
0293     struct amd76xrom_window *window = &amd76xrom_window;
0294 
0295     amd76xrom_cleanup(window);
0296 }
0297 
0298 static const struct pci_device_id amd76xrom_pci_tbl[] = {
0299     { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7410,
0300         PCI_ANY_ID, PCI_ANY_ID, },
0301     { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7440,
0302         PCI_ANY_ID, PCI_ANY_ID, },
0303     { PCI_VENDOR_ID_AMD, 0x7468 }, /* amd8111 support */
0304     { 0, }
0305 };
0306 
0307 MODULE_DEVICE_TABLE(pci, amd76xrom_pci_tbl);
0308 
0309 #if 0
0310 static struct pci_driver amd76xrom_driver = {
0311     .name =     MOD_NAME,
0312     .id_table = amd76xrom_pci_tbl,
0313     .probe =    amd76xrom_init_one,
0314     .remove =   amd76xrom_remove_one,
0315 };
0316 #endif
0317 
0318 static int __init init_amd76xrom(void)
0319 {
0320     struct pci_dev *pdev;
0321     const struct pci_device_id *id;
0322     pdev = NULL;
0323     for(id = amd76xrom_pci_tbl; id->vendor; id++) {
0324         pdev = pci_get_device(id->vendor, id->device, NULL);
0325         if (pdev) {
0326             break;
0327         }
0328     }
0329     if (pdev) {
0330         return amd76xrom_init_one(pdev, &amd76xrom_pci_tbl[0]);
0331     }
0332     return -ENXIO;
0333 #if 0
0334     return pci_register_driver(&amd76xrom_driver);
0335 #endif
0336 }
0337 
0338 static void __exit cleanup_amd76xrom(void)
0339 {
0340     amd76xrom_remove_one(amd76xrom_window.pdev);
0341 }
0342 
0343 module_init(init_amd76xrom);
0344 module_exit(cleanup_amd76xrom);
0345 
0346 MODULE_LICENSE("GPL");
0347 MODULE_AUTHOR("Eric Biederman <ebiederman@lnxi.com>");
0348 MODULE_DESCRIPTION("MTD map driver for BIOS chips on the AMD76X southbridge");