blob: 1de747501dc0e8a0534ab55b79601fcde6552a62 [file] [log] [blame]
/*
<:copyright-BRCM:2016:DUAL/GPL:standard
Broadcom Proprietary and Confidential.(c) 2016 Broadcom
All Rights Reserved
Unless you and Broadcom execute a separate written software license
agreement governing use of this software, this software is licensed
to you under the terms of the GNU General Public License version 2
(the "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php,
with the following added to such license:
As a special exception, the copyright holders of this software give
you permission to link this software with independent modules, and
to copy and distribute the resulting executable under terms of your
choice, provided that you also meet, for each linked independent
module, the terms and conditions of the license of that module.
An independent module is a module which is not derived from this
software. The special exception does not apply to any modifications
of the software.
Not withstanding the above, under no circumstances may you combine
this software in any way with any other Broadcom software provided
under a license other than the GPL, without Broadcom's express prior
written consent.
:>
*/
#include <vxWorks.h>
#include <drv/pci/pciConfigLib.h>
#include "bcmolt_llpcie.h"
/* Define PCIE device BAR registers */
#define BAR_REGS 0
#define BAR_DDR 2
#define BAR_SRAM 4
/*
Define PCIE device BAR space length:
bar 0 = 8 Mbyte register space
bar 2 = 16 Mbyte DDR space
bar 4 = 64 Kbyte SRAM space
*/
#define MAPLE_REGS_LENGTH 0x00800000
#define MAPLE_DDR_LENGTH 0x01000000
#define MAPLE_SRAM_LENGTH 0x00010000
/* Define special registers address */
#ifdef TX_ENABLE_EVENT_TRACE
#define PCIE_PCIE_0_MISC_CPU_2_PCIE_MEM_WIN1_LO 0x064014U
#define PCIE_PCIE_0_MISC_CPU_2_PCIE_MEM_WIN1_HI 0x064018U
#define PCIE_PCIE_0_MISC_CPU_2_PCIE_MEM_WIN1_BASE_LIMIT 0x064074U
#endif
#define PCIE_REVISION_REGISTER_OFFSET 0x6406C /* PCIE_PCIE_PCIE_0_PCIE_PCIE_0_MISC_REVISION */
#define PCIE_STATUS_REGISTER_OFFSET 0x64068 /* PCIE_PCIE_PCIE_0_PCIE_PCIE_0_MISC_PCIE_STATUS */
#define PCIE_HARD_DEBUG_REGISTER_OFFSET 0x64204U /* PCIE_PCIE_PCIE_0_PCIE_PCIE_0_MISC_HARD_DEBUG */
#define PCIE_INT_STATUS_REGISTER_OFFSET 0x69400 /* PCIE_PCIE_PCIE_0_CPU_INTR1_INTR_STATUS */
#define PCIE_INT_CLEAR_MASK_OFFSET 0x6940C /* PCIE_PCIE_PCIE_0_CPU_INTR1_INTR_MASK_CLEAR */
#define PCIE_INTR1_STATUS_REGISTER_OFFSET 0x69300 /* Interrupt Status Register */
/* Maple device ID */
#define PCIE_MAPLE_VENDOR_ID 0x14E4 /* PCIE_CFG_TYPE0_EP_SUBSYSTEM_ID_VENDOR_ID */
#define PCIE_MAPLE_DEVICE_ID 0x6862
#define PCIE_MAPLE_6863_SKU_DEVICE_ID 0x6863
#define PCIE_MAPLE_EPON_DEVICE_ID 0x5554
/* Define interrupt vector number for MPC8308 */
#define DRV_PCIE_INT_IRQ_BASE 96
#define PCIE_DEV0_IV_0 (DRV_PCIE_INT_IRQ_BASE + 24)
#define PCIE_DEV0_IV_1 (DRV_PCIE_INT_IRQ_BASE + 25)
#define PCIE_DEV1_IV_0 (DRV_PCIE_INT_IRQ_BASE + 0)
#define PCIE_DEV1_IV_1 (DRV_PCIE_INT_IRQ_BASE + 1)
/* Maple device object struct */
typedef struct
{
uint32_t llpcie_irq;
uint32_t llpcie_status_irq;
} maple_llpcie_device_irqs;
maple_llpcie_device_irqs llpcie_device_irqs[BCMOLT_MAX_MAPLE_DEVICES] =
{
{PCIE_DEV0_IV_0,PCIE_DEV0_IV_1},
{PCIE_DEV1_IV_0,PCIE_DEV1_IV_1}
};
#ifdef LLPCIE_SET_BASE_ADDRESSES_MANUALLY
typedef struct
{
unsigned long soc_regs_base; /**< Device registers base in host address space */
unsigned long soc_sram_base; /**< Device SRAM base in host address space */
unsigned long soc_ddr_base; /**< Device DDR base in host address space */
} maple_llpcie_base_addresses;
maple_llpcie_base_addresses llpcie_base_addresses[BCMOLT_MAX_MAPLE_DEVICES] =
{
{.soc_regs_base = 0xe0000000, .soc_sram_base = 0xe2000000, .soc_ddr_base = 0xe1000000},
/* in this example there is only one device*/
{.soc_regs_base = 0x00000000, .soc_sram_base = 0x00000000, .soc_ddr_base = 0x00000000}
};
#endif
/* Maple device object struct */
typedef struct
{
bcm_ll_dev_info device;
bcmos_fastlock lock;
int err_status;
int phylink;
int prev_datalink;
int datalink;
uint32_t deviceid; // start from 0
unsigned int *traceaddr;
void *pdev;
int pciBusNo; /* PCI bus number */
int pciDevNo; /* PCI device number */
int pciFuncNo; /* PCI function number */
uint32_t dev_status_irq;
} maple_device_info;
/* Maple device objects */
maple_device_info g_maple_devs_info[BCMOLT_MAX_MAPLE_DEVICES];
int g_maple_dev_num = 0;
/* Device PCIE interface status change callback */
bcm_ll_pcie_status_change g_dev_status_change_cb;
/** Device status change ISR
* \irq IRQ number
* \dev_instance device object
*/
int dev_status_interrupt (int irq, void *dev_instance)
{
uint32_t reg_value = 0;
maple_device_info *device_info = NULL;
long flags = 0;
int handled = 0;
uint32_t dev_id = 0;
device_info = (maple_device_info *)dev_instance;
dev_id = device_info->deviceid;
flags = bcmos_fastlock_lock(&device_info->lock);
reg_value = bcm_pci_read32((uint32_t *)(device_info->device.soc_regs_base + PCIE_INT_STATUS_REGISTER_OFFSET));
{
if (device_info->datalink != device_info->prev_datalink)
{
if (device_info->datalink == BCM_LL_PCIE_LINK_UP)
printf("Device=%d : Link is up !!!\n", dev_id);
else
{
printf("Device=%d : Link is down !!!\n", dev_id);
printf("phy status = 0x%x error status = 0x%x\n", device_info->phylink, device_info->err_status);
}
device_info->prev_datalink = device_info->datalink;
if (g_dev_status_change_cb)
{
g_dev_status_change_cb(dev_id, device_info->datalink);
}
}
reg_value = bcm_pci_read32(
(uint32_t *)(device_info->device.soc_regs_base + PCIE_INTR1_STATUS_REGISTER_OFFSET));
{
handled = 1;
}
}
bcmos_fastlock_unlock(&device_info->lock, flags);
return handled;
}
/** Maple device detection and initialization
*/
bcmos_errno bcm_ll_pcie_interface_init()
{
STATUS ret_status;
maple_device_info *dev_info = NULL;
uint32_t readval = 0;
uint8_t readvalb = 0;
uint32_t pci_dev_idx = 0;
printf("%s()\r\n", __FUNCTION__);
// check maple device number
if (g_maple_dev_num >= BCMOLT_MAX_MAPLE_DEVICES)
{
printf("Maximum Maple devices already defined (%d)\n", BCMOLT_MAX_MAPLE_DEVICES);
return BCM_ERR_ALREADY;
}
// Support multiple Maple devices
for (pci_dev_idx = 0; pci_dev_idx < BCMOLT_MAX_MAPLE_DEVICES; pci_dev_idx++)
{
uint16_t device_id;
// Init device object struct
dev_info = &g_maple_devs_info[pci_dev_idx];
memset(dev_info, 0, sizeof(maple_device_info));
// Try to find maple device
ret_status = pciFindDevice(PCIE_MAPLE_VENDOR_ID,
PCIE_MAPLE_DEVICE_ID,
pci_dev_idx,
&dev_info->pciBusNo,
&dev_info->pciDevNo,
&dev_info->pciFuncNo);
if (ret_status == OK)
{
device_id = PCIE_MAPLE_DEVICE_ID;
goto found_device_id;
}
ret_status = pciFindDevice(PCIE_MAPLE_VENDOR_ID,
PCIE_MAPLE_6863_SKU_DEVICE_ID,
pci_dev_idx,
&dev_info->pciBusNo,
&dev_info->pciDevNo,
&dev_info->pciFuncNo);
if (ret_status == OK)
{
device_id = PCIE_MAPLE_6863_SKU_DEVICE_ID;
goto found_device_id;
}
ret_status = pciFindDevice(PCIE_MAPLE_VENDOR_ID,
PCIE_MAPLE_EPON_DEVICE_ID,
pci_dev_idx,
&dev_info->pciBusNo,
&dev_info->pciDevNo,
&dev_info->pciFuncNo);
if (ret_status == OK)
{
device_id = PCIE_MAPLE_EPON_DEVICE_ID;
goto found_device_id;
}
printf("No more devices, Found %d maple device(s)\n", g_maple_dev_num);
break;
found_device_id:
// Found new Maple device
printf("Found maple device[%x - %x][%d] @ Bus %d, Dev %d, Func %d\n",
PCIE_MAPLE_VENDOR_ID, PCIE_MAPLE_DEVICE_ID, pci_dev_idx,
dev_info->pciBusNo, dev_info->pciDevNo, dev_info->pciFuncNo);
g_maple_dev_num += 1;
// init
dev_info->deviceid = pci_dev_idx;
dev_info->pdev = NULL;
// Enable PCI address map
pciConfigInByte(dev_info->pciBusNo,
dev_info->pciDevNo,
dev_info->pciFuncNo,
PCI_CFG_COMMAND,
(UINT8 *)&readvalb);
printf("CMD reg = 0x%x\n", readvalb);
readvalb |= 0x6;
pciConfigOutByte(dev_info->pciBusNo,
dev_info->pciDevNo,
dev_info->pciFuncNo,
PCI_CFG_COMMAND,
(UINT8)readvalb);
pciConfigInByte(dev_info->pciBusNo,
dev_info->pciDevNo,
dev_info->pciFuncNo,
PCI_CFG_COMMAND,
(UINT8 *)&readvalb);
printf("Adjusted CMD reg = 0x%x\n", readvalb);
// Init base addresses
#ifdef LLPCIE_SET_BASE_ADDRESSES_MANUALLY
dev_info->device.soc_regs_base = llpcie_base_addresses.soc_regs_base;
dev_info->device.soc_sram_base = llpcie_base_addresses.soc_sram_base;
dev_info->device.soc_ddr_base = llpcie_base_addresses.soc_ddr_base;
dev_info->device.soc_ddr_length = MAPLE_DDR_LENGTH; // 16M */
#else
pciConfigInLong(dev_info->pciBusNo,
dev_info->pciDevNo,
dev_info->pciFuncNo,
PCI_CFG_BASE_ADDRESS_0,
(UINT32 *)&readval);
printf("BAR0 = 0x%x\n", readval);
dev_info->device.soc_regs_base = (readval & PCI_MEMBASE_MASK);
pciConfigInLong(dev_info->pciBusNo,
dev_info->pciDevNo,
dev_info->pciFuncNo,
PCI_CFG_BASE_ADDRESS_2,
(UINT32 *)&readval);
printf("BAR2 = 0x%x\n", readval);
dev_info->device.soc_ddr_base = (readval & PCI_MEMBASE_MASK);
dev_info->device.soc_ddr_length = MAPLE_DDR_LENGTH; // 16M
pciConfigInLong(dev_info->pciBusNo,
dev_info->pciDevNo,
dev_info->pciFuncNo,
PCI_CFG_BASE_ADDRESS_4,
(UINT32 *)&readval);
printf("BAR4 = 0x%x\n", readval);
dev_info->device.soc_sram_base = (readval & PCI_MEMBASE_MASK);
#endif
printf("Regs Base = 0x%lx, DDR Base = 0x%lx, DDR Length = 0x%x, SRAM Base = 0x%lx\n",
dev_info->device.soc_regs_base,
dev_info->device.soc_ddr_base,
dev_info->device.soc_ddr_length,
dev_info->device.soc_sram_base);
// init interrupt
dev_info->device.irq = llpcie_device_irqs[pci_dev_idx].llpcie_irq;
dev_info->dev_status_irq = llpcie_device_irqs[pci_dev_idx].llpcie_status_irq;
printf("DMA IRQ = %d, Device status IRQ = %d\n",
dev_info->device.irq, dev_info->dev_status_irq);
// read revision register
readval = bcm_pci_read32((uint32_t *)(dev_info->device.soc_regs_base + PCIE_REVISION_REGISTER_OFFSET));
printf("readval = 0x%x\n", readval);
printf("Card %d version major=%02x minor=%02x\n",
dev_info->deviceid,
((readval & 0x0000ff00) >> 8),
(readval & 0x000000ff));
// read status register
readval = bcm_pci_read32((uint32_t *)(dev_info->device.soc_regs_base + PCIE_STATUS_REGISTER_OFFSET));
printf("readval = 0x%x\n", readval);
dev_info->err_status = (readval & 0x0000000f);
dev_info->phylink = ((readval >> 4) & 0x1);
dev_info->datalink = ((readval >> 5) & 0x1);
dev_info->prev_datalink = dev_info->datalink;
// connect INT for device status
bcmos_fastlock_init(&dev_info->lock, 0);
bcmos_int_connect((int)dev_info->dev_status_irq,
0,
BCMOS_IRQ_SHARED,
dev_status_interrupt,
"status_isr",
dev_info);
}
// Return status
if (0 >=g_maple_dev_num)
{
return BCM_ERR_NODEV;
}
else
{
return BCM_ERR_OK;
}
}
/** Get Maple device object struct
* \crt devie index,start from 0
*/
static maple_device_info *get_maple_pci_info(int crt)
{
bcmos_errno err = BCM_ERR_OK;
uint32_t readval = 0;
maple_device_info *device_info = NULL;
/* check input parameter */
/* don't access invalid device regs base address */
if (crt >= g_maple_dev_num)
{
return NULL;
}
device_info = &g_maple_devs_info[crt];
/* read status register */
readval = bcm_pci_read32((uint32_t *)(device_info->device.soc_regs_base + PCIE_STATUS_REGISTER_OFFSET));
device_info->err_status = (readval & 0x0000000f);
device_info->phylink = ((readval >> 4) & 0x1);
device_info->datalink = ((readval >> 5) & 0x1);
/* return device */
return device_info;
}
/** Register status change notification callback
* \param[in] cb Status change notification callback
* \return 0=OK or error <0
*/
bcmos_errno bcm_ll_pcie_status_change_register(bcm_ll_pcie_status_change cb)
{
int i;
maple_device_info *dev_info;
g_dev_status_change_cb = cb;
for (i = 0; i < g_maple_dev_num; i++)
{
dev_info = get_maple_pci_info(i);
g_dev_status_change_cb(i, dev_info->datalink);
}
return BCM_ERR_OK;
}
/** Unregister status change notification callback
* \return 0=OK or error <0
*/
bcmos_errno bcm_ll_pcie_status_change_unregister(void)
{
g_dev_status_change_cb = NULL;
return BCM_ERR_OK;
}
/** Query PCIe device
* \param[in] dev_id Device id
* \param[out] info Device info
* \return 0=OK, BCM_ERR_IO-dev_id is in proper range, but link is down
*/
bcmos_errno bcm_ll_pcie_query(uint8_t dev_id, bcm_ll_dev_info *info)
{
maple_device_info *dev_info = NULL;
/* check input parameter */
if (NULL == info)
{
return BCM_ERR_PARM;
}
/* don't access invalid device regs base address */
if (dev_id < g_maple_dev_num)
{
dev_info = get_maple_pci_info(dev_id);
if (NULL == dev_info)
{
return BCM_ERR_NOENT;
}
if (dev_info->datalink == BCM_LL_PCIE_LINK_DOWN)
{
return BCM_ERR_IO;
}
*info = dev_info->device;
return BCM_ERR_OK;
}
return BCM_ERR_RANGE;
}
/** Get low-level device handle
* \param[in] dev_id Device id
* \param[out] lldev Low-level device handle
* \return device handle or NULL if link is down
*/
bcm_ll_pcie_dev bcm_ll_pcie_dev_get(uint8_t dev_id)
{
maple_device_info *dev_info = NULL;
/* check input parameter */
/* don't access invalid device regs base address */
if (dev_id < g_maple_dev_num)
{
dev_info = get_maple_pci_info(dev_id);
if (NULL == dev_info)
{
return NULL;
}
else
{
return dev_info->pdev;
}
}
return NULL;
}
/** Host reset enable
* \enabled
*/
bcmos_errno bcm_ll_pcie_host_reset_enable(uint8_t dev_id, bcmos_bool enabled)
{
uint32_t val;
/* check input parameter */
/* don't access invalid device regs base address */
if (dev_id >= g_maple_dev_num)
{
return BCM_ERR_OVERFLOW;
}
val = enabled ? 0 : 1;
bcm_pci_write32((uint32_t *)(g_maple_devs_info[dev_id].device.soc_regs_base + PCIE_HARD_DEBUG_REGISTER_OFFSET),
val);
return BCM_ERR_OK;
}