Skip to content
Snippets Groups Projects
pci.h 51.7 KiB
Newer Older
  • Learn to ignore specific revisions
  •  * pci_bus_read_config() - Read a configuration value from a device
     *
     * TODO(sjg@chromium.org): We should be able to pass just a device and have
     * it do the right thing. It would be good to have that function also.
     *
     * @bus:	Bus to read from
     * @bdf:	PCI device address: bus, device and function -see PCI_BDF()
     * @valuep:	Place to put the returned value
     * @size:	Access size
     * @return 0 if OK, -ve on error
     */
    int pci_bus_read_config(struct udevice *bus, pci_dev_t bdf, int offset,
    			unsigned long *valuep, enum pci_size_t size);
    
    /**
     * pci_bus_write_config() - Write a configuration value to a device
     *
     * @bus:	Bus to write from
     * @bdf:	PCI device address: bus, device and function -see PCI_BDF()
     * @value:	Value to write
     * @size:	Access size
     * @return 0 if OK, -ve on error
     */
    int pci_bus_write_config(struct udevice *bus, pci_dev_t bdf, int offset,
    			 unsigned long value, enum pci_size_t size);
    
    
    /**
     * Driver model PCI config access functions. Use these in preference to others
     * when you have a valid device
     */
    int dm_pci_read_config(struct udevice *dev, int offset, unsigned long *valuep,
    		       enum pci_size_t size);
    
    int dm_pci_read_config8(struct udevice *dev, int offset, u8 *valuep);
    int dm_pci_read_config16(struct udevice *dev, int offset, u16 *valuep);
    int dm_pci_read_config32(struct udevice *dev, int offset, u32 *valuep);
    
    int dm_pci_write_config(struct udevice *dev, int offset, unsigned long value,
    			enum pci_size_t size);
    
    int dm_pci_write_config8(struct udevice *dev, int offset, u8 value);
    int dm_pci_write_config16(struct udevice *dev, int offset, u16 value);
    int dm_pci_write_config32(struct udevice *dev, int offset, u32 value);
    
    
    /*
     * The following functions provide access to the above without needing the
     * size parameter. We are trying to encourage the use of the 8/16/32-style
     * functions, rather than byte/word/dword. But both are supported.
     */
    int pci_write_config32(pci_dev_t pcidev, int offset, u32 value);
    
    
    #ifdef CONFIG_DM_PCI_COMPAT
    
    /* Compatibility with old naming */
    static inline int pci_write_config_dword(pci_dev_t pcidev, int offset,
    					 u32 value)
    {
    	return pci_write_config32(pcidev, offset, value);
    }
    
    int pci_write_config16(pci_dev_t pcidev, int offset, u16 value);
    
    /* Compatibility with old naming */
    static inline int pci_write_config_word(pci_dev_t pcidev, int offset,
    					u16 value)
    {
    	return pci_write_config16(pcidev, offset, value);
    }
    
    int pci_write_config8(pci_dev_t pcidev, int offset, u8 value);
    
    /* Compatibility with old naming */
    static inline int pci_write_config_byte(pci_dev_t pcidev, int offset,
    					u8 value)
    {
    	return pci_write_config8(pcidev, offset, value);
    }
    
    int pci_read_config32(pci_dev_t pcidev, int offset, u32 *valuep);
    
    /* Compatibility with old naming */
    static inline int pci_read_config_dword(pci_dev_t pcidev, int offset,
    					u32 *valuep)
    {
    	return pci_read_config32(pcidev, offset, valuep);
    }
    
    int pci_read_config16(pci_dev_t pcidev, int offset, u16 *valuep);
    
    /* Compatibility with old naming */
    static inline int pci_read_config_word(pci_dev_t pcidev, int offset,
    				       u16 *valuep)
    {
    	return pci_read_config16(pcidev, offset, valuep);
    }
    
    int pci_read_config8(pci_dev_t pcidev, int offset, u8 *valuep);
    
    /* Compatibility with old naming */
    static inline int pci_read_config_byte(pci_dev_t pcidev, int offset,
    				       u8 *valuep)
    {
    	return pci_read_config8(pcidev, offset, valuep);
    }
    
    
    #endif /* CONFIG_DM_PCI_COMPAT */
    
    /**
     * dm_pciauto_config_device() - configure a device ready for use
     *
     * Space is allocated for each PCI base address register (BAR) so that the
     * devices are mapped into memory and I/O space ready for use.
     *
     * @dev:	Device to configure
     * @return 0 if OK, -ve on error
     */
    int dm_pciauto_config_device(struct udevice *dev);
    
    
    /**
     * pci_conv_32_to_size() - convert a 32-bit read value to the given size
     *
     * Some PCI buses must always perform 32-bit reads. The data must then be
     * shifted and masked to reflect the required access size and offset. This
     * function performs this transformation.
     *
     * @value:	Value to transform (32-bit value read from @offset & ~3)
     * @offset:	Register offset that was read
     * @size:	Required size of the result
     * @return the value that would have been obtained if the read had been
     * performed at the given offset with the correct size
     */
    ulong pci_conv_32_to_size(ulong value, uint offset, enum pci_size_t size);
    
    /**
     * pci_conv_size_to_32() - update a 32-bit value to prepare for a write
     *
     * Some PCI buses must always perform 32-bit writes. To emulate a smaller
     * write the old 32-bit data must be read, updated with the required new data
     * and written back as a 32-bit value. This function performs the
     * transformation from the old value to the new value.
     *
     * @value:	Value to transform (32-bit value read from @offset & ~3)
     * @offset:	Register offset that should be written
     * @size:	Required size of the write
     * @return the value that should be written as a 32-bit access to @offset & ~3.
     */
    ulong pci_conv_size_to_32(ulong old, ulong value, uint offset,
    			  enum pci_size_t size);
    
    
    /**
     * pci_get_controller() - obtain the controller to use for a bus
     *
     * @dev:	Device to check
     * @return pointer to the controller device for this bus
     */
    struct udevice *pci_get_controller(struct udevice *dev);
    
    
    /**
     * pci_get_regions() - obtain pointers to all the region types
     *
     * @dev:	Device to check
     * @iop:	Returns a pointer to the I/O region, or NULL if none
     * @memp:	Returns a pointer to the memory region, or NULL if none
     * @prefp:	Returns a pointer to the pre-fetch region, or NULL if none
     * @return the number of non-NULL regions returned, normally 3
     */
    int pci_get_regions(struct udevice *dev, struct pci_region **iop,
    		    struct pci_region **memp, struct pci_region **prefp);
    
    
    /**
     * dm_pci_find_device() - find a device by vendor/device ID
     *
     * @vendor:	Vendor ID
     * @device:	Device ID
     * @index:	0 to find the first match, 1 for second, etc.
     * @devp:	Returns pointer to the device, if found
     * @return 0 if found, -ve on error
     */
    int dm_pci_find_device(unsigned int vendor, unsigned int device, int index,
    		       struct udevice **devp);
    
    
    /**
     * dm_pci_find_class() - find a device by class
     *
     * @find_class: 3-byte (24-bit) class value to find
     * @index:	0 to find the first match, 1 for second, etc.
     * @devp:	Returns pointer to the device, if found
     * @return 0 if found, -ve on error
     */
    int dm_pci_find_class(uint find_class, int index, struct udevice **devp);
    
    
    /**
     * struct dm_pci_emul_ops - PCI device emulator operations
     */
    struct dm_pci_emul_ops {
    	/**
    	 * get_devfn(): Check which device and function this emulators
    	 *
    	 * @dev:	device to check
    	 * @return the device and function this emulates, or -ve on error
    	 */
    	int (*get_devfn)(struct udevice *dev);
    	/**
    	 * read_config() - Read a PCI configuration value
    	 *
    	 * @dev:	Emulated device to read from
    	 * @offset:	Byte offset within the device's configuration space
    	 * @valuep:	Place to put the returned value
    	 * @size:	Access size
    	 * @return 0 if OK, -ve on error
    	 */
    	int (*read_config)(struct udevice *dev, uint offset, ulong *valuep,
    			   enum pci_size_t size);
    	/**
    	 * write_config() - Write a PCI configuration value
    	 *
    	 * @dev:	Emulated device to write to
    	 * @offset:	Byte offset within the device's configuration space
    	 * @value:	Value to write
    	 * @size:	Access size
    	 * @return 0 if OK, -ve on error
    	 */
    	int (*write_config)(struct udevice *dev, uint offset, ulong value,
    			    enum pci_size_t size);
    	/**
    	 * read_io() - Read a PCI I/O value
    	 *
    	 * @dev:	Emulated device to read from
    	 * @addr:	I/O address to read
    	 * @valuep:	Place to put the returned value
    	 * @size:	Access size
    	 * @return 0 if OK, -ENOENT if @addr is not mapped by this device,
    	 *		other -ve value on error
    	 */
    	int (*read_io)(struct udevice *dev, unsigned int addr, ulong *valuep,
    		       enum pci_size_t size);
    	/**
    	 * write_io() - Write a PCI I/O value
    	 *
    	 * @dev:	Emulated device to write from
    	 * @addr:	I/O address to write
    	 * @value:	Value to write
    	 * @size:	Access size
    	 * @return 0 if OK, -ENOENT if @addr is not mapped by this device,
    	 *		other -ve value on error
    	 */
    	int (*write_io)(struct udevice *dev, unsigned int addr,
    			ulong value, enum pci_size_t size);
    	/**
    	 * map_physmem() - Map a device into sandbox memory
    	 *
    	 * @dev:	Emulated device to map
    	 * @addr:	Memory address, normally corresponding to a PCI BAR.
    	 *		The device should have been configured to have a BAR
    	 *		at this address.
    	 * @lenp:	On entry, the size of the area to map, On exit it is
    	 *		updated to the size actually mapped, which may be less
    	 *		if the device has less space
    	 * @ptrp:	Returns a pointer to the mapped address. The device's
    	 *		space can be accessed as @lenp bytes starting here
    	 * @return 0 if OK, -ENOENT if @addr is not mapped by this device,
    	 *		other -ve value on error
    	 */
    	int (*map_physmem)(struct udevice *dev, phys_addr_t addr,
    			   unsigned long *lenp, void **ptrp);
    	/**
    	 * unmap_physmem() - undo a memory mapping
    	 *
    	 * This must be called after map_physmem() to undo the mapping.
    	 * Some devices can use this to check what has been written into
    	 * their mapped memory and perform an operations they require on it.
    	 * In this way, map/unmap can be used as a sort of handshake between
    	 * the emulated device and its users.
    	 *
    	 * @dev:	Emuated device to unmap
    	 * @vaddr:	Mapped memory address, as passed to map_physmem()
    	 * @len:	Size of area mapped, as returned by map_physmem()
    	 * @return 0 if OK, -ve on error
    	 */
    	int (*unmap_physmem)(struct udevice *dev, const void *vaddr,
    			     unsigned long len);
    };
    
    /* Get access to a PCI device emulator's operations */
    #define pci_get_emul_ops(dev)	((struct dm_pci_emul_ops *)(dev)->driver->ops)
    
    /**
     * sandbox_pci_get_emul() - Get the emulation device for a PCI device
     *
     * Searches for a suitable emulator for the given PCI bus device
     *
     * @bus:	PCI bus to search
     * @find_devfn:	PCI device and function address (PCI_DEVFN())
     * @emulp:	Returns emulated device if found
     * @return 0 if found, -ENODEV if not found
     */
    int sandbox_pci_get_emul(struct udevice *bus, pci_dev_t find_devfn,
    			 struct udevice **emulp);
    
    
    #endif /* CONFIG_DM_PCI */
    
    /**
     * PCI_DEVICE - macro used to describe a specific pci device
     * @vend: the 16 bit PCI Vendor ID
     * @dev: the 16 bit PCI Device ID
     *
     * This macro is used to create a struct pci_device_id that matches a
     * specific device.  The subvendor and subdevice fields will be set to
     * PCI_ANY_ID.
     */
    #define PCI_DEVICE(vend, dev) \
    	.vendor = (vend), .device = (dev), \
    	.subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID
    
    /**
     * PCI_DEVICE_SUB - macro used to describe a specific pci device with subsystem
     * @vend: the 16 bit PCI Vendor ID
     * @dev: the 16 bit PCI Device ID
     * @subvend: the 16 bit PCI Subvendor ID
     * @subdev: the 16 bit PCI Subdevice ID
     *
     * This macro is used to create a struct pci_device_id that matches a
     * specific device with subsystem information.
     */
    #define PCI_DEVICE_SUB(vend, dev, subvend, subdev) \
    	.vendor = (vend), .device = (dev), \
    	.subvendor = (subvend), .subdevice = (subdev)
    
    /**
     * PCI_DEVICE_CLASS - macro used to describe a specific pci device class
     * @dev_class: the class, subclass, prog-if triple for this device
     * @dev_class_mask: the class mask for this device
     *
     * This macro is used to create a struct pci_device_id that matches a
     * specific PCI class.  The vendor, device, subvendor, and subdevice
     * fields will be set to PCI_ANY_ID.
     */
    #define PCI_DEVICE_CLASS(dev_class, dev_class_mask) \
    	.class = (dev_class), .class_mask = (dev_class_mask), \
    	.vendor = PCI_ANY_ID, .device = PCI_ANY_ID, \
    	.subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID
    
    /**
     * PCI_VDEVICE - macro used to describe a specific pci device in short form
     * @vend: the vendor name
     * @dev: the 16 bit PCI Device ID
     *
     * This macro is used to create a struct pci_device_id that matches a
     * specific PCI device.  The subvendor, and subdevice fields will be set
     * to PCI_ANY_ID. The macro allows the next field to follow as the device
     * private data.
     */
    
    #define PCI_VDEVICE(vend, dev) \
    	.vendor = PCI_VENDOR_ID_##vend, .device = (dev), \
    	.subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, 0, 0
    
    /**
     * struct pci_driver_entry - Matches a driver to its pci_device_id list
     * @driver: Driver to use
     * @match: List of match records for this driver, terminated by {}
     */
    struct pci_driver_entry {
    	struct driver *driver;
    	const struct pci_device_id *match;
    };
    
    #define U_BOOT_PCI_DEVICE(__name, __match)				\
    	ll_entry_declare(struct pci_driver_entry, __name, pci_driver_entry) = {\
    		.driver = llsym(struct driver, __name, driver), \
    		.match = __match, \
    		}
    
    #endif /* __ASSEMBLY__ */
    #endif /* _PCI_H */