brintos

brintos / linux-shallow public Read only

0
0
Text · 4.3 KiB · 771b9d9 Raw
198 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * PCIe RC driver for Synopsys DesignWare Core4 *5 * Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com)6 *7 * Authors: Joao Pinto <Joao.Pinto@synopsys.com>8 */9#include <linux/clk.h>10#include <linux/delay.h>11#include <linux/gpio.h>12#include <linux/interrupt.h>13#include <linux/kernel.h>14#include <linux/init.h>15#include <linux/of.h>16#include <linux/pci.h>17#include <linux/platform_device.h>18#include <linux/resource.h>19#include <linux/types.h>20 21#include "pcie-designware.h"22 23struct dw_plat_pcie {24	struct dw_pcie			*pci;25	enum dw_pcie_device_mode	mode;26};27 28struct dw_plat_pcie_of_data {29	enum dw_pcie_device_mode	mode;30};31 32static const struct dw_pcie_host_ops dw_plat_pcie_host_ops = {33};34 35static void dw_plat_pcie_ep_init(struct dw_pcie_ep *ep)36{37	struct dw_pcie *pci = to_dw_pcie_from_ep(ep);38	enum pci_barno bar;39 40	for (bar = 0; bar < PCI_STD_NUM_BARS; bar++)41		dw_pcie_ep_reset_bar(pci, bar);42}43 44static int dw_plat_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,45				     unsigned int type, u16 interrupt_num)46{47	struct dw_pcie *pci = to_dw_pcie_from_ep(ep);48 49	switch (type) {50	case PCI_IRQ_INTX:51		return dw_pcie_ep_raise_intx_irq(ep, func_no);52	case PCI_IRQ_MSI:53		return dw_pcie_ep_raise_msi_irq(ep, func_no, interrupt_num);54	case PCI_IRQ_MSIX:55		return dw_pcie_ep_raise_msix_irq(ep, func_no, interrupt_num);56	default:57		dev_err(pci->dev, "UNKNOWN IRQ type\n");58	}59 60	return 0;61}62 63static const struct pci_epc_features dw_plat_pcie_epc_features = {64	.linkup_notifier = false,65	.msi_capable = true,66	.msix_capable = true,67};68 69static const struct pci_epc_features*70dw_plat_pcie_get_features(struct dw_pcie_ep *ep)71{72	return &dw_plat_pcie_epc_features;73}74 75static const struct dw_pcie_ep_ops pcie_ep_ops = {76	.init = dw_plat_pcie_ep_init,77	.raise_irq = dw_plat_pcie_ep_raise_irq,78	.get_features = dw_plat_pcie_get_features,79};80 81static int dw_plat_add_pcie_port(struct dw_plat_pcie *dw_plat_pcie,82				 struct platform_device *pdev)83{84	struct dw_pcie *pci = dw_plat_pcie->pci;85	struct dw_pcie_rp *pp = &pci->pp;86	struct device *dev = &pdev->dev;87	int ret;88 89	pp->irq = platform_get_irq(pdev, 1);90	if (pp->irq < 0)91		return pp->irq;92 93	pp->num_vectors = MAX_MSI_IRQS;94	pp->ops = &dw_plat_pcie_host_ops;95 96	ret = dw_pcie_host_init(pp);97	if (ret) {98		dev_err(dev, "Failed to initialize host\n");99		return ret;100	}101 102	return 0;103}104 105static int dw_plat_pcie_probe(struct platform_device *pdev)106{107	struct device *dev = &pdev->dev;108	struct dw_plat_pcie *dw_plat_pcie;109	struct dw_pcie *pci;110	int ret;111	const struct dw_plat_pcie_of_data *data;112	enum dw_pcie_device_mode mode;113 114	data = of_device_get_match_data(dev);115	if (!data)116		return -EINVAL;117 118	mode = (enum dw_pcie_device_mode)data->mode;119 120	dw_plat_pcie = devm_kzalloc(dev, sizeof(*dw_plat_pcie), GFP_KERNEL);121	if (!dw_plat_pcie)122		return -ENOMEM;123 124	pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL);125	if (!pci)126		return -ENOMEM;127 128	pci->dev = dev;129 130	dw_plat_pcie->pci = pci;131	dw_plat_pcie->mode = mode;132 133	platform_set_drvdata(pdev, dw_plat_pcie);134 135	switch (dw_plat_pcie->mode) {136	case DW_PCIE_RC_TYPE:137		if (!IS_ENABLED(CONFIG_PCIE_DW_PLAT_HOST))138			return -ENODEV;139 140		ret = dw_plat_add_pcie_port(dw_plat_pcie, pdev);141		break;142	case DW_PCIE_EP_TYPE:143		if (!IS_ENABLED(CONFIG_PCIE_DW_PLAT_EP))144			return -ENODEV;145 146		pci->ep.ops = &pcie_ep_ops;147		ret = dw_pcie_ep_init(&pci->ep);148		if (ret)149			return ret;150 151		ret = dw_pcie_ep_init_registers(&pci->ep);152		if (ret) {153			dev_err(dev, "Failed to initialize DWC endpoint registers\n");154			dw_pcie_ep_deinit(&pci->ep);155		}156 157		pci_epc_init_notify(pci->ep.epc);158 159		break;160	default:161		dev_err(dev, "INVALID device type %d\n", dw_plat_pcie->mode);162		ret = -EINVAL;163		break;164	}165 166	return ret;167}168 169static const struct dw_plat_pcie_of_data dw_plat_pcie_rc_of_data = {170	.mode = DW_PCIE_RC_TYPE,171};172 173static const struct dw_plat_pcie_of_data dw_plat_pcie_ep_of_data = {174	.mode = DW_PCIE_EP_TYPE,175};176 177static const struct of_device_id dw_plat_pcie_of_match[] = {178	{179		.compatible = "snps,dw-pcie",180		.data = &dw_plat_pcie_rc_of_data,181	},182	{183		.compatible = "snps,dw-pcie-ep",184		.data = &dw_plat_pcie_ep_of_data,185	},186	{},187};188 189static struct platform_driver dw_plat_pcie_driver = {190	.driver = {191		.name	= "dw-pcie",192		.of_match_table = dw_plat_pcie_of_match,193		.suppress_bind_attrs = true,194	},195	.probe = dw_plat_pcie_probe,196};197builtin_platform_driver(dw_plat_pcie_driver);198