592 lines
16 KiB
C
592 lines
16 KiB
C
/*
|
|
* (C) Copyright 2011 Quantenna Communications Inc.
|
|
*
|
|
* See file CREDITS for list of people who contributed to this
|
|
* project.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License as
|
|
* published by the Free Software Foundation; either version 2 of
|
|
* the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
|
* MA 02111-1307 USA
|
|
*/
|
|
|
|
/*
|
|
* Header file which describes Ruby PCI Express specific functions.
|
|
*/
|
|
|
|
|
|
#include <common.h>
|
|
#include <command.h>
|
|
#include <asm/arch/platform.h>
|
|
#include <environment.h>
|
|
#include "ruby.h"
|
|
#include "ruby_board_cfg.h"
|
|
#include "ruby_pcie_bda.h"
|
|
#include "pcie.h"
|
|
#include "board_cfg.h"
|
|
|
|
|
|
static inline void arc_write_uncached_32(volatile void *ptr, uint32_t data)
|
|
{
|
|
uint32_t start = (unsigned long)ptr;
|
|
invalidate_dcache_range(start, start + sizeof(uint32_t));
|
|
_arc_write_uncached_32(ptr, data);
|
|
}
|
|
|
|
/*
|
|
* for End Point mode
|
|
* Allocate and setup BAR mapping for shared memory
|
|
*/
|
|
static int32_t setup_atu_shmem(void)
|
|
{
|
|
uint32_t val = 0x0;
|
|
|
|
/* Select shared mem region */
|
|
writel(PCIE_SHMEM_REGION, RUBY_PCIE_ATU_VIEW);
|
|
|
|
/* Bar mapped area in EP */
|
|
writel(PCIE_BAR_SHMEM_LO, RUBY_PCIE_ATU_TARGET_LO);
|
|
writel(PCIE_BAR_SHMEM_HI, RUBY_PCIE_ATU_TARGET_HI);
|
|
|
|
/* Set BAR size to EP memory */
|
|
writel(PCIE_BAR_SHMEM_LEN, RUBY_PCIE_ATU_BASE_LIMIT);
|
|
|
|
/* Define region of type memory */
|
|
writel(PCIE_ATU_MEMREGION, RUBY_PCIE_ATU_CTL1);
|
|
|
|
/* Enable BAR mapped region */
|
|
writel(PCIE_SHMEM_ENABLE, RUBY_PCIE_ATU_CTL2);
|
|
val = readl(RUBY_PCIE_ATU_CTL2);
|
|
printf("PCIe Shmem BAR%u=0x%x Len:%uk\n", PCIE_BAR_SHMEM,
|
|
PCIE_BAR_SHMEM_LO, (PCIE_BAR_SHMEM_LEN >> 10) + 1);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* for End Point mode
|
|
* Allocate and setup BAR mapping for syscontrol
|
|
*/
|
|
static int32_t setup_atu_sysctl(void)
|
|
{
|
|
uint32_t val = 0x0;
|
|
|
|
/* Select shared mem region */
|
|
writel(PCIE_SYSCTL_REGION, RUBY_PCIE_ATU_VIEW);
|
|
|
|
/* Bar mapped area in EP */
|
|
writel(PCIE_BAR_SYSCTL_LO, RUBY_PCIE_ATU_TARGET_LO);
|
|
writel(PCIE_BAR_SYSCTL_HI, RUBY_PCIE_ATU_TARGET_HI);
|
|
|
|
/* Set size */
|
|
writel(PCIE_BAR_SYSCTL_LEN, RUBY_PCIE_ATU_BASE_LIMIT);
|
|
|
|
/* Define region of type memory */
|
|
writel(PCIE_ATU_MEMREGION, RUBY_PCIE_ATU_CTL1);
|
|
|
|
/* Enable BAR mapped region */
|
|
writel(PCIE_SYSCTL_ENABLE, RUBY_PCIE_ATU_CTL2);
|
|
val = readl(RUBY_PCIE_ATU_CTL2);
|
|
|
|
printf("PCIe Sysctl BAR%u=0x%x Len:%uk\n", PCIE_BAR_SYSCTL,
|
|
PCIE_BAR_SYSCTL_LO, ( PCIE_BAR_SYSCTL_LEN >> 10) + 1);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* for End Point mode *
|
|
* map the host memory to target
|
|
*/
|
|
static int32_t setup_atu_host(uint32_t addr_mask)
|
|
{
|
|
uint32_t val = 0x0;
|
|
|
|
/* Select shared mem region */
|
|
writel(PCIE_HOSTMEM_REGION, RUBY_PCIE_ATU_VIEW);
|
|
|
|
/* Memory mapped area in EP )*/
|
|
writel(PCIE_HOSTMEM_EP_START_LO, RUBY_PCIE_ATU_BASE_LO);
|
|
writel(PCIE_HOSTMEM_EP_START_HI, RUBY_PCIE_ATU_BASE_HI);
|
|
|
|
/* Memory mapped area in Host*/
|
|
writel(PCIE_HOSTMEM_START_LO, RUBY_PCIE_ATU_TARGET_LO);
|
|
writel(PCIE_HOSTMEM_START_HI, RUBY_PCIE_ATU_TARGET_HI);
|
|
|
|
/* Set size */
|
|
writel(PCIE_HOSTMEM_EP_START_LO + addr_mask, RUBY_PCIE_ATU_BASE_LIMIT);
|
|
|
|
/* Define region of type memory */
|
|
writel(PCIE_ATU_MEMREGION, RUBY_PCIE_ATU_CTL1);
|
|
|
|
/* Enable BAR mapped region */
|
|
writel(PCIE_HOSTMEM_REGION_ENABLE, RUBY_PCIE_ATU_CTL2);
|
|
val = readl(RUBY_PCIE_ATU_CTL2);
|
|
printf("%u:Mem: EP(0x%x->0x%x) Host(0x%x->0x%x)\n", PCIE_HOSTMEM_REGION,
|
|
PCIE_HOSTMEM_EP_START_LO,PCIE_HOSTMEM_EP_START_LO + addr_mask,
|
|
PCIE_HOSTMEM_START_LO,PCIE_HOSTMEM_START_LO + addr_mask);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* for End Point mode
|
|
* Setup 64KB region ATU for target to access host msi register
|
|
*/
|
|
static int setup_atu_msi(volatile ruby_pcie_bda_t *bda, uint32_t end_addr)
|
|
{
|
|
uint16_t flag = 0;
|
|
uint32_t msi_addr = 0x0;
|
|
uint32_t msi_addr_up = 0x0;
|
|
uint32_t val = 0x0;
|
|
uint32_t msi64;
|
|
|
|
flag = readl(PCIE_MSI_CAP) >> 16;
|
|
msi_addr = readl(PCIE_MSI_LOW_ADDR);
|
|
msi64 = (flag & MSI_64_EN);
|
|
|
|
/* Exit if MSI is not enabled */
|
|
if (!(flag & MSI_EN)) {
|
|
return 1;
|
|
}
|
|
/* If address range of of MSI data area is within primary ATU region, we can use one ATU for both */
|
|
if ((msi_addr + 2) <= end_addr)
|
|
{
|
|
/* Setup EP MSI address */
|
|
arc_write_uncached_32(&bda->bda_msi_addr,PCIE_MSI_EP_START_LO + PCIE_MSI_ADDR_OFFSET(msi_addr));
|
|
return 1;
|
|
}
|
|
/* Enable ATU viewport */
|
|
writel(PCIE_MSI_REGION, RUBY_PCIE_ATU_VIEW);
|
|
|
|
/* mapped region area in EP */
|
|
writel(PCIE_MSI_EP_START_LO, RUBY_PCIE_ATU_BASE_LO);
|
|
writel(PCIE_MSI_EP_START_HI, RUBY_PCIE_ATU_BASE_HI);
|
|
|
|
writel(PCIE_MSI_EP_END, RUBY_PCIE_ATU_BASE_LIMIT);
|
|
|
|
/* Set host side msi addr */
|
|
writel(PCIE_MSI_ADDR_ALIGN(msi_addr), RUBY_PCIE_ATU_TARGET_LO);
|
|
arc_write_uncached_32(&bda->bda_flags,PCIE_BDA_MSI| arc_read_uncached_32(&bda->bda_flags));
|
|
if (msi64) {
|
|
msi_addr_up = readl(PCIE_MSI_HIG_ADDR);
|
|
writel(msi_addr_up, RUBY_PCIE_ATU_TARGET_HI);
|
|
} else {
|
|
writel(0x00000000, RUBY_PCIE_ATU_TARGET_HI);
|
|
}
|
|
|
|
/* Setup EP MSI address */
|
|
arc_write_uncached_32(&bda->bda_msi_addr,PCIE_MSI_EP_START_LO + PCIE_MSI_ADDR_OFFSET(msi_addr));
|
|
|
|
/* Define region of type memory */
|
|
writel(PCIE_ATU_MEMREGION, RUBY_PCIE_ATU_CTL1);
|
|
|
|
/* Enable region */
|
|
writel(PCIE_MSI_REGION_ENABLE, RUBY_PCIE_ATU_CTL2);
|
|
val = readl(RUBY_PCIE_ATU_CTL2);
|
|
|
|
printf("%u:MSI%s: Host:0x%x%x EP:0x%x\n",PCIE_MSI_REGION, (msi64) ? "64" : "",
|
|
msi_addr_up, msi_addr, bda->bda_msi_addr);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* for End Point mode
|
|
*/
|
|
static void setup_atu_outbound(volatile ruby_pcie_bda_t *bda)
|
|
{
|
|
uint32_t dma_mask = 0;
|
|
uint32_t region_size_mask = (PCIE_REGION_END - PCIE_REGION_BASE);
|
|
if (setup_atu_msi(bda, region_size_mask)){
|
|
dma_mask = region_size_mask ;
|
|
} else {
|
|
dma_mask = region_size_mask - PCIE_MSIMEM_SIZE;
|
|
}
|
|
setup_atu_host(dma_mask);
|
|
arc_write_uncached_32(&bda->bda_dma_mask, dma_mask);
|
|
}
|
|
|
|
/*
|
|
* for End Point mode
|
|
*/
|
|
static void setup_atu_inbound(void)
|
|
{
|
|
setup_atu_shmem();
|
|
setup_atu_sysctl();
|
|
}
|
|
|
|
static int bootpoll(volatile ruby_pcie_bda_t *bda, uint32_t state)
|
|
{
|
|
while (arc_read_uncached_32(&bda->bda_bootstate) != state)
|
|
{
|
|
if (arc_read_uncached_32(&bda->bda_flags) & PCIE_BDA_ERROR_MASK)
|
|
return -1;
|
|
udelay(1000);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void set_bootstate(volatile ruby_pcie_bda_t *bda, uint32_t state)
|
|
{
|
|
arc_write_uncached_32(&bda->bda_bootstate, state);
|
|
}
|
|
|
|
static void booterror(volatile ruby_pcie_bda_t *bda)
|
|
{
|
|
if (PCIE_BDA_HOST_NOFW_ERR & arc_read_uncached_32(&bda->bda_flags))
|
|
printf("There is no firmware in host file system!\n");
|
|
else if (PCIE_BDA_HOST_MEMALLOC_ERR & arc_read_uncached_32(&bda->bda_flags))
|
|
printf("Host alloc memory block for firmware download failed!\n");
|
|
else if (PCIE_BDA_HOST_MEMMAP_ERR & arc_read_uncached_32(&bda->bda_flags))
|
|
printf("Host do dma map for share memory block failed!\n");
|
|
else
|
|
printf("Other error found in host side , bda flag: 0x%x!\n", bda->bda_flags);
|
|
}
|
|
|
|
#define RUN(args...) _run(__FUNCTION__, args)
|
|
static int _run(const char* function_name, ...)
|
|
{
|
|
va_list args;
|
|
char cmdbuf[64];
|
|
sprintf(cmdbuf, args);
|
|
printf("%s: %s\n", function_name, cmdbuf);
|
|
return run_command(cmdbuf, 0);
|
|
}
|
|
|
|
/*
|
|
* for End Point mode
|
|
*/
|
|
int do_flash_boot (volatile ruby_pcie_bda_t *bda)
|
|
{
|
|
unsigned long live_addr = 0;
|
|
unsigned long live_size = 0;
|
|
const unsigned long mem_addr = QTNBOOT_COPY_DRAM_ADDR;
|
|
char *live_addr_str = getenv (LIVE_IMG_ADDR_ARG);
|
|
char *live_size_str = getenv (LIVE_IMG_SIZE_ARG);
|
|
|
|
|
|
printf("do flash boot\n");
|
|
set_bootstate(bda,RUBY_BDA_FW_FLASH_BOOT);
|
|
if (live_addr_str && live_size_str) {
|
|
live_addr = simple_strtoul(live_addr_str, NULL, 0);
|
|
live_size = simple_strtoul(live_size_str, NULL, 0);
|
|
} else {
|
|
printf("Variables: %s %s must be set\n",
|
|
LIVE_IMG_ADDR_ARG,
|
|
LIVE_IMG_SIZE_ARG);
|
|
arc_write_uncached_32(&bda->bda_flags, PCIE_BDA_TARGET_FBOOT_ERR | arc_read_uncached_32(&bda->bda_flags));
|
|
return 1;
|
|
}
|
|
|
|
/* attempt to load the live image into memory and boot it. */
|
|
RUN("spi_flash read 0x%08lx 0x%08lx 0x%08lx", live_addr, mem_addr, live_size);
|
|
RUN("bootm 0x%08lx", mem_addr);
|
|
|
|
/* never gets to here */
|
|
arc_write_uncached_32(&bda->bda_flags, PCIE_BDA_TARGET_FBOOT_ERR | arc_read_uncached_32(&bda->bda_flags));
|
|
printf("flash boot error!\n");
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* for End Point mode
|
|
*/
|
|
static int do_pcieboot (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
|
|
{
|
|
int rc = 0;
|
|
volatile ruby_pcie_bda_t *bda = (ruby_pcie_bda_t *)(PCIE_BDA);
|
|
void *start = (void *)PCIE_FW_LZMA_LOAD;
|
|
void *dstaddr = start;
|
|
uint32_t size, i=0;
|
|
volatile void *srcaddr;
|
|
char *local_args[2];
|
|
char load_addr[16];
|
|
char *s;
|
|
|
|
extern int do_bootm (cmd_tbl_t *, int, int, char *[]);
|
|
|
|
/* set the flash_present flag if env indicate we have firmware in flash */
|
|
s = getenv("flash_img");
|
|
if (s && (*s == '1')) {
|
|
arc_write_uncached_32(&bda->bda_flags,PCIE_BDA_FLASH_PRESENT| arc_read_uncached_32(&bda->bda_flags));
|
|
}
|
|
/* Wait for host ready */
|
|
bootpoll(bda, RUBY_BDA_FW_HOST_RDY);
|
|
|
|
setup_atu_outbound(bda);
|
|
set_bootstate(bda,RUBY_BDA_FW_TARGET_RDY);
|
|
bootpoll(bda, RUBY_BDA_FW_TARGET_BOOT);
|
|
/* boot from flash */
|
|
if (PCIE_BDA_FLASH_BOOT & arc_read_uncached_32((void *)&bda->bda_flags)) {
|
|
do_flash_boot(bda);
|
|
return rc;
|
|
}
|
|
set_bootstate(bda,RUBY_BDA_FW_LOAD_RDY);
|
|
|
|
printf("Ready to load firmware....\n");
|
|
if (bootpoll(bda, RUBY_BDA_FW_HOST_LOAD)) {
|
|
booterror(bda);
|
|
return -1;
|
|
}
|
|
set_bootstate(bda,RUBY_BDA_FW_EP_RDY);
|
|
|
|
bootpoll(bda, RUBY_BDA_FW_BLOCK_RDY);
|
|
|
|
srcaddr = (void *)arc_read_uncached_32(&bda->bda_img);
|
|
size = arc_read_uncached_32(&bda->bda_img_size);
|
|
|
|
dcache_disable();
|
|
|
|
/* Keep loading until we see a zero sized block */
|
|
while(srcaddr && size){
|
|
printf("PCIe Load FW[%u] 0x%x->0x%x Sz:%u...\n", i++, (uint32_t)srcaddr, (uint32_t)dstaddr, size);
|
|
memcpy_fromio(dstaddr, srcaddr, size);
|
|
|
|
/* No error checking done, do_bootm() performs the CRC32 check */
|
|
|
|
/* Block done, inform host */
|
|
set_bootstate(bda, RUBY_BDA_FW_BLOCK_DONE);
|
|
|
|
/* Wait for next block */
|
|
bootpoll(bda, RUBY_BDA_FW_BLOCK_RDY);
|
|
srcaddr = (void *)arc_read_uncached_32(&bda->bda_img);
|
|
dstaddr += size;
|
|
size = arc_read_uncached_32(&bda->bda_img_size);
|
|
}
|
|
|
|
/* Invalidate i-cache */
|
|
invalidate_icache_range((int)start, (int)(dstaddr - 1));
|
|
|
|
/* Acknowledge the last zero sized block */
|
|
set_bootstate(bda, RUBY_BDA_FW_BLOCK_DONE);
|
|
|
|
/* Wait for bootload end message */
|
|
bootpoll(bda, RUBY_BDA_FW_BLOCK_END);
|
|
|
|
/* Tell host we are done */
|
|
set_bootstate(bda, RUBY_BDA_FW_LOAD_DONE);
|
|
|
|
dcache_enable();
|
|
|
|
sprintf(load_addr,"0x%08lx", (unsigned long)PCIE_FW_LZMA_LOAD);
|
|
local_args[0] = argv[0];
|
|
local_args[1] = load_addr;
|
|
|
|
printf("PCIe Loadaddr:%s\n",load_addr);
|
|
rc = do_bootm(cmdtp, 0 , 2 ,local_args);
|
|
|
|
if (rc) {
|
|
set_bootstate(bda, RUBY_BDA_FW_LOAD_FAIL);
|
|
arc_write_uncached_32(&bda->bda_flags, PCIE_BDA_TARGET_FWLOAD_ERR | arc_read_uncached_32(&bda->bda_flags));
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
static int on_off (const char *s)
|
|
{
|
|
if (strcmp(s, "on") == 0) {
|
|
return (1);
|
|
} else if (strcmp(s, "off") == 0) {
|
|
return (0);
|
|
}
|
|
return (-1);
|
|
};
|
|
|
|
static void msi_enable(void)
|
|
{
|
|
ulong var=0;
|
|
var = readl(PCIE_MSI_CAP);
|
|
writel(var|RUBY_PCIE_MSI_ENABLE, PCIE_MSI_CAP);
|
|
printf("msi enabled\n");
|
|
}
|
|
|
|
static void msi_disable(void)
|
|
{
|
|
ulong var=0;
|
|
var = readl(PCIE_MSI_CAP);
|
|
writel(var&~RUBY_PCIE_MSI_ENABLE, PCIE_MSI_CAP);
|
|
printf("msi disabled\n");
|
|
}
|
|
|
|
/*
|
|
* for End Point mode
|
|
*/
|
|
static int msi_config (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
|
|
{
|
|
switch (argc) {
|
|
case 2: /* on / off */
|
|
switch (on_off(argv[1])) {
|
|
case 1:
|
|
msi_enable();
|
|
break;
|
|
case 0:
|
|
msi_disable();
|
|
break;
|
|
default: cmd_usage(cmdtp);
|
|
return 1;
|
|
}
|
|
break;
|
|
case 1: /* default on */
|
|
msi_enable();
|
|
break;
|
|
default: cmd_usage(cmdtp);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* Exported functions - visible outside of this module
|
|
*/
|
|
|
|
/* enable or disable MSI */
|
|
U_BOOT_CMD(
|
|
msi_cfg, 2, 1, msi_config,
|
|
"enable or disable msi",
|
|
"[on, off]\n"
|
|
" - enable or disable msi with cmd msi_cfg [on, off]\n"
|
|
);
|
|
|
|
/* pcieboot */
|
|
U_BOOT_CMD(pcieboot,CONFIG_SYS_MAXARGS, 0, do_pcieboot,
|
|
"boot from pcie. Waits for host to load memory and then calls bootm",
|
|
NULL);
|
|
|
|
/*
|
|
* maybe move this later, for now we just need to remove pcie reset and set link
|
|
* flags will be used to do any back door init we might require
|
|
*/
|
|
void pcie_ep_init(size_t memsz, uint32_t flags )
|
|
{
|
|
|
|
uint32_t i = 0;
|
|
uint32_t bar64 = PCIE_CFG_BAR64;
|
|
uint32_t msi = PCIE_CFG_MSI;
|
|
volatile ruby_pcie_bda_t *bda = (ruby_pcie_bda_t *)(PCIE_BDA);
|
|
char *msi_en;
|
|
|
|
/* PCIe init */
|
|
writel(RUBY_SYS_CTL_RESET_IOSS|RUBY_SYS_CTL_RESET_PCIE,RUBY_SYS_CTL_CPU_VEC_MASK);
|
|
writel(0,RUBY_SYS_CTL_CPU_VEC);
|
|
udelay(10);
|
|
writel(RUBY_SYS_CTL_RESET_IOSS|RUBY_SYS_CTL_RESET_PCIE,RUBY_SYS_CTL_CPU_VEC);
|
|
|
|
/* Zero out boot data area */
|
|
memset((void *)bda, 0, PCIE_BDA_LEN);
|
|
arc_write_uncached_32(&bda->bda_flags, (RUBY_PCIE_BDA_VERSION << 4));
|
|
arc_write_uncached_32(&bda->bda_dma_offset, PCIE_HOSTMEM_EP_START_LO);
|
|
set_bootstate(bda, RUBY_BDA_PCIE_INIT);
|
|
|
|
/* Disable all BARs */
|
|
for (i = 0 ; i < RUBY_PCIE_BAR_NUM; i++)
|
|
{
|
|
writel(1, RUBY_PCIE_BAR_MASK(i));
|
|
writel(0x0, RUBY_PCIE_BAR_MASK(i));
|
|
}
|
|
|
|
/* Disable expansion ROM */
|
|
writel(1, PCIE_ROM_MASK_ADDR);
|
|
writel(0x0, PCIE_ROM_MASK_ADDR);
|
|
|
|
/* Setup Sysctl BAR */
|
|
writel(1, RUBY_PCIE_BAR_MASK(PCIE_BAR_SYSCTL));
|
|
writel(PCIE_BAR_SYSCTL_LEN, RUBY_PCIE_BAR_MASK(PCIE_BAR_SYSCTL));
|
|
writel(PCIE_BAR_CFG(bar64), RUBY_PCIE_BAR(PCIE_BAR_SYSCTL));
|
|
|
|
/* Setup Shared memory BAR */
|
|
writel(1, RUBY_PCIE_BAR_MASK(PCIE_BAR_SHMEM));
|
|
writel(PCIE_BAR_SHMEM_LEN, RUBY_PCIE_BAR_MASK(PCIE_BAR_SHMEM));
|
|
writel(PCIE_BAR_CFG(bar64), RUBY_PCIE_BAR(PCIE_BAR_SHMEM));
|
|
|
|
/* Check to see if MSI override has been added to uboot env */
|
|
msi_en = getenv(PCIE_MSI_ENV);
|
|
if (msi_en) {
|
|
msi = simple_strtoul(msi_en, NULL, 0);
|
|
}
|
|
|
|
/* Enable MSI */
|
|
if (msi) {
|
|
uint32_t var = readl(PCIE_MSI_CAP);
|
|
writel(var|RUBY_PCIE_MSI_ENABLE, PCIE_MSI_CAP);
|
|
}
|
|
/* Setup ATU Inbound BAR mappings*/
|
|
setup_atu_inbound();
|
|
/* Enable and wait for link up */
|
|
writel(PCIE_DEFAULT_CFG0,RUBY_SYS_CTL_PCIE_CFG0);
|
|
printf("polling for PCIe Link up\n");
|
|
while (1) {
|
|
if (readl(RUBY_SYS_CTL_CSR) & PCIE_LINKUP)
|
|
break;
|
|
udelay(10); /* Delay. */
|
|
}
|
|
set_bootstate(bda, RUBY_BDA_PCIE_RDY);
|
|
|
|
}
|
|
|
|
/*
|
|
* init for root complex mode
|
|
*/
|
|
void pcie_rc_init(void)
|
|
{
|
|
/* set as RC mode */
|
|
writel(SYS_RST_PCIE|SYS_RST_IOSS, RUBY_SYS_CTL_CPU_VEC_MASK);
|
|
writel(SYS_RST_PCIE|SYS_RST_IOSS, RUBY_SYS_CTL_CPU_VEC);
|
|
writel(PCIE_CFG0_DEFAULT_VALUE, RUBY_SYS_CTL_PCIE_CFG0); /* reset */
|
|
writel(PCIE_CFG0_DEFAULT_VALUE|PCIE_CFG_RC_MODE, RUBY_SYS_CTL_PCIE_CFG0); /* RC-mode */
|
|
|
|
/* pci config space map: Define outbound region-0 that maps PCIE slave region to PCI config space */
|
|
writel(RUBY_PCIE_ATU_OB_REGION(0), RUBY_PCIE_ATU_VIEW);
|
|
writel(RUBY_PCIE_CONFIG_REGION, RUBY_PCIE_ATU_BASE_LO);
|
|
writel(0x00000000, RUBY_PCIE_ATU_BASE_HI);
|
|
writel(RUBY_PCIE_CONFIG_REGION + (RUBY_PCI_RC_CFG_SIZE - 1), RUBY_PCIE_ATU_BASE_LIMIT );
|
|
writel(0x00000000, RUBY_PCIE_ATU_TARGET_LO);
|
|
writel(0, RUBY_PCIE_ATU_TARGET_HI);
|
|
writel(4, RUBY_PCIE_ATU_CTL1);
|
|
writel(RUBY_PCIE_ATU_OB_ENABLE|RUBY_PCIE_ATU_CFG_SHIFT, RUBY_PCIE_ATU_CTL2);
|
|
|
|
/* pci memory space map: Define outbound region-1 that maps PCIE slave region to PCI mem space */
|
|
writel(RUBY_PCIE_ATU_OB_REGION(1), RUBY_PCIE_ATU_VIEW);
|
|
writel(RUBY_PCI_RC_MEM_START, RUBY_PCIE_ATU_BASE_LO);
|
|
writel(0x00000000, RUBY_PCIE_ATU_BASE_HI);
|
|
writel(RUBY_PCI_RC_MEM_START + (RUBY_PCI_RC_MEM_WINDOW - 1), RUBY_PCIE_ATU_BASE_LIMIT );
|
|
writel(0xc0000000, RUBY_PCIE_ATU_TARGET_LO);
|
|
writel(0, RUBY_PCIE_ATU_TARGET_HI);
|
|
writel(0, RUBY_PCIE_ATU_CTL1);
|
|
writel(RUBY_PCIE_ATU_OB_ENABLE, RUBY_PCIE_ATU_CTL2);
|
|
|
|
/* pci access enable */
|
|
//writel(RUBY_PCI_RC_MEM_START, RUBY_PCIE_BAR(0));
|
|
writel(PCIE_MEM_EN | PCIE_IO_EN | PCIE_BUS_MASTER_EN, RUBY_PCIE_CMD_REG);
|
|
|
|
/* Set up msi generation info */
|
|
writel(RUBY_PCIE_MSI_REGION, RUBY_MSI_ADDR_LOWER);
|
|
writel(0, RUBY_MSI_ADDR_UPPER);
|
|
writel(BIT(0), RUBY_MSI_INT_ENABLE);
|
|
writel(0, RUBY_PCIE_MSI_MASK);
|
|
}
|
|
|
|
void board_pcie_init(size_t memsz, uint32_t flags )
|
|
{
|
|
if (flags & PCIE_RC_MODE) {
|
|
printf("init board as PCIe Root Complex mode\n");
|
|
pcie_rc_init();
|
|
} else {
|
|
printf("init board as PCIe End Point mode\n");
|
|
pcie_ep_init(memsz, 0);
|
|
}
|
|
}
|
|
|