13d0407baSopenharmony_ci// SPDX-License-Identifier: GPL-2.0 23d0407baSopenharmony_ci/* 33d0407baSopenharmony_ci * PCIe host controller driver for Rockchip SoCs 43d0407baSopenharmony_ci * 53d0407baSopenharmony_ci * Copyright (C) 2018 Rockchip Electronics Co., Ltd. 63d0407baSopenharmony_ci * http://www.rock-chips.com 73d0407baSopenharmony_ci * 83d0407baSopenharmony_ci * Author: Simon Xue <xxm@rock-chips.com> 93d0407baSopenharmony_ci */ 103d0407baSopenharmony_ci 113d0407baSopenharmony_ci#include <linux/clk.h> 123d0407baSopenharmony_ci#include <linux/delay.h> 133d0407baSopenharmony_ci#include <linux/fs.h> 143d0407baSopenharmony_ci#include <linux/gpio.h> 153d0407baSopenharmony_ci#include <linux/init.h> 163d0407baSopenharmony_ci#include <linux/interrupt.h> 173d0407baSopenharmony_ci#include <linux/irq.h> 183d0407baSopenharmony_ci#include <linux/irqchip/chained_irq.h> 193d0407baSopenharmony_ci#include <linux/irqdomain.h> 203d0407baSopenharmony_ci#include <linux/kernel.h> 213d0407baSopenharmony_ci#include <linux/kthread.h> 223d0407baSopenharmony_ci#include <linux/list.h> 233d0407baSopenharmony_ci#include <linux/mfd/syscon.h> 243d0407baSopenharmony_ci#include <linux/miscdevice.h> 253d0407baSopenharmony_ci#include <linux/module.h> 263d0407baSopenharmony_ci#include <linux/of_address.h> 273d0407baSopenharmony_ci#include <linux/of_device.h> 283d0407baSopenharmony_ci#include <linux/of_gpio.h> 293d0407baSopenharmony_ci#include <linux/of_pci.h> 303d0407baSopenharmony_ci#include <linux/pci.h> 313d0407baSopenharmony_ci#include <linux/phy/phy.h> 323d0407baSopenharmony_ci#include <linux/phy/pcie.h> 333d0407baSopenharmony_ci#include <linux/platform_device.h> 343d0407baSopenharmony_ci#include <linux/poll.h> 353d0407baSopenharmony_ci#include <linux/regmap.h> 363d0407baSopenharmony_ci#include <linux/reset.h> 373d0407baSopenharmony_ci#include <linux/resource.h> 383d0407baSopenharmony_ci#include <linux/rfkill-wlan.h> 393d0407baSopenharmony_ci#include <linux/signal.h> 403d0407baSopenharmony_ci#include <linux/types.h> 413d0407baSopenharmony_ci#include <linux/uaccess.h> 423d0407baSopenharmony_ci#include <linux/pci-epf.h> 433d0407baSopenharmony_ci 443d0407baSopenharmony_ci#include "pcie-designware.h" 453d0407baSopenharmony_ci#include "../../pci.h" 463d0407baSopenharmony_ci#include "../rockchip-pcie-dma.h" 473d0407baSopenharmony_ci 483d0407baSopenharmony_cienum rk_pcie_device_mode { 493d0407baSopenharmony_ci RK_PCIE_EP_TYPE, 503d0407baSopenharmony_ci RK_PCIE_RC_TYPE, 513d0407baSopenharmony_ci}; 523d0407baSopenharmony_ci 533d0407baSopenharmony_cistruct reset_bulk_data { 543d0407baSopenharmony_ci const char *id; 553d0407baSopenharmony_ci struct reset_control *rst; 563d0407baSopenharmony_ci}; 573d0407baSopenharmony_ci 583d0407baSopenharmony_ci#define PCIE_DMA_OFFSET 0x380000 593d0407baSopenharmony_ci 603d0407baSopenharmony_ci#define PCIE_DMA_WR_ENB 0xc 613d0407baSopenharmony_ci#define PCIE_DMA_WR_CTRL_LO 0x200 623d0407baSopenharmony_ci#define PCIE_DMA_WR_CTRL_HI 0x204 633d0407baSopenharmony_ci#define PCIE_DMA_WR_XFERSIZE 0x208 643d0407baSopenharmony_ci#define PCIE_DMA_WR_SAR_PTR_LO 0x20c 653d0407baSopenharmony_ci#define PCIE_DMA_WR_SAR_PTR_HI 0x210 663d0407baSopenharmony_ci#define PCIE_DMA_WR_DAR_PTR_LO 0x214 673d0407baSopenharmony_ci#define PCIE_DMA_WR_DAR_PTR_HI 0x218 683d0407baSopenharmony_ci#define PCIE_DMA_WR_WEILO 0x18 693d0407baSopenharmony_ci#define PCIE_DMA_WR_WEIHI 0x1c 703d0407baSopenharmony_ci#define PCIE_DMA_WR_DOORBELL 0x10 713d0407baSopenharmony_ci#define PCIE_DMA_WR_INT_STATUS 0x4c 723d0407baSopenharmony_ci#define PCIE_DMA_WR_INT_MASK 0x54 733d0407baSopenharmony_ci#define PCIE_DMA_WR_INT_CLEAR 0x58 743d0407baSopenharmony_ci 753d0407baSopenharmony_ci#define PCIE_DMA_RD_ENB 0x2c 763d0407baSopenharmony_ci#define PCIE_DMA_RD_CTRL_LO 0x300 773d0407baSopenharmony_ci#define PCIE_DMA_RD_CTRL_HI 0x304 783d0407baSopenharmony_ci#define PCIE_DMA_RD_XFERSIZE 0x308 793d0407baSopenharmony_ci#define PCIE_DMA_RD_SAR_PTR_LO 0x30c 803d0407baSopenharmony_ci#define PCIE_DMA_RD_SAR_PTR_HI 0x310 813d0407baSopenharmony_ci#define PCIE_DMA_RD_DAR_PTR_LO 0x314 823d0407baSopenharmony_ci#define PCIE_DMA_RD_DAR_PTR_HI 0x318 833d0407baSopenharmony_ci#define PCIE_DMA_RD_WEILO 0x38 843d0407baSopenharmony_ci#define PCIE_DMA_RD_WEIHI 0x3c 853d0407baSopenharmony_ci#define PCIE_DMA_RD_DOORBELL 0x30 863d0407baSopenharmony_ci#define PCIE_DMA_RD_INT_STATUS 0xa0 873d0407baSopenharmony_ci#define PCIE_DMA_RD_INT_MASK 0xa8 883d0407baSopenharmony_ci#define PCIE_DMA_RD_INT_CLEAR 0xac 893d0407baSopenharmony_ci 903d0407baSopenharmony_ci/* Parameters for the waiting for iATU enabled routine */ 913d0407baSopenharmony_ci#define LINK_WAIT_IATU_MIN 9000 923d0407baSopenharmony_ci#define LINK_WAIT_IATU_MAX 10000 933d0407baSopenharmony_ci 943d0407baSopenharmony_ci#define PCIE_DIRECT_SPEED_CHANGE (0x1 << 17) 953d0407baSopenharmony_ci 963d0407baSopenharmony_ci#define PCIE_TYPE0_STATUS_COMMAND_REG 0x4 973d0407baSopenharmony_ci#define PCIE_TYPE0_BAR0_REG 0x10 983d0407baSopenharmony_ci 993d0407baSopenharmony_ci#define PCIE_CAP_LINK_CONTROL2_LINK_STATUS 0xa0 1003d0407baSopenharmony_ci 1013d0407baSopenharmony_ci#define PCIE_CLIENT_INTR_STATUS_LEGACY 0x08 1023d0407baSopenharmony_ci#define PCIE_CLIENT_INTR_STATUS_MISC 0x10 1033d0407baSopenharmony_ci#define PCIE_CLIENT_INTR_MASK_LEGACY 0x1c 1043d0407baSopenharmony_ci#define UNMASK_ALL_LEGACY_INT 0xffff0000 1053d0407baSopenharmony_ci#define MASK_LEGACY_INT(x) (0x00110011 << x) 1063d0407baSopenharmony_ci#define UNMASK_LEGACY_INT(x) (0x00110000 << x) 1073d0407baSopenharmony_ci#define PCIE_CLIENT_INTR_MASK 0x24 1083d0407baSopenharmony_ci#define PCIE_CLIENT_GENERAL_DEBUG 0x104 1093d0407baSopenharmony_ci#define PCIE_CLIENT_HOT_RESET_CTRL 0x180 1103d0407baSopenharmony_ci#define PCIE_LTSSM_ENABLE_ENHANCE BIT(4) 1113d0407baSopenharmony_ci#define PCIE_CLIENT_LTSSM_STATUS 0x300 1123d0407baSopenharmony_ci#define SMLH_LINKUP BIT(16) 1133d0407baSopenharmony_ci#define RDLH_LINKUP BIT(17) 1143d0407baSopenharmony_ci#define PCIE_CLIENT_DBG_FIFO_MODE_CON 0x310 1153d0407baSopenharmony_ci#define PCIE_CLIENT_DBG_FIFO_PTN_HIT_D0 0x320 1163d0407baSopenharmony_ci#define PCIE_CLIENT_DBG_FIFO_PTN_HIT_D1 0x324 1173d0407baSopenharmony_ci#define PCIE_CLIENT_DBG_FIFO_TRN_HIT_D0 0x328 1183d0407baSopenharmony_ci#define PCIE_CLIENT_DBG_FIFO_TRN_HIT_D1 0x32c 1193d0407baSopenharmony_ci#define PCIE_CLIENT_DBG_FIFO_STATUS 0x350 1203d0407baSopenharmony_ci#define PCIE_CLIENT_DBG_TRANSITION_DATA 0xffff0000 1213d0407baSopenharmony_ci#define PCIE_CLIENT_DBF_EN 0xffff0003 1223d0407baSopenharmony_ci#define RK_PCIE_DBG 0 1233d0407baSopenharmony_ci 1243d0407baSopenharmony_ci#define PCIE_PHY_LINKUP BIT(0) 1253d0407baSopenharmony_ci#define PCIE_DATA_LINKUP BIT(1) 1263d0407baSopenharmony_ci 1273d0407baSopenharmony_ci#define PCIE_SB_BAR0_MASK_REG 0x100010 1283d0407baSopenharmony_ci 1293d0407baSopenharmony_ci#define PCIE_PL_ORDER_RULE_CTRL_OFF 0x8B4 1303d0407baSopenharmony_ci 1313d0407baSopenharmony_cistruct rk_pcie { 1323d0407baSopenharmony_ci struct dw_pcie *pci; 1333d0407baSopenharmony_ci enum rk_pcie_device_mode mode; 1343d0407baSopenharmony_ci enum phy_mode phy_mode; 1353d0407baSopenharmony_ci int phy_sub_mode; 1363d0407baSopenharmony_ci unsigned char bar_to_atu[6]; 1373d0407baSopenharmony_ci phys_addr_t *outbound_addr; 1383d0407baSopenharmony_ci unsigned long *ib_window_map; 1393d0407baSopenharmony_ci unsigned long *ob_window_map; 1403d0407baSopenharmony_ci unsigned int num_ib_windows; 1413d0407baSopenharmony_ci unsigned int num_ob_windows; 1423d0407baSopenharmony_ci void __iomem *dbi_base; 1433d0407baSopenharmony_ci void __iomem *apb_base; 1443d0407baSopenharmony_ci struct phy *phy; 1453d0407baSopenharmony_ci struct clk_bulk_data *clks; 1463d0407baSopenharmony_ci unsigned int clk_cnt; 1473d0407baSopenharmony_ci struct reset_bulk_data *rsts; 1483d0407baSopenharmony_ci struct gpio_desc *rst_gpio; 1493d0407baSopenharmony_ci phys_addr_t mem_start; 1503d0407baSopenharmony_ci size_t mem_size; 1513d0407baSopenharmony_ci struct pcie_port pp; 1523d0407baSopenharmony_ci struct regmap *usb_pcie_grf; 1533d0407baSopenharmony_ci struct regmap *pmu_grf; 1543d0407baSopenharmony_ci struct dma_trx_obj *dma_obj; 1553d0407baSopenharmony_ci bool in_suspend; 1563d0407baSopenharmony_ci bool skip_scan_in_resume; 1573d0407baSopenharmony_ci bool is_rk1808; 1583d0407baSopenharmony_ci bool is_signal_test; 1593d0407baSopenharmony_ci bool bifurcation; 1603d0407baSopenharmony_ci struct regulator *vpcie3v3; 1613d0407baSopenharmony_ci struct irq_domain *irq_domain; 1623d0407baSopenharmony_ci raw_spinlock_t intx_lock; 1633d0407baSopenharmony_ci}; 1643d0407baSopenharmony_ci 1653d0407baSopenharmony_cistruct rk_pcie_of_data { 1663d0407baSopenharmony_ci enum rk_pcie_device_mode mode; 1673d0407baSopenharmony_ci}; 1683d0407baSopenharmony_ci 1693d0407baSopenharmony_ci#define to_rk_pcie(x) dev_get_drvdata((x)->dev) 1703d0407baSopenharmony_ci 1713d0407baSopenharmony_cistatic int rk_pcie_read(void __iomem *addr, int size, u32 *val) 1723d0407baSopenharmony_ci{ 1733d0407baSopenharmony_ci if ((uintptr_t)addr & (size - 1)) { 1743d0407baSopenharmony_ci *val = 0; 1753d0407baSopenharmony_ci return PCIBIOS_BAD_REGISTER_NUMBER; 1763d0407baSopenharmony_ci } 1773d0407baSopenharmony_ci 1783d0407baSopenharmony_ci if (size == 4) { 1793d0407baSopenharmony_ci *val = readl(addr); 1803d0407baSopenharmony_ci } else if (size == 2) { 1813d0407baSopenharmony_ci *val = readw(addr); 1823d0407baSopenharmony_ci } else if (size == 1) { 1833d0407baSopenharmony_ci *val = readb(addr); 1843d0407baSopenharmony_ci } else { 1853d0407baSopenharmony_ci *val = 0; 1863d0407baSopenharmony_ci return PCIBIOS_BAD_REGISTER_NUMBER; 1873d0407baSopenharmony_ci } 1883d0407baSopenharmony_ci 1893d0407baSopenharmony_ci return PCIBIOS_SUCCESSFUL; 1903d0407baSopenharmony_ci} 1913d0407baSopenharmony_ci 1923d0407baSopenharmony_cistatic int rk_pcie_write(void __iomem *addr, int size, u32 val) 1933d0407baSopenharmony_ci{ 1943d0407baSopenharmony_ci if ((uintptr_t)addr & (size - 1)) 1953d0407baSopenharmony_ci return PCIBIOS_BAD_REGISTER_NUMBER; 1963d0407baSopenharmony_ci 1973d0407baSopenharmony_ci if (size == 4) 1983d0407baSopenharmony_ci writel(val, addr); 1993d0407baSopenharmony_ci else if (size == 2) 2003d0407baSopenharmony_ci writew(val, addr); 2013d0407baSopenharmony_ci else if (size == 1) 2023d0407baSopenharmony_ci writeb(val, addr); 2033d0407baSopenharmony_ci else 2043d0407baSopenharmony_ci return PCIBIOS_BAD_REGISTER_NUMBER; 2053d0407baSopenharmony_ci 2063d0407baSopenharmony_ci return PCIBIOS_SUCCESSFUL; 2073d0407baSopenharmony_ci} 2083d0407baSopenharmony_ci 2093d0407baSopenharmony_cistatic u32 __rk_pcie_read_apb(struct rk_pcie *rk_pcie, void __iomem *base, 2103d0407baSopenharmony_ci u32 reg, size_t size) 2113d0407baSopenharmony_ci{ 2123d0407baSopenharmony_ci int ret; 2133d0407baSopenharmony_ci u32 val; 2143d0407baSopenharmony_ci 2153d0407baSopenharmony_ci ret = rk_pcie_read(base + reg, size, &val); 2163d0407baSopenharmony_ci if (ret) 2173d0407baSopenharmony_ci dev_err(rk_pcie->pci->dev, "Read APB address failed\n"); 2183d0407baSopenharmony_ci 2193d0407baSopenharmony_ci return val; 2203d0407baSopenharmony_ci} 2213d0407baSopenharmony_ci 2223d0407baSopenharmony_cistatic void __rk_pcie_write_apb(struct rk_pcie *rk_pcie, void __iomem *base, 2233d0407baSopenharmony_ci u32 reg, size_t size, u32 val) 2243d0407baSopenharmony_ci{ 2253d0407baSopenharmony_ci int ret; 2263d0407baSopenharmony_ci 2273d0407baSopenharmony_ci ret = rk_pcie_write(base + reg, size, val); 2283d0407baSopenharmony_ci if (ret) 2293d0407baSopenharmony_ci dev_err(rk_pcie->pci->dev, "Write APB address failed\n"); 2303d0407baSopenharmony_ci} 2313d0407baSopenharmony_ci 2323d0407baSopenharmony_cistatic inline u32 rk_pcie_readl_apb(struct rk_pcie *rk_pcie, u32 reg) 2333d0407baSopenharmony_ci{ 2343d0407baSopenharmony_ci return __rk_pcie_read_apb(rk_pcie, rk_pcie->apb_base, reg, 0x4); 2353d0407baSopenharmony_ci} 2363d0407baSopenharmony_ci 2373d0407baSopenharmony_cistatic inline void rk_pcie_writel_apb(struct rk_pcie *rk_pcie, u32 reg, 2383d0407baSopenharmony_ci u32 val) 2393d0407baSopenharmony_ci{ 2403d0407baSopenharmony_ci __rk_pcie_write_apb(rk_pcie, rk_pcie->apb_base, reg, 0x4, val); 2413d0407baSopenharmony_ci} 2423d0407baSopenharmony_ci 2433d0407baSopenharmony_cistatic u8 rk_pcie_iatu_unroll_enabled(struct dw_pcie *pci) 2443d0407baSopenharmony_ci{ 2453d0407baSopenharmony_ci u32 val; 2463d0407baSopenharmony_ci 2473d0407baSopenharmony_ci val = dw_pcie_readl_dbi(pci, PCIE_ATU_VIEWPORT); 2483d0407baSopenharmony_ci if (val == 0xffffffff) 2493d0407baSopenharmony_ci return 1; 2503d0407baSopenharmony_ci 2513d0407baSopenharmony_ci return 0; 2523d0407baSopenharmony_ci} 2533d0407baSopenharmony_ci 2543d0407baSopenharmony_cistatic void rk_pcie_writel_atu(struct dw_pcie *pci, u32 reg, u32 val) 2553d0407baSopenharmony_ci{ 2563d0407baSopenharmony_ci int ret; 2573d0407baSopenharmony_ci 2583d0407baSopenharmony_ci if (pci->ops->write_dbi) { 2593d0407baSopenharmony_ci pci->ops->write_dbi(pci, pci->atu_base, reg, 4, val); 2603d0407baSopenharmony_ci return; 2613d0407baSopenharmony_ci } 2623d0407baSopenharmony_ci 2633d0407baSopenharmony_ci ret = dw_pcie_write(pci->atu_base + reg, 4, val); 2643d0407baSopenharmony_ci if (ret) 2653d0407baSopenharmony_ci dev_err(pci->dev, "Write ATU address failed\n"); 2663d0407baSopenharmony_ci} 2673d0407baSopenharmony_ci 2683d0407baSopenharmony_cistatic void rk_pcie_writel_ib_unroll(struct dw_pcie *pci, u32 index, u32 reg, 2693d0407baSopenharmony_ci u32 val) 2703d0407baSopenharmony_ci{ 2713d0407baSopenharmony_ci u32 offset = PCIE_GET_ATU_INB_UNR_REG_OFFSET(index); 2723d0407baSopenharmony_ci 2733d0407baSopenharmony_ci rk_pcie_writel_atu(pci, offset + reg, val); 2743d0407baSopenharmony_ci} 2753d0407baSopenharmony_ci 2763d0407baSopenharmony_cistatic u32 rk_pcie_readl_atu(struct dw_pcie *pci, u32 reg) 2773d0407baSopenharmony_ci{ 2783d0407baSopenharmony_ci int ret; 2793d0407baSopenharmony_ci u32 val; 2803d0407baSopenharmony_ci 2813d0407baSopenharmony_ci if (pci->ops->read_dbi) 2823d0407baSopenharmony_ci return pci->ops->read_dbi(pci, pci->atu_base, reg, 4); 2833d0407baSopenharmony_ci 2843d0407baSopenharmony_ci ret = dw_pcie_read(pci->atu_base + reg, 4, &val); 2853d0407baSopenharmony_ci if (ret) 2863d0407baSopenharmony_ci dev_err(pci->dev, "Read ATU address failed\n"); 2873d0407baSopenharmony_ci 2883d0407baSopenharmony_ci return val; 2893d0407baSopenharmony_ci} 2903d0407baSopenharmony_ci 2913d0407baSopenharmony_cistatic u32 rk_pcie_readl_ib_unroll(struct dw_pcie *pci, u32 index, u32 reg) 2923d0407baSopenharmony_ci{ 2933d0407baSopenharmony_ci u32 offset = PCIE_GET_ATU_INB_UNR_REG_OFFSET(index); 2943d0407baSopenharmony_ci 2953d0407baSopenharmony_ci return rk_pcie_readl_atu(pci, offset + reg); 2963d0407baSopenharmony_ci} 2973d0407baSopenharmony_ci 2983d0407baSopenharmony_cistatic int rk_pcie_prog_inbound_atu_unroll(struct dw_pcie *pci, u8 func_no, 2993d0407baSopenharmony_ci int index, int bar, u64 cpu_addr, 3003d0407baSopenharmony_ci enum dw_pcie_as_type as_type) 3013d0407baSopenharmony_ci{ 3023d0407baSopenharmony_ci int type; 3033d0407baSopenharmony_ci u32 retries, val; 3043d0407baSopenharmony_ci 3053d0407baSopenharmony_ci rk_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_LOWER_TARGET, 3063d0407baSopenharmony_ci lower_32_bits(cpu_addr)); 3073d0407baSopenharmony_ci rk_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET, 3083d0407baSopenharmony_ci upper_32_bits(cpu_addr)); 3093d0407baSopenharmony_ci 3103d0407baSopenharmony_ci switch (as_type) { 3113d0407baSopenharmony_ci case DW_PCIE_AS_MEM: 3123d0407baSopenharmony_ci type = PCIE_ATU_TYPE_MEM; 3133d0407baSopenharmony_ci break; 3143d0407baSopenharmony_ci case DW_PCIE_AS_IO: 3153d0407baSopenharmony_ci type = PCIE_ATU_TYPE_IO; 3163d0407baSopenharmony_ci break; 3173d0407baSopenharmony_ci default: 3183d0407baSopenharmony_ci return -EINVAL; 3193d0407baSopenharmony_ci } 3203d0407baSopenharmony_ci 3213d0407baSopenharmony_ci rk_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, type | 3223d0407baSopenharmony_ci PCIE_ATU_FUNC_NUM(func_no)); 3233d0407baSopenharmony_ci rk_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2, 3243d0407baSopenharmony_ci PCIE_ATU_FUNC_NUM_MATCH_EN | 3253d0407baSopenharmony_ci PCIE_ATU_ENABLE | 3263d0407baSopenharmony_ci PCIE_ATU_BAR_MODE_ENABLE | (bar << 8)); 3273d0407baSopenharmony_ci 3283d0407baSopenharmony_ci /* 3293d0407baSopenharmony_ci * Make sure ATU enable takes effect before any subsequent config 3303d0407baSopenharmony_ci * and I/O accesses. 3313d0407baSopenharmony_ci */ 3323d0407baSopenharmony_ci for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) { 3333d0407baSopenharmony_ci val = rk_pcie_readl_ib_unroll(pci, index, 3343d0407baSopenharmony_ci PCIE_ATU_UNR_REGION_CTRL2); 3353d0407baSopenharmony_ci if (val & PCIE_ATU_ENABLE) 3363d0407baSopenharmony_ci return 0; 3373d0407baSopenharmony_ci 3383d0407baSopenharmony_ci mdelay(LINK_WAIT_IATU); 3393d0407baSopenharmony_ci } 3403d0407baSopenharmony_ci dev_err(pci->dev, "Inbound iATU is not being enabled\n"); 3413d0407baSopenharmony_ci 3423d0407baSopenharmony_ci return -EBUSY; 3433d0407baSopenharmony_ci} 3443d0407baSopenharmony_ci 3453d0407baSopenharmony_ci 3463d0407baSopenharmony_cistatic int rk_pcie_prog_inbound_atu(struct dw_pcie *pci, u8 func_no, int index, 3473d0407baSopenharmony_ci int bar, u64 cpu_addr, 3483d0407baSopenharmony_ci enum dw_pcie_as_type as_type) 3493d0407baSopenharmony_ci{ 3503d0407baSopenharmony_ci int type; 3513d0407baSopenharmony_ci u32 retries, val; 3523d0407baSopenharmony_ci 3533d0407baSopenharmony_ci if (pci->iatu_unroll_enabled) 3543d0407baSopenharmony_ci return rk_pcie_prog_inbound_atu_unroll(pci, func_no, index, bar, 3553d0407baSopenharmony_ci cpu_addr, as_type); 3563d0407baSopenharmony_ci 3573d0407baSopenharmony_ci dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, PCIE_ATU_REGION_INBOUND | 3583d0407baSopenharmony_ci index); 3593d0407baSopenharmony_ci dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_TARGET, lower_32_bits(cpu_addr)); 3603d0407baSopenharmony_ci dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_TARGET, upper_32_bits(cpu_addr)); 3613d0407baSopenharmony_ci 3623d0407baSopenharmony_ci switch (as_type) { 3633d0407baSopenharmony_ci case DW_PCIE_AS_MEM: 3643d0407baSopenharmony_ci type = PCIE_ATU_TYPE_MEM; 3653d0407baSopenharmony_ci break; 3663d0407baSopenharmony_ci case DW_PCIE_AS_IO: 3673d0407baSopenharmony_ci type = PCIE_ATU_TYPE_IO; 3683d0407baSopenharmony_ci break; 3693d0407baSopenharmony_ci default: 3703d0407baSopenharmony_ci return -EINVAL; 3713d0407baSopenharmony_ci } 3723d0407baSopenharmony_ci 3733d0407baSopenharmony_ci dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, type | 3743d0407baSopenharmony_ci PCIE_ATU_FUNC_NUM(func_no)); 3753d0407baSopenharmony_ci dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, PCIE_ATU_ENABLE | 3763d0407baSopenharmony_ci PCIE_ATU_FUNC_NUM_MATCH_EN | 3773d0407baSopenharmony_ci PCIE_ATU_BAR_MODE_ENABLE | (bar << 8)); 3783d0407baSopenharmony_ci 3793d0407baSopenharmony_ci /* 3803d0407baSopenharmony_ci * Make sure ATU enable takes effect before any subsequent config 3813d0407baSopenharmony_ci * and I/O accesses. 3823d0407baSopenharmony_ci */ 3833d0407baSopenharmony_ci for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) { 3843d0407baSopenharmony_ci val = dw_pcie_readl_dbi(pci, PCIE_ATU_CR2); 3853d0407baSopenharmony_ci if (val & PCIE_ATU_ENABLE) 3863d0407baSopenharmony_ci return 0; 3873d0407baSopenharmony_ci 3883d0407baSopenharmony_ci mdelay(LINK_WAIT_IATU); 3893d0407baSopenharmony_ci } 3903d0407baSopenharmony_ci dev_err(pci->dev, "Inbound iATU is not being enabled\n"); 3913d0407baSopenharmony_ci 3923d0407baSopenharmony_ci return -EBUSY; 3933d0407baSopenharmony_ci} 3943d0407baSopenharmony_ci 3953d0407baSopenharmony_cistatic int rk_pcie_ep_inbound_atu(struct rk_pcie *rk_pcie, 3963d0407baSopenharmony_ci enum pci_barno bar, dma_addr_t cpu_addr, 3973d0407baSopenharmony_ci enum dw_pcie_as_type as_type) 3983d0407baSopenharmony_ci{ 3993d0407baSopenharmony_ci int ret; 4003d0407baSopenharmony_ci u32 free_win; 4013d0407baSopenharmony_ci u8 func_no = 0x0; 4023d0407baSopenharmony_ci 4033d0407baSopenharmony_ci if (rk_pcie->in_suspend) { 4043d0407baSopenharmony_ci free_win = rk_pcie->bar_to_atu[bar]; 4053d0407baSopenharmony_ci } else { 4063d0407baSopenharmony_ci free_win = find_first_zero_bit(rk_pcie->ib_window_map, 4073d0407baSopenharmony_ci rk_pcie->num_ib_windows); 4083d0407baSopenharmony_ci if (free_win >= rk_pcie->num_ib_windows) { 4093d0407baSopenharmony_ci dev_err(rk_pcie->pci->dev, "No free inbound window\n"); 4103d0407baSopenharmony_ci return -EINVAL; 4113d0407baSopenharmony_ci } 4123d0407baSopenharmony_ci } 4133d0407baSopenharmony_ci 4143d0407baSopenharmony_ci ret = rk_pcie_prog_inbound_atu(rk_pcie->pci, func_no, free_win, bar, 4153d0407baSopenharmony_ci cpu_addr, as_type); 4163d0407baSopenharmony_ci if (ret < 0) { 4173d0407baSopenharmony_ci dev_err(rk_pcie->pci->dev, "Failed to program IB window\n"); 4183d0407baSopenharmony_ci return ret; 4193d0407baSopenharmony_ci } 4203d0407baSopenharmony_ci 4213d0407baSopenharmony_ci if (rk_pcie->in_suspend) 4223d0407baSopenharmony_ci return 0; 4233d0407baSopenharmony_ci 4243d0407baSopenharmony_ci rk_pcie->bar_to_atu[bar] = free_win; 4253d0407baSopenharmony_ci set_bit(free_win, rk_pcie->ib_window_map); 4263d0407baSopenharmony_ci 4273d0407baSopenharmony_ci return 0; 4283d0407baSopenharmony_ci} 4293d0407baSopenharmony_ci 4303d0407baSopenharmony_cistatic void rk_pcie_writel_ob_unroll(struct dw_pcie *pci, u32 index, u32 reg, 4313d0407baSopenharmony_ci u32 val) 4323d0407baSopenharmony_ci{ 4333d0407baSopenharmony_ci u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index); 4343d0407baSopenharmony_ci 4353d0407baSopenharmony_ci rk_pcie_writel_atu(pci, offset + reg, val); 4363d0407baSopenharmony_ci} 4373d0407baSopenharmony_ci 4383d0407baSopenharmony_cistatic u32 rk_pcie_readl_ob_unroll(struct dw_pcie *pci, u32 index, u32 reg) 4393d0407baSopenharmony_ci{ 4403d0407baSopenharmony_ci u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index); 4413d0407baSopenharmony_ci 4423d0407baSopenharmony_ci return rk_pcie_readl_atu(pci, offset + reg); 4433d0407baSopenharmony_ci} 4443d0407baSopenharmony_ci 4453d0407baSopenharmony_cistatic void rk_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no, 4463d0407baSopenharmony_ci int index, int type, 4473d0407baSopenharmony_ci u64 cpu_addr, u64 pci_addr, 4483d0407baSopenharmony_ci u32 size) 4493d0407baSopenharmony_ci{ 4503d0407baSopenharmony_ci u32 retries, val; 4513d0407baSopenharmony_ci u64 limit_addr = cpu_addr + size - 1; 4523d0407baSopenharmony_ci 4533d0407baSopenharmony_ci rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_BASE, 4543d0407baSopenharmony_ci lower_32_bits(cpu_addr)); 4553d0407baSopenharmony_ci rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_BASE, 4563d0407baSopenharmony_ci upper_32_bits(cpu_addr)); 4573d0407baSopenharmony_ci rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_LIMIT, 4583d0407baSopenharmony_ci lower_32_bits(limit_addr)); 4593d0407baSopenharmony_ci rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_LIMIT, 4603d0407baSopenharmony_ci upper_32_bits(limit_addr)); 4613d0407baSopenharmony_ci rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_TARGET, 4623d0407baSopenharmony_ci lower_32_bits(pci_addr)); 4633d0407baSopenharmony_ci rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET, 4643d0407baSopenharmony_ci upper_32_bits(pci_addr)); 4653d0407baSopenharmony_ci rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, 4663d0407baSopenharmony_ci type | PCIE_ATU_FUNC_NUM(func_no)); 4673d0407baSopenharmony_ci rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2, 4683d0407baSopenharmony_ci PCIE_ATU_ENABLE); 4693d0407baSopenharmony_ci 4703d0407baSopenharmony_ci /* 4713d0407baSopenharmony_ci * Make sure ATU enable takes effect before any subsequent config 4723d0407baSopenharmony_ci * and I/O accesses. 4733d0407baSopenharmony_ci */ 4743d0407baSopenharmony_ci for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) { 4753d0407baSopenharmony_ci val = rk_pcie_readl_ob_unroll(pci, index, 4763d0407baSopenharmony_ci PCIE_ATU_UNR_REGION_CTRL2); 4773d0407baSopenharmony_ci if (val & PCIE_ATU_ENABLE) 4783d0407baSopenharmony_ci return; 4793d0407baSopenharmony_ci 4803d0407baSopenharmony_ci mdelay(LINK_WAIT_IATU); 4813d0407baSopenharmony_ci } 4823d0407baSopenharmony_ci dev_err(pci->dev, "Outbound iATU is not being enabled\n"); 4833d0407baSopenharmony_ci} 4843d0407baSopenharmony_ci 4853d0407baSopenharmony_cistatic void rk_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, 4863d0407baSopenharmony_ci int type, u64 cpu_addr, u64 pci_addr, u32 size) 4873d0407baSopenharmony_ci{ 4883d0407baSopenharmony_ci u32 retries, val; 4893d0407baSopenharmony_ci 4903d0407baSopenharmony_ci if (pci->ops->cpu_addr_fixup) 4913d0407baSopenharmony_ci cpu_addr = pci->ops->cpu_addr_fixup(pci, cpu_addr); 4923d0407baSopenharmony_ci 4933d0407baSopenharmony_ci if (pci->iatu_unroll_enabled) { 4943d0407baSopenharmony_ci rk_pcie_prog_outbound_atu_unroll(pci, 0x0, index, type, 4953d0407baSopenharmony_ci cpu_addr, pci_addr, size); 4963d0407baSopenharmony_ci return; 4973d0407baSopenharmony_ci } 4983d0407baSopenharmony_ci 4993d0407baSopenharmony_ci dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, 5003d0407baSopenharmony_ci PCIE_ATU_REGION_OUTBOUND | index); 5013d0407baSopenharmony_ci dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_BASE, 5023d0407baSopenharmony_ci lower_32_bits(cpu_addr)); 5033d0407baSopenharmony_ci dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_BASE, 5043d0407baSopenharmony_ci upper_32_bits(cpu_addr)); 5053d0407baSopenharmony_ci dw_pcie_writel_dbi(pci, PCIE_ATU_LIMIT, 5063d0407baSopenharmony_ci lower_32_bits(cpu_addr + size - 1)); 5073d0407baSopenharmony_ci dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_TARGET, 5083d0407baSopenharmony_ci lower_32_bits(pci_addr)); 5093d0407baSopenharmony_ci dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_TARGET, 5103d0407baSopenharmony_ci upper_32_bits(pci_addr)); 5113d0407baSopenharmony_ci dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, type | 5123d0407baSopenharmony_ci PCIE_ATU_FUNC_NUM(0x0)); 5133d0407baSopenharmony_ci dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, PCIE_ATU_ENABLE); 5143d0407baSopenharmony_ci 5153d0407baSopenharmony_ci /* 5163d0407baSopenharmony_ci * Make sure ATU enable takes effect before any subsequent config 5173d0407baSopenharmony_ci * and I/O accesses. 5183d0407baSopenharmony_ci */ 5193d0407baSopenharmony_ci for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) { 5203d0407baSopenharmony_ci val = dw_pcie_readl_dbi(pci, PCIE_ATU_CR2); 5213d0407baSopenharmony_ci if (val & PCIE_ATU_ENABLE) 5223d0407baSopenharmony_ci return; 5233d0407baSopenharmony_ci 5243d0407baSopenharmony_ci mdelay(LINK_WAIT_IATU); 5253d0407baSopenharmony_ci } 5263d0407baSopenharmony_ci dev_err(pci->dev, "Outbound iATU is not being enabled\n"); 5273d0407baSopenharmony_ci} 5283d0407baSopenharmony_ci 5293d0407baSopenharmony_cistatic int rk_pcie_ep_outbound_atu(struct rk_pcie *rk_pcie, 5303d0407baSopenharmony_ci phys_addr_t phys_addr, u64 pci_addr, 5313d0407baSopenharmony_ci size_t size) 5323d0407baSopenharmony_ci{ 5333d0407baSopenharmony_ci u32 free_win; 5343d0407baSopenharmony_ci 5353d0407baSopenharmony_ci if (rk_pcie->in_suspend) { 5363d0407baSopenharmony_ci free_win = find_first_bit(rk_pcie->ob_window_map, 5373d0407baSopenharmony_ci rk_pcie->num_ob_windows); 5383d0407baSopenharmony_ci } else { 5393d0407baSopenharmony_ci free_win = find_first_zero_bit(rk_pcie->ob_window_map, 5403d0407baSopenharmony_ci rk_pcie->num_ob_windows); 5413d0407baSopenharmony_ci if (free_win >= rk_pcie->num_ob_windows) { 5423d0407baSopenharmony_ci dev_err(rk_pcie->pci->dev, "No free outbound window\n"); 5433d0407baSopenharmony_ci return -EINVAL; 5443d0407baSopenharmony_ci } 5453d0407baSopenharmony_ci } 5463d0407baSopenharmony_ci 5473d0407baSopenharmony_ci rk_pcie_prog_outbound_atu(rk_pcie->pci, free_win, PCIE_ATU_TYPE_MEM, 5483d0407baSopenharmony_ci phys_addr, pci_addr, size); 5493d0407baSopenharmony_ci 5503d0407baSopenharmony_ci if (rk_pcie->in_suspend) 5513d0407baSopenharmony_ci return 0; 5523d0407baSopenharmony_ci 5533d0407baSopenharmony_ci set_bit(free_win, rk_pcie->ob_window_map); 5543d0407baSopenharmony_ci rk_pcie->outbound_addr[free_win] = phys_addr; 5553d0407baSopenharmony_ci 5563d0407baSopenharmony_ci return 0; 5573d0407baSopenharmony_ci} 5583d0407baSopenharmony_ci 5593d0407baSopenharmony_cistatic void __rk_pcie_ep_reset_bar(struct rk_pcie *rk_pcie, 5603d0407baSopenharmony_ci enum pci_barno bar, int flags) 5613d0407baSopenharmony_ci{ 5623d0407baSopenharmony_ci u32 reg; 5633d0407baSopenharmony_ci 5643d0407baSopenharmony_ci reg = PCI_BASE_ADDRESS_0 + (4 * bar); 5653d0407baSopenharmony_ci dw_pcie_writel_dbi(rk_pcie->pci, reg, 0x0); 5663d0407baSopenharmony_ci if (flags & PCI_BASE_ADDRESS_MEM_TYPE_64) 5673d0407baSopenharmony_ci dw_pcie_writel_dbi(rk_pcie->pci, reg + 4, 0x0); 5683d0407baSopenharmony_ci} 5693d0407baSopenharmony_ci 5703d0407baSopenharmony_cistatic void rk_pcie_ep_reset_bar(struct rk_pcie *rk_pcie, enum pci_barno bar) 5713d0407baSopenharmony_ci{ 5723d0407baSopenharmony_ci __rk_pcie_ep_reset_bar(rk_pcie, bar, 0); 5733d0407baSopenharmony_ci} 5743d0407baSopenharmony_ci 5753d0407baSopenharmony_cistatic int rk_pcie_ep_atu_init(struct rk_pcie *rk_pcie) 5763d0407baSopenharmony_ci{ 5773d0407baSopenharmony_ci int ret; 5783d0407baSopenharmony_ci enum pci_barno bar; 5793d0407baSopenharmony_ci enum dw_pcie_as_type as_type; 5803d0407baSopenharmony_ci dma_addr_t cpu_addr; 5813d0407baSopenharmony_ci phys_addr_t phys_addr; 5823d0407baSopenharmony_ci u64 pci_addr; 5833d0407baSopenharmony_ci size_t size; 5843d0407baSopenharmony_ci 5853d0407baSopenharmony_ci for (bar = BAR_0; bar <= BAR_5; bar++) 5863d0407baSopenharmony_ci rk_pcie_ep_reset_bar(rk_pcie, bar); 5873d0407baSopenharmony_ci 5883d0407baSopenharmony_ci cpu_addr = rk_pcie->mem_start; 5893d0407baSopenharmony_ci as_type = DW_PCIE_AS_MEM; 5903d0407baSopenharmony_ci ret = rk_pcie_ep_inbound_atu(rk_pcie, BAR_0, cpu_addr, as_type); 5913d0407baSopenharmony_ci if (ret) 5923d0407baSopenharmony_ci return ret; 5933d0407baSopenharmony_ci 5943d0407baSopenharmony_ci phys_addr = 0x0; 5953d0407baSopenharmony_ci pci_addr = 0x0; 5963d0407baSopenharmony_ci size = SZ_2G; 5973d0407baSopenharmony_ci ret = rk_pcie_ep_outbound_atu(rk_pcie, phys_addr, pci_addr, size); 5983d0407baSopenharmony_ci if (ret) 5993d0407baSopenharmony_ci return ret; 6003d0407baSopenharmony_ci 6013d0407baSopenharmony_ci return 0; 6023d0407baSopenharmony_ci} 6033d0407baSopenharmony_ci 6043d0407baSopenharmony_cistatic inline void rk_pcie_set_mode(struct rk_pcie *rk_pcie) 6053d0407baSopenharmony_ci{ 6063d0407baSopenharmony_ci switch (rk_pcie->mode) { 6073d0407baSopenharmony_ci case RK_PCIE_EP_TYPE: 6083d0407baSopenharmony_ci rk_pcie_writel_apb(rk_pcie, 0x0, 0xf00000); 6093d0407baSopenharmony_ci break; 6103d0407baSopenharmony_ci case RK_PCIE_RC_TYPE: 6113d0407baSopenharmony_ci rk_pcie_writel_apb(rk_pcie, 0x0, 0xf00040); 6123d0407baSopenharmony_ci /* 6133d0407baSopenharmony_ci * Disable order rule for CPL can't pass halted P queue. 6143d0407baSopenharmony_ci * Need to check producer-consumer model. 6153d0407baSopenharmony_ci * Just for RK1808 platform. 6163d0407baSopenharmony_ci */ 6173d0407baSopenharmony_ci if (rk_pcie->is_rk1808) 6183d0407baSopenharmony_ci dw_pcie_writel_dbi(rk_pcie->pci, 6193d0407baSopenharmony_ci PCIE_PL_ORDER_RULE_CTRL_OFF, 6203d0407baSopenharmony_ci 0xff00); 6213d0407baSopenharmony_ci break; 6223d0407baSopenharmony_ci } 6233d0407baSopenharmony_ci} 6243d0407baSopenharmony_ci 6253d0407baSopenharmony_cistatic inline void rk_pcie_link_status_clear(struct rk_pcie *rk_pcie) 6263d0407baSopenharmony_ci{ 6273d0407baSopenharmony_ci rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_GENERAL_DEBUG, 0x0); 6283d0407baSopenharmony_ci} 6293d0407baSopenharmony_ci 6303d0407baSopenharmony_cistatic inline void rk_pcie_disable_ltssm(struct rk_pcie *rk_pcie) 6313d0407baSopenharmony_ci{ 6323d0407baSopenharmony_ci rk_pcie_writel_apb(rk_pcie, 0x0, 0xc0008); 6333d0407baSopenharmony_ci} 6343d0407baSopenharmony_ci 6353d0407baSopenharmony_cistatic inline void rk_pcie_enable_ltssm(struct rk_pcie *rk_pcie) 6363d0407baSopenharmony_ci{ 6373d0407baSopenharmony_ci rk_pcie_writel_apb(rk_pcie, 0x0, 0xC000C); 6383d0407baSopenharmony_ci} 6393d0407baSopenharmony_ci 6403d0407baSopenharmony_cistatic int rk_pcie_link_up(struct dw_pcie *pci) 6413d0407baSopenharmony_ci{ 6423d0407baSopenharmony_ci struct rk_pcie *rk_pcie = to_rk_pcie(pci); 6433d0407baSopenharmony_ci u32 val; 6443d0407baSopenharmony_ci 6453d0407baSopenharmony_ci if (rk_pcie->is_rk1808) { 6463d0407baSopenharmony_ci val = rk_pcie_readl_apb(rk_pcie, PCIE_CLIENT_GENERAL_DEBUG); 6473d0407baSopenharmony_ci if ((val & (PCIE_PHY_LINKUP | PCIE_DATA_LINKUP)) == 0x3 && 6483d0407baSopenharmony_ci ((val & GENMASK(15, 10)) >> 10) == 0x11) 6493d0407baSopenharmony_ci return 1; 6503d0407baSopenharmony_ci } else { 6513d0407baSopenharmony_ci val = rk_pcie_readl_apb(rk_pcie, PCIE_CLIENT_LTSSM_STATUS); 6523d0407baSopenharmony_ci if ((val & (RDLH_LINKUP | SMLH_LINKUP)) == 0x30000) 6533d0407baSopenharmony_ci return 1; 6543d0407baSopenharmony_ci } 6553d0407baSopenharmony_ci 6563d0407baSopenharmony_ci return 0; 6573d0407baSopenharmony_ci} 6583d0407baSopenharmony_ci 6593d0407baSopenharmony_cistatic void rk_pcie_enable_debug(struct rk_pcie *rk_pcie) 6603d0407baSopenharmony_ci{ 6613d0407baSopenharmony_ci#if RK_PCIE_DBG 6623d0407baSopenharmony_ci if (rk_pcie->is_rk1808 == true) 6633d0407baSopenharmony_ci return; 6643d0407baSopenharmony_ci 6653d0407baSopenharmony_ci rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_DBG_FIFO_PTN_HIT_D0, 6663d0407baSopenharmony_ci PCIE_CLIENT_DBG_TRANSITION_DATA); 6673d0407baSopenharmony_ci rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_DBG_FIFO_PTN_HIT_D1, 6683d0407baSopenharmony_ci PCIE_CLIENT_DBG_TRANSITION_DATA); 6693d0407baSopenharmony_ci rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_DBG_FIFO_TRN_HIT_D0, 6703d0407baSopenharmony_ci PCIE_CLIENT_DBG_TRANSITION_DATA); 6713d0407baSopenharmony_ci rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_DBG_FIFO_TRN_HIT_D1, 6723d0407baSopenharmony_ci PCIE_CLIENT_DBG_TRANSITION_DATA); 6733d0407baSopenharmony_ci rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_DBG_FIFO_MODE_CON, 6743d0407baSopenharmony_ci PCIE_CLIENT_DBF_EN); 6753d0407baSopenharmony_ci#endif 6763d0407baSopenharmony_ci} 6773d0407baSopenharmony_ci 6783d0407baSopenharmony_cistatic void rk_pcie_debug_dump(struct rk_pcie *rk_pcie) 6793d0407baSopenharmony_ci{ 6803d0407baSopenharmony_ci#if RK_PCIE_DBG 6813d0407baSopenharmony_ci u32 loop; 6823d0407baSopenharmony_ci struct dw_pcie *pci = rk_pcie->pci; 6833d0407baSopenharmony_ci 6843d0407baSopenharmony_ci dev_info(pci->dev, "ltssm = 0x%x\n", 6853d0407baSopenharmony_ci rk_pcie_readl_apb(rk_pcie, PCIE_CLIENT_LTSSM_STATUS)); 6863d0407baSopenharmony_ci for (loop = 0; loop < 64; loop++) 6873d0407baSopenharmony_ci dev_info(pci->dev, "fifo_status = 0x%x\n", 6883d0407baSopenharmony_ci rk_pcie_readl_apb(rk_pcie, PCIE_CLIENT_DBG_FIFO_STATUS)); 6893d0407baSopenharmony_ci#endif 6903d0407baSopenharmony_ci} 6913d0407baSopenharmony_ci 6923d0407baSopenharmony_cistatic int rk_pcie_establish_link(struct dw_pcie *pci) 6933d0407baSopenharmony_ci{ 6943d0407baSopenharmony_ci int retries, power; 6953d0407baSopenharmony_ci struct rk_pcie *rk_pcie = to_rk_pcie(pci); 6963d0407baSopenharmony_ci bool std_rc = rk_pcie->mode == RK_PCIE_RC_TYPE && !rk_pcie->dma_obj; 6973d0407baSopenharmony_ci 6983d0407baSopenharmony_ci /* 6993d0407baSopenharmony_ci * For standard RC, even if the link has been setup by firmware, 7003d0407baSopenharmony_ci * we still need to reset link as we need to remove all resource info 7013d0407baSopenharmony_ci * from devices, for instance BAR, as it wasn't assigned by kernel. 7023d0407baSopenharmony_ci */ 7033d0407baSopenharmony_ci if (dw_pcie_link_up(pci) && !std_rc) { 7043d0407baSopenharmony_ci dev_err(pci->dev, "link is already up\n"); 7053d0407baSopenharmony_ci return 0; 7063d0407baSopenharmony_ci } 7073d0407baSopenharmony_ci 7083d0407baSopenharmony_ci /* Rest the device */ 7093d0407baSopenharmony_ci gpiod_set_value_cansleep(rk_pcie->rst_gpio, 0); 7103d0407baSopenharmony_ci 7113d0407baSopenharmony_ci rk_pcie_disable_ltssm(rk_pcie); 7123d0407baSopenharmony_ci rk_pcie_link_status_clear(rk_pcie); 7133d0407baSopenharmony_ci rk_pcie_enable_debug(rk_pcie); 7143d0407baSopenharmony_ci 7153d0407baSopenharmony_ci /* Enable client reset or link down interrupt */ 7163d0407baSopenharmony_ci rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_INTR_MASK, 0x40000); 7173d0407baSopenharmony_ci 7183d0407baSopenharmony_ci /* Enable LTSSM */ 7193d0407baSopenharmony_ci rk_pcie_enable_ltssm(rk_pcie); 7203d0407baSopenharmony_ci 7213d0407baSopenharmony_ci /* 7223d0407baSopenharmony_ci * In resume routine, function devices' resume function must be late after 7233d0407baSopenharmony_ci * controllers'. Some devices, such as Wi-Fi, need special IO setting before 7243d0407baSopenharmony_ci * finishing training. So there must be timeout here. These kinds of devices 7253d0407baSopenharmony_ci * need rescan devices by its driver when used. So no need to waste time waiting 7263d0407baSopenharmony_ci * for training pass. 7273d0407baSopenharmony_ci */ 7283d0407baSopenharmony_ci if (rk_pcie->in_suspend && rk_pcie->skip_scan_in_resume) { 7293d0407baSopenharmony_ci rfkill_get_wifi_power_state(&power); 7303d0407baSopenharmony_ci if (!power) { 7313d0407baSopenharmony_ci gpiod_set_value_cansleep(rk_pcie->rst_gpio, 1); 7323d0407baSopenharmony_ci return 0; 7333d0407baSopenharmony_ci } 7343d0407baSopenharmony_ci } 7353d0407baSopenharmony_ci 7363d0407baSopenharmony_ci /* 7373d0407baSopenharmony_ci * PCIe requires the refclk to be stable for 100µs prior to releasing 7383d0407baSopenharmony_ci * PERST and T_PVPERL (Power stable to PERST# inactive) should be a 7393d0407baSopenharmony_ci * minimum of 100ms. See table 2-4 in section 2.6.2 AC, the PCI Express 7403d0407baSopenharmony_ci * Card Electromechanical Specification 3.0. So 100ms in total is the min 7413d0407baSopenharmony_ci * requuirement here. We add a 200ms for sake of hoping everthings work fine. 7423d0407baSopenharmony_ci */ 7433d0407baSopenharmony_ci msleep(200); 7443d0407baSopenharmony_ci gpiod_set_value_cansleep(rk_pcie->rst_gpio, 1); 7453d0407baSopenharmony_ci 7463d0407baSopenharmony_ci /* 7473d0407baSopenharmony_ci * Add this 1ms delay because we observe link is always up stably after it and 7483d0407baSopenharmony_ci * could help us save 20ms for scanning devices. 7493d0407baSopenharmony_ci */ 7503d0407baSopenharmony_ci usleep_range(1000, 1100); 7513d0407baSopenharmony_ci 7523d0407baSopenharmony_ci for (retries = 0; retries < 100; retries++) { 7533d0407baSopenharmony_ci if (dw_pcie_link_up(pci)) { 7543d0407baSopenharmony_ci /* 7553d0407baSopenharmony_ci * We may be here in case of L0 in Gen1. But if EP is capable 7563d0407baSopenharmony_ci * of Gen2 or Gen3, Gen switch may happen just in this time, but 7573d0407baSopenharmony_ci * we keep on accessing devices in unstable link status. Given 7583d0407baSopenharmony_ci * that LTSSM max timeout is 24ms per period, we can wait a bit 7593d0407baSopenharmony_ci * more for Gen switch. 7603d0407baSopenharmony_ci */ 7613d0407baSopenharmony_ci msleep(50); 7623d0407baSopenharmony_ci dev_info(pci->dev, "PCIe Link up, LTSSM is 0x%x\n", 7633d0407baSopenharmony_ci rk_pcie_readl_apb(rk_pcie, PCIE_CLIENT_LTSSM_STATUS)); 7643d0407baSopenharmony_ci rk_pcie_debug_dump(rk_pcie); 7653d0407baSopenharmony_ci return 0; 7663d0407baSopenharmony_ci } 7673d0407baSopenharmony_ci 7683d0407baSopenharmony_ci dev_info_ratelimited(pci->dev, "PCIe Linking... LTSSM is 0x%x\n", 7693d0407baSopenharmony_ci rk_pcie_readl_apb(rk_pcie, PCIE_CLIENT_LTSSM_STATUS)); 7703d0407baSopenharmony_ci rk_pcie_debug_dump(rk_pcie); 7713d0407baSopenharmony_ci msleep(20); 7723d0407baSopenharmony_ci } 7733d0407baSopenharmony_ci 7743d0407baSopenharmony_ci dev_err(pci->dev, "PCIe Link Fail\n"); 7753d0407baSopenharmony_ci 7763d0407baSopenharmony_ci return rk_pcie->is_signal_test == true ? 0 : -EINVAL; 7773d0407baSopenharmony_ci} 7783d0407baSopenharmony_ci 7793d0407baSopenharmony_cistatic int rk_pcie_host_init_dma_trx(struct rk_pcie *rk_pcie) 7803d0407baSopenharmony_ci{ 7813d0407baSopenharmony_ci rk_pcie->dma_obj = rk_pcie_dma_obj_probe(rk_pcie->pci->dev); 7823d0407baSopenharmony_ci if (IS_ERR(rk_pcie->dma_obj)) { 7833d0407baSopenharmony_ci dev_err(rk_pcie->pci->dev, "failed to prepare dma object\n"); 7843d0407baSopenharmony_ci return -EINVAL; 7853d0407baSopenharmony_ci } 7863d0407baSopenharmony_ci 7873d0407baSopenharmony_ci /* Enable client write and read interrupt */ 7883d0407baSopenharmony_ci rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_INTR_MASK, 0xc000000); 7893d0407baSopenharmony_ci 7903d0407baSopenharmony_ci /* Enable core write interrupt */ 7913d0407baSopenharmony_ci dw_pcie_writel_dbi(rk_pcie->pci, PCIE_DMA_OFFSET + PCIE_DMA_WR_INT_MASK, 7923d0407baSopenharmony_ci 0x0); 7933d0407baSopenharmony_ci /* Enable core read interrupt */ 7943d0407baSopenharmony_ci dw_pcie_writel_dbi(rk_pcie->pci, PCIE_DMA_OFFSET + PCIE_DMA_RD_INT_MASK, 7953d0407baSopenharmony_ci 0x0); 7963d0407baSopenharmony_ci return 0; 7973d0407baSopenharmony_ci} 7983d0407baSopenharmony_ci 7993d0407baSopenharmony_cistatic int rk_pci_find_resbar_capability(struct rk_pcie *rk_pcie) 8003d0407baSopenharmony_ci{ 8013d0407baSopenharmony_ci u32 header; 8023d0407baSopenharmony_ci int ttl; 8033d0407baSopenharmony_ci int start = 0; 8043d0407baSopenharmony_ci int pos = PCI_CFG_SPACE_SIZE; 8053d0407baSopenharmony_ci int cap = PCI_EXT_CAP_ID_REBAR; 8063d0407baSopenharmony_ci 8073d0407baSopenharmony_ci /* minimum 8 bytes per capability */ 8083d0407baSopenharmony_ci ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8; 8093d0407baSopenharmony_ci 8103d0407baSopenharmony_ci header = dw_pcie_readl_dbi(rk_pcie->pci, pos); 8113d0407baSopenharmony_ci 8123d0407baSopenharmony_ci /* 8133d0407baSopenharmony_ci * If we have no capabilities, this is indicated by cap ID, 8143d0407baSopenharmony_ci * cap version and next pointer all being 0. 8153d0407baSopenharmony_ci */ 8163d0407baSopenharmony_ci if (header == 0) 8173d0407baSopenharmony_ci return 0; 8183d0407baSopenharmony_ci 8193d0407baSopenharmony_ci while (ttl-- > 0) { 8203d0407baSopenharmony_ci if (PCI_EXT_CAP_ID(header) == cap && pos != start) 8213d0407baSopenharmony_ci return pos; 8223d0407baSopenharmony_ci 8233d0407baSopenharmony_ci pos = PCI_EXT_CAP_NEXT(header); 8243d0407baSopenharmony_ci if (pos < PCI_CFG_SPACE_SIZE) 8253d0407baSopenharmony_ci break; 8263d0407baSopenharmony_ci 8273d0407baSopenharmony_ci header = dw_pcie_readl_dbi(rk_pcie->pci, pos); 8283d0407baSopenharmony_ci if (!header) 8293d0407baSopenharmony_ci break; 8303d0407baSopenharmony_ci } 8313d0407baSopenharmony_ci 8323d0407baSopenharmony_ci return 0; 8333d0407baSopenharmony_ci} 8343d0407baSopenharmony_ci 8353d0407baSopenharmony_cistatic void rk_pcie_ep_setup(struct rk_pcie *rk_pcie) 8363d0407baSopenharmony_ci{ 8373d0407baSopenharmony_ci int ret; 8383d0407baSopenharmony_ci u32 val; 8393d0407baSopenharmony_ci u32 lanes; 8403d0407baSopenharmony_ci struct device *dev = rk_pcie->pci->dev; 8413d0407baSopenharmony_ci struct device_node *np = dev->of_node; 8423d0407baSopenharmony_ci int resbar_base; 8433d0407baSopenharmony_ci int bar; 8443d0407baSopenharmony_ci 8453d0407baSopenharmony_ci /* Enable client write and read interrupt */ 8463d0407baSopenharmony_ci rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_INTR_MASK, 0xc000000); 8473d0407baSopenharmony_ci 8483d0407baSopenharmony_ci /* Enable core write interrupt */ 8493d0407baSopenharmony_ci dw_pcie_writel_dbi(rk_pcie->pci, PCIE_DMA_OFFSET + PCIE_DMA_WR_INT_MASK, 8503d0407baSopenharmony_ci 0x0); 8513d0407baSopenharmony_ci /* Enable core read interrupt */ 8523d0407baSopenharmony_ci dw_pcie_writel_dbi(rk_pcie->pci, PCIE_DMA_OFFSET + PCIE_DMA_RD_INT_MASK, 8533d0407baSopenharmony_ci 0x0); 8543d0407baSopenharmony_ci 8553d0407baSopenharmony_ci ret = of_property_read_u32(np, "num-lanes", &lanes); 8563d0407baSopenharmony_ci if (ret) 8573d0407baSopenharmony_ci lanes = 0; 8583d0407baSopenharmony_ci 8593d0407baSopenharmony_ci /* Set the number of lanes */ 8603d0407baSopenharmony_ci val = dw_pcie_readl_dbi(rk_pcie->pci, PCIE_PORT_LINK_CONTROL); 8613d0407baSopenharmony_ci val &= ~PORT_LINK_MODE_MASK; 8623d0407baSopenharmony_ci switch (lanes) { 8633d0407baSopenharmony_ci case 1: 8643d0407baSopenharmony_ci val |= PORT_LINK_MODE_1_LANES; 8653d0407baSopenharmony_ci break; 8663d0407baSopenharmony_ci case 2: 8673d0407baSopenharmony_ci val |= PORT_LINK_MODE_2_LANES; 8683d0407baSopenharmony_ci break; 8693d0407baSopenharmony_ci case 4: 8703d0407baSopenharmony_ci val |= PORT_LINK_MODE_4_LANES; 8713d0407baSopenharmony_ci break; 8723d0407baSopenharmony_ci case 8: 8733d0407baSopenharmony_ci val |= PORT_LINK_MODE_8_LANES; 8743d0407baSopenharmony_ci break; 8753d0407baSopenharmony_ci default: 8763d0407baSopenharmony_ci dev_err(dev, "num-lanes %u: invalid value\n", lanes); 8773d0407baSopenharmony_ci return; 8783d0407baSopenharmony_ci } 8793d0407baSopenharmony_ci 8803d0407baSopenharmony_ci dw_pcie_writel_dbi(rk_pcie->pci, PCIE_PORT_LINK_CONTROL, val); 8813d0407baSopenharmony_ci 8823d0407baSopenharmony_ci /* Set link width speed control register */ 8833d0407baSopenharmony_ci val = dw_pcie_readl_dbi(rk_pcie->pci, PCIE_LINK_WIDTH_SPEED_CONTROL); 8843d0407baSopenharmony_ci val &= ~PORT_LOGIC_LINK_WIDTH_MASK; 8853d0407baSopenharmony_ci switch (lanes) { 8863d0407baSopenharmony_ci case 1: 8873d0407baSopenharmony_ci val |= PORT_LOGIC_LINK_WIDTH_1_LANES; 8883d0407baSopenharmony_ci break; 8893d0407baSopenharmony_ci case 2: 8903d0407baSopenharmony_ci val |= PORT_LOGIC_LINK_WIDTH_2_LANES; 8913d0407baSopenharmony_ci break; 8923d0407baSopenharmony_ci case 4: 8933d0407baSopenharmony_ci val |= PORT_LOGIC_LINK_WIDTH_4_LANES; 8943d0407baSopenharmony_ci break; 8953d0407baSopenharmony_ci case 8: 8963d0407baSopenharmony_ci val |= PORT_LOGIC_LINK_WIDTH_8_LANES; 8973d0407baSopenharmony_ci break; 8983d0407baSopenharmony_ci } 8993d0407baSopenharmony_ci 9003d0407baSopenharmony_ci val |= PCIE_DIRECT_SPEED_CHANGE; 9013d0407baSopenharmony_ci 9023d0407baSopenharmony_ci dw_pcie_writel_dbi(rk_pcie->pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val); 9033d0407baSopenharmony_ci 9043d0407baSopenharmony_ci /* Enable bus master and memory space */ 9053d0407baSopenharmony_ci dw_pcie_writel_dbi(rk_pcie->pci, PCIE_TYPE0_STATUS_COMMAND_REG, 0x6); 9063d0407baSopenharmony_ci 9073d0407baSopenharmony_ci resbar_base = rk_pci_find_resbar_capability(rk_pcie); 9083d0407baSopenharmony_ci if (!resbar_base) { 9093d0407baSopenharmony_ci dev_warn(dev, "failed to find resbar_base\n"); 9103d0407baSopenharmony_ci } else { 9113d0407baSopenharmony_ci /* Resize BAR0 to support 512GB */ 9123d0407baSopenharmony_ci dw_pcie_writel_dbi(rk_pcie->pci, resbar_base + 0x4, 0xfffff0); 9133d0407baSopenharmony_ci /* Bit13-8 set to 19 means 2^19MB (512GB) */ 9143d0407baSopenharmony_ci dw_pcie_writel_dbi(rk_pcie->pci, resbar_base + 0x8, 0x13c0); 9153d0407baSopenharmony_ci /* Resize bar1 - bar6 to 64M */ 9163d0407baSopenharmony_ci for (bar = 1; bar < 6; bar++) { 9173d0407baSopenharmony_ci dw_pcie_writel_dbi(rk_pcie->pci, resbar_base + 9183d0407baSopenharmony_ci 0x4 + bar * 0x8, 0xfffff0); 9193d0407baSopenharmony_ci dw_pcie_writel_dbi(rk_pcie->pci, resbar_base + 9203d0407baSopenharmony_ci 0x8 + bar * 0x8, 0x6c0); 9213d0407baSopenharmony_ci } 9223d0407baSopenharmony_ci } 9233d0407baSopenharmony_ci 9243d0407baSopenharmony_ci /* Device id and class id needed for request bar address */ 9253d0407baSopenharmony_ci dw_pcie_writew_dbi(rk_pcie->pci, PCI_DEVICE_ID, 0x356a); 9263d0407baSopenharmony_ci dw_pcie_writew_dbi(rk_pcie->pci, PCI_CLASS_DEVICE, 0x0580); 9273d0407baSopenharmony_ci 9283d0407baSopenharmony_ci /* Set shadow BAR0 */ 9293d0407baSopenharmony_ci if (rk_pcie->is_rk1808) { 9303d0407baSopenharmony_ci val = rk_pcie->mem_size - 1; 9313d0407baSopenharmony_ci dw_pcie_writel_dbi(rk_pcie->pci, PCIE_SB_BAR0_MASK_REG, val); 9323d0407baSopenharmony_ci } 9333d0407baSopenharmony_ci} 9343d0407baSopenharmony_ci 9353d0407baSopenharmony_cistatic int rk_pcie_ep_win_parse(struct rk_pcie *rk_pcie) 9363d0407baSopenharmony_ci{ 9373d0407baSopenharmony_ci int ret; 9383d0407baSopenharmony_ci void *addr; 9393d0407baSopenharmony_ci struct device *dev = rk_pcie->pci->dev; 9403d0407baSopenharmony_ci struct device_node *np = dev->of_node; 9413d0407baSopenharmony_ci 9423d0407baSopenharmony_ci ret = of_property_read_u32(np, "num-ib-windows", 9433d0407baSopenharmony_ci &rk_pcie->num_ib_windows); 9443d0407baSopenharmony_ci if (ret < 0) { 9453d0407baSopenharmony_ci dev_err(dev, "unable to read *num-ib-windows* property\n"); 9463d0407baSopenharmony_ci return ret; 9473d0407baSopenharmony_ci } 9483d0407baSopenharmony_ci 9493d0407baSopenharmony_ci if (rk_pcie->num_ib_windows > MAX_IATU_IN) { 9503d0407baSopenharmony_ci dev_err(dev, "Invalid *num-ib-windows*\n"); 9513d0407baSopenharmony_ci return -EINVAL; 9523d0407baSopenharmony_ci } 9533d0407baSopenharmony_ci 9543d0407baSopenharmony_ci ret = of_property_read_u32(np, "num-ob-windows", 9553d0407baSopenharmony_ci &rk_pcie->num_ob_windows); 9563d0407baSopenharmony_ci if (ret < 0) { 9573d0407baSopenharmony_ci dev_err(dev, "Unable to read *num-ob-windows* property\n"); 9583d0407baSopenharmony_ci return ret; 9593d0407baSopenharmony_ci } 9603d0407baSopenharmony_ci 9613d0407baSopenharmony_ci if (rk_pcie->num_ob_windows > MAX_IATU_OUT) { 9623d0407baSopenharmony_ci dev_err(dev, "Invalid *num-ob-windows*\n"); 9633d0407baSopenharmony_ci return -EINVAL; 9643d0407baSopenharmony_ci } 9653d0407baSopenharmony_ci 9663d0407baSopenharmony_ci rk_pcie->ib_window_map = devm_kcalloc(dev, 9673d0407baSopenharmony_ci BITS_TO_LONGS(rk_pcie->num_ib_windows), 9683d0407baSopenharmony_ci sizeof(long), GFP_KERNEL); 9693d0407baSopenharmony_ci if (!rk_pcie->ib_window_map) 9703d0407baSopenharmony_ci return -ENOMEM; 9713d0407baSopenharmony_ci 9723d0407baSopenharmony_ci rk_pcie->ob_window_map = devm_kcalloc(dev, 9733d0407baSopenharmony_ci BITS_TO_LONGS(rk_pcie->num_ob_windows), 9743d0407baSopenharmony_ci sizeof(long), GFP_KERNEL); 9753d0407baSopenharmony_ci if (!rk_pcie->ob_window_map) 9763d0407baSopenharmony_ci return -ENOMEM; 9773d0407baSopenharmony_ci 9783d0407baSopenharmony_ci addr = devm_kcalloc(dev, rk_pcie->num_ob_windows, sizeof(phys_addr_t), 9793d0407baSopenharmony_ci GFP_KERNEL); 9803d0407baSopenharmony_ci if (!addr) 9813d0407baSopenharmony_ci return -ENOMEM; 9823d0407baSopenharmony_ci 9833d0407baSopenharmony_ci rk_pcie->outbound_addr = addr; 9843d0407baSopenharmony_ci 9853d0407baSopenharmony_ci return 0; 9863d0407baSopenharmony_ci} 9873d0407baSopenharmony_ci 9883d0407baSopenharmony_cistatic int rk_pcie_msi_host_init(struct pcie_port *pp) 9893d0407baSopenharmony_ci{ 9903d0407baSopenharmony_ci return 0; 9913d0407baSopenharmony_ci} 9923d0407baSopenharmony_ci 9933d0407baSopenharmony_cistatic int rk_pcie_host_init(struct pcie_port *pp) 9943d0407baSopenharmony_ci{ 9953d0407baSopenharmony_ci int ret; 9963d0407baSopenharmony_ci struct dw_pcie *pci = to_dw_pcie_from_pp(pp); 9973d0407baSopenharmony_ci 9983d0407baSopenharmony_ci dw_pcie_setup_rc(pp); 9993d0407baSopenharmony_ci 10003d0407baSopenharmony_ci ret = rk_pcie_establish_link(pci); 10013d0407baSopenharmony_ci 10023d0407baSopenharmony_ci return ret; 10033d0407baSopenharmony_ci} 10043d0407baSopenharmony_ci 10053d0407baSopenharmony_cistatic const struct dw_pcie_host_ops rk_pcie_host_ops = { 10063d0407baSopenharmony_ci .host_init = rk_pcie_host_init, 10073d0407baSopenharmony_ci .msi_host_init = rk_pcie_msi_host_init, 10083d0407baSopenharmony_ci}; 10093d0407baSopenharmony_ci 10103d0407baSopenharmony_cistatic int rk_add_pcie_port(struct rk_pcie *rk_pcie) 10113d0407baSopenharmony_ci{ 10123d0407baSopenharmony_ci int ret; 10133d0407baSopenharmony_ci struct dw_pcie *pci = rk_pcie->pci; 10143d0407baSopenharmony_ci struct pcie_port *pp = &pci->pp; 10153d0407baSopenharmony_ci struct device *dev = pci->dev; 10163d0407baSopenharmony_ci 10173d0407baSopenharmony_ci pp->ops = &rk_pcie_host_ops; 10183d0407baSopenharmony_ci 10193d0407baSopenharmony_ci ret = dw_pcie_host_init(pp); 10203d0407baSopenharmony_ci if (ret) { 10213d0407baSopenharmony_ci dev_err(dev, "failed to initialize host\n"); 10223d0407baSopenharmony_ci return ret; 10233d0407baSopenharmony_ci } 10243d0407baSopenharmony_ci 10253d0407baSopenharmony_ci ret = rk_pcie_host_init_dma_trx(rk_pcie); 10263d0407baSopenharmony_ci if (ret) { 10273d0407baSopenharmony_ci dev_err(dev, "failed to init host dma trx\n"); 10283d0407baSopenharmony_ci return ret; 10293d0407baSopenharmony_ci } 10303d0407baSopenharmony_ci return 0; 10313d0407baSopenharmony_ci} 10323d0407baSopenharmony_ci 10333d0407baSopenharmony_cistatic int rk_pcie_add_ep(struct rk_pcie *rk_pcie) 10343d0407baSopenharmony_ci{ 10353d0407baSopenharmony_ci int ret; 10363d0407baSopenharmony_ci struct device *dev = rk_pcie->pci->dev; 10373d0407baSopenharmony_ci struct device_node *np = dev->of_node; 10383d0407baSopenharmony_ci struct device_node *mem; 10393d0407baSopenharmony_ci struct resource reg; 10403d0407baSopenharmony_ci 10413d0407baSopenharmony_ci mem = of_parse_phandle(np, "memory-region", 0); 10423d0407baSopenharmony_ci if (!mem) { 10433d0407baSopenharmony_ci dev_err(dev, "missing \"memory-region\" property\n"); 10443d0407baSopenharmony_ci return -ENODEV; 10453d0407baSopenharmony_ci } 10463d0407baSopenharmony_ci 10473d0407baSopenharmony_ci ret = of_address_to_resource(mem, 0, ®); 10483d0407baSopenharmony_ci if (ret < 0) { 10493d0407baSopenharmony_ci dev_err(dev, "missing \"reg\" property\n"); 10503d0407baSopenharmony_ci return ret; 10513d0407baSopenharmony_ci } 10523d0407baSopenharmony_ci 10533d0407baSopenharmony_ci rk_pcie->mem_start = reg.start; 10543d0407baSopenharmony_ci rk_pcie->mem_size = resource_size(®); 10553d0407baSopenharmony_ci 10563d0407baSopenharmony_ci ret = rk_pcie_ep_win_parse(rk_pcie); 10573d0407baSopenharmony_ci if (ret) { 10583d0407baSopenharmony_ci dev_err(dev, "failed to parse ep dts\n"); 10593d0407baSopenharmony_ci return ret; 10603d0407baSopenharmony_ci } 10613d0407baSopenharmony_ci 10623d0407baSopenharmony_ci rk_pcie->pci->atu_base = rk_pcie->pci->dbi_base + DEFAULT_DBI_ATU_OFFSET; 10633d0407baSopenharmony_ci rk_pcie->pci->iatu_unroll_enabled = rk_pcie_iatu_unroll_enabled(rk_pcie->pci); 10643d0407baSopenharmony_ci 10653d0407baSopenharmony_ci ret = rk_pcie_ep_atu_init(rk_pcie); 10663d0407baSopenharmony_ci if (ret) { 10673d0407baSopenharmony_ci dev_err(dev, "failed to init ep device\n"); 10683d0407baSopenharmony_ci return ret; 10693d0407baSopenharmony_ci } 10703d0407baSopenharmony_ci 10713d0407baSopenharmony_ci rk_pcie_ep_setup(rk_pcie); 10723d0407baSopenharmony_ci 10733d0407baSopenharmony_ci ret = rk_pcie_establish_link(rk_pcie->pci); 10743d0407baSopenharmony_ci if (ret) { 10753d0407baSopenharmony_ci dev_err(dev, "failed to establish pcie link\n"); 10763d0407baSopenharmony_ci return ret; 10773d0407baSopenharmony_ci } 10783d0407baSopenharmony_ci 10793d0407baSopenharmony_ci rk_pcie->dma_obj = rk_pcie_dma_obj_probe(dev); 10803d0407baSopenharmony_ci if (IS_ERR(rk_pcie->dma_obj)) { 10813d0407baSopenharmony_ci dev_err(dev, "failed to prepare dma object\n"); 10823d0407baSopenharmony_ci return -EINVAL; 10833d0407baSopenharmony_ci } 10843d0407baSopenharmony_ci 10853d0407baSopenharmony_ci return 0; 10863d0407baSopenharmony_ci} 10873d0407baSopenharmony_ci 10883d0407baSopenharmony_cistatic void rk_pcie_clk_deinit(struct rk_pcie *rk_pcie) 10893d0407baSopenharmony_ci{ 10903d0407baSopenharmony_ci clk_bulk_disable(rk_pcie->clk_cnt, rk_pcie->clks); 10913d0407baSopenharmony_ci clk_bulk_unprepare(rk_pcie->clk_cnt, rk_pcie->clks); 10923d0407baSopenharmony_ci} 10933d0407baSopenharmony_ci 10943d0407baSopenharmony_cistatic int rk_pcie_clk_init(struct rk_pcie *rk_pcie) 10953d0407baSopenharmony_ci{ 10963d0407baSopenharmony_ci struct device *dev = rk_pcie->pci->dev; 10973d0407baSopenharmony_ci struct property *prop; 10983d0407baSopenharmony_ci const char *name; 10993d0407baSopenharmony_ci int i = 0, ret, count; 11003d0407baSopenharmony_ci 11013d0407baSopenharmony_ci count = of_property_count_strings(dev->of_node, "clock-names"); 11023d0407baSopenharmony_ci if (count < 1) 11033d0407baSopenharmony_ci return -ENODEV; 11043d0407baSopenharmony_ci 11053d0407baSopenharmony_ci rk_pcie->clks = devm_kcalloc(dev, count, 11063d0407baSopenharmony_ci sizeof(struct clk_bulk_data), 11073d0407baSopenharmony_ci GFP_KERNEL); 11083d0407baSopenharmony_ci if (!rk_pcie->clks) 11093d0407baSopenharmony_ci return -ENOMEM; 11103d0407baSopenharmony_ci 11113d0407baSopenharmony_ci rk_pcie->clk_cnt = count; 11123d0407baSopenharmony_ci 11133d0407baSopenharmony_ci of_property_for_each_string(dev->of_node, "clock-names", prop, name) { 11143d0407baSopenharmony_ci rk_pcie->clks[i].id = name; 11153d0407baSopenharmony_ci if (!rk_pcie->clks[i].id) 11163d0407baSopenharmony_ci return -ENOMEM; 11173d0407baSopenharmony_ci i++; 11183d0407baSopenharmony_ci } 11193d0407baSopenharmony_ci 11203d0407baSopenharmony_ci ret = devm_clk_bulk_get(dev, count, rk_pcie->clks); 11213d0407baSopenharmony_ci if (ret) 11223d0407baSopenharmony_ci return ret; 11233d0407baSopenharmony_ci 11243d0407baSopenharmony_ci ret = clk_bulk_prepare(count, rk_pcie->clks); 11253d0407baSopenharmony_ci if (ret) 11263d0407baSopenharmony_ci return ret; 11273d0407baSopenharmony_ci 11283d0407baSopenharmony_ci ret = clk_bulk_enable(count, rk_pcie->clks); 11293d0407baSopenharmony_ci if (ret) { 11303d0407baSopenharmony_ci clk_bulk_unprepare(count, rk_pcie->clks); 11313d0407baSopenharmony_ci return ret; 11323d0407baSopenharmony_ci } 11333d0407baSopenharmony_ci 11343d0407baSopenharmony_ci return 0; 11353d0407baSopenharmony_ci} 11363d0407baSopenharmony_ci 11373d0407baSopenharmony_cistatic int rk_pcie_resource_get(struct platform_device *pdev, 11383d0407baSopenharmony_ci struct rk_pcie *rk_pcie) 11393d0407baSopenharmony_ci{ 11403d0407baSopenharmony_ci struct resource *dbi_base; 11413d0407baSopenharmony_ci struct resource *apb_base; 11423d0407baSopenharmony_ci 11433d0407baSopenharmony_ci dbi_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, 11443d0407baSopenharmony_ci "pcie-dbi"); 11453d0407baSopenharmony_ci if (!dbi_base) { 11463d0407baSopenharmony_ci dev_err(&pdev->dev, "get pcie-dbi failed\n"); 11473d0407baSopenharmony_ci return -ENODEV; 11483d0407baSopenharmony_ci } 11493d0407baSopenharmony_ci 11503d0407baSopenharmony_ci rk_pcie->dbi_base = devm_ioremap_resource(&pdev->dev, dbi_base); 11513d0407baSopenharmony_ci if (IS_ERR(rk_pcie->dbi_base)) 11523d0407baSopenharmony_ci return PTR_ERR(rk_pcie->dbi_base); 11533d0407baSopenharmony_ci 11543d0407baSopenharmony_ci rk_pcie->pci->dbi_base = rk_pcie->dbi_base; 11553d0407baSopenharmony_ci 11563d0407baSopenharmony_ci apb_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, 11573d0407baSopenharmony_ci "pcie-apb"); 11583d0407baSopenharmony_ci if (!apb_base) { 11593d0407baSopenharmony_ci dev_err(&pdev->dev, "get pcie-apb failed\n"); 11603d0407baSopenharmony_ci return -ENODEV; 11613d0407baSopenharmony_ci } 11623d0407baSopenharmony_ci rk_pcie->apb_base = devm_ioremap_resource(&pdev->dev, apb_base); 11633d0407baSopenharmony_ci if (IS_ERR(rk_pcie->apb_base)) 11643d0407baSopenharmony_ci return PTR_ERR(rk_pcie->apb_base); 11653d0407baSopenharmony_ci 11663d0407baSopenharmony_ci /* 11673d0407baSopenharmony_ci * Rest the device before enabling power because some of the 11683d0407baSopenharmony_ci * platforms may use external refclk input with the some power 11693d0407baSopenharmony_ci * rail connect to 100MHz OSC chip. So once the power is up for 11703d0407baSopenharmony_ci * the slot and the refclk is available, which isn't quite follow 11713d0407baSopenharmony_ci * the spec. We should make sure it is in reset state before 11723d0407baSopenharmony_ci * everthing's ready. 11733d0407baSopenharmony_ci */ 11743d0407baSopenharmony_ci rk_pcie->rst_gpio = devm_gpiod_get_optional(&pdev->dev, "reset", 11753d0407baSopenharmony_ci GPIOD_OUT_LOW); 11763d0407baSopenharmony_ci if (IS_ERR(rk_pcie->rst_gpio)) { 11773d0407baSopenharmony_ci dev_err(&pdev->dev, "invalid reset-gpios property in node\n"); 11783d0407baSopenharmony_ci return PTR_ERR(rk_pcie->rst_gpio); 11793d0407baSopenharmony_ci } 11803d0407baSopenharmony_ci 11813d0407baSopenharmony_ci return 0; 11823d0407baSopenharmony_ci} 11833d0407baSopenharmony_ci 11843d0407baSopenharmony_cistatic int rk_pcie_phy_init(struct rk_pcie *rk_pcie) 11853d0407baSopenharmony_ci{ 11863d0407baSopenharmony_ci int ret; 11873d0407baSopenharmony_ci struct device *dev = rk_pcie->pci->dev; 11883d0407baSopenharmony_ci 11893d0407baSopenharmony_ci rk_pcie->phy = devm_phy_get(dev, "pcie-phy"); 11903d0407baSopenharmony_ci if (IS_ERR(rk_pcie->phy)) { 11913d0407baSopenharmony_ci if (PTR_ERR(rk_pcie->phy) != -EPROBE_DEFER) 11923d0407baSopenharmony_ci dev_info(dev, "missing phy\n"); 11933d0407baSopenharmony_ci return PTR_ERR(rk_pcie->phy); 11943d0407baSopenharmony_ci } 11953d0407baSopenharmony_ci 11963d0407baSopenharmony_ci switch (rk_pcie->mode) { 11973d0407baSopenharmony_ci case RK_PCIE_RC_TYPE: 11983d0407baSopenharmony_ci rk_pcie->phy_mode = PHY_MODE_PCIE; /* make no sense */ 11993d0407baSopenharmony_ci rk_pcie->phy_sub_mode = PHY_MODE_PCIE_RC; 12003d0407baSopenharmony_ci break; 12013d0407baSopenharmony_ci case RK_PCIE_EP_TYPE: 12023d0407baSopenharmony_ci rk_pcie->phy_mode = PHY_MODE_PCIE; 12033d0407baSopenharmony_ci rk_pcie->phy_sub_mode = PHY_MODE_PCIE_EP; 12043d0407baSopenharmony_ci break; 12053d0407baSopenharmony_ci } 12063d0407baSopenharmony_ci 12073d0407baSopenharmony_ci ret = phy_set_mode_ext(rk_pcie->phy, rk_pcie->phy_mode, 12083d0407baSopenharmony_ci rk_pcie->phy_sub_mode); 12093d0407baSopenharmony_ci if (ret) { 12103d0407baSopenharmony_ci dev_err(dev, "fail to set phy to mode %s, err %d\n", 12113d0407baSopenharmony_ci (rk_pcie->phy_sub_mode == PHY_MODE_PCIE_RC) ? "RC" : "EP", 12123d0407baSopenharmony_ci ret); 12133d0407baSopenharmony_ci return ret; 12143d0407baSopenharmony_ci } 12153d0407baSopenharmony_ci 12163d0407baSopenharmony_ci if (rk_pcie->bifurcation) 12173d0407baSopenharmony_ci ret = phy_set_mode_ext(rk_pcie->phy, rk_pcie->phy_mode, 12183d0407baSopenharmony_ci PHY_MODE_PCIE_BIFURCATION); 12193d0407baSopenharmony_ci 12203d0407baSopenharmony_ci ret = phy_init(rk_pcie->phy); 12213d0407baSopenharmony_ci if (ret < 0) { 12223d0407baSopenharmony_ci dev_err(dev, "fail to init phy, err %d\n", ret); 12233d0407baSopenharmony_ci return ret; 12243d0407baSopenharmony_ci } 12253d0407baSopenharmony_ci 12263d0407baSopenharmony_ci phy_power_on(rk_pcie->phy); 12273d0407baSopenharmony_ci 12283d0407baSopenharmony_ci return 0; 12293d0407baSopenharmony_ci} 12303d0407baSopenharmony_ci 12313d0407baSopenharmony_cistatic int rk_pcie_reset_control_release(struct rk_pcie *rk_pcie) 12323d0407baSopenharmony_ci{ 12333d0407baSopenharmony_ci struct device *dev = rk_pcie->pci->dev; 12343d0407baSopenharmony_ci struct property *prop; 12353d0407baSopenharmony_ci const char *name; 12363d0407baSopenharmony_ci int ret, count, i = 0; 12373d0407baSopenharmony_ci 12383d0407baSopenharmony_ci count = of_property_count_strings(dev->of_node, "reset-names"); 12393d0407baSopenharmony_ci if (count < 1) 12403d0407baSopenharmony_ci return -ENODEV; 12413d0407baSopenharmony_ci 12423d0407baSopenharmony_ci rk_pcie->rsts = devm_kcalloc(dev, count, 12433d0407baSopenharmony_ci sizeof(struct reset_bulk_data), 12443d0407baSopenharmony_ci GFP_KERNEL); 12453d0407baSopenharmony_ci if (!rk_pcie->rsts) 12463d0407baSopenharmony_ci return -ENOMEM; 12473d0407baSopenharmony_ci 12483d0407baSopenharmony_ci of_property_for_each_string(dev->of_node, "reset-names", 12493d0407baSopenharmony_ci prop, name) { 12503d0407baSopenharmony_ci rk_pcie->rsts[i].id = name; 12513d0407baSopenharmony_ci if (!rk_pcie->rsts[i].id) 12523d0407baSopenharmony_ci return -ENOMEM; 12533d0407baSopenharmony_ci i++; 12543d0407baSopenharmony_ci } 12553d0407baSopenharmony_ci 12563d0407baSopenharmony_ci for (i = 0; i < count; i++) { 12573d0407baSopenharmony_ci rk_pcie->rsts[i].rst = devm_reset_control_get_exclusive(dev, 12583d0407baSopenharmony_ci rk_pcie->rsts[i].id); 12593d0407baSopenharmony_ci if (IS_ERR_OR_NULL(rk_pcie->rsts[i].rst)) { 12603d0407baSopenharmony_ci dev_err(dev, "failed to get %s\n", 12613d0407baSopenharmony_ci rk_pcie->clks[i].id); 12623d0407baSopenharmony_ci return -PTR_ERR(rk_pcie->rsts[i].rst); 12633d0407baSopenharmony_ci } 12643d0407baSopenharmony_ci } 12653d0407baSopenharmony_ci 12663d0407baSopenharmony_ci for (i = 0; i < count; i++) { 12673d0407baSopenharmony_ci ret = reset_control_deassert(rk_pcie->rsts[i].rst); 12683d0407baSopenharmony_ci if (ret) { 12693d0407baSopenharmony_ci dev_err(dev, "failed to release %s\n", 12703d0407baSopenharmony_ci rk_pcie->rsts[i].id); 12713d0407baSopenharmony_ci return ret; 12723d0407baSopenharmony_ci } 12733d0407baSopenharmony_ci } 12743d0407baSopenharmony_ci 12753d0407baSopenharmony_ci return 0; 12763d0407baSopenharmony_ci} 12773d0407baSopenharmony_ci 12783d0407baSopenharmony_cistatic int rk_pcie_reset_grant_ctrl(struct rk_pcie *rk_pcie, 12793d0407baSopenharmony_ci bool enable) 12803d0407baSopenharmony_ci{ 12813d0407baSopenharmony_ci int ret; 12823d0407baSopenharmony_ci u32 val = (0x1 << 18); /* Write mask bit */ 12833d0407baSopenharmony_ci 12843d0407baSopenharmony_ci if (enable) 12853d0407baSopenharmony_ci val |= (0x1 << 2); 12863d0407baSopenharmony_ci 12873d0407baSopenharmony_ci ret = regmap_write(rk_pcie->usb_pcie_grf, 0x0, val); 12883d0407baSopenharmony_ci return ret; 12893d0407baSopenharmony_ci} 12903d0407baSopenharmony_ci 12913d0407baSopenharmony_cistatic void rk_pcie_start_dma_rd(struct dma_trx_obj *obj, int ctr_off) 12923d0407baSopenharmony_ci{ 12933d0407baSopenharmony_ci struct rk_pcie *rk_pcie = dev_get_drvdata(obj->dev); 12943d0407baSopenharmony_ci struct dma_table *cur = obj->cur; 12953d0407baSopenharmony_ci 12963d0407baSopenharmony_ci dw_pcie_writel_dbi(rk_pcie->pci, PCIE_DMA_OFFSET + PCIE_DMA_RD_ENB, 12973d0407baSopenharmony_ci cur->enb.asdword); 12983d0407baSopenharmony_ci dw_pcie_writel_dbi(rk_pcie->pci, ctr_off + PCIE_DMA_RD_CTRL_LO, 12993d0407baSopenharmony_ci cur->ctx_reg.ctrllo.asdword); 13003d0407baSopenharmony_ci dw_pcie_writel_dbi(rk_pcie->pci, ctr_off + PCIE_DMA_RD_CTRL_HI, 13013d0407baSopenharmony_ci cur->ctx_reg.ctrlhi.asdword); 13023d0407baSopenharmony_ci dw_pcie_writel_dbi(rk_pcie->pci, ctr_off + PCIE_DMA_RD_XFERSIZE, 13033d0407baSopenharmony_ci cur->ctx_reg.xfersize); 13043d0407baSopenharmony_ci dw_pcie_writel_dbi(rk_pcie->pci, ctr_off + PCIE_DMA_RD_SAR_PTR_LO, 13053d0407baSopenharmony_ci cur->ctx_reg.sarptrlo); 13063d0407baSopenharmony_ci dw_pcie_writel_dbi(rk_pcie->pci, ctr_off + PCIE_DMA_RD_SAR_PTR_HI, 13073d0407baSopenharmony_ci cur->ctx_reg.sarptrhi); 13083d0407baSopenharmony_ci dw_pcie_writel_dbi(rk_pcie->pci, ctr_off + PCIE_DMA_RD_DAR_PTR_LO, 13093d0407baSopenharmony_ci cur->ctx_reg.darptrlo); 13103d0407baSopenharmony_ci dw_pcie_writel_dbi(rk_pcie->pci, ctr_off + PCIE_DMA_RD_DAR_PTR_HI, 13113d0407baSopenharmony_ci cur->ctx_reg.darptrhi); 13123d0407baSopenharmony_ci dw_pcie_writel_dbi(rk_pcie->pci, PCIE_DMA_OFFSET + PCIE_DMA_RD_DOORBELL, 13133d0407baSopenharmony_ci cur->start.asdword); 13143d0407baSopenharmony_ci} 13153d0407baSopenharmony_ci 13163d0407baSopenharmony_cistatic void rk_pcie_start_dma_wr(struct dma_trx_obj *obj, int ctr_off) 13173d0407baSopenharmony_ci{ 13183d0407baSopenharmony_ci struct rk_pcie *rk_pcie = dev_get_drvdata(obj->dev); 13193d0407baSopenharmony_ci struct dma_table *cur = obj->cur; 13203d0407baSopenharmony_ci 13213d0407baSopenharmony_ci dw_pcie_writel_dbi(rk_pcie->pci, PCIE_DMA_OFFSET + PCIE_DMA_WR_ENB, 13223d0407baSopenharmony_ci cur->enb.asdword); 13233d0407baSopenharmony_ci dw_pcie_writel_dbi(rk_pcie->pci, ctr_off + PCIE_DMA_WR_CTRL_LO, 13243d0407baSopenharmony_ci cur->ctx_reg.ctrllo.asdword); 13253d0407baSopenharmony_ci dw_pcie_writel_dbi(rk_pcie->pci, ctr_off + PCIE_DMA_WR_CTRL_HI, 13263d0407baSopenharmony_ci cur->ctx_reg.ctrlhi.asdword); 13273d0407baSopenharmony_ci dw_pcie_writel_dbi(rk_pcie->pci, ctr_off + PCIE_DMA_WR_XFERSIZE, 13283d0407baSopenharmony_ci cur->ctx_reg.xfersize); 13293d0407baSopenharmony_ci dw_pcie_writel_dbi(rk_pcie->pci, ctr_off + PCIE_DMA_WR_SAR_PTR_LO, 13303d0407baSopenharmony_ci cur->ctx_reg.sarptrlo); 13313d0407baSopenharmony_ci dw_pcie_writel_dbi(rk_pcie->pci, ctr_off + PCIE_DMA_WR_SAR_PTR_HI, 13323d0407baSopenharmony_ci cur->ctx_reg.sarptrhi); 13333d0407baSopenharmony_ci dw_pcie_writel_dbi(rk_pcie->pci, ctr_off + PCIE_DMA_WR_DAR_PTR_LO, 13343d0407baSopenharmony_ci cur->ctx_reg.darptrlo); 13353d0407baSopenharmony_ci dw_pcie_writel_dbi(rk_pcie->pci, ctr_off + PCIE_DMA_WR_DAR_PTR_HI, 13363d0407baSopenharmony_ci cur->ctx_reg.darptrhi); 13373d0407baSopenharmony_ci dw_pcie_writel_dbi(rk_pcie->pci, ctr_off + PCIE_DMA_WR_WEILO, 13383d0407baSopenharmony_ci cur->weilo.asdword); 13393d0407baSopenharmony_ci dw_pcie_writel_dbi(rk_pcie->pci, PCIE_DMA_OFFSET + PCIE_DMA_WR_DOORBELL, 13403d0407baSopenharmony_ci cur->start.asdword); 13413d0407baSopenharmony_ci} 13423d0407baSopenharmony_ci 13433d0407baSopenharmony_cistatic void rk_pcie_start_dma_dwc(struct dma_trx_obj *obj) 13443d0407baSopenharmony_ci{ 13453d0407baSopenharmony_ci int dir = obj->cur->dir; 13463d0407baSopenharmony_ci int chn = obj->cur->chn; 13473d0407baSopenharmony_ci 13483d0407baSopenharmony_ci int ctr_off = PCIE_DMA_OFFSET + chn * 0x200; 13493d0407baSopenharmony_ci 13503d0407baSopenharmony_ci if (dir == DMA_FROM_BUS) 13513d0407baSopenharmony_ci rk_pcie_start_dma_rd(obj, ctr_off); 13523d0407baSopenharmony_ci else if (dir == DMA_TO_BUS) 13533d0407baSopenharmony_ci rk_pcie_start_dma_wr(obj, ctr_off); 13543d0407baSopenharmony_ci} 13553d0407baSopenharmony_ci 13563d0407baSopenharmony_cistatic void rk_pcie_config_dma_dwc(struct dma_table *table) 13573d0407baSopenharmony_ci{ 13583d0407baSopenharmony_ci table->enb.enb = 0x1; 13593d0407baSopenharmony_ci table->ctx_reg.ctrllo.lie = 0x1; 13603d0407baSopenharmony_ci table->ctx_reg.ctrllo.rie = 0x0; 13613d0407baSopenharmony_ci table->ctx_reg.ctrllo.td = 0x1; 13623d0407baSopenharmony_ci table->ctx_reg.ctrlhi.asdword = 0x0; 13633d0407baSopenharmony_ci table->ctx_reg.xfersize = table->buf_size; 13643d0407baSopenharmony_ci if (table->dir == DMA_FROM_BUS) { 13653d0407baSopenharmony_ci table->ctx_reg.sarptrlo = (u32)(table->bus & 0xffffffff); 13663d0407baSopenharmony_ci table->ctx_reg.sarptrhi = (u32)(table->bus >> 32); 13673d0407baSopenharmony_ci table->ctx_reg.darptrlo = (u32)(table->local & 0xffffffff); 13683d0407baSopenharmony_ci table->ctx_reg.darptrhi = (u32)(table->local >> 32); 13693d0407baSopenharmony_ci } else if (table->dir == DMA_TO_BUS) { 13703d0407baSopenharmony_ci table->ctx_reg.sarptrlo = (u32)(table->local & 0xffffffff); 13713d0407baSopenharmony_ci table->ctx_reg.sarptrhi = (u32)(table->local >> 32); 13723d0407baSopenharmony_ci table->ctx_reg.darptrlo = (u32)(table->bus & 0xffffffff); 13733d0407baSopenharmony_ci table->ctx_reg.darptrhi = (u32)(table->bus >> 32); 13743d0407baSopenharmony_ci } 13753d0407baSopenharmony_ci table->weilo.weight0 = 0x0; 13763d0407baSopenharmony_ci table->start.stop = 0x0; 13773d0407baSopenharmony_ci table->start.chnl = table->chn; 13783d0407baSopenharmony_ci} 13793d0407baSopenharmony_ci 13803d0407baSopenharmony_cistatic inline void 13813d0407baSopenharmony_cirk_pcie_handle_dma_interrupt(struct rk_pcie *rk_pcie) 13823d0407baSopenharmony_ci{ 13833d0407baSopenharmony_ci struct dma_trx_obj *obj = rk_pcie->dma_obj; 13843d0407baSopenharmony_ci struct dma_table *cur; 13853d0407baSopenharmony_ci 13863d0407baSopenharmony_ci if (!obj) 13873d0407baSopenharmony_ci return; 13883d0407baSopenharmony_ci 13893d0407baSopenharmony_ci cur = obj->cur; 13903d0407baSopenharmony_ci if (!cur) { 13913d0407baSopenharmony_ci pr_err("no pcie dma table\n"); 13923d0407baSopenharmony_ci return; 13933d0407baSopenharmony_ci } 13943d0407baSopenharmony_ci 13953d0407baSopenharmony_ci obj->dma_free = true; 13963d0407baSopenharmony_ci obj->irq_num++; 13973d0407baSopenharmony_ci 13983d0407baSopenharmony_ci if (cur->dir == DMA_TO_BUS) { 13993d0407baSopenharmony_ci if (list_empty(&obj->tbl_list)) { 14003d0407baSopenharmony_ci if (obj->dma_free && 14013d0407baSopenharmony_ci obj->loop_count >= obj->loop_count_threshold) 14023d0407baSopenharmony_ci complete(&obj->done); 14033d0407baSopenharmony_ci } 14043d0407baSopenharmony_ci } 14053d0407baSopenharmony_ci} 14063d0407baSopenharmony_ci 14073d0407baSopenharmony_cistatic irqreturn_t rk_pcie_sys_irq_handler(int irq, void *arg) 14083d0407baSopenharmony_ci{ 14093d0407baSopenharmony_ci struct rk_pcie *rk_pcie = arg; 14103d0407baSopenharmony_ci u32 chn = 0; 14113d0407baSopenharmony_ci union int_status status; 14123d0407baSopenharmony_ci union int_clear clears; 14133d0407baSopenharmony_ci u32 reg, val; 14143d0407baSopenharmony_ci 14153d0407baSopenharmony_ci status.asdword = dw_pcie_readl_dbi(rk_pcie->pci, PCIE_DMA_OFFSET + 14163d0407baSopenharmony_ci PCIE_DMA_WR_INT_STATUS); 14173d0407baSopenharmony_ci 14183d0407baSopenharmony_ci if (rk_pcie->dma_obj && rk_pcie->dma_obj->cur) 14193d0407baSopenharmony_ci chn = rk_pcie->dma_obj->cur->chn; 14203d0407baSopenharmony_ci 14213d0407baSopenharmony_ci if (status.donesta & BIT(chn)) { 14223d0407baSopenharmony_ci clears.doneclr = 0x1 << chn; 14233d0407baSopenharmony_ci dw_pcie_writel_dbi(rk_pcie->pci, PCIE_DMA_OFFSET + 14243d0407baSopenharmony_ci PCIE_DMA_WR_INT_CLEAR, clears.asdword); 14253d0407baSopenharmony_ci rk_pcie_handle_dma_interrupt(rk_pcie); 14263d0407baSopenharmony_ci } 14273d0407baSopenharmony_ci 14283d0407baSopenharmony_ci if (status.abortsta & BIT(chn)) { 14293d0407baSopenharmony_ci dev_err(rk_pcie->pci->dev, "%s, abort\n", __func__); 14303d0407baSopenharmony_ci clears.abortclr = 0x1 << chn; 14313d0407baSopenharmony_ci dw_pcie_writel_dbi(rk_pcie->pci, PCIE_DMA_OFFSET + 14323d0407baSopenharmony_ci PCIE_DMA_WR_INT_CLEAR, clears.asdword); 14333d0407baSopenharmony_ci } 14343d0407baSopenharmony_ci 14353d0407baSopenharmony_ci status.asdword = dw_pcie_readl_dbi(rk_pcie->pci, PCIE_DMA_OFFSET + 14363d0407baSopenharmony_ci PCIE_DMA_RD_INT_STATUS); 14373d0407baSopenharmony_ci 14383d0407baSopenharmony_ci if (status.donesta & BIT(chn)) { 14393d0407baSopenharmony_ci clears.doneclr = 0x1 << chn; 14403d0407baSopenharmony_ci dw_pcie_writel_dbi(rk_pcie->pci, PCIE_DMA_OFFSET + 14413d0407baSopenharmony_ci PCIE_DMA_RD_INT_CLEAR, clears.asdword); 14423d0407baSopenharmony_ci rk_pcie_handle_dma_interrupt(rk_pcie); 14433d0407baSopenharmony_ci } 14443d0407baSopenharmony_ci 14453d0407baSopenharmony_ci if (status.abortsta & BIT(chn)) { 14463d0407baSopenharmony_ci dev_err(rk_pcie->pci->dev, "%s, abort\n", __func__); 14473d0407baSopenharmony_ci clears.abortclr = 0x1 << chn; 14483d0407baSopenharmony_ci dw_pcie_writel_dbi(rk_pcie->pci, PCIE_DMA_OFFSET + 14493d0407baSopenharmony_ci PCIE_DMA_RD_INT_CLEAR, clears.asdword); 14503d0407baSopenharmony_ci } 14513d0407baSopenharmony_ci 14523d0407baSopenharmony_ci reg = rk_pcie_readl_apb(rk_pcie, PCIE_CLIENT_INTR_STATUS_MISC); 14533d0407baSopenharmony_ci if (reg & BIT(2)) { 14543d0407baSopenharmony_ci /* Setup command register */ 14553d0407baSopenharmony_ci val = dw_pcie_readl_dbi(rk_pcie->pci, PCI_COMMAND); 14563d0407baSopenharmony_ci val &= 0xffff0000; 14573d0407baSopenharmony_ci val |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | 14583d0407baSopenharmony_ci PCI_COMMAND_MASTER | PCI_COMMAND_SERR; 14593d0407baSopenharmony_ci dw_pcie_writel_dbi(rk_pcie->pci, PCI_COMMAND, val); 14603d0407baSopenharmony_ci } 14613d0407baSopenharmony_ci 14623d0407baSopenharmony_ci rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_INTR_STATUS_MISC, reg); 14633d0407baSopenharmony_ci 14643d0407baSopenharmony_ci return IRQ_HANDLED; 14653d0407baSopenharmony_ci} 14663d0407baSopenharmony_ci 14673d0407baSopenharmony_cistatic int rk_pcie_request_sys_irq(struct rk_pcie *rk_pcie, 14683d0407baSopenharmony_ci struct platform_device *pdev) 14693d0407baSopenharmony_ci{ 14703d0407baSopenharmony_ci int irq; 14713d0407baSopenharmony_ci int ret; 14723d0407baSopenharmony_ci 14733d0407baSopenharmony_ci irq = platform_get_irq_byname(pdev, "sys"); 14743d0407baSopenharmony_ci if (irq < 0) { 14753d0407baSopenharmony_ci dev_err(rk_pcie->pci->dev, "missing sys IRQ resource\n"); 14763d0407baSopenharmony_ci return -EINVAL; 14773d0407baSopenharmony_ci } 14783d0407baSopenharmony_ci 14793d0407baSopenharmony_ci ret = devm_request_irq(rk_pcie->pci->dev, irq, rk_pcie_sys_irq_handler, 14803d0407baSopenharmony_ci IRQF_SHARED, "pcie-sys", rk_pcie); 14813d0407baSopenharmony_ci if (ret) { 14823d0407baSopenharmony_ci dev_err(rk_pcie->pci->dev, "failed to request PCIe subsystem IRQ\n"); 14833d0407baSopenharmony_ci return ret; 14843d0407baSopenharmony_ci } 14853d0407baSopenharmony_ci 14863d0407baSopenharmony_ci return 0; 14873d0407baSopenharmony_ci} 14883d0407baSopenharmony_ci 14893d0407baSopenharmony_cistatic const struct rk_pcie_of_data rk_pcie_rc_of_data = { 14903d0407baSopenharmony_ci .mode = RK_PCIE_RC_TYPE, 14913d0407baSopenharmony_ci}; 14923d0407baSopenharmony_ci 14933d0407baSopenharmony_cistatic const struct rk_pcie_of_data rk_pcie_ep_of_data = { 14943d0407baSopenharmony_ci .mode = RK_PCIE_EP_TYPE, 14953d0407baSopenharmony_ci}; 14963d0407baSopenharmony_ci 14973d0407baSopenharmony_cistatic const struct of_device_id rk_pcie_of_match[] = { 14983d0407baSopenharmony_ci { 14993d0407baSopenharmony_ci .compatible = "rockchip,rk1808-pcie", 15003d0407baSopenharmony_ci .data = &rk_pcie_rc_of_data, 15013d0407baSopenharmony_ci }, 15023d0407baSopenharmony_ci { 15033d0407baSopenharmony_ci .compatible = "rockchip,rk1808-pcie-ep", 15043d0407baSopenharmony_ci .data = &rk_pcie_ep_of_data, 15053d0407baSopenharmony_ci }, 15063d0407baSopenharmony_ci { 15073d0407baSopenharmony_ci .compatible = "rockchip,rk3568-pcie", 15083d0407baSopenharmony_ci .data = &rk_pcie_rc_of_data, 15093d0407baSopenharmony_ci }, 15103d0407baSopenharmony_ci { 15113d0407baSopenharmony_ci .compatible = "rockchip,rk3568-pcie-ep", 15123d0407baSopenharmony_ci .data = &rk_pcie_ep_of_data, 15133d0407baSopenharmony_ci }, 15143d0407baSopenharmony_ci { 15153d0407baSopenharmony_ci .compatible = "rockchip,rk3588-pcie", 15163d0407baSopenharmony_ci .data = &rk_pcie_rc_of_data, 15173d0407baSopenharmony_ci }, 15183d0407baSopenharmony_ci { 15193d0407baSopenharmony_ci .compatible = "rockchip,rk3588-pcie-ep", 15203d0407baSopenharmony_ci .data = &rk_pcie_ep_of_data, 15213d0407baSopenharmony_ci }, 15223d0407baSopenharmony_ci {}, 15233d0407baSopenharmony_ci}; 15243d0407baSopenharmony_ci 15253d0407baSopenharmony_ciMODULE_DEVICE_TABLE(of, rk_pcie_of_match); 15263d0407baSopenharmony_ci 15273d0407baSopenharmony_cistatic const struct dw_pcie_ops dw_pcie_ops = { 15283d0407baSopenharmony_ci .start_link = rk_pcie_establish_link, 15293d0407baSopenharmony_ci .link_up = rk_pcie_link_up, 15303d0407baSopenharmony_ci}; 15313d0407baSopenharmony_ci 15323d0407baSopenharmony_cistatic int rk1808_pcie_fixup(struct rk_pcie *rk_pcie, struct device_node *np) 15333d0407baSopenharmony_ci{ 15343d0407baSopenharmony_ci int ret; 15353d0407baSopenharmony_ci struct device *dev = rk_pcie->pci->dev; 15363d0407baSopenharmony_ci 15373d0407baSopenharmony_ci rk_pcie->usb_pcie_grf = syscon_regmap_lookup_by_phandle(np, 15383d0407baSopenharmony_ci "rockchip,usbpciegrf"); 15393d0407baSopenharmony_ci if (IS_ERR(rk_pcie->usb_pcie_grf)) { 15403d0407baSopenharmony_ci dev_err(dev, "failed to find usb_pcie_grf regmap\n"); 15413d0407baSopenharmony_ci return PTR_ERR(rk_pcie->usb_pcie_grf); 15423d0407baSopenharmony_ci } 15433d0407baSopenharmony_ci 15443d0407baSopenharmony_ci rk_pcie->pmu_grf = syscon_regmap_lookup_by_phandle(np, 15453d0407baSopenharmony_ci "rockchip,pmugrf"); 15463d0407baSopenharmony_ci if (IS_ERR(rk_pcie->pmu_grf)) { 15473d0407baSopenharmony_ci dev_err(dev, "failed to find pmugrf regmap\n"); 15483d0407baSopenharmony_ci return PTR_ERR(rk_pcie->pmu_grf); 15493d0407baSopenharmony_ci } 15503d0407baSopenharmony_ci 15513d0407baSopenharmony_ci /* Workaround for pcie, switch to PCIe_PRSTNm0 */ 15523d0407baSopenharmony_ci ret = regmap_write(rk_pcie->pmu_grf, 0x100, 0x01000100); 15533d0407baSopenharmony_ci if (ret) 15543d0407baSopenharmony_ci return ret; 15553d0407baSopenharmony_ci 15563d0407baSopenharmony_ci ret = regmap_write(rk_pcie->pmu_grf, 0x0, 0x0c000000); 15573d0407baSopenharmony_ci if (ret) 15583d0407baSopenharmony_ci return ret; 15593d0407baSopenharmony_ci 15603d0407baSopenharmony_ci /* release link reset grant */ 15613d0407baSopenharmony_ci ret = rk_pcie_reset_grant_ctrl(rk_pcie, true); 15623d0407baSopenharmony_ci return ret; 15633d0407baSopenharmony_ci} 15643d0407baSopenharmony_ci 15653d0407baSopenharmony_cistatic void rk_pcie_fast_link_setup(struct rk_pcie *rk_pcie) 15663d0407baSopenharmony_ci{ 15673d0407baSopenharmony_ci u32 val; 15683d0407baSopenharmony_ci 15693d0407baSopenharmony_ci /* LTSSM EN ctrl mode */ 15703d0407baSopenharmony_ci val = rk_pcie_readl_apb(rk_pcie, PCIE_CLIENT_HOT_RESET_CTRL); 15713d0407baSopenharmony_ci val |= PCIE_LTSSM_ENABLE_ENHANCE | (PCIE_LTSSM_ENABLE_ENHANCE << 16); 15723d0407baSopenharmony_ci rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_HOT_RESET_CTRL, val); 15733d0407baSopenharmony_ci} 15743d0407baSopenharmony_ci 15753d0407baSopenharmony_cistatic void rk_pcie_legacy_irq_mask(struct irq_data *d) 15763d0407baSopenharmony_ci{ 15773d0407baSopenharmony_ci struct rk_pcie *rk_pcie = irq_data_get_irq_chip_data(d); 15783d0407baSopenharmony_ci unsigned long flags; 15793d0407baSopenharmony_ci 15803d0407baSopenharmony_ci raw_spin_lock_irqsave(&rk_pcie->intx_lock, flags); 15813d0407baSopenharmony_ci rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_INTR_MASK_LEGACY, 15823d0407baSopenharmony_ci MASK_LEGACY_INT(d->hwirq)); 15833d0407baSopenharmony_ci raw_spin_unlock_irqrestore(&rk_pcie->intx_lock, flags); 15843d0407baSopenharmony_ci} 15853d0407baSopenharmony_ci 15863d0407baSopenharmony_cistatic void rk_pcie_legacy_irq_unmask(struct irq_data *d) 15873d0407baSopenharmony_ci{ 15883d0407baSopenharmony_ci struct rk_pcie *rk_pcie = irq_data_get_irq_chip_data(d); 15893d0407baSopenharmony_ci unsigned long flags; 15903d0407baSopenharmony_ci 15913d0407baSopenharmony_ci raw_spin_lock_irqsave(&rk_pcie->intx_lock, flags); 15923d0407baSopenharmony_ci rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_INTR_MASK_LEGACY, 15933d0407baSopenharmony_ci UNMASK_LEGACY_INT(d->hwirq)); 15943d0407baSopenharmony_ci raw_spin_unlock_irqrestore(&rk_pcie->intx_lock, flags); 15953d0407baSopenharmony_ci} 15963d0407baSopenharmony_ci 15973d0407baSopenharmony_cistatic struct irq_chip rk_pcie_legacy_irq_chip = { 15983d0407baSopenharmony_ci .name = "rk-pcie-legacy-int", 15993d0407baSopenharmony_ci .irq_enable = rk_pcie_legacy_irq_unmask, 16003d0407baSopenharmony_ci .irq_disable = rk_pcie_legacy_irq_mask, 16013d0407baSopenharmony_ci .irq_mask = rk_pcie_legacy_irq_mask, 16023d0407baSopenharmony_ci .irq_unmask = rk_pcie_legacy_irq_unmask, 16033d0407baSopenharmony_ci .flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND, 16043d0407baSopenharmony_ci}; 16053d0407baSopenharmony_ci 16063d0407baSopenharmony_cistatic int rk_pcie_intx_map(struct irq_domain *domain, unsigned int irq, 16073d0407baSopenharmony_ci irq_hw_number_t hwirq) 16083d0407baSopenharmony_ci{ 16093d0407baSopenharmony_ci irq_set_chip_and_handler(irq, &rk_pcie_legacy_irq_chip, handle_simple_irq); 16103d0407baSopenharmony_ci irq_set_chip_data(irq, domain->host_data); 16113d0407baSopenharmony_ci 16123d0407baSopenharmony_ci return 0; 16133d0407baSopenharmony_ci} 16143d0407baSopenharmony_ci 16153d0407baSopenharmony_cistatic const struct irq_domain_ops intx_domain_ops = { 16163d0407baSopenharmony_ci .map = rk_pcie_intx_map, 16173d0407baSopenharmony_ci}; 16183d0407baSopenharmony_ci 16193d0407baSopenharmony_cistatic void rk_pcie_legacy_int_handler(struct irq_desc *desc) 16203d0407baSopenharmony_ci{ 16213d0407baSopenharmony_ci struct irq_chip *chip = irq_desc_get_chip(desc); 16223d0407baSopenharmony_ci struct rk_pcie *rockchip = irq_desc_get_handler_data(desc); 16233d0407baSopenharmony_ci struct device *dev = rockchip->pci->dev; 16243d0407baSopenharmony_ci u32 reg; 16253d0407baSopenharmony_ci u32 hwirq; 16263d0407baSopenharmony_ci u32 virq; 16273d0407baSopenharmony_ci 16283d0407baSopenharmony_ci chained_irq_enter(chip, desc); 16293d0407baSopenharmony_ci 16303d0407baSopenharmony_ci reg = rk_pcie_readl_apb(rockchip, PCIE_CLIENT_INTR_STATUS_LEGACY); 16313d0407baSopenharmony_ci reg = reg & 0xf; 16323d0407baSopenharmony_ci 16333d0407baSopenharmony_ci while (reg) { 16343d0407baSopenharmony_ci hwirq = ffs(reg) - 1; 16353d0407baSopenharmony_ci reg &= ~BIT(hwirq); 16363d0407baSopenharmony_ci 16373d0407baSopenharmony_ci virq = irq_find_mapping(rockchip->irq_domain, hwirq); 16383d0407baSopenharmony_ci if (virq) 16393d0407baSopenharmony_ci generic_handle_irq(virq); 16403d0407baSopenharmony_ci else 16413d0407baSopenharmony_ci dev_err(dev, "unexpected IRQ, INT%d\n", hwirq); 16423d0407baSopenharmony_ci } 16433d0407baSopenharmony_ci 16443d0407baSopenharmony_ci chained_irq_exit(chip, desc); 16453d0407baSopenharmony_ci} 16463d0407baSopenharmony_ci 16473d0407baSopenharmony_cistatic int rk_pcie_init_irq_domain(struct rk_pcie *rockchip) 16483d0407baSopenharmony_ci{ 16493d0407baSopenharmony_ci struct device *dev = rockchip->pci->dev; 16503d0407baSopenharmony_ci struct device_node *intc = of_get_next_child(dev->of_node, NULL); 16513d0407baSopenharmony_ci 16523d0407baSopenharmony_ci if (!intc) { 16533d0407baSopenharmony_ci dev_err(dev, "missing child interrupt-controller node\n"); 16543d0407baSopenharmony_ci return -EINVAL; 16553d0407baSopenharmony_ci } 16563d0407baSopenharmony_ci 16573d0407baSopenharmony_ci raw_spin_lock_init(&rockchip->intx_lock); 16583d0407baSopenharmony_ci rockchip->irq_domain = irq_domain_add_linear(intc, PCI_NUM_INTX, 16593d0407baSopenharmony_ci &intx_domain_ops, rockchip); 16603d0407baSopenharmony_ci if (!rockchip->irq_domain) { 16613d0407baSopenharmony_ci dev_err(dev, "failed to get a INTx IRQ domain\n"); 16623d0407baSopenharmony_ci return -EINVAL; 16633d0407baSopenharmony_ci } 16643d0407baSopenharmony_ci 16653d0407baSopenharmony_ci return 0; 16663d0407baSopenharmony_ci} 16673d0407baSopenharmony_ci 16683d0407baSopenharmony_cistatic int rk_pcie_enable_power(struct rk_pcie *rk_pcie) 16693d0407baSopenharmony_ci{ 16703d0407baSopenharmony_ci int ret = 0; 16713d0407baSopenharmony_ci struct device *dev = rk_pcie->pci->dev; 16723d0407baSopenharmony_ci 16733d0407baSopenharmony_ci if (IS_ERR(rk_pcie->vpcie3v3)) 16743d0407baSopenharmony_ci return ret; 16753d0407baSopenharmony_ci 16763d0407baSopenharmony_ci ret = regulator_enable(rk_pcie->vpcie3v3); 16773d0407baSopenharmony_ci if (ret) 16783d0407baSopenharmony_ci dev_err(dev, "fail to enable vpcie3v3 regulator\n"); 16793d0407baSopenharmony_ci 16803d0407baSopenharmony_ci return ret; 16813d0407baSopenharmony_ci} 16823d0407baSopenharmony_ci 16833d0407baSopenharmony_cistatic int rk_pcie_disable_power(struct rk_pcie *rk_pcie) 16843d0407baSopenharmony_ci{ 16853d0407baSopenharmony_ci int ret = 0; 16863d0407baSopenharmony_ci struct device *dev = rk_pcie->pci->dev; 16873d0407baSopenharmony_ci 16883d0407baSopenharmony_ci if (IS_ERR(rk_pcie->vpcie3v3)) 16893d0407baSopenharmony_ci return ret; 16903d0407baSopenharmony_ci 16913d0407baSopenharmony_ci ret = regulator_disable(rk_pcie->vpcie3v3); 16923d0407baSopenharmony_ci if (ret) 16933d0407baSopenharmony_ci dev_err(dev, "fail to disable vpcie3v3 regulator\n"); 16943d0407baSopenharmony_ci 16953d0407baSopenharmony_ci return ret; 16963d0407baSopenharmony_ci} 16973d0407baSopenharmony_ci 16983d0407baSopenharmony_cistatic int rk_pcie_really_probe(void *p) 16993d0407baSopenharmony_ci{ 17003d0407baSopenharmony_ci struct platform_device *pdev = p; 17013d0407baSopenharmony_ci struct device *dev = &pdev->dev; 17023d0407baSopenharmony_ci struct rk_pcie *rk_pcie; 17033d0407baSopenharmony_ci struct dw_pcie *pci; 17043d0407baSopenharmony_ci int ret; 17053d0407baSopenharmony_ci const struct of_device_id *match; 17063d0407baSopenharmony_ci const struct rk_pcie_of_data *data; 17073d0407baSopenharmony_ci enum rk_pcie_device_mode mode; 17083d0407baSopenharmony_ci struct device_node *np = pdev->dev.of_node; 17093d0407baSopenharmony_ci u32 val; 17103d0407baSopenharmony_ci int irq; 17113d0407baSopenharmony_ci 17123d0407baSopenharmony_ci match = of_match_device(rk_pcie_of_match, dev); 17133d0407baSopenharmony_ci if (!match) 17143d0407baSopenharmony_ci return -EINVAL; 17153d0407baSopenharmony_ci 17163d0407baSopenharmony_ci data = (struct rk_pcie_of_data *)match->data; 17173d0407baSopenharmony_ci mode = (enum rk_pcie_device_mode)data->mode; 17183d0407baSopenharmony_ci 17193d0407baSopenharmony_ci rk_pcie = devm_kzalloc(dev, sizeof(*rk_pcie), GFP_KERNEL); 17203d0407baSopenharmony_ci if (!rk_pcie) 17213d0407baSopenharmony_ci return -ENOMEM; 17223d0407baSopenharmony_ci 17233d0407baSopenharmony_ci pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL); 17243d0407baSopenharmony_ci if (!pci) 17253d0407baSopenharmony_ci return -ENOMEM; 17263d0407baSopenharmony_ci 17273d0407baSopenharmony_ci pci->dev = dev; 17283d0407baSopenharmony_ci pci->ops = &dw_pcie_ops; 17293d0407baSopenharmony_ci 17303d0407baSopenharmony_ci rk_pcie->mode = mode; 17313d0407baSopenharmony_ci rk_pcie->pci = pci; 17323d0407baSopenharmony_ci 17333d0407baSopenharmony_ci if (of_device_is_compatible(np, "rockchip,rk1808-pcie") || 17343d0407baSopenharmony_ci of_device_is_compatible(np, "rockchip,rk1808-pcie-ep")) 17353d0407baSopenharmony_ci rk_pcie->is_rk1808 = true; 17363d0407baSopenharmony_ci else 17373d0407baSopenharmony_ci rk_pcie->is_rk1808 = false; 17383d0407baSopenharmony_ci 17393d0407baSopenharmony_ci if (device_property_read_bool(dev, "rockchip,bifurcation")) 17403d0407baSopenharmony_ci rk_pcie->bifurcation = true; 17413d0407baSopenharmony_ci 17423d0407baSopenharmony_ci ret = rk_pcie_resource_get(pdev, rk_pcie); 17433d0407baSopenharmony_ci if (ret) { 17443d0407baSopenharmony_ci dev_err(dev, "resource init failed\n"); 17453d0407baSopenharmony_ci return ret; 17463d0407baSopenharmony_ci } 17473d0407baSopenharmony_ci 17483d0407baSopenharmony_ci /* DON'T MOVE ME: must be enable before phy init */ 17493d0407baSopenharmony_ci rk_pcie->vpcie3v3 = devm_regulator_get_optional(dev, "vpcie3v3"); 17503d0407baSopenharmony_ci if (IS_ERR(rk_pcie->vpcie3v3)) { 17513d0407baSopenharmony_ci if (PTR_ERR(rk_pcie->vpcie3v3) != -ENODEV) 17523d0407baSopenharmony_ci return PTR_ERR(rk_pcie->vpcie3v3); 17533d0407baSopenharmony_ci dev_info(dev, "no vpcie3v3 regulator found\n"); 17543d0407baSopenharmony_ci } 17553d0407baSopenharmony_ci 17563d0407baSopenharmony_ci ret = rk_pcie_enable_power(rk_pcie); 17573d0407baSopenharmony_ci if (ret) 17583d0407baSopenharmony_ci return ret; 17593d0407baSopenharmony_ci 17603d0407baSopenharmony_ci ret = rk_pcie_phy_init(rk_pcie); 17613d0407baSopenharmony_ci if (ret) { 17623d0407baSopenharmony_ci dev_err(dev, "phy init failed\n"); 17633d0407baSopenharmony_ci goto disable_vpcie3v3; 17643d0407baSopenharmony_ci } 17653d0407baSopenharmony_ci 17663d0407baSopenharmony_ci ret = rk_pcie_reset_control_release(rk_pcie); 17673d0407baSopenharmony_ci if (ret) { 17683d0407baSopenharmony_ci dev_err(dev, "reset control init failed\n"); 17693d0407baSopenharmony_ci goto disable_phy; 17703d0407baSopenharmony_ci } 17713d0407baSopenharmony_ci 17723d0407baSopenharmony_ci ret = rk_pcie_request_sys_irq(rk_pcie, pdev); 17733d0407baSopenharmony_ci if (ret) { 17743d0407baSopenharmony_ci dev_err(dev, "pcie irq init failed\n"); 17753d0407baSopenharmony_ci goto disable_phy; 17763d0407baSopenharmony_ci } 17773d0407baSopenharmony_ci 17783d0407baSopenharmony_ci platform_set_drvdata(pdev, rk_pcie); 17793d0407baSopenharmony_ci 17803d0407baSopenharmony_ci ret = rk_pcie_clk_init(rk_pcie); 17813d0407baSopenharmony_ci if (ret) { 17823d0407baSopenharmony_ci dev_err(dev, "clock init failed\n"); 17833d0407baSopenharmony_ci goto disable_phy; 17843d0407baSopenharmony_ci } 17853d0407baSopenharmony_ci 17863d0407baSopenharmony_ci dw_pcie_dbi_ro_wr_en(pci); 17873d0407baSopenharmony_ci 17883d0407baSopenharmony_ci if (rk_pcie->is_rk1808) { 17893d0407baSopenharmony_ci ret = rk1808_pcie_fixup(rk_pcie, np); 17903d0407baSopenharmony_ci if (ret) 17913d0407baSopenharmony_ci goto deinit_clk; 17923d0407baSopenharmony_ci } else { 17933d0407baSopenharmony_ci rk_pcie_fast_link_setup(rk_pcie); 17943d0407baSopenharmony_ci } 17953d0407baSopenharmony_ci 17963d0407baSopenharmony_ci /* Legacy interrupt is optional */ 17973d0407baSopenharmony_ci ret = rk_pcie_init_irq_domain(rk_pcie); 17983d0407baSopenharmony_ci if (!ret) { 17993d0407baSopenharmony_ci irq = platform_get_irq_byname(pdev, "legacy"); 18003d0407baSopenharmony_ci if (irq >= 0) { 18013d0407baSopenharmony_ci irq_set_chained_handler_and_data(irq, rk_pcie_legacy_int_handler, 18023d0407baSopenharmony_ci rk_pcie); 18033d0407baSopenharmony_ci /* Unmask all legacy interrupt from INTA~INTD */ 18043d0407baSopenharmony_ci rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_INTR_MASK_LEGACY, 18053d0407baSopenharmony_ci UNMASK_ALL_LEGACY_INT); 18063d0407baSopenharmony_ci } 18073d0407baSopenharmony_ci 18083d0407baSopenharmony_ci dev_info(dev, "missing legacy IRQ resource\n"); 18093d0407baSopenharmony_ci } 18103d0407baSopenharmony_ci 18113d0407baSopenharmony_ci /* Set PCIe mode */ 18123d0407baSopenharmony_ci rk_pcie_set_mode(rk_pcie); 18133d0407baSopenharmony_ci 18143d0407baSopenharmony_ci /* Force into loopback master mode */ 18153d0407baSopenharmony_ci if (device_property_read_bool(dev, "rockchip,lpbk-master")) { 18163d0407baSopenharmony_ci val = dw_pcie_readl_dbi(pci, PCIE_PORT_LINK_CONTROL); 18173d0407baSopenharmony_ci val |= PORT_LINK_LPBK_ENABLE; 18183d0407baSopenharmony_ci dw_pcie_writel_dbi(pci, PCIE_PORT_LINK_CONTROL, val); 18193d0407baSopenharmony_ci rk_pcie->is_signal_test = true; 18203d0407baSopenharmony_ci } 18213d0407baSopenharmony_ci 18223d0407baSopenharmony_ci /* Force into compliance mode */ 18233d0407baSopenharmony_ci if (device_property_read_bool(dev, "rockchip,compliance-mode")) { 18243d0407baSopenharmony_ci val = dw_pcie_readl_dbi(pci, PCIE_CAP_LINK_CONTROL2_LINK_STATUS); 18253d0407baSopenharmony_ci val |= BIT(4); 18263d0407baSopenharmony_ci dw_pcie_writel_dbi(pci, PCIE_CAP_LINK_CONTROL2_LINK_STATUS, val); 18273d0407baSopenharmony_ci rk_pcie->is_signal_test = true; 18283d0407baSopenharmony_ci } 18293d0407baSopenharmony_ci 18303d0407baSopenharmony_ci /* Skip waiting for training to pass in system PM routine */ 18313d0407baSopenharmony_ci if (device_property_read_bool(dev, "rockchip,skip-scan-in-resume")) 18323d0407baSopenharmony_ci rk_pcie->skip_scan_in_resume = true; 18333d0407baSopenharmony_ci 18343d0407baSopenharmony_ci switch (rk_pcie->mode) { 18353d0407baSopenharmony_ci case RK_PCIE_RC_TYPE: 18363d0407baSopenharmony_ci ret = rk_add_pcie_port(rk_pcie); 18373d0407baSopenharmony_ci break; 18383d0407baSopenharmony_ci case RK_PCIE_EP_TYPE: 18393d0407baSopenharmony_ci ret = rk_pcie_add_ep(rk_pcie); 18403d0407baSopenharmony_ci break; 18413d0407baSopenharmony_ci } 18423d0407baSopenharmony_ci 18433d0407baSopenharmony_ci if (rk_pcie->is_signal_test == true) 18443d0407baSopenharmony_ci return 0; 18453d0407baSopenharmony_ci 18463d0407baSopenharmony_ci if (ret) 18473d0407baSopenharmony_ci goto remove_irq_domain; 18483d0407baSopenharmony_ci 18493d0407baSopenharmony_ci if (rk_pcie->dma_obj) { 18503d0407baSopenharmony_ci rk_pcie->dma_obj->start_dma_func = rk_pcie_start_dma_dwc; 18513d0407baSopenharmony_ci rk_pcie->dma_obj->config_dma_func = rk_pcie_config_dma_dwc; 18523d0407baSopenharmony_ci } 18533d0407baSopenharmony_ci 18543d0407baSopenharmony_ci if (rk_pcie->is_rk1808) { 18553d0407baSopenharmony_ci /* hold link reset grant after link-up */ 18563d0407baSopenharmony_ci ret = rk_pcie_reset_grant_ctrl(rk_pcie, false); 18573d0407baSopenharmony_ci if (ret) 18583d0407baSopenharmony_ci goto remove_irq_domain; 18593d0407baSopenharmony_ci } 18603d0407baSopenharmony_ci 18613d0407baSopenharmony_ci dw_pcie_dbi_ro_wr_dis(pci); 18623d0407baSopenharmony_ci 18633d0407baSopenharmony_ci device_init_wakeup(dev, true); 18643d0407baSopenharmony_ci 18653d0407baSopenharmony_ci /* Enable async system PM for multiports SoC */ 18663d0407baSopenharmony_ci device_enable_async_suspend(dev); 18673d0407baSopenharmony_ci 18683d0407baSopenharmony_ci return 0; 18693d0407baSopenharmony_ci 18703d0407baSopenharmony_ciremove_irq_domain: 18713d0407baSopenharmony_ci if (rk_pcie->irq_domain) 18723d0407baSopenharmony_ci irq_domain_remove(rk_pcie->irq_domain); 18733d0407baSopenharmony_cidisable_phy: 18743d0407baSopenharmony_ci phy_power_off(rk_pcie->phy); 18753d0407baSopenharmony_ci phy_exit(rk_pcie->phy); 18763d0407baSopenharmony_cideinit_clk: 18773d0407baSopenharmony_ci rk_pcie_clk_deinit(rk_pcie); 18783d0407baSopenharmony_cidisable_vpcie3v3: 18793d0407baSopenharmony_ci rk_pcie_disable_power(rk_pcie); 18803d0407baSopenharmony_ci 18813d0407baSopenharmony_ci device_release_driver(dev); 18823d0407baSopenharmony_ci 18833d0407baSopenharmony_ci return ret; 18843d0407baSopenharmony_ci} 18853d0407baSopenharmony_ci 18863d0407baSopenharmony_cistatic int rk_pcie_probe(struct platform_device *pdev) 18873d0407baSopenharmony_ci{ 18883d0407baSopenharmony_ci struct task_struct *tsk; 18893d0407baSopenharmony_ci 18903d0407baSopenharmony_ci tsk = kthread_run(rk_pcie_really_probe, pdev, "rk-pcie"); 18913d0407baSopenharmony_ci if (IS_ERR(tsk)) { 18923d0407baSopenharmony_ci dev_err(&pdev->dev, "start rk-pcie thread failed\n"); 18933d0407baSopenharmony_ci return PTR_ERR(tsk); 18943d0407baSopenharmony_ci } 18953d0407baSopenharmony_ci return 0; 18963d0407baSopenharmony_ci} 18973d0407baSopenharmony_ci 18983d0407baSopenharmony_cistatic int __maybe_unused rockchip_dw_pcie_suspend(struct device *dev) 18993d0407baSopenharmony_ci{ 19003d0407baSopenharmony_ci struct rk_pcie *rk_pcie = dev_get_drvdata(dev); 19013d0407baSopenharmony_ci int ret; 19023d0407baSopenharmony_ci 19033d0407baSopenharmony_ci rk_pcie_link_status_clear(rk_pcie); 19043d0407baSopenharmony_ci rk_pcie_disable_ltssm(rk_pcie); 19053d0407baSopenharmony_ci 19063d0407baSopenharmony_ci /* make sure assert phy success */ 19073d0407baSopenharmony_ci usleep_range(200, 300); 19083d0407baSopenharmony_ci 19093d0407baSopenharmony_ci phy_power_off(rk_pcie->phy); 19103d0407baSopenharmony_ci phy_exit(rk_pcie->phy); 19113d0407baSopenharmony_ci 19123d0407baSopenharmony_ci clk_bulk_disable(rk_pcie->clk_cnt, rk_pcie->clks); 19133d0407baSopenharmony_ci 19143d0407baSopenharmony_ci rk_pcie->in_suspend = true; 19153d0407baSopenharmony_ci 19163d0407baSopenharmony_ci gpiod_set_value_cansleep(rk_pcie->rst_gpio, 0); 19173d0407baSopenharmony_ci ret = rk_pcie_disable_power(rk_pcie); 19183d0407baSopenharmony_ci 19193d0407baSopenharmony_ci return ret; 19203d0407baSopenharmony_ci} 19213d0407baSopenharmony_ci 19223d0407baSopenharmony_cistatic int __maybe_unused rockchip_dw_pcie_resume(struct device *dev) 19233d0407baSopenharmony_ci{ 19243d0407baSopenharmony_ci struct rk_pcie *rk_pcie = dev_get_drvdata(dev); 19253d0407baSopenharmony_ci bool std_rc = rk_pcie->mode == RK_PCIE_RC_TYPE && !rk_pcie->dma_obj; 19263d0407baSopenharmony_ci int ret; 19273d0407baSopenharmony_ci 19283d0407baSopenharmony_ci ret = rk_pcie_enable_power(rk_pcie); 19293d0407baSopenharmony_ci if (ret) 19303d0407baSopenharmony_ci return ret; 19313d0407baSopenharmony_ci 19323d0407baSopenharmony_ci ret = clk_bulk_enable(rk_pcie->clk_cnt, rk_pcie->clks); 19333d0407baSopenharmony_ci if (ret) { 19343d0407baSopenharmony_ci clk_bulk_unprepare(rk_pcie->clk_cnt, rk_pcie->clks); 19353d0407baSopenharmony_ci return ret; 19363d0407baSopenharmony_ci } 19373d0407baSopenharmony_ci 19383d0407baSopenharmony_ci ret = phy_set_mode_ext(rk_pcie->phy, rk_pcie->phy_mode, 19393d0407baSopenharmony_ci rk_pcie->phy_sub_mode); 19403d0407baSopenharmony_ci if (ret) { 19413d0407baSopenharmony_ci dev_err(dev, "fail to set phy to mode %s, err %d\n", 19423d0407baSopenharmony_ci (rk_pcie->phy_sub_mode == PHY_MODE_PCIE_RC) ? "RC" : "EP", 19433d0407baSopenharmony_ci ret); 19443d0407baSopenharmony_ci return ret; 19453d0407baSopenharmony_ci } 19463d0407baSopenharmony_ci 19473d0407baSopenharmony_ci ret = phy_init(rk_pcie->phy); 19483d0407baSopenharmony_ci if (ret < 0) { 19493d0407baSopenharmony_ci dev_err(dev, "fail to init phy, err %d\n", ret); 19503d0407baSopenharmony_ci return ret; 19513d0407baSopenharmony_ci } 19523d0407baSopenharmony_ci 19533d0407baSopenharmony_ci phy_power_on(rk_pcie->phy); 19543d0407baSopenharmony_ci 19553d0407baSopenharmony_ci dw_pcie_dbi_ro_wr_en(rk_pcie->pci); 19563d0407baSopenharmony_ci 19573d0407baSopenharmony_ci if (rk_pcie->is_rk1808) { 19583d0407baSopenharmony_ci /* release link reset grant */ 19593d0407baSopenharmony_ci ret = rk_pcie_reset_grant_ctrl(rk_pcie, true); 19603d0407baSopenharmony_ci if (ret) 19613d0407baSopenharmony_ci return ret; 19623d0407baSopenharmony_ci } else { 19633d0407baSopenharmony_ci rk_pcie_fast_link_setup(rk_pcie); 19643d0407baSopenharmony_ci } 19653d0407baSopenharmony_ci 19663d0407baSopenharmony_ci /* Set PCIe mode */ 19673d0407baSopenharmony_ci rk_pcie_set_mode(rk_pcie); 19683d0407baSopenharmony_ci 19693d0407baSopenharmony_ci if (std_rc) 19703d0407baSopenharmony_ci dw_pcie_setup_rc(&rk_pcie->pci->pp); 19713d0407baSopenharmony_ci 19723d0407baSopenharmony_ci ret = rk_pcie_establish_link(rk_pcie->pci); 19733d0407baSopenharmony_ci if (ret) { 19743d0407baSopenharmony_ci dev_err(dev, "failed to establish pcie link\n"); 19753d0407baSopenharmony_ci goto err; 19763d0407baSopenharmony_ci } 19773d0407baSopenharmony_ci 19783d0407baSopenharmony_ci if (std_rc) 19793d0407baSopenharmony_ci goto std_rc_done; 19803d0407baSopenharmony_ci 19813d0407baSopenharmony_ci ret = rk_pcie_ep_atu_init(rk_pcie); 19823d0407baSopenharmony_ci if (ret) { 19833d0407baSopenharmony_ci dev_err(dev, "failed to init ep device\n"); 19843d0407baSopenharmony_ci goto err; 19853d0407baSopenharmony_ci } 19863d0407baSopenharmony_ci 19873d0407baSopenharmony_ci rk_pcie_ep_setup(rk_pcie); 19883d0407baSopenharmony_ci 19893d0407baSopenharmony_ci rk_pcie->in_suspend = false; 19903d0407baSopenharmony_ci 19913d0407baSopenharmony_cistd_rc_done: 19923d0407baSopenharmony_ci dw_pcie_dbi_ro_wr_dis(rk_pcie->pci); 19933d0407baSopenharmony_ci /* hold link reset grant after link-up */ 19943d0407baSopenharmony_ci if (rk_pcie->is_rk1808) { 19953d0407baSopenharmony_ci ret = rk_pcie_reset_grant_ctrl(rk_pcie, false); 19963d0407baSopenharmony_ci if (ret) 19973d0407baSopenharmony_ci goto err; 19983d0407baSopenharmony_ci } 19993d0407baSopenharmony_ci 20003d0407baSopenharmony_ci return 0; 20013d0407baSopenharmony_cierr: 20023d0407baSopenharmony_ci rk_pcie_disable_power(rk_pcie); 20033d0407baSopenharmony_ci 20043d0407baSopenharmony_ci return ret; 20053d0407baSopenharmony_ci} 20063d0407baSopenharmony_ci 20073d0407baSopenharmony_cistatic const struct dev_pm_ops rockchip_dw_pcie_pm_ops = { 20083d0407baSopenharmony_ci SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(rockchip_dw_pcie_suspend, 20093d0407baSopenharmony_ci rockchip_dw_pcie_resume) 20103d0407baSopenharmony_ci}; 20113d0407baSopenharmony_ci 20123d0407baSopenharmony_cistatic struct platform_driver rk_plat_pcie_driver = { 20133d0407baSopenharmony_ci .driver = { 20143d0407baSopenharmony_ci .name = "rk-pcie", 20153d0407baSopenharmony_ci .of_match_table = rk_pcie_of_match, 20163d0407baSopenharmony_ci .suppress_bind_attrs = true, 20173d0407baSopenharmony_ci .pm = &rockchip_dw_pcie_pm_ops, 20183d0407baSopenharmony_ci }, 20193d0407baSopenharmony_ci .probe = rk_pcie_probe, 20203d0407baSopenharmony_ci}; 20213d0407baSopenharmony_ci 20223d0407baSopenharmony_cimodule_platform_driver(rk_plat_pcie_driver); 20233d0407baSopenharmony_ci 20243d0407baSopenharmony_ciMODULE_AUTHOR("Simon Xue <xxm@rock-chips.com>"); 20253d0407baSopenharmony_ciMODULE_DESCRIPTION("RockChip PCIe Controller driver"); 20263d0407baSopenharmony_ciMODULE_LICENSE("GPL v2"); 2027