// SPDX-License-Identifier: GPL-2.0
/*
* PCIe host controller driver for Texas Instruments Keystone SoCs
*
* Copyright (C) 2013-2014 Texas Instruments., Ltd.
* http://www.ti.com
*
* Author: Murali Karicheri <m-karicheri2@ti.com>
* Implementation based on pci-exynos.c and pcie-designware.c
*/
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/irqchip/chained_irq.h>
#include <linux/irqdomain.h>
#include <linux/mfd/syscon.h>
#include <linux/msi.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/of_pci.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/resource.h>
#include <linux/signal.h>
#include "pcie-designware.h"
#define PCIE_VENDORID_MASK 0xffff
#define PCIE_DEVICEID_SHIFT 16
/* Application registers */
#define CMD_STATUS 0x004
#define LTSSM_EN_VAL BIT(0)
#define OB_XLAT_EN_VAL BIT(1)
#define DBI_CS2 BIT(5)
#define CFG_SETUP 0x008
#define CFG_BUS(x) (((x) & 0xff) << 16)
#define CFG_DEVICE(x) (((x) & 0x1f) << 8)
#define CFG_FUNC(x) ((x) & 0x7)
#define CFG_TYPE1 BIT(24)
#define OB_SIZE 0x030
#define SPACE0_REMOTE_CFG_OFFSET 0x1000
#define OB_OFFSET_INDEX(n) (0x200 + (8 * (n)))
#define OB_OFFSET_HI(n) (0x204 + (8 * (n)))
#define OB_ENABLEN BIT(0)
#define OB_WIN_SIZE 8 /* 8MB */
/* IRQ register defines */
#define IRQ_EOI 0x050
#define MSI_IRQ 0x054
#define MSI_IRQ_STATUS(n) (0x104 + ((n) << 4))
#define MSI_IRQ_ENABLE_SET(n) (0x108 + ((n) << 4))
#define MSI_IRQ_ENABLE_CLR(n) (0x10c + ((n) << 4))
#define MSI_IRQ_OFFSET 4
#define IRQ_STATUS(n) (0x184 + ((n) << 4))
#define IRQ_ENABLE_SET(n) (0x188 + ((n) << 4))
#define INTx_EN BIT(0)
#define ERR_IRQ_STATUS 0x1c4
#define ERR_IRQ_ENABLE_SET 0x1c8
#define ERR_AER BIT(5) /* ECRC error */
#define ERR_AXI BIT(4) /* AXI tag lookup fatal error */
#define ERR_CORR BIT(3) /* Correctable error */
#define ERR_NONFATAL BIT(2) /* Non-fatal error */
#define ERR_FATAL BIT(1) /* Fatal error */
#define ERR_SYS BIT(0) /* System error */
#define ERR_IRQ_ALL (ERR_AER | ERR_AXI | ERR_CORR | \
ERR_NONFATAL | ERR_FATAL | ERR_SYS)
/* PCIE controller device IDs */
#define PCIE_RC_K2HK 0xb008
#define PCIE_RC_K2E 0xb009
#define PCIE_RC_K2L 0xb00a
#define PCIE_RC_K2G 0xb00b
#define to_keystone_pcie(x) dev_get_drvdata((x)->dev)
struct keystone_pcie {
struct dw_pcie *pci;
/* PCI Device ID */
u32 device_id;
int legacy_host_irqs[PCI_NUM_INTX];
struct device_node *legacy_intc_np;
int msi_host_irq;
int num_lanes;
u32 num_viewport;
struct phy **phy;
struct device_link **link;
struct device_node *msi_intc_np;
struct irq_domain *legacy_irq_domain;
struct device_node *np;
int error_irq;
/* Application register space */
void __iomem *va_app_base; /* DT 1st resource */
struct resource app;
};
static u32 ks_pcie_app_readl(struct keystone_pcie *ks_pcie, u32 offset)
{
return readl(ks_pcie->va_app_base + offset);
}
static void ks_pcie_app_writel(struct keystone_pcie *ks_pcie, u32 offset,
u32 val)
{
writel(val, ks_pcie->va_app_base + offset);
}
static void ks_pcie_msi_irq_ack(struct irq_data *data)
{
struct pcie_port *pp = irq_data_get_irq_chip_data(data);
struct keystone_pcie *ks_pcie;
u32 irq = data->hwirq;
struct dw_pcie *pci;
u32 reg_offset;
u32 bit_pos;
pci = to_dw_pcie_from_pp(pp);
ks_pcie = to_keystone_pcie(pci);
reg_offset = irq % 8;
bit_pos = irq >> 3;
ks_pcie_app_writel(ks_pcie, MSI_IRQ_STATUS(reg_offset),
BIT(bit_pos));
ks_pcie_app_writel(ks_pcie, IRQ_EOI, reg_offset + MSI_IRQ_OFFSET);
}
static void ks_pcie_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
{
struct pcie_port *pp = irq_data_get_irq_chip_data(data);
struct keystone_pcie *ks_pcie;
struct dw_pcie *pci;
u64 msi_target;
pci = to_dw_pcie_from_pp(pp);
ks_pcie = to_keystone_pcie(pci);
msi_target = ks_pcie->app.start + MSI_IRQ;
msg->address_lo = lower_32_bits(msi_target);
msg->address_hi = upper_32_bits(msi_target);
msg->data = data->hwirq;
dev_dbg(pci->dev, "msi#%d address_hi %#x address_lo %#x\n",
(int)data->hwirq, msg->address_hi, msg->address_lo);
}
static int ks_pcie_msi_set_affinity(struct irq_data *irq_data,
const struct cpumask *mask, bool force)
{
return -EINVAL;
}
static void ks_pcie_msi_mask(struct irq_data *data)
{
struct pcie_port *pp = irq_data_get_irq_chip_data(data);
struct keystone_pcie *ks_pcie;
u32 irq = data->hwirq;
struct dw_pcie *pci;
unsigned long flags;
u32 reg_offset;
u32 bit_pos;
raw_spin_lock_irqsave(&pp->lock, flags);
pci = to_dw_pcie_from_pp(pp);
ks_pcie = to_keystone_pcie(pci);
reg_offset = irq % 8;
bit_pos = irq >> 3;
ks_pcie_app_writel(ks_pcie, MSI_IRQ_ENABLE_CLR(reg_offset),
BIT(bit_pos));
raw_spin_unlock_irqrestore(&pp->lock, flags);
}
static void ks_pcie_msi_unmask(struct irq_data *data)
{
struct pcie_port *pp = irq_data_get_irq_chip_data(data);
struct keystone_pcie *ks_pcie;
u32 irq = data->hwirq;
struct dw_pcie *pci;
unsigned long flags;
u32 reg_offset;
u32 bit_pos;
raw_spin_lock_irqsave(&pp->lock, flags);
pci = to_dw_pcie_from_pp