// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2021, MediaTek Inc. * Copyright (c) 2021-2022, Intel Corporation. * * Authors: * Haijun Liu * Moises Veleta * Sreehari Kancharla * * Contributors: * Amir Hanania * Chiranjeevi Rapolu * Ricardo Martinez */ #include #include #include #include #include #include #include #include "t7xx_pci.h" #include "t7xx_pcie_mac.h" #include "t7xx_reg.h" #define T7XX_PCIE_REG_BAR 2 #define T7XX_PCIE_REG_PORT ATR_SRC_PCI_WIN0 #define T7XX_PCIE_REG_TABLE_NUM 0 #define T7XX_PCIE_REG_TRSL_PORT ATR_DST_AXIM_0 #define T7XX_PCIE_DEV_DMA_PORT_START ATR_SRC_AXIS_0 #define T7XX_PCIE_DEV_DMA_PORT_END ATR_SRC_AXIS_2 #define T7XX_PCIE_DEV_DMA_TABLE_NUM 0 #define T7XX_PCIE_DEV_DMA_TRSL_ADDR 0 #define T7XX_PCIE_DEV_DMA_SRC_ADDR 0 #define T7XX_PCIE_DEV_DMA_TRANSPARENT 1 #define T7XX_PCIE_DEV_DMA_SIZE 0 enum t7xx_atr_src_port { ATR_SRC_PCI_WIN0, ATR_SRC_PCI_WIN1, ATR_SRC_AXIS_0, ATR_SRC_AXIS_1, ATR_SRC_AXIS_2, ATR_SRC_AXIS_3, }; enum t7xx_atr_dst_port { ATR_DST_PCI_TRX, ATR_DST_PCI_CONFIG, ATR_DST_AXIM_0 = 4, ATR_DST_AXIM_1, ATR_DST_AXIM_2, ATR_DST_AXIM_3, }; struct t7xx_atr_config { u64 src_addr; u64 trsl_addr; u64 size; u32 port; u32 table; enum t7xx_atr_dst_port trsl_id; u32 transparent; }; static void t7xx_pcie_mac_atr_tables_dis(void __iomem *pbase, enum t7xx_atr_src_port port) { void __iomem *reg; int i, offset; for (i = 0; i < ATR_TABLE_NUM_PER_ATR; i++) { offset = ATR_PORT_OFFSET * port + ATR_TABLE_OFFSET * i; reg = pbase + ATR_PCIE_WIN0_T0_ATR_PARAM_SRC_ADDR + offset; iowrite64_lo_hi(0, reg); } } static int t7xx_pcie_mac_atr_cfg(struct t7xx_pci_dev *t7xx_dev, struct t7xx_atr_config *cfg) { struct device *dev = &t7xx_dev->pdev->dev; void __iomem *pbase = IREG_BASE(t7xx_dev); int atr_size, pos, offset; void __iomem *reg; u64 value; if (cfg->transparent) { /* No address conversion is performed */ atr_size = ATR_TRANSPARENT_SIZE; } else { if (cfg->src_addr & (cfg->size - 1)) { dev_err(dev, "Source address is not aligned to size\n"); return -EINVAL; } if (cfg->trsl_addr & (cfg->size - 1)) { dev_err(dev, "Translation address %llx is not aligned to size %llx\n", cfg->trsl_addr, cfg->size - 1); return -EINVAL; } pos = __ffs64(cfg->size); /* HW calculates the address translation space as 2^(atr_size + 1) */ atr_size = pos - 1; } offset = ATR_PORT_OFFSET * cfg->port + ATR_TABLE_OFFSET * cfg->table; reg = pbase + ATR_PCIE_WIN0_T0_TRSL_ADDR + offset; value = cfg->trsl_addr & ATR_PCIE_WIN0_ADDR_ALGMT; iowrite64_lo_hi(value, reg); reg = pbase + ATR_PCIE_WIN0_T0_TRSL_PARAM + offset; iowrite32(cfg->trsl_id, reg); reg = pbase + ATR_PCIE_WIN0_T0_ATR_PARAM_SRC_ADDR + offset; value = (cfg->src_addr & ATR_PCIE_WIN0_ADDR_ALGMT) | (atr_size << 1) | BIT(0); iowrite64_lo_hi(value, reg); /* Ensure ATR is set */ ioread64_lo_hi(reg); return 0; } /** * t7xx_pcie_mac_atr_init() - Initialize address translation. * @t7xx_dev: MTK device. * * Setup ATR for ports & device. */ void t7xx_pcie_mac_atr_init(struct t7xx_pci_dev *t7xx_dev) { struct t7xx_atr_config cfg; u32 i; /* Disable for all ports */ for (i = ATR_SRC_PCI_WIN0; i <= ATR_SRC_AXIS_3; i++) t7xx_pcie_mac_atr_tables_dis(IREG_BASE(t7xx_dev), i); memset(&cfg, 0, sizeof(cfg)); /* Config ATR for RC to access device's register */ cfg.src_addr = pci_resource_start(t7xx_dev->pdev, T7XX_PCIE_REG_BAR); cfg.size = T7XX_PCIE_REG_SIZE_CHIP; cfg.trsl_addr = T7XX_PCIE_REG_TRSL_ADDR_CHIP; cfg.port = T7XX_PCIE_REG_PORT; cfg.table = T7XX_PCIE_REG_TABLE_NUM; cfg.trsl_id = T7XX_PCIE_REG_TRSL_PORT; t7xx_pcie_mac_atr_tables_dis(IREG_BASE(t7xx_dev), cfg.port); t7xx_pcie_mac_atr_cfg(t7xx_dev, &cfg); t7xx_dev->base_addr.pcie_dev_reg_trsl_addr = T7XX_PCIE_REG_TRSL_ADDR_CHIP; /* Config ATR for EP to access RC's memory */ for (i = T7XX_PCIE_DEV_DMA_PORT_START; i <= T7XX_PCIE_DEV_DMA_PORT_END; i++) { cfg.src_addr = T7XX_PCIE_DEV_DMA_SRC_ADDR; cfg.size = T7XX_PCIE_DEV_DMA_SIZE; cfg.trsl_addr = T7XX_PCIE_DEV_DMA_TRSL_ADDR; cfg.port = i; cfg.table = T7XX_PCIE_DEV_DMA_TABLE_NUM; cfg.trsl_id = ATR_DST_PCI_TRX; cfg.transparent = T7XX_PCIE_DEV_DMA_TRANSPARENT; t7xx_pcie_mac_atr_tables_dis(IREG_BASE(t7xx_dev), cfg.port); t7xx_pcie_mac_atr_cfg(t7xx_dev, &cfg); } } /** * t7xx_pcie_mac_enable_disable_int() - Enable/disable interrupts. * @t7xx_dev: MTK device. * @enable: Enable/disable. * * Enable or disable device interrupts. */ static void t7xx_pcie_mac_enable_disable_int(struct t7xx_pci_dev *t7xx_dev, bool enable) { u32 value; value = ioread32(IREG_BASE(t7xx_dev) + ISTAT_HST_CTRL); if (enable) value &= ~ISTAT_HST_CTRL_DIS; else value |= ISTAT_HST_CTRL_DIS; iowrite32(value, IREG_BASE(t7xx_dev) + ISTAT_HST_CTRL); } void t7xx_pcie_mac_interrupts_en(struct t7xx_pci_dev *t7xx_dev) { t7xx_pcie_mac_enable_disable_int(t7xx_dev, true); } void t7xx_pcie_mac_interrupts_dis(struct t7xx_pci_dev *t7xx_dev) { t7xx_pcie_mac_enable_disable_int(t7xx_dev, false); } /** * t7xx_pcie_mac_clear_set_int() - Clear/set interrupt by type. * @t7xx_dev: MTK device. * @int_type: Interrupt type. * @clear: Clear/set. * * Clear or set device interrupt by type. */ static void t7xx_pcie_mac_clear_set_int(struct t7xx_pci_dev *t7xx_dev, enum t7xx_int int_type, bool clear) { void __iomem *reg; u32 val; if (clear) reg = IREG_BASE(t7xx_dev) + IMASK_HOST_MSIX_CLR_GRP0_0; else reg = IREG_BASE(t7xx_dev) + IMASK_HOST_MSIX_SET_GRP0_0; val = BIT(EXT_INT_START + int_type); iowrite32(val, reg); } void t7xx_pcie_mac_clear_int(struct t7xx_pci_dev *t7xx_dev, enum t7xx_int int_type) { t7xx_pcie_mac_clear_set_int(t7xx_dev, int_type, true); } void t7xx_pcie_mac_set_int(struct t7xx_pci_dev *t7xx_dev, enum t7xx_int int_type) { t7xx_pcie_mac_clear_set_int(t7xx_dev, int_type, false); } /** * t7xx_pcie_mac_clear_int_status() - Clear interrupt status by type. * @t7xx_dev: MTK device. * @int_type: Interrupt type. * * Enable or disable device interrupts' status by type. */ void t7xx_pcie_mac_clear_int_status(struct t7xx_pci_dev *t7xx_dev, enum t7xx_int int_type) { void __iomem *reg = IREG_BASE(t7xx_dev) + MSIX_ISTAT_HST_GRP0_0; u32 val = BIT(EXT_INT_START + int_type); iowrite32(val, reg); } /** * t7xx_pcie_set_mac_msix_cfg() - Write MSIX control configuration. * @t7xx_dev: MTK device. * @irq_count: Number of MSIX IRQ vectors. * * Write IRQ count to device. */ void t7xx_pcie_set_mac_msix_cfg(struct t7xx_pci_dev *t7xx_dev, unsigned int irq_count) { u32 val = ffs(irq_count) * 2 - 1; iowrite32(val, IREG_BASE(t7xx_dev) + T7XX_PCIE_CFG_MSIX); }