u-boot/drivers/pci/pci_msc01.c
Paul Burton baf37f06c5 malta: support for coreFPGA6 boards
This patch adds support for running on Malta boards using coreFPGA6
core cards, including support for the msc01 system controller used
with them. The system controller is detected at runtime allowing one
U-boot binary to run on a Malta with either.

Due to the PCI I/O base differing between Maltas using gt64120 & msc01
system controllers, the UART setup is modified slightly. A second UART
is added so that there is one pointing at the correct address for each
system controller. The Malta board then defines its own
default_serial_console function to select the correct one at runtime.
The incorrect UART will simply not function.

Tested on:
  - A coreFPGA6 Malta running interAptiv and proAptiv bitstreams, both
    with and without an L2 cache.
  - QEMU.

Signed-off-by: Paul Burton <paul.burton@imgtec.com>
2013-11-09 17:21:01 +01:00

126 lines
3.3 KiB
C

/*
* Copyright (C) 2013 Imagination Technologies
* Author: Paul Burton <paul.burton@imgtec.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <msc01.h>
#include <pci.h>
#include <pci_msc01.h>
#include <asm/io.h>
#define PCI_ACCESS_READ 0
#define PCI_ACCESS_WRITE 1
struct msc01_pci_controller {
struct pci_controller hose;
void *base;
};
static inline struct msc01_pci_controller *
hose_to_msc01(struct pci_controller *hose)
{
return container_of(hose, struct msc01_pci_controller, hose);
}
static int msc01_config_access(struct msc01_pci_controller *msc01,
unsigned char access_type, pci_dev_t bdf,
int where, u32 *data)
{
const u32 aborts = MSC01_PCI_INTSTAT_MA_MSK | MSC01_PCI_INTSTAT_TA_MSK;
void *intstat = msc01->base + MSC01_PCI_INTSTAT_OFS;
void *cfgdata = msc01->base + MSC01_PCI_CFGDATA_OFS;
unsigned int bus = PCI_BUS(bdf);
unsigned int dev = PCI_DEV(bdf);
unsigned int devfn = PCI_DEV(bdf) << 3 | PCI_FUNC(bdf);
/* clear abort status */
__raw_writel(aborts, intstat);
/* setup address */
__raw_writel((bus << MSC01_PCI_CFGADDR_BNUM_SHF) |
(dev << MSC01_PCI_CFGADDR_DNUM_SHF) |
(devfn << MSC01_PCI_CFGADDR_FNUM_SHF) |
((where / 4) << MSC01_PCI_CFGADDR_RNUM_SHF),
msc01->base + MSC01_PCI_CFGADDR_OFS);
/* perform access */
if (access_type == PCI_ACCESS_WRITE)
__raw_writel(*data, cfgdata);
else
*data = __raw_readl(cfgdata);
/* check for aborts */
if (__raw_readl(intstat) & aborts) {
/* clear abort status */
__raw_writel(aborts, intstat);
return -1;
}
return 0;
}
static int msc01_read_config_dword(struct pci_controller *hose, pci_dev_t dev,
int where, u32 *value)
{
struct msc01_pci_controller *msc01 = hose_to_msc01(hose);
*value = 0xffffffff;
return msc01_config_access(msc01, PCI_ACCESS_READ, dev, where, value);
}
static int msc01_write_config_dword(struct pci_controller *hose, pci_dev_t dev,
int where, u32 value)
{
struct msc01_pci_controller *gt = hose_to_msc01(hose);
u32 data = value;
return msc01_config_access(gt, PCI_ACCESS_WRITE, dev, where, &data);
}
void msc01_pci_init(void *base, unsigned long sys_bus, unsigned long sys_phys,
unsigned long sys_size, unsigned long mem_bus,
unsigned long mem_phys, unsigned long mem_size,
unsigned long io_bus, unsigned long io_phys,
unsigned long io_size)
{
static struct msc01_pci_controller global_msc01;
struct msc01_pci_controller *msc01;
struct pci_controller *hose;
msc01 = &global_msc01;
msc01->base = base;
hose = &msc01->hose;
hose->first_busno = 0;
hose->last_busno = 0;
/* System memory space */
pci_set_region(&hose->regions[0], sys_bus, sys_phys, sys_size,
PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
/* PCI memory space */
pci_set_region(&hose->regions[1], mem_bus, mem_phys, mem_size,
PCI_REGION_MEM);
/* PCI I/O space */
pci_set_region(&hose->regions[2], io_bus, io_phys, io_size,
PCI_REGION_IO);
hose->region_count = 3;
pci_set_ops(hose,
pci_hose_read_config_byte_via_dword,
pci_hose_read_config_word_via_dword,
msc01_read_config_dword,
pci_hose_write_config_byte_via_dword,
pci_hose_write_config_word_via_dword,
msc01_write_config_dword);
pci_register_hose(hose);
hose->last_busno = pci_hose_scan(hose);
}