Skip to content
Snippets Groups Projects
pci_io.c 2.58 KiB
Newer Older
  • Learn to ignore specific revisions
  • /*
     * Copyright (c) 2014 Google, Inc
     * Written by Simon Glass <sjg@chromium.org>
     *
     * SPDX-License-Identifier:     GPL-2.0+
     */
    
    /*
     * IO space access commands.
     */
    
    #include <common.h>
    #include <command.h>
    #include <dm.h>
    #include <asm/io.h>
    
    int pci_map_physmem(phys_addr_t paddr, unsigned long *lenp,
    		    struct udevice **devp, void **ptrp)
    {
    	struct udevice *dev;
    	int ret;
    
    	*ptrp = 0;
    	for (uclass_first_device(UCLASS_PCI_EMUL, &dev);
    	     dev;
    	     uclass_next_device(&dev)) {
    		struct dm_pci_emul_ops *ops = pci_get_emul_ops(dev);
    
    		if (!ops || !ops->map_physmem)
    			continue;
    		ret = (ops->map_physmem)(dev, paddr, lenp, ptrp);
    		if (ret)
    			continue;
    		*devp = dev;
    		return 0;
    	}
    
    	debug("%s: failed: addr=%x\n", __func__, paddr);
    	return -ENOSYS;
    }
    
    int pci_unmap_physmem(const void *vaddr, unsigned long len,
    		      struct udevice *dev)
    {
    	struct dm_pci_emul_ops *ops = pci_get_emul_ops(dev);
    
    	if (!ops || !ops->unmap_physmem)
    		return -ENOSYS;
    	return (ops->unmap_physmem)(dev, vaddr, len);
    }
    
    static int pci_io_read(unsigned int addr, ulong *valuep, pci_size_t size)
    {
    	struct udevice *dev;
    	int ret;
    
    	*valuep = pci_get_ff(size);
    	for (uclass_first_device(UCLASS_PCI_EMUL, &dev);
    	     dev;
    	     uclass_next_device(&dev)) {
    		struct dm_pci_emul_ops *ops = pci_get_emul_ops(dev);
    
    		if (ops && ops->read_io) {
    			ret = (ops->read_io)(dev, addr, valuep, size);
    			if (!ret)
    				return 0;
    		}
    	}
    
    	debug("%s: failed: addr=%x\n", __func__, addr);
    	return -ENOSYS;
    }
    
    static int pci_io_write(unsigned int addr, ulong value, pci_size_t size)
    {
    	struct udevice *dev;
    	int ret;
    
    	for (uclass_first_device(UCLASS_PCI_EMUL, &dev);
    	     dev;
    	     uclass_next_device(&dev)) {
    		struct dm_pci_emul_ops *ops = pci_get_emul_ops(dev);
    
    		if (ops && ops->write_io) {
    			ret = (ops->write_io)(dev, addr, value, size);
    			if (!ret)
    				return 0;
    		}
    	}
    
    	debug("%s: failed: addr=%x, value=%lx\n", __func__, addr, value);
    	return -ENOSYS;
    }
    
    int inl(unsigned int addr)
    {
    	unsigned long value;
    	int ret;
    
    	ret = pci_io_read(addr, &value, PCI_SIZE_32);
    
    	return ret ? 0 : value;
    }
    
    int inw(unsigned int addr)
    {
    	unsigned long value;
    	int ret;
    
    	ret = pci_io_read(addr, &value, PCI_SIZE_16);
    
    	return ret ? 0 : value;
    }
    
    int inb(unsigned int addr)
    {
    	unsigned long value;
    	int ret;
    
    	ret = pci_io_read(addr, &value, PCI_SIZE_8);
    
    	return ret ? 0 : value;
    }
    
    void outl(unsigned int value, unsigned int addr)
    {
    	pci_io_write(addr, value, PCI_SIZE_32);
    }
    
    void outw(unsigned int value, unsigned int addr)
    {
    	pci_io_write(addr, value, PCI_SIZE_16);
    }
    
    void outb(unsigned int value, unsigned int addr)
    {
    	pci_io_write(addr, value, PCI_SIZE_8);
    }