dm: pci: Add functions to emulate 8- and 16-bit access

Provide a few functions to support using 32-bit access to emulate 8- and
16-bit access.

Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Stephen Warren <swarren@nvidia.com>
Tested-by: Stephen Warren <swarren@nvidia.com>
This commit is contained in:
Simon Glass 2015-11-19 20:26:59 -07:00
parent 9526d83ac5
commit 9289db6c60
2 changed files with 70 additions and 0 deletions

View File

@ -927,6 +927,45 @@ int pci_find_first_device(struct udevice **devp)
return skip_to_next_device(bus, devp);
}
ulong pci_conv_32_to_size(ulong value, uint offset, enum pci_size_t size)
{
switch (size) {
case PCI_SIZE_8:
return (value >> ((offset & 3) * 8)) & 0xff;
case PCI_SIZE_16:
return (value >> ((offset & 2) * 8)) & 0xffff;
default:
return value;
}
}
ulong pci_conv_size_to_32(ulong old, ulong value, uint offset,
enum pci_size_t size)
{
uint off_mask;
uint val_mask, shift;
ulong ldata, mask;
switch (size) {
case PCI_SIZE_8:
off_mask = 3;
val_mask = 0xff;
break;
case PCI_SIZE_16:
off_mask = 2;
val_mask = 0xffff;
break;
default:
return value;
}
shift = (offset & off_mask) * 8;
ldata = (value & val_mask) << shift;
mask = val_mask << shift;
value = (old & ~mask) | ldata;
return value;
}
UCLASS_DRIVER(pci) = {
.id = UCLASS_PCI,
.name = "pci",

View File

@ -1091,6 +1091,37 @@ static inline int pci_read_config_byte(pci_dev_t pcidev, int offset,
return pci_read_config8(pcidev, offset, valuep);
}
/**
* 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);
/**
* struct dm_pci_emul_ops - PCI device emulator operations
*/