// SPDX-License-Identifier: GPL-2.0-only /* * PMC551 PCI Mezzanine Ram Device * * Author: * Mark Ferrell <[email protected]> * Copyright 1999,2000 Nortel Networks * * Description: * This driver is intended to support the PMC551 PCI Ram device * from Ramix Inc. The PMC551 is a PMC Mezzanine module for * cPCI embedded systems. The device contains a single SROM * that initially programs the V370PDC chipset onboard the * device, and various banks of DRAM/SDRAM onboard. This driver * implements this PCI Ram device as an MTD (Memory Technology * Device) so that it can be used to hold a file system, or for * added swap space in embedded systems. Since the memory on * this board isn't as fast as main memory we do not try to hook * it into main memory as that would simply reduce performance * on the system. Using it as a block device allows us to use * it as high speed swap or for a high speed disk device of some * sort. Which becomes very useful on diskless systems in the * embedded market I might add. * * Notes: * Due to what I assume is more buggy SROM, the 64M PMC551 I * have available claims that all 4 of its DRAM banks have 64MiB * of ram configured (making a grand total of 256MiB onboard). * This is slightly annoying since the BAR0 size reflects the * aperture size, not the dram size, and the V370PDC supplies no * other method for memory size discovery. This problem is * mostly only relevant when compiled as a module, as the * unloading of the module with an aperture size smaller than * the ram will cause the driver to detect the onboard memory * size to be equal to the aperture size when the module is * reloaded. Soooo, to help, the module supports an msize * option to allow the specification of the onboard memory, and * an asize option, to allow the specification of the aperture * size. The aperture must be equal to or less then the memory * size, the driver will correct this if you screw it up. This * problem is not relevant for compiled in drivers as compiled * in drivers only init once. * * Credits: * Saeed Karamooz <[email protected]> of Ramix INC. for the * initial example code of how to initialize this device and for * help with questions I had concerning operation of the device. * * Most of the MTD code for this driver was originally written * for the slram.o module in the MTD drivers package which * allows the mapping of system memory into an MTD device. * Since the PMC551 memory module is accessed in the same * fashion as system memory, the slram.c code became a very nice * fit to the needs of this driver. All we added was PCI * detection/initialization to the driver and automatically figure * out the size via the PCI detection.o, later changes by Corey * Minyard set up the card to utilize a 1M sliding apature. * * Corey Minyard <[email protected]> * * Modified driver to utilize a sliding aperture instead of * mapping all memory into kernel space which turned out to * be very wasteful. * * Located a bug in the SROM's initialization sequence that * made the memory unusable, added a fix to code to touch up * the DRAM some. * * Bugs/FIXMEs: * * MUST fix the init function to not spin on a register * waiting for it to set .. this does not safely handle busted * devices that never reset the register correctly which will * cause the system to hang w/ a reboot being the only chance at * recover. [sort of fixed, could be better] * * Add I2C handling of the SROM so we can read the SROM's information * about the aperture size. This should always accurately reflect the * onboard memory size. * * Comb the init routine. It's still a bit cludgy on a few things. */ #include <linux/kernel.h> #include <linux/module.h> #include <linux/uaccess.h> #include <linux/types.h> #include <linux/init.h> #include <linux/ptrace.h> #include <linux/slab.h> #include <linux/string.h> #include <linux/timer.h> #include <linux/major.h> #include <linux/fs.h> #include <linux/ioctl.h> #include <asm/io.h> #include <linux/pci.h> #include <linux/mtd/mtd.h> #define PMC551_VERSION … #define PCI_VENDOR_ID_V3_SEMI … #define PCI_DEVICE_ID_V3_SEMI_V370PDC … #define PMC551_PCI_MEM_MAP0 … #define PMC551_PCI_MEM_MAP1 … #define PMC551_PCI_MEM_MAP_MAP_ADDR_MASK … #define PMC551_PCI_MEM_MAP_APERTURE_MASK … #define PMC551_PCI_MEM_MAP_REG_EN … #define PMC551_PCI_MEM_MAP_ENABLE … #define PMC551_SDRAM_MA … #define PMC551_SDRAM_CMD … #define PMC551_DRAM_CFG … #define PMC551_SYS_CTRL_REG … #define PMC551_DRAM_BLK0 … #define PMC551_DRAM_BLK1 … #define PMC551_DRAM_BLK2 … #define PMC551_DRAM_BLK3 … #define PMC551_DRAM_BLK_GET_SIZE(x) … #define PMC551_DRAM_BLK_SET_COL_MUX(x, v) … #define PMC551_DRAM_BLK_SET_ROW_MUX(x, v) … struct mypriv { … }; static struct mtd_info *pmc551list; static int pmc551_point(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, void **virt, resource_size_t *phys); static int pmc551_erase(struct mtd_info *mtd, struct erase_info *instr) { … } static int pmc551_point(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, void **virt, resource_size_t *phys) { … } static int pmc551_unpoint(struct mtd_info *mtd, loff_t from, size_t len) { … } static int pmc551_read(struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf) { … } static int pmc551_write(struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf) { … } /* * Fixup routines for the V370PDC * PCI device ID 0x020011b0 * * This function basically kick starts the DRAM oboard the card and gets it * ready to be used. Before this is done the device reads VERY erratic, so * much that it can crash the Linux 2.2.x series kernels when a user cat's * /proc/pci .. though that is mainly a kernel bug in handling the PCI DEVSEL * register. FIXME: stop spinning on registers .. must implement a timeout * mechanism * returns the size of the memory region found. */ static int __init fixup_pmc551(struct pci_dev *dev) { … } /* * Kernel version specific module stuffages */ MODULE_LICENSE(…) …; MODULE_AUTHOR(…) …; MODULE_DESCRIPTION(…); /* * Stuff these outside the ifdef so as to not bust compiled in driver support */ static int msize = …; static int asize = …; module_param(msize, int, 0); MODULE_PARM_DESC(…) …; module_param(asize, int, 0); MODULE_PARM_DESC(…) …; /* * PMC551 Card Initialization */ static int __init init_pmc551(void) { … } /* * PMC551 Card Cleanup */ static void __exit cleanup_pmc551(void) { … } module_init(…) …; module_exit(cleanup_pmc551);