1*4882a593Smuzhiyun /* SPDX-License-Identifier: GPL-2.0 */
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * PCIe host controller driver for Mobiveil PCIe Host controller
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (c) 2018 Mobiveil Inc.
6*4882a593Smuzhiyun * Copyright 2019 NXP
7*4882a593Smuzhiyun *
8*4882a593Smuzhiyun * Author: Subrahmanya Lingappa <l.subrahmanya@mobiveil.co.in>
9*4882a593Smuzhiyun * Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
10*4882a593Smuzhiyun */
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun #ifndef _PCIE_MOBIVEIL_H
13*4882a593Smuzhiyun #define _PCIE_MOBIVEIL_H
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun #include <linux/pci.h>
16*4882a593Smuzhiyun #include <linux/irq.h>
17*4882a593Smuzhiyun #include <linux/msi.h>
18*4882a593Smuzhiyun #include "../../pci.h"
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun /* register offsets and bit positions */
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun /*
23*4882a593Smuzhiyun * translation tables are grouped into windows, each window registers are
24*4882a593Smuzhiyun * grouped into blocks of 4 or 16 registers each
25*4882a593Smuzhiyun */
26*4882a593Smuzhiyun #define PAB_REG_BLOCK_SIZE 16
27*4882a593Smuzhiyun #define PAB_EXT_REG_BLOCK_SIZE 4
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun #define PAB_REG_ADDR(offset, win) \
30*4882a593Smuzhiyun (offset + (win * PAB_REG_BLOCK_SIZE))
31*4882a593Smuzhiyun #define PAB_EXT_REG_ADDR(offset, win) \
32*4882a593Smuzhiyun (offset + (win * PAB_EXT_REG_BLOCK_SIZE))
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun #define LTSSM_STATUS 0x0404
35*4882a593Smuzhiyun #define LTSSM_STATUS_L0_MASK 0x3f
36*4882a593Smuzhiyun #define LTSSM_STATUS_L0 0x2d
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun #define PAB_CTRL 0x0808
39*4882a593Smuzhiyun #define AMBA_PIO_ENABLE_SHIFT 0
40*4882a593Smuzhiyun #define PEX_PIO_ENABLE_SHIFT 1
41*4882a593Smuzhiyun #define PAGE_SEL_SHIFT 13
42*4882a593Smuzhiyun #define PAGE_SEL_MASK 0x3f
43*4882a593Smuzhiyun #define PAGE_LO_MASK 0x3ff
44*4882a593Smuzhiyun #define PAGE_SEL_OFFSET_SHIFT 10
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun #define PAB_ACTIVITY_STAT 0x81c
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun #define PAB_AXI_PIO_CTRL 0x0840
49*4882a593Smuzhiyun #define APIO_EN_MASK 0xf
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun #define PAB_PEX_PIO_CTRL 0x08c0
52*4882a593Smuzhiyun #define PIO_ENABLE_SHIFT 0
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun #define PAB_INTP_AMBA_MISC_ENB 0x0b0c
55*4882a593Smuzhiyun #define PAB_INTP_AMBA_MISC_STAT 0x0b1c
56*4882a593Smuzhiyun #define PAB_INTP_RESET BIT(1)
57*4882a593Smuzhiyun #define PAB_INTP_MSI BIT(3)
58*4882a593Smuzhiyun #define PAB_INTP_INTA BIT(5)
59*4882a593Smuzhiyun #define PAB_INTP_INTB BIT(6)
60*4882a593Smuzhiyun #define PAB_INTP_INTC BIT(7)
61*4882a593Smuzhiyun #define PAB_INTP_INTD BIT(8)
62*4882a593Smuzhiyun #define PAB_INTP_PCIE_UE BIT(9)
63*4882a593Smuzhiyun #define PAB_INTP_IE_PMREDI BIT(29)
64*4882a593Smuzhiyun #define PAB_INTP_IE_EC BIT(30)
65*4882a593Smuzhiyun #define PAB_INTP_MSI_MASK PAB_INTP_MSI
66*4882a593Smuzhiyun #define PAB_INTP_INTX_MASK (PAB_INTP_INTA | PAB_INTP_INTB |\
67*4882a593Smuzhiyun PAB_INTP_INTC | PAB_INTP_INTD)
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun #define PAB_AXI_AMAP_CTRL(win) PAB_REG_ADDR(0x0ba0, win)
70*4882a593Smuzhiyun #define WIN_ENABLE_SHIFT 0
71*4882a593Smuzhiyun #define WIN_TYPE_SHIFT 1
72*4882a593Smuzhiyun #define WIN_TYPE_MASK 0x3
73*4882a593Smuzhiyun #define WIN_SIZE_MASK 0xfffffc00
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun #define PAB_EXT_AXI_AMAP_SIZE(win) PAB_EXT_REG_ADDR(0xbaf0, win)
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun #define PAB_EXT_AXI_AMAP_AXI_WIN(win) PAB_EXT_REG_ADDR(0x80a0, win)
78*4882a593Smuzhiyun #define PAB_AXI_AMAP_AXI_WIN(win) PAB_REG_ADDR(0x0ba4, win)
79*4882a593Smuzhiyun #define AXI_WINDOW_ALIGN_MASK 3
80*4882a593Smuzhiyun
81*4882a593Smuzhiyun #define PAB_AXI_AMAP_PEX_WIN_L(win) PAB_REG_ADDR(0x0ba8, win)
82*4882a593Smuzhiyun #define PAB_BUS_SHIFT 24
83*4882a593Smuzhiyun #define PAB_DEVICE_SHIFT 19
84*4882a593Smuzhiyun #define PAB_FUNCTION_SHIFT 16
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun #define PAB_AXI_AMAP_PEX_WIN_H(win) PAB_REG_ADDR(0x0bac, win)
87*4882a593Smuzhiyun #define PAB_INTP_AXI_PIO_CLASS 0x474
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun #define PAB_PEX_AMAP_CTRL(win) PAB_REG_ADDR(0x4ba0, win)
90*4882a593Smuzhiyun #define AMAP_CTRL_EN_SHIFT 0
91*4882a593Smuzhiyun #define AMAP_CTRL_TYPE_SHIFT 1
92*4882a593Smuzhiyun #define AMAP_CTRL_TYPE_MASK 3
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun #define PAB_EXT_PEX_AMAP_SIZEN(win) PAB_EXT_REG_ADDR(0xbef0, win)
95*4882a593Smuzhiyun #define PAB_EXT_PEX_AMAP_AXI_WIN(win) PAB_EXT_REG_ADDR(0xb4a0, win)
96*4882a593Smuzhiyun #define PAB_PEX_AMAP_AXI_WIN(win) PAB_REG_ADDR(0x4ba4, win)
97*4882a593Smuzhiyun #define PAB_PEX_AMAP_PEX_WIN_L(win) PAB_REG_ADDR(0x4ba8, win)
98*4882a593Smuzhiyun #define PAB_PEX_AMAP_PEX_WIN_H(win) PAB_REG_ADDR(0x4bac, win)
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun /* starting offset of INTX bits in status register */
101*4882a593Smuzhiyun #define PAB_INTX_START 5
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun /* supported number of MSI interrupts */
104*4882a593Smuzhiyun #define PCI_NUM_MSI 16
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun /* MSI registers */
107*4882a593Smuzhiyun #define MSI_BASE_LO_OFFSET 0x04
108*4882a593Smuzhiyun #define MSI_BASE_HI_OFFSET 0x08
109*4882a593Smuzhiyun #define MSI_SIZE_OFFSET 0x0c
110*4882a593Smuzhiyun #define MSI_ENABLE_OFFSET 0x14
111*4882a593Smuzhiyun #define MSI_STATUS_OFFSET 0x18
112*4882a593Smuzhiyun #define MSI_DATA_OFFSET 0x20
113*4882a593Smuzhiyun #define MSI_ADDR_L_OFFSET 0x24
114*4882a593Smuzhiyun #define MSI_ADDR_H_OFFSET 0x28
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun /* outbound and inbound window definitions */
117*4882a593Smuzhiyun #define WIN_NUM_0 0
118*4882a593Smuzhiyun #define WIN_NUM_1 1
119*4882a593Smuzhiyun #define CFG_WINDOW_TYPE 0
120*4882a593Smuzhiyun #define IO_WINDOW_TYPE 1
121*4882a593Smuzhiyun #define MEM_WINDOW_TYPE 2
122*4882a593Smuzhiyun #define IB_WIN_SIZE ((u64)256 * 1024 * 1024 * 1024)
123*4882a593Smuzhiyun #define MAX_PIO_WINDOWS 8
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun /* Parameters for the waiting for link up routine */
126*4882a593Smuzhiyun #define LINK_WAIT_MAX_RETRIES 10
127*4882a593Smuzhiyun #define LINK_WAIT_MIN 90000
128*4882a593Smuzhiyun #define LINK_WAIT_MAX 100000
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun #define PAGED_ADDR_BNDRY 0xc00
131*4882a593Smuzhiyun #define OFFSET_TO_PAGE_ADDR(off) \
132*4882a593Smuzhiyun ((off & PAGE_LO_MASK) | PAGED_ADDR_BNDRY)
133*4882a593Smuzhiyun #define OFFSET_TO_PAGE_IDX(off) \
134*4882a593Smuzhiyun ((off >> PAGE_SEL_OFFSET_SHIFT) & PAGE_SEL_MASK)
135*4882a593Smuzhiyun
136*4882a593Smuzhiyun struct mobiveil_msi { /* MSI information */
137*4882a593Smuzhiyun struct mutex lock; /* protect bitmap variable */
138*4882a593Smuzhiyun struct irq_domain *msi_domain;
139*4882a593Smuzhiyun struct irq_domain *dev_domain;
140*4882a593Smuzhiyun phys_addr_t msi_pages_phys;
141*4882a593Smuzhiyun int num_of_vectors;
142*4882a593Smuzhiyun DECLARE_BITMAP(msi_irq_in_use, PCI_NUM_MSI);
143*4882a593Smuzhiyun };
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun struct mobiveil_pcie;
146*4882a593Smuzhiyun
147*4882a593Smuzhiyun struct mobiveil_rp_ops {
148*4882a593Smuzhiyun int (*interrupt_init)(struct mobiveil_pcie *pcie);
149*4882a593Smuzhiyun };
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun struct mobiveil_root_port {
152*4882a593Smuzhiyun void __iomem *config_axi_slave_base; /* endpoint config base */
153*4882a593Smuzhiyun struct resource *ob_io_res;
154*4882a593Smuzhiyun struct mobiveil_rp_ops *ops;
155*4882a593Smuzhiyun int irq;
156*4882a593Smuzhiyun raw_spinlock_t intx_mask_lock;
157*4882a593Smuzhiyun struct irq_domain *intx_domain;
158*4882a593Smuzhiyun struct mobiveil_msi msi;
159*4882a593Smuzhiyun struct pci_host_bridge *bridge;
160*4882a593Smuzhiyun };
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun struct mobiveil_pab_ops {
163*4882a593Smuzhiyun int (*link_up)(struct mobiveil_pcie *pcie);
164*4882a593Smuzhiyun };
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun struct mobiveil_pcie {
167*4882a593Smuzhiyun struct platform_device *pdev;
168*4882a593Smuzhiyun void __iomem *csr_axi_slave_base; /* root port config base */
169*4882a593Smuzhiyun void __iomem *apb_csr_base; /* MSI register base */
170*4882a593Smuzhiyun phys_addr_t pcie_reg_base; /* Physical PCIe Controller Base */
171*4882a593Smuzhiyun int apio_wins;
172*4882a593Smuzhiyun int ppio_wins;
173*4882a593Smuzhiyun int ob_wins_configured; /* configured outbound windows */
174*4882a593Smuzhiyun int ib_wins_configured; /* configured inbound windows */
175*4882a593Smuzhiyun const struct mobiveil_pab_ops *ops;
176*4882a593Smuzhiyun struct mobiveil_root_port rp;
177*4882a593Smuzhiyun };
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun int mobiveil_pcie_host_probe(struct mobiveil_pcie *pcie);
180*4882a593Smuzhiyun int mobiveil_host_init(struct mobiveil_pcie *pcie, bool reinit);
181*4882a593Smuzhiyun bool mobiveil_pcie_link_up(struct mobiveil_pcie *pcie);
182*4882a593Smuzhiyun int mobiveil_bringup_link(struct mobiveil_pcie *pcie);
183*4882a593Smuzhiyun void program_ob_windows(struct mobiveil_pcie *pcie, int win_num, u64 cpu_addr,
184*4882a593Smuzhiyun u64 pci_addr, u32 type, u64 size);
185*4882a593Smuzhiyun void program_ib_windows(struct mobiveil_pcie *pcie, int win_num, u64 cpu_addr,
186*4882a593Smuzhiyun u64 pci_addr, u32 type, u64 size);
187*4882a593Smuzhiyun u32 mobiveil_csr_read(struct mobiveil_pcie *pcie, u32 off, size_t size);
188*4882a593Smuzhiyun void mobiveil_csr_write(struct mobiveil_pcie *pcie, u32 val, u32 off,
189*4882a593Smuzhiyun size_t size);
190*4882a593Smuzhiyun
mobiveil_csr_readl(struct mobiveil_pcie * pcie,u32 off)191*4882a593Smuzhiyun static inline u32 mobiveil_csr_readl(struct mobiveil_pcie *pcie, u32 off)
192*4882a593Smuzhiyun {
193*4882a593Smuzhiyun return mobiveil_csr_read(pcie, off, 0x4);
194*4882a593Smuzhiyun }
195*4882a593Smuzhiyun
mobiveil_csr_readw(struct mobiveil_pcie * pcie,u32 off)196*4882a593Smuzhiyun static inline u16 mobiveil_csr_readw(struct mobiveil_pcie *pcie, u32 off)
197*4882a593Smuzhiyun {
198*4882a593Smuzhiyun return mobiveil_csr_read(pcie, off, 0x2);
199*4882a593Smuzhiyun }
200*4882a593Smuzhiyun
mobiveil_csr_readb(struct mobiveil_pcie * pcie,u32 off)201*4882a593Smuzhiyun static inline u8 mobiveil_csr_readb(struct mobiveil_pcie *pcie, u32 off)
202*4882a593Smuzhiyun {
203*4882a593Smuzhiyun return mobiveil_csr_read(pcie, off, 0x1);
204*4882a593Smuzhiyun }
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun
mobiveil_csr_writel(struct mobiveil_pcie * pcie,u32 val,u32 off)207*4882a593Smuzhiyun static inline void mobiveil_csr_writel(struct mobiveil_pcie *pcie, u32 val,
208*4882a593Smuzhiyun u32 off)
209*4882a593Smuzhiyun {
210*4882a593Smuzhiyun mobiveil_csr_write(pcie, val, off, 0x4);
211*4882a593Smuzhiyun }
212*4882a593Smuzhiyun
mobiveil_csr_writew(struct mobiveil_pcie * pcie,u16 val,u32 off)213*4882a593Smuzhiyun static inline void mobiveil_csr_writew(struct mobiveil_pcie *pcie, u16 val,
214*4882a593Smuzhiyun u32 off)
215*4882a593Smuzhiyun {
216*4882a593Smuzhiyun mobiveil_csr_write(pcie, val, off, 0x2);
217*4882a593Smuzhiyun }
218*4882a593Smuzhiyun
mobiveil_csr_writeb(struct mobiveil_pcie * pcie,u8 val,u32 off)219*4882a593Smuzhiyun static inline void mobiveil_csr_writeb(struct mobiveil_pcie *pcie, u8 val,
220*4882a593Smuzhiyun u32 off)
221*4882a593Smuzhiyun {
222*4882a593Smuzhiyun mobiveil_csr_write(pcie, val, off, 0x1);
223*4882a593Smuzhiyun }
224*4882a593Smuzhiyun
225*4882a593Smuzhiyun #endif /* _PCIE_MOBIVEIL_H */
226