blob: df6d3c0283f4067b9f466f637d378d5411604c1c [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 1 = 8 Mbyte register space
bar 2 = 16 Mbyte DDR space
bar 3 = 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 according BCM53003 BSP */
#define PCIE1_IV_0 86
#define PCIE1_IV_1 87
#define PCIE1_INT_LINE 4
/* 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 */
static maple_device_info devices[MAPLE_MAX_DEVICES];
int crt_device = 0;
/* Device PCIE interface status change callback */
static bcm_ll_pcie_status_change callback;
/** Device status change ISR
* \irq IRQ number
* \dev_instance device object
*/
int dev_status_interrupt (int irq, void *dev_instance)
{
bcmos_errno err = BCM_ERR_OK;
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 (callback)
{
callback(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;
bcmos_errno err = BCM_ERR_OK;
uint8_t irq = 0;
uint16_t device_id;
printf("%s()\r\n", __FUNCTION__);
// check maple device number
if (crt_device == MAPLE_MAX_DEVICES)
{
printf(" Maximum Maple devices already defined (%d)\n", MAPLE_MAX_DEVICES);
return BCM_ERR_ALREADY;
}
// Init device object struct
dev_info = &devices[crt_device++];
memset(dev_info, 0, sizeof(maple_device_info));
// find maple 6862 device
ret_status = pciFindDevice(PCIE_MAPLE_VENDOR_ID,
PCIE_MAPLE_DEVICE_ID,
0,
&dev_info->pciBusNo,
&dev_info->pciDevNo,
&dev_info->pciFuncNo);
if (OK == ret_status)
{
device_id = PCIE_MAPLE_DEVICE_ID;
goto found_device_id;
}
// find maple 6863 device
ret_status = pciFindDevice(PCIE_MAPLE_VENDOR_ID,
PCIE_MAPLE_6863_SKU_DEVICE_ID,
0,
&dev_info->pciBusNo,
&dev_info->pciDevNo,
&dev_info->pciFuncNo);
if (OK == ret_status)
{
device_id = PCIE_MAPLE_6863_SKU_DEVICE_ID;
goto found_device_id;
}
// find maple epon device
ret_status = pciFindDevice(PCIE_MAPLE_VENDOR_ID,
PCIE_MAPLE_EPON_DEVICE_ID,
0,
&dev_info->pciBusNo,
&dev_info->pciDevNo,
&dev_info->pciFuncNo);
if (OK == ret_status)
{
device_id = PCIE_MAPLE_EPON_DEVICE_ID;
goto found_device_id;
}
printf("Can't find any device[%d]\n", PCIE_MAPLE_VENDOR_ID);
return BCM_ERR_NODEV;
found_device_id:
printf("Found maple device[%x - %x]\n", PCIE_MAPLE_VENDOR_ID, device_id);
// init
dev_info->deviceid = (crt_device - 1);
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
dev_info->device.soc_regs_base = 0xe0000000;
dev_info->device.soc_sram_base = 0xe2000000;
dev_info->device.soc_ddr_base = 0xe1000000;
dev_info->device.soc_ddr_length = 0x1000000; // 16M
// init interrupt line
readvalb = PCIE1_INT_LINE;
pciConfigOutByte(dev_info->pciBusNo,
dev_info->pciDevNo,
dev_info->pciFuncNo,
PCI_CFG_DEV_INT_LINE,
(UINT8)readvalb);
pciConfigInByte(dev_info->pciBusNo,
dev_info->pciDevNo,
dev_info->pciFuncNo,
PCI_CFG_DEV_INT_LINE,
(UINT8 *)&readvalb);
printf("Adjusted INT Line reg = 0x%x\n", readvalb);
// init interrupt
dev_info->device.irq = PCIE1_IV_0;
dev_info->dev_status_irq = PCIE1_IV_1;
// 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 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 */
if (MAPLE_MAX_DEVICES <= crt)
{
return NULL;
}
device_info = &devices[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;
callback = cb;
for (i = 0; i < crt_device; i++)
{
dev_info = get_maple_pci_info(i);
callback(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)
{
callback = 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;
if (NULL == info)
{
return BCM_ERR_PARM;
}
if (dev_id < crt_device)
{
dev_info = get_maple_pci_info(dev_id);
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;
if (dev_id < MAPLE_MAX_DEVICES)
{
dev_info = get_maple_pci_info(dev_id);
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;
val = enabled ? 0 : 1;
bcm_pci_write32((uint32_t *)(devices[dev_id].device.soc_regs_base + PCIE_HARD_DEBUG_REGISTER_OFFSET) , val);
return BCM_ERR_OK;
}