// SPDX-License-Identifier: GPL-2.0
/*
* MediaTek PCIe host controller driver.
*
* Copyright (c) 2017 MediaTek Inc.
* Author: Ryder Lee <ryder.lee@mediatek.com>
* Honghui Zhang <honghui.zhang@mediatek.com>
*/
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/iopoll.h>
#include <linux/irq.h>
#include <linux/irqchip/chained_irq.h>
#include <linux/irqdomain.h>
#include <linux/kernel.h>
#include <linux/msi.h>
#include <linux/of_address.h>
#include <linux/of_pci.h>
#include <linux/of_platform.h>
#include <linux/pci.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
#include "../pci.h"
/* PCIe shared registers */
#define PCIE_SYS_CFG 0x00
#define PCIE_INT_ENABLE 0x0c
#define PCIE_CFG_ADDR 0x20
#define PCIE_CFG_DATA 0x24
/* PCIe per port registers */
#define PCIE_BAR0_SETUP 0x10
#define PCIE_CLASS 0x34
#define PCIE_LINK_STATUS 0x50
#define PCIE_PORT_INT_EN(x) BIT(20 + (x))
#define PCIE_PORT_PERST(x) BIT(1 + (x))
#define PCIE_PORT_LINKUP BIT(0)
#define PCIE_BAR_MAP_MAX GENMASK(31, 16)
#define PCIE_BAR_ENABLE BIT(0)
#define PCIE_REVISION_ID BIT(0)
#define PCIE_CLASS_CODE (0x60400 << 8)
#define PCIE_CONF_REG(regn) (((regn) & GENMASK(7, 2)) | \
((((regn) >> 8) & GENMASK(3, 0)) << 24))
#define PCIE_CONF_FUN(fun) (((fun) << 8) & GENMASK(10, 8))
#define PCIE_CONF_DEV(dev) (((dev) << 11) & GENMASK(15, 11))
#define PCIE_CONF_BUS(bus) (((bus) << 16) & GENMASK(23, 16))
#define PCIE_CONF_ADDR(regn, fun, dev, bus) \
(PCIE_CONF_REG(regn) | PCIE_CONF_FUN(fun) | \
PCIE_CONF_DEV(dev) | PCIE_CONF_BUS(bus))
/* MediaTek specific configuration registers */
#define PCIE_FTS_NUM 0x70c
#define PCIE_FTS_NUM_MASK GENMASK(15, 8)
#define PCIE_FTS_NUM_L0(x) ((x) & 0xff << 8)
#define PCIE_FC_CREDIT 0x73c
#define PCIE_FC_CREDIT_MASK (GENMASK(31, 31) | GENMASK(28, 16))
#define PCIE_FC_CREDIT_VAL(x) ((x) << 16)
/* PCIe V2 share registers */
#define PCIE_SYS_CFG_V2 0x0
#define PCIE_CSR_LTSSM_EN(x) BIT(0 + (x) * 8)
#define PCIE_CSR_ASPM_L1_EN(x) BIT(1 + (x) * 8)
/* PCIe V2 per-port registers */
#define PCIE_MSI_VECTOR 0x0c0
#define PCIE_CONF_VEND_ID 0x100
#define PCIE_CONF_CLASS_ID 0x106
#define PCIE_INT_MASK 0x420
#define INTX_MASK GENMASK(19, 16)
#define INTX_SHIFT 16
#define PCIE_INT_STATUS 0x424
#define MSI_STATUS BIT(23)
#define PCIE_IMSI_STATUS 0x42c
#define PCIE_IMSI_ADDR 0x430
#define MSI_MASK BIT(23)
#define MTK_MSI_IRQS_NUM 32
#define PCIE_AHB_TRANS_BASE0_L 0x438
#define PCIE_AHB_TRANS_BASE0_H 0x43c
#define AHB2PCIE_SIZE(x) ((x) & GENMASK(4, 0))
#define PCIE_AXI_WINDOW0 0x448
#define WIN_ENABLE BIT(7)
/* PCIe V2 configuration transaction header */
#define PCIE_CFG_HEADER0 0x460
#define PCIE_CFG_HEADER1 0x464
#define PCIE_CFG_HEADER2 0x468
#define PCIE_CFG_WDATA 0x470
#define PCIE_APP_TLP_REQ 0x488
#define PCIE_CFG_RDATA 0x48c
#define APP_CFG_REQ BIT(0)
#define APP_CPL_STATUS GENMASK(7, 5)
#define CFG_WRRD_TYPE_0 4
#define CFG_WR_FMT 2
#define CFG_RD_FMT 0
#define CFG_DW0_LENGTH(length) ((length) & GENMASK(9, 0))
#define CFG_DW0_TYPE(type) (((type) << 24) & GENMASK(28, 24))
#define CFG_DW0_FMT(fmt) (((fmt) << 29) & GENMASK(31, 29))
#define CFG_DW2_REGN(regn) ((regn) & GENMASK(11, 2))
#define CFG_DW2_FUN(fun) (((fun) << 16) & GENMASK(18, 16))
#define CFG_DW2_DEV(dev) (((dev) << 19) & GENMASK(23, 19))
#define CFG_DW2_BUS(bus) (((bus) << 24) & GENMASK(31, 24))
#define CFG_HEADER_DW0(type, fmt) \
(CFG_DW0_LENGTH(1) | CFG_DW0_TYPE(type) | CFG_DW0_FMT(fmt))
#define CFG_HEADER_DW1(where, size) \
(GENMASK(((size) - 1), 0) << ((where) & 0x3))
#define CFG_HEADER_DW2(regn, fun, dev, bus) \
(CFG_DW2_REGN(regn) | CFG_DW2_FUN(fun) | \
CFG_DW2_DEV(dev) | CFG_DW2_BUS(bus))
#define PCIE_RST_CTRL 0x510
#define PCIE_PHY_RSTB BIT(0)
#define PCIE_PIPE_SRSTB BIT(1)
#define PCIE_MAC_SRSTB BIT(2)
#define PCIE_CRSTB BIT(3)
#define PCIE_PERSTB BIT(8)
#define PCIE_LINKDOWN_RST_EN GENMASK(15, 13)
#define PCIE_LINK_STATUS_V2 0x804
#define PCIE_PORT_LINKUP_V2 BIT(10)
struct mtk_pcie_port;
/**
* struct mtk_pcie_soc - differentiate between host generations
* @need_fix_class_id: whether this host's class ID needed to be fixed or not
* @ops: pointer to configuration access functions
* @startup: pointer to controller setting functions
* @setup_irq: pointer to initialize IRQ functions
*/
struct mtk_pcie_soc {
bool need_fix_class_id;
struct pci_ops *ops;
int (*startup)(struct mtk_pcie_port *port);
int (*setup_irq)(struct mtk_pcie_port *port, struct device_node *node);
};
/**
* struct mtk_pcie_port - PCIe port information
* @base: IO mapped register base
* @list: port list
* @pcie: pointer to PCIe host info
* @reset: pointer to port reset control
* @sys_ck: pointer to transaction/data link layer clock
* @ahb_ck: pointer to AHB slave interface operating clock for CSR access
* and RC initiated MMIO access
* @axi_ck: pointer to application layer MMIO channel operating clock
* @aux_ck: pointer to pe2_mac_bridge and pe2_mac_core operating clock
* when pcie_mac_ck/pcie_pipe_ck is turned off
* @obff_ck: pointer to OBFF functional block operating clock
* @pipe_ck: pointer to LTSSM and PHY/MAC layer operating clock
* @phy: pointer to PHY control block
* @lane: lane count
* @slot: port slot
* @irq_domain: legacy INTx IRQ domain
* @inner_domain: inner IRQ domain
* @msi_domain: MSI IRQ domain
* @lock: protect the msi_irq_in_use bitmap
* @msi_irq_in_use: bit map for assigned MSI IRQ
*/
struct mtk_pcie_port {
void __iomem *base;
struct list_head list;
struct mtk_pcie *pcie;
struct reset_control *reset;
struct clk *sys_ck;
struct clk *ahb_ck;
struct clk *axi_ck;
struct clk *aux_ck;
struct clk *obff_ck;
struct clk *pipe_ck;
struct phy *phy;
u32 lane;
u32 slot;
struct irq_domain *irq_domain;
struct irq_domain *inner_domain;
struct irq_domain *msi_domain;
struct mutex lock;
DECLARE_BITMAP(msi_irq_in_use, MTK_MSI_IRQS_NUM);
};
/**
* struct mtk_pcie - PCIe host information
* @dev: pointer to PCIe device
* @base: IO mapped register base
* @free_ck: free-run reference clock
* @io: IO resource
* @pio: PIO resource
* @mem: non-prefetchable memory resource
* @busn: bus range
* @offset: IO / Memory offset
* @ports: pointer to PCIe port information
* @soc: pointer to SoC-dependent operations
*/
struct mtk_pcie {
struct device *dev;
void __iomem *base