cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

pcie-mobiveil.c (5855B)


      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 */
     28static 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
     39static 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
     52static 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
     77static 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
     99u32 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
    114void 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
    127bool 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
    136void 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 */
    173void 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
    216int 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}