dm: sandbox: pci: Add PCI support for sandbox

Add the required header information, device tree nodes and I/O accessor
functions to support PCI on sandbox. All devices are emulated by drivers
which can be added as required for testing or development.

Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
Simon Glass 2015-03-05 12:25:26 -07:00
parent ff3e077bd2
commit 9569c40668
9 changed files with 284 additions and 7 deletions

View file

@ -34,4 +34,11 @@ config DM_I2C
config DM_TEST
default y
config PCI
bool "PCI support"
help
Enable support for PCI (Peripheral Interconnect Bus), a type of bus
used on some devices to allow the CPU to communicate with its
peripherals.
endmenu

View file

@ -2,7 +2,7 @@
* Copyright (c) 2011 The Chromium OS Authors.
* SPDX-License-Identifier: GPL-2.0+
*/
#define DEBUG
#include <common.h>
#include <dm/root.h>
#include <os.h>
@ -10,6 +10,15 @@
DECLARE_GLOBAL_DATA_PTR;
/* Enable access to PCI memory with map_sysmem() */
static bool enable_pci_map;
#ifdef CONFIG_PCI
/* Last device that was mapped into memory, and length of mapping */
static struct udevice *map_dev;
unsigned long map_len;
#endif
void reset_cpu(ulong ignored)
{
if (state_uninit())
@ -59,9 +68,39 @@ int cleanup_before_linux(void)
void *map_physmem(phys_addr_t paddr, unsigned long len, unsigned long flags)
{
#ifdef CONFIG_PCI
unsigned long plen = len;
void *ptr;
map_dev = NULL;
if (enable_pci_map && !pci_map_physmem(paddr, &len, &map_dev, &ptr)) {
if (plen != len) {
printf("%s: Warning: partial map at %x, wanted %lx, got %lx\n",
__func__, paddr, len, plen);
}
map_len = len;
return ptr;
}
#endif
return (void *)(gd->arch.ram_buf + paddr);
}
void unmap_physmem(const void *vaddr, unsigned long flags)
{
#ifdef CONFIG_PCI
if (map_dev) {
pci_unmap_physmem(vaddr, map_len, map_dev);
map_dev = NULL;
}
#endif
}
void sandbox_set_enable_pci_map(int enable)
{
enable_pci_map = enable;
}
phys_addr_t map_to_sysmem(const void *ptr)
{
return (u8 *)ptr - gd->arch.ram_buf;

View file

@ -4,6 +4,10 @@
#address-cells = <1>;
#size-cells = <1>;
aliases {
pci0 = &pci;
};
chosen {
stdout-path = "/serial";
};
@ -181,4 +185,20 @@
};
};
pci: pci-controller {
compatible = "sandbox,pci";
device_type = "pci";
#address-cells = <3>;
#size-cells = <2>;
ranges = <0x02000000 0 0x10000000 0x10000000 0 0x2000
0x01000000 0 0x20000000 0x20000000 0 0x2000>;
pci@1f,0 {
compatible = "pci-generic";
reg = <0xf800 0 0 0 0>;
emul@1f,0 {
compatible = "sandbox,swap-case";
};
};
};
};

View file

@ -22,10 +22,7 @@ void *map_physmem(phys_addr_t paddr, unsigned long len, unsigned long flags);
/*
* Take down a mapping set up by map_physmem().
*/
static inline void unmap_physmem(void *vaddr, unsigned long flags)
{
}
void unmap_physmem(const void *vaddr, unsigned long flags);
/* For sandbox, we want addresses to point into our RAM buffer */
static inline void *map_sysmem(phys_addr_t paddr, unsigned long len)
@ -33,8 +30,10 @@ static inline void *map_sysmem(phys_addr_t paddr, unsigned long len)
return map_physmem(paddr, len, MAP_WRBACK);
}
/* Remove a previous mapping */
static inline void unmap_sysmem(const void *vaddr)
{
unmap_physmem(vaddr, MAP_WRBACK);
}
/* Map from a pointer to our RAM buffer */
@ -48,6 +47,15 @@ phys_addr_t map_to_sysmem(const void *ptr);
#define writew(v, addr)
#define writel(v, addr)
/* I/O access functions */
int inl(unsigned int addr);
int inw(unsigned int addr);
int inb(unsigned int addr);
void outl(unsigned int value, unsigned int addr);
void outw(unsigned int value, unsigned int addr);
void outb(unsigned int value, unsigned int addr);
#include <iotrace.h>
#endif

View file

@ -0,0 +1,12 @@
/*
* Copyright (c) 2014 Google, Inc
*
* SPDX-License-Identifier: GPL-2.0+
*/
#ifndef _ASM_PROCESSOR_H
#define _ASM_PROCESSOR_H
/* This file is required for PCI */
#endif

View file

@ -10,7 +10,12 @@
#define __ASM_TEST_H
/* The sandbox driver always permits an I2C device with this address */
#define SANDBOX_I2C_TEST_ADDR 0x59
#define SANDBOX_I2C_TEST_ADDR 0x59
#define SANDBOX_PCI_VENDOR_ID 0x1234
#define SANDBOX_PCI_DEVICE_ID 0x5678
#define SANDBOX_PCI_CLASS_CODE PCI_CLASS_CODE_COMM
#define SANDBOX_PCI_CLASS_SUB_CODE PCI_CLASS_SUB_CODE_COMM_SERIAL
enum sandbox_i2c_eeprom_test_mode {
SIE_TEST_MODE_NONE,

View file

@ -27,4 +27,52 @@ int cleanup_before_linux(void);
/* drivers/video/sandbox_sdl.c */
int sandbox_lcd_sdl_early_init(void);
/**
* pci_map_physmem() - map a PCI device into memory
*
* This is used on sandbox to map a device into memory so that it can be
* used with normal memory access. After this call, some part of the device's
* internal structure becomes visible.
*
* This function is normally called from sandbox's map_sysmem() automatically.
*
* @paddr: Physical memory address, normally corresponding to a PCI BAR
* @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
* @devp: Returns the device which mapped into this 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, -ve on error
*/
int pci_map_physmem(phys_addr_t paddr, unsigned long *lenp,
struct udevice **devp, void **ptrp);
/**
* pci_unmap_physmem() - undo a memory mapping
*
* This must be called after pci_map_physmem() to undo the mapping.
*
* @paddr: Physical memory address, as passed to pci_map_physmem()
* @len: Size of area mapped, as returned by pci_map_physmem()
* @dev: Device to unmap, as returned by pci_map_physmem()
* @return 0 if OK, -ve on error
*/
int pci_unmap_physmem(const void *addr, unsigned long len,
struct udevice *dev);
/**
* sandbox_set_enable_pci_map() - Enable / disable PCI address mapping
*
* Since address mapping involves calling every driver, provide a way to
* enable and disable this. It can be handled automatically by the emulator
* uclass, which knows if any emulators are currently active.
*
* If this is disabled, pci_map_physmem() will not be called from
* map_sysmem().
*
* @enable: 0 to disable, 1 to enable
*/
void sandbox_set_enable_pci_map(int enable);
#endif /* _U_BOOT_SANDBOX_H_ */

View file

@ -7,5 +7,5 @@
# SPDX-License-Identifier: GPL-2.0+
#
obj-y += interrupts.o
obj-$(CONFIG_PCI) += pci_io.o

138
arch/sandbox/lib/pci_io.c Normal file
View file

@ -0,0 +1,138 @@
/*
* 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);
}