mirror of
https://github.com/brain-hackers/u-boot-brain
synced 2024-08-24 10:58:52 +09:00
![Paul Burton](/assets/img/avatar_default.png)
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>
126 lines
3.3 KiB
C
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);
|
|
}
|