1  // SPDX-License-Identifier: GPL-2.0
2  /*
3   * PCIe host controller driver for Mobiveil PCIe Host controller
4   *
5   * Copyright (c) 2018 Mobiveil Inc.
6   * Copyright 2019 NXP
7   *
8   * Author: Subrahmanya Lingappa <l.subrahmanya@mobiveil.co.in>
9   *	   Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
10   */
11  
12  #include <linux/delay.h>
13  #include <linux/init.h>
14  #include <linux/kernel.h>
15  #include <linux/pci.h>
16  #include <linux/platform_device.h>
17  
18  #include "pcie-mobiveil.h"
19  
20  /*
21   * mobiveil_pcie_sel_page - routine to access paged register
22   *
23   * Registers whose address greater than PAGED_ADDR_BNDRY (0xc00) are paged,
24   * for this scheme to work extracted higher 6 bits of the offset will be
25   * written to pg_sel field of PAB_CTRL register and rest of the lower 10
26   * bits enabled with PAGED_ADDR_BNDRY are used as offset of the register.
27   */
mobiveil_pcie_sel_page(struct mobiveil_pcie * pcie,u8 pg_idx)28  static void mobiveil_pcie_sel_page(struct mobiveil_pcie *pcie, u8 pg_idx)
29  {
30  	u32 val;
31  
32  	val = readl(pcie->csr_axi_slave_base + PAB_CTRL);
33  	val &= ~(PAGE_SEL_MASK << PAGE_SEL_SHIFT);
34  	val |= (pg_idx & PAGE_SEL_MASK) << PAGE_SEL_SHIFT;
35  
36  	writel(val, pcie->csr_axi_slave_base + PAB_CTRL);
37  }
38  
mobiveil_pcie_comp_addr(struct mobiveil_pcie * pcie,u32 off)39  static void __iomem *mobiveil_pcie_comp_addr(struct mobiveil_pcie *pcie,
40  					     u32 off)
41  {
42  	if (off < PAGED_ADDR_BNDRY) {
43  		/* For directly accessed registers, clear the pg_sel field */
44  		mobiveil_pcie_sel_page(pcie, 0);
45  		return pcie->csr_axi_slave_base + off;
46  	}
47  
48  	mobiveil_pcie_sel_page(pcie, OFFSET_TO_PAGE_IDX(off));
49  	return pcie->csr_axi_slave_base + OFFSET_TO_PAGE_ADDR(off);
50  }
51  
mobiveil_pcie_read(void __iomem * addr,int size,u32 * val)52  static int mobiveil_pcie_read(void __iomem *addr, int size, u32 *val)
53  {
54  	if ((uintptr_t)addr & (size - 1)) {
55  		*val = 0;
56  		return PCIBIOS_BAD_REGISTER_NUMBER;
57  	}
58  
59  	switch (size) {
60  	case 4:
61  		*val = readl(addr);
62  		break;
63  	case 2:
64  		*val = readw(addr);
65  		break;
66  	case 1:
67  		*val = readb(addr);
68  		break;
69  	default:
70  		*val = 0;
71  		return PCIBIOS_BAD_REGISTER_NUMBER;
72  	}
73  
74  	return PCIBIOS_SUCCESSFUL;
75  }
76  
mobiveil_pcie_write(void __iomem * addr,int size,u32 val)77  static int mobiveil_pcie_write(void __iomem *addr, int size, u32 val)
78  {
79  	if ((uintptr_t)addr & (size - 1))
80  		return PCIBIOS_BAD_REGISTER_NUMBER;
81  
82  	switch (size) {
83  	case 4:
84  		writel(val, addr);
85  		break;
86  	case 2:
87  		writew(val, addr);
88  		break;
89  	case 1:
90  		writeb(val, addr);
91  		break;
92  	default:
93  		return PCIBIOS_BAD_REGISTER_NUMBER;
94  	}
95  
96  	return PCIBIOS_SUCCESSFUL;
97  }
98  
mobiveil_csr_read(struct mobiveil_pcie * pcie,u32 off,size_t size)99  u32 mobiveil_csr_read(struct mobiveil_pcie *pcie, u32 off, size_t size)
100  {
101  	void __iomem *addr;
102  	u32 val;
103  	int ret;
104  
105  	addr = mobiveil_pcie_comp_addr(pcie, off);
106  
107  	ret = mobiveil_pcie_read(addr, size, &val);
108  	if (ret)
109  		dev_err(&pcie->pdev->dev, "read CSR address failed\n");
110  
111  	return val;
112  }
113  
mobiveil_csr_write(struct mobiveil_pcie * pcie,u32 val,u32 off,size_t size)114  void mobiveil_csr_write(struct mobiveil_pcie *pcie, u32 val, u32 off,
115  			       size_t size)
116  {
117  	void __iomem *addr;
118  	int ret;
119  
120  	addr = mobiveil_pcie_comp_addr(pcie, off);
121  
122  	ret = mobiveil_pcie_write(addr, size, val);
123  	if (ret)
124  		dev_err(&pcie->pdev->dev, "write CSR address failed\n");
125  }
126  
mobiveil_pcie_link_up(struct mobiveil_pcie * pcie)127  bool mobiveil_pcie_link_up(struct mobiveil_pcie *pcie)
128  {
129  	if (pcie->ops->link_up)
130  		return pcie->ops->link_up(pcie);
131  
132  	return (mobiveil_csr_readl(pcie, LTSSM_STATUS) &
133  		LTSSM_STATUS_L0_MASK) == LTSSM_STATUS_L0;
134  }
135  
program_ib_windows(struct mobiveil_pcie * pcie,int win_num,u64 cpu_addr,u64 pci_addr,u32 type,u64 size)136  void program_ib_windows(struct mobiveil_pcie *pcie, int win_num,
137  			u64 cpu_addr, u64 pci_addr, u32 type, u64 size)
138  {
139  	u32 value;
140  	u64 size64 = ~(size - 1);
141  
142  	if (win_num >= pcie->ppio_wins) {
143  		dev_err(&pcie->pdev->dev,
144  			"ERROR: max inbound windows reached !\n");
145  		return;
146  	}
147  
148  	value = mobiveil_csr_readl(pcie, PAB_PEX_AMAP_CTRL(win_num));
149  	value &= ~(AMAP_CTRL_TYPE_MASK << AMAP_CTRL_TYPE_SHIFT | WIN_SIZE_MASK);
150  	value |= type << AMAP_CTRL_TYPE_SHIFT | 1 << AMAP_CTRL_EN_SHIFT |
151  		 (lower_32_bits(size64) & WIN_SIZE_MASK);
152  	mobiveil_csr_writel(pcie, value, PAB_PEX_AMAP_CTRL(win_num));
153  
154  	mobiveil_csr_writel(pcie, upper_32_bits(size64),
155  			    PAB_EXT_PEX_AMAP_SIZEN(win_num));
156  
157  	mobiveil_csr_writel(pcie, lower_32_bits(cpu_addr),
158  			    PAB_PEX_AMAP_AXI_WIN(win_num));
159  	mobiveil_csr_writel(pcie, upper_32_bits(cpu_addr),
160  			    PAB_EXT_PEX_AMAP_AXI_WIN(win_num));
161  
162  	mobiveil_csr_writel(pcie, lower_32_bits(pci_addr),
163  			    PAB_PEX_AMAP_PEX_WIN_L(win_num));
164  	mobiveil_csr_writel(pcie, upper_32_bits(pci_addr),
165  			    PAB_PEX_AMAP_PEX_WIN_H(win_num));
166  
167  	pcie->ib_wins_configured++;
168  }
169  
170  /*
171   * routine to program the outbound windows
172   */
program_ob_windows(struct mobiveil_pcie * pcie,int win_num,u64 cpu_addr,u64 pci_addr,u32 type,u64 size)173  void program_ob_windows(struct mobiveil_pcie *pcie, int win_num,
174  			u64 cpu_addr, u64 pci_addr, u32 type, u64 size)
175  {
176  	u32 value;
177  	u64 size64 = ~(size - 1);
178  
179  	if (win_num >= pcie->apio_wins) {
180  		dev_err(&pcie->pdev->dev,
181  			"ERROR: max outbound windows reached !\n");
182  		return;
183  	}
184  
185  	/*
186  	 * program Enable Bit to 1, Type Bit to (00) base 2, AXI Window Size Bit
187  	 * to 4 KB in PAB_AXI_AMAP_CTRL register
188  	 */
189  	value = mobiveil_csr_readl(pcie, PAB_AXI_AMAP_CTRL(win_num));
190  	value &= ~(WIN_TYPE_MASK << WIN_TYPE_SHIFT | WIN_SIZE_MASK);
191  	value |= 1 << WIN_ENABLE_SHIFT | type << WIN_TYPE_SHIFT |
192  		 (lower_32_bits(size64) & WIN_SIZE_MASK);
193  	mobiveil_csr_writel(pcie, value, PAB_AXI_AMAP_CTRL(win_num));
194  
195  	mobiveil_csr_writel(pcie, upper_32_bits(size64),
196  			    PAB_EXT_AXI_AMAP_SIZE(win_num));
197  
198  	/*
199  	 * program AXI window base with appropriate value in
200  	 * PAB_AXI_AMAP_AXI_WIN0 register
201  	 */
202  	mobiveil_csr_writel(pcie,
203  			    lower_32_bits(cpu_addr) & (~AXI_WINDOW_ALIGN_MASK),
204  			    PAB_AXI_AMAP_AXI_WIN(win_num));
205  	mobiveil_csr_writel(pcie, upper_32_bits(cpu_addr),
206  			    PAB_EXT_AXI_AMAP_AXI_WIN(win_num));
207  
208  	mobiveil_csr_writel(pcie, lower_32_bits(pci_addr),
209  			    PAB_AXI_AMAP_PEX_WIN_L(win_num));
210  	mobiveil_csr_writel(pcie, upper_32_bits(pci_addr),
211  			    PAB_AXI_AMAP_PEX_WIN_H(win_num));
212  
213  	pcie->ob_wins_configured++;
214  }
215  
mobiveil_bringup_link(struct mobiveil_pcie * pcie)216  int mobiveil_bringup_link(struct mobiveil_pcie *pcie)
217  {
218  	int retries;
219  
220  	/* check if the link is up or not */
221  	for (retries = 0; retries < LINK_WAIT_MAX_RETRIES; retries++) {
222  		if (mobiveil_pcie_link_up(pcie))
223  			return 0;
224  
225  		usleep_range(LINK_WAIT_MIN, LINK_WAIT_MAX);
226  	}
227  
228  	dev_err(&pcie->pdev->dev, "link never came up\n");
229  
230  	return -ETIMEDOUT;
231  }
232