Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * PCIe host controller driver for Mobiveil PCIe Host controller
0004  *
0005  * Copyright (c) 2018 Mobiveil Inc.
0006  * Copyright 2019 NXP
0007  *
0008  * Author: Subrahmanya Lingappa <l.subrahmanya@mobiveil.co.in>
0009  *     Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
0010  */
0011 
0012 #include <linux/delay.h>
0013 #include <linux/init.h>
0014 #include <linux/kernel.h>
0015 #include <linux/pci.h>
0016 #include <linux/platform_device.h>
0017 
0018 #include "pcie-mobiveil.h"
0019 
0020 /*
0021  * mobiveil_pcie_sel_page - routine to access paged register
0022  *
0023  * Registers whose address greater than PAGED_ADDR_BNDRY (0xc00) are paged,
0024  * for this scheme to work extracted higher 6 bits of the offset will be
0025  * written to pg_sel field of PAB_CTRL register and rest of the lower 10
0026  * bits enabled with PAGED_ADDR_BNDRY are used as offset of the register.
0027  */
0028 static void mobiveil_pcie_sel_page(struct mobiveil_pcie *pcie, u8 pg_idx)
0029 {
0030     u32 val;
0031 
0032     val = readl(pcie->csr_axi_slave_base + PAB_CTRL);
0033     val &= ~(PAGE_SEL_MASK << PAGE_SEL_SHIFT);
0034     val |= (pg_idx & PAGE_SEL_MASK) << PAGE_SEL_SHIFT;
0035 
0036     writel(val, pcie->csr_axi_slave_base + PAB_CTRL);
0037 }
0038 
0039 static void __iomem *mobiveil_pcie_comp_addr(struct mobiveil_pcie *pcie,
0040                          u32 off)
0041 {
0042     if (off < PAGED_ADDR_BNDRY) {
0043         /* For directly accessed registers, clear the pg_sel field */
0044         mobiveil_pcie_sel_page(pcie, 0);
0045         return pcie->csr_axi_slave_base + off;
0046     }
0047 
0048     mobiveil_pcie_sel_page(pcie, OFFSET_TO_PAGE_IDX(off));
0049     return pcie->csr_axi_slave_base + OFFSET_TO_PAGE_ADDR(off);
0050 }
0051 
0052 static int mobiveil_pcie_read(void __iomem *addr, int size, u32 *val)
0053 {
0054     if ((uintptr_t)addr & (size - 1)) {
0055         *val = 0;
0056         return PCIBIOS_BAD_REGISTER_NUMBER;
0057     }
0058 
0059     switch (size) {
0060     case 4:
0061         *val = readl(addr);
0062         break;
0063     case 2:
0064         *val = readw(addr);
0065         break;
0066     case 1:
0067         *val = readb(addr);
0068         break;
0069     default:
0070         *val = 0;
0071         return PCIBIOS_BAD_REGISTER_NUMBER;
0072     }
0073 
0074     return PCIBIOS_SUCCESSFUL;
0075 }
0076 
0077 static int mobiveil_pcie_write(void __iomem *addr, int size, u32 val)
0078 {
0079     if ((uintptr_t)addr & (size - 1))
0080         return PCIBIOS_BAD_REGISTER_NUMBER;
0081 
0082     switch (size) {
0083     case 4:
0084         writel(val, addr);
0085         break;
0086     case 2:
0087         writew(val, addr);
0088         break;
0089     case 1:
0090         writeb(val, addr);
0091         break;
0092     default:
0093         return PCIBIOS_BAD_REGISTER_NUMBER;
0094     }
0095 
0096     return PCIBIOS_SUCCESSFUL;
0097 }
0098 
0099 u32 mobiveil_csr_read(struct mobiveil_pcie *pcie, u32 off, size_t size)
0100 {
0101     void __iomem *addr;
0102     u32 val;
0103     int ret;
0104 
0105     addr = mobiveil_pcie_comp_addr(pcie, off);
0106 
0107     ret = mobiveil_pcie_read(addr, size, &val);
0108     if (ret)
0109         dev_err(&pcie->pdev->dev, "read CSR address failed\n");
0110 
0111     return val;
0112 }
0113 
0114 void mobiveil_csr_write(struct mobiveil_pcie *pcie, u32 val, u32 off,
0115                    size_t size)
0116 {
0117     void __iomem *addr;
0118     int ret;
0119 
0120     addr = mobiveil_pcie_comp_addr(pcie, off);
0121 
0122     ret = mobiveil_pcie_write(addr, size, val);
0123     if (ret)
0124         dev_err(&pcie->pdev->dev, "write CSR address failed\n");
0125 }
0126 
0127 bool mobiveil_pcie_link_up(struct mobiveil_pcie *pcie)
0128 {
0129     if (pcie->ops->link_up)
0130         return pcie->ops->link_up(pcie);
0131 
0132     return (mobiveil_csr_readl(pcie, LTSSM_STATUS) &
0133         LTSSM_STATUS_L0_MASK) == LTSSM_STATUS_L0;
0134 }
0135 
0136 void program_ib_windows(struct mobiveil_pcie *pcie, int win_num,
0137             u64 cpu_addr, u64 pci_addr, u32 type, u64 size)
0138 {
0139     u32 value;
0140     u64 size64 = ~(size - 1);
0141 
0142     if (win_num >= pcie->ppio_wins) {
0143         dev_err(&pcie->pdev->dev,
0144             "ERROR: max inbound windows reached !\n");
0145         return;
0146     }
0147 
0148     value = mobiveil_csr_readl(pcie, PAB_PEX_AMAP_CTRL(win_num));
0149     value &= ~(AMAP_CTRL_TYPE_MASK << AMAP_CTRL_TYPE_SHIFT | WIN_SIZE_MASK);
0150     value |= type << AMAP_CTRL_TYPE_SHIFT | 1 << AMAP_CTRL_EN_SHIFT |
0151          (lower_32_bits(size64) & WIN_SIZE_MASK);
0152     mobiveil_csr_writel(pcie, value, PAB_PEX_AMAP_CTRL(win_num));
0153 
0154     mobiveil_csr_writel(pcie, upper_32_bits(size64),
0155                 PAB_EXT_PEX_AMAP_SIZEN(win_num));
0156 
0157     mobiveil_csr_writel(pcie, lower_32_bits(cpu_addr),
0158                 PAB_PEX_AMAP_AXI_WIN(win_num));
0159     mobiveil_csr_writel(pcie, upper_32_bits(cpu_addr),
0160                 PAB_EXT_PEX_AMAP_AXI_WIN(win_num));
0161 
0162     mobiveil_csr_writel(pcie, lower_32_bits(pci_addr),
0163                 PAB_PEX_AMAP_PEX_WIN_L(win_num));
0164     mobiveil_csr_writel(pcie, upper_32_bits(pci_addr),
0165                 PAB_PEX_AMAP_PEX_WIN_H(win_num));
0166 
0167     pcie->ib_wins_configured++;
0168 }
0169 
0170 /*
0171  * routine to program the outbound windows
0172  */
0173 void program_ob_windows(struct mobiveil_pcie *pcie, int win_num,
0174             u64 cpu_addr, u64 pci_addr, u32 type, u64 size)
0175 {
0176     u32 value;
0177     u64 size64 = ~(size - 1);
0178 
0179     if (win_num >= pcie->apio_wins) {
0180         dev_err(&pcie->pdev->dev,
0181             "ERROR: max outbound windows reached !\n");
0182         return;
0183     }
0184 
0185     /*
0186      * program Enable Bit to 1, Type Bit to (00) base 2, AXI Window Size Bit
0187      * to 4 KB in PAB_AXI_AMAP_CTRL register
0188      */
0189     value = mobiveil_csr_readl(pcie, PAB_AXI_AMAP_CTRL(win_num));
0190     value &= ~(WIN_TYPE_MASK << WIN_TYPE_SHIFT | WIN_SIZE_MASK);
0191     value |= 1 << WIN_ENABLE_SHIFT | type << WIN_TYPE_SHIFT |
0192          (lower_32_bits(size64) & WIN_SIZE_MASK);
0193     mobiveil_csr_writel(pcie, value, PAB_AXI_AMAP_CTRL(win_num));
0194 
0195     mobiveil_csr_writel(pcie, upper_32_bits(size64),
0196                 PAB_EXT_AXI_AMAP_SIZE(win_num));
0197 
0198     /*
0199      * program AXI window base with appropriate value in
0200      * PAB_AXI_AMAP_AXI_WIN0 register
0201      */
0202     mobiveil_csr_writel(pcie,
0203                 lower_32_bits(cpu_addr) & (~AXI_WINDOW_ALIGN_MASK),
0204                 PAB_AXI_AMAP_AXI_WIN(win_num));
0205     mobiveil_csr_writel(pcie, upper_32_bits(cpu_addr),
0206                 PAB_EXT_AXI_AMAP_AXI_WIN(win_num));
0207 
0208     mobiveil_csr_writel(pcie, lower_32_bits(pci_addr),
0209                 PAB_AXI_AMAP_PEX_WIN_L(win_num));
0210     mobiveil_csr_writel(pcie, upper_32_bits(pci_addr),
0211                 PAB_AXI_AMAP_PEX_WIN_H(win_num));
0212 
0213     pcie->ob_wins_configured++;
0214 }
0215 
0216 int mobiveil_bringup_link(struct mobiveil_pcie *pcie)
0217 {
0218     int retries;
0219 
0220     /* check if the link is up or not */
0221     for (retries = 0; retries < LINK_WAIT_MAX_RETRIES; retries++) {
0222         if (mobiveil_pcie_link_up(pcie))
0223             return 0;
0224 
0225         usleep_range(LINK_WAIT_MIN, LINK_WAIT_MAX);
0226     }
0227 
0228     dev_err(&pcie->pdev->dev, "link never came up\n");
0229 
0230     return -ETIMEDOUT;
0231 }