/*
* Copyright (C) 2014 Hauke Mehrtens <hauke@hauke-m.de>
* Copyright (C) 2015 Broadcom Corporation
*
* 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 version 2.
*
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
* kind, whether express or implied; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/msi.h>
#include <linux/clk.h>
#include <linux/module.h>
#include <linux/mbus.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/irqchip/arm-gic-v3.h>
#include <linux/platform_device.h>
#include <linux/of_address.h>
#include <linux/of_pci.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/phy/phy.h>
#include "pcie-iproc.h"
#define EP_PERST_SOURCE_SELECT_SHIFT 2
#define EP_PERST_SOURCE_SELECT BIT(EP_PERST_SOURCE_SELECT_SHIFT)
#define EP_MODE_SURVIVE_PERST_SHIFT 1
#define EP_MODE_SURVIVE_PERST BIT(EP_MODE_SURVIVE_PERST_SHIFT)
#define RC_PCIE_RST_OUTPUT_SHIFT 0
#define RC_PCIE_RST_OUTPUT BIT(RC_PCIE_RST_OUTPUT_SHIFT)
#define PAXC_RESET_MASK 0x7f
#define GIC_V3_CFG_SHIFT 0
#define GIC_V3_CFG BIT(GIC_V3_CFG_SHIFT)
#define MSI_ENABLE_CFG_SHIFT 0
#define MSI_ENABLE_CFG BIT(MSI_ENABLE_CFG_SHIFT)
#define CFG_IND_ADDR_MASK 0x00001ffc
#define CFG_ADDR_BUS_NUM_SHIFT 20
#define CFG_ADDR_BUS_NUM_MASK 0x0ff00000
#define CFG_ADDR_DEV_NUM_SHIFT 15
#define CFG_ADDR_DEV_NUM_MASK 0x000f8000
#define CFG_ADDR_FUNC_NUM_SHIFT 12
#define CFG_ADDR_FUNC_NUM_MASK 0x00007000
#define CFG_ADDR_REG_NUM_SHIFT 2
#define CFG_ADDR_REG_NUM_MASK 0x00000ffc
#define CFG_ADDR_CFG_TYPE_SHIFT 0
#define CFG_ADDR_CFG_TYPE_MASK 0x00000003
#define SYS_RC_INTX_MASK 0xf
#define PCIE_PHYLINKUP_SHIFT 3
#define PCIE_PHYLINKUP BIT(PCIE_PHYLINKUP_SHIFT)
#define PCIE_DL_ACTIVE_SHIFT 2
#define PCIE_DL_ACTIVE BIT(PCIE_DL_ACTIVE_SHIFT)
#define APB_ERR_EN_SHIFT 0
#define APB_ERR_EN BIT(APB_ERR_EN_SHIFT)
/* derive the enum index of the outbound/inbound mapping registers */
#define MAP_REG(base_reg, index) ((base_reg) + (index) * 2)
/*
* Maximum number of outbound mapping window sizes that can be supported by any
* OARR/OMAP mapping pair
*/
#define MAX_NUM_OB_WINDOW_SIZES 4
#define OARR_VALID_SHIFT 0
#define OARR_VALID BIT(OARR_VALID_SHIFT)
#define OARR_SIZE_CFG_SHIFT 1
/*
* Maximum number of inbound mapping region sizes that can be supported by an
* IARR
*/
#define MAX_NUM_IB_REGION_SIZES 9
#define IMAP_VALID_SHIFT 0
#define IMAP_VALID BIT(IMAP_VALID_SHIFT)
#define PCI_EXP_CAP 0xac
#define IPROC_PCIE_REG_INVALID 0xffff
/**
* iProc PCIe outbound mapping controller specific parameters
*
* @window_sizes: list of supported outbound mapping window sizes in MB
* @nr_sizes: number of supported outbound mapping window sizes
*/
struct iproc_pcie_ob_map {
resource_size_t window_sizes[MAX_NUM_OB_WINDOW_SIZES];
unsigned int nr_sizes;
};
static const struct iproc_pcie_ob_map paxb_ob_map[] = {
{
/* OARR0/OMAP0 */
.window_sizes = { 128, 256 },
.nr_sizes = 2,
},
{
/* OARR1/OMAP1 */
.window_sizes = { 128, 256 },
.nr_sizes = 2,
},
};
static const struct iproc_pcie_ob_map paxb_v2_ob_map[] = {
{
/* OARR0/OMAP0 */
.window_sizes = { 128, 256 },
.nr_sizes = 2,
},
{
/* OARR1/OMAP1 */
.window_sizes = { 128, 256 },
.nr_sizes = 2,
},
{
/* OARR2/OMAP2 */
.window_sizes = { 128, 256, 512, 1024 },
.nr_sizes = 4,
},
{
/* OARR3/OMAP3 */
.window_sizes = { 128, 256, 512, 1024 },
.nr_sizes = 4,
},
};
/**
* iProc PCIe inbound mapping type
*/
enum iproc_pcie_ib_map_type {
/* for DDR memory */
IPROC_PCIE_IB_MAP_MEM = 0,
/* for device I/O memory */
IPROC_PCIE_IB_MAP_IO,
/* invalid or unused */
IPROC_PCIE_IB_MAP_INVALID
};
/**
* iProc PCI