brintos

brintos / linux-shallow public Read only

0
0
Text · 5.7 KiB · 62ecbae Raw
232 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * PCIe host controller driver for Mobiveil PCIe Host controller4 *5 * Copyright (c) 2018 Mobiveil Inc.6 * Copyright 2019 NXP7 *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 register22 *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 be25 * written to pg_sel field of PAB_CTRL register and rest of the lower 1026 * 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 windows172 */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 Bit187	 * to 4 KB in PAB_AXI_AMAP_CTRL register188	 */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 in200	 * PAB_AXI_AMAP_AXI_WIN0 register201	 */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}232