Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9b41b7ec authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: ep_pcie: add PCIe endpoint driver snapshot"

parents 1b9a46d9 50222ad7
Loading
Loading
Loading
Loading
+141 −0
Original line number Diff line number Diff line
MSM PCI express endpoint

Required properties:
  - compatible: should be "qcom,pcie-ep".
  - reg: should contain PCIe register maps.
  - reg-names: indicates various resources passed to driver by name.
		Should be "msi", "dm_core", "elbi", "parf", "phy", "mmio".
		These correspond to different modules within the PCIe domain.
  - #address-cells: Should provide a value of 0.
  - interrupt-parent: Should be the PCIe device node itself here.
  - interrupts: Should be in the format <0 1 2> and it is an index to the
		interrupt-map that contains PCIe related interrupts.
  - #interrupt-cells: Should provide a value of 1.
  - #interrupt-map-mask: should provide a value of 0xffffffff.
  - interrupt-map:  Must create mapping for the number of interrupts
		    that are defined in above interrupts property.
		    For PCIe device node, it should define 6 mappings for
		    the corresponding PCIe interrupts supporting the
		    specification.
  - interrupt-names: indicates interrupts passed to driver by name.
		     Should be "int_pm_turnoff", "int_dstate_change",
				"int_l1sub_timeout", "int_link_up",
				"int_link_down", "int_bridge_flush_n".
  - perst-gpio: PERST GPIO specified by PCIe spec.
  - wake-gpio: WAKE GPIO specified by PCIe spec.
  - clkreq-gpio: CLKREQ GPIO specified by PCIe spec.
  - <supply-name>-supply: phandle to the regulator device tree node.
    Refer to the schematics for the corresponding voltage regulators.
    vreg-1.8-supply: phandle to the analog supply for the PCIe controller.
    vreg-0.9-supply: phandle to the analog supply for the PCIe controller.

Optional Properties:
  - qcom,<supply-name>-voltage-level: specifies voltage levels for supply.
    Should be specified in pairs (max, min, optimal), units uV.
  - clock-names: list of names of clock inputs.
		     Should be "pcie_0_pipe_clk",
				"pcie_0_aux_clk", "pcie_0_cfg_ahb_clk",
				"pcie_0_mstr_axi_clk", "pcie_0_slv_axi_clk",
				"pcie_0_ldo";
  - max-clock-frequency-hz: list of the maximum operating frequencies stored
				in the same order of clock names;
  - resets: reset specifier pair consists of phandle for the reset controller
    and reset lines used by this controller.
  - reset-names: reset signal names sorted in the same order as the property
    of resets.
  - qcom,pcie-phy-ver: version of PCIe PHY.
  - qcom,phy-init: The initialization sequence to bring up the PCIe PHY.
    Should be specified in groups (offset, value, delay, direction).
  - qcom,phy-status-reg: Register offset for PHY status.
  - qcom,dbi-base-reg: Register offset for DBI base address.
  - qcom,slv-space-reg: Register offset for slave address space size.
  - qcom,pcie-link-speed: generation of PCIe link speed. The value could be
    1, 2 or 3.
  - qcom,pcie-active-config: boolean type; active configuration of PCIe
    addressing.
  - qcom,pcie-aggregated-irq: boolean type; interrupts are aggregated.
  - qcom,pcie-mhi-a7-irq: boolean type; MHI a7 has separate irq.
  - qcom,pcie-perst-enum: Link enumeration will be triggered by PERST
    deassertion.
  - mdm2apstatus-gpio: GPIO used by PCIe endpoint side to notify the host side.
  - Refer to "Documentation/devicetree/bindings/arm/msm/msm_bus.txt" for
    below optional properties:
	- qcom,msm-bus,name
	- qcom,msm-bus,num-cases
	- qcom,msm-bus,num-paths
	- qcom,msm-bus,vectors-KBps

Example:

	pcie_ep: qcom,pcie@bfffd000 {
		compatible = "qcom,pcie-ep";

		reg = <0xbfffd000 0x1000>,
			<0xbfffe000 0x1000>,
			<0xbffff000 0x1000>,
			<0xfc520000 0x2000>,
			<0xfc526000 0x1000>,
			<0xfc527000 0x1000>;
		reg-names = "msi", "dm_core", "elbi", "parf", "phy", "mmio";

		#address-cells = <0>;
		interrupt-parent = <&pcie_ep>;
		interrupts = <0 1 2 3 4 5>;
		#interrupt-cells = <1>;
		interrupt-map-mask = <0xffffffff>;
		interrupt-map = <0 &intc 0 44 0
				1 &intc 0 46 0
				2 &intc 0 47 0
				3 &intc 0 50 0
				4 &intc 0 51 0
				5 &intc 0 52 0>;
		interrupt-names = "int_pm_turnoff", "int_dstate_change",
				"int_l1sub_timeout", "int_link_up",
				"int_link_down", "int_bridge_flush_n";

		perst-gpio = <&msmgpio 65 0>;
		wake-gpio = <&msmgpio 61 0>;
		clkreq-gpio = <&msmgpio 64 0>;
		mdm2apstatus-gpio = <&tlmm_pinmux 16 0>;

		gdsc-vdd-supply = <&gdsc_pcie_0>;
		vreg-1.8-supply = <&pmd9635_l8>;
		vreg-0.9-supply = <&pmd9635_l4>;

		qcom,vreg-1.8-voltage-level = <1800000 1800000 1000>;
		qcom,vreg-0.9-voltage-level = <950000 950000 24000>;

		clock-names = "pcie_0_pipe_clk",
				"pcie_0_aux_clk", "pcie_0_cfg_ahb_clk",
				"pcie_0_mstr_axi_clk", "pcie_0_slv_axi_clk",
				"pcie_0_ldo";
		max-clock-frequency-hz = <62500000>, <1000000>,
						<0>, <0>, <0>, <0>;

		resets = <&clock_gcc GCC_PCIE_BCR>,
			<&clock_gcc GCC_PCIE_PHY_BCR>;

		reset-names = "pcie_0_core_reset", "pcie_0_phy_reset";

		qcom,msm-bus,name = "pcie-ep";
		qcom,msm-bus,num-cases = <2>;
		qcom,msm-bus,num-paths = <1>;
		qcom,msm-bus,vectors-KBps =
				<45 512 0 0>,
				<45 512 500 800>;

		qcom,pcie-link-speed = <1>;
		qcom,pcie-active-config;
		qcom,pcie-aggregated-irq;
		qcom,pcie-mhi-a7-irq;
		qcom,pcie-perst-enum;
		qcom,phy-status-reg = <0x728>;
		qcom,dbi-base-reg = <0x168>;
		qcom,slv-space-reg = <0x16c>;

		qcom,phy-init = <0x604 0x03 0x0 0x1
					0x048 0x08 0x0 0x1
					0x64c 0x4d 0x0 0x1
					0x600 0x00 0x0 0x1
					0x608 0x03 0x0 0x1>;
	};
+21 −0
Original line number Diff line number Diff line
@@ -112,6 +112,27 @@ config SPS_SUPPORT_NDP_BAM
	help
	  No-Data-Path BAM is used to improve BAM performance.

config EP_PCIE
	bool "PCIe Endpoint mode support"
	select GENERIC_ALLOCATOR
	help
	  PCIe controller is in endpoint mode.
	  It supports the APIs to clients as a service layer, and allows
	  clients to enable/disable PCIe link, configure the address
	  mapping for the access to host memory, trigger wake interrupt
	  on host side to wake up host, and trigger MSI to host side.

config EP_PCIE_HW
	bool "PCIe Endpoint HW driver"
	depends on EP_PCIE
	help
	  PCIe endpoint HW specific implementation.
	  It supports:
		1. link training with Root Complex.
		2. Address mapping.
		3. Sideband signaling.
		4. Power management.

config QPNP_COINCELL
	tristate "QPNP coincell charger support"
	depends on SPMI
+1 −0
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@ obj-$(CONFIG_IPA3) += ipa/
obj-$(CONFIG_SPS) += sps/
obj-$(CONFIG_QPNP_COINCELL) += qpnp-coincell.o
obj-$(CONFIG_QPNP_REVID) += qpnp-revid.o
obj-$(CONFIG_EP_PCIE) += ep_pcie/
obj-$(CONFIG_MSM_MHI_DEV) += mhi_dev/
obj-$(CONFIG_USB_BAM) += usb_bam.o
obj-$(CONFIG_MSM_11AD) += msm_11ad/
+2 −0
Original line number Diff line number Diff line
obj-$(CONFIG_EP_PCIE) += ep_pcie.o
obj-$(CONFIG_EP_PCIE_HW) += ep_pcie_core.o ep_pcie_phy.o ep_pcie_dbg.o
+230 −0
Original line number Diff line number Diff line
/* Copyright (c) 2015, 2017, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
 * only version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

/*
 * MSM PCIe endpoint service layer.
 */
#include <linux/types.h>
#include <linux/list.h>
#include <linux/compiler.h>
#include <linux/kernel.h>
#include <linux/bitops.h>
#include <linux/errno.h>
#include "ep_pcie_com.h"

LIST_HEAD(head);

int ep_pcie_register_drv(struct ep_pcie_hw *handle)
{
	struct ep_pcie_hw *present;
	bool new = true;

	if (!handle) {
		pr_err("ep_pcie:%s: the input handle is NULL.",
			__func__);
		return -EINVAL;
	}

	list_for_each_entry(present, &head, node) {
		if (present->device_id == handle->device_id) {
			new = false;
			break;
		}
	}

	if (new) {
		list_add(&handle->node, &head);
		pr_debug("ep_pcie:%s: register a new driver for device 0x%x.",
			__func__, handle->device_id);
		return 0;
	}
	pr_debug(
		"ep_pcie:%s: driver to register for device 0x%x has already existed.",
		__func__, handle->device_id);
	return -EEXIST;
}
EXPORT_SYMBOL(ep_pcie_register_drv);

int ep_pcie_deregister_drv(struct ep_pcie_hw *handle)
{
	struct ep_pcie_hw *present;
	bool found = false;

	if (!handle) {
		pr_err("ep_pcie:%s: the input handle is NULL.",
			__func__);
		return -EINVAL;
	}

	list_for_each_entry(present, &head, node) {
		if (present->device_id == handle->device_id) {
			found = true;
			list_del(&handle->node);
			break;
		}
	}

	if (found) {
		pr_debug("ep_pcie:%s: deregistered driver for device 0x%x.",
			__func__, handle->device_id);
		return 0;
	}
	pr_err("ep_pcie:%s: driver for device 0x%x does not exist.",
		__func__, handle->device_id);
	return -EEXIST;
}
EXPORT_SYMBOL(ep_pcie_deregister_drv);

struct ep_pcie_hw *ep_pcie_get_phandle(u32 id)
{
	struct ep_pcie_hw *present;

	list_for_each_entry(present, &head, node) {
		if (present->device_id == id) {
			pr_debug("ep_pcie:%s: found driver for device 0x%x.",
				__func__, id);
			return present;
		}
	}

	pr_debug("ep_pcie:%s: driver for device 0x%x does not exist.",
			__func__, id);
	return NULL;
}
EXPORT_SYMBOL(ep_pcie_get_phandle);

int ep_pcie_register_event(struct ep_pcie_hw *phandle,
			struct ep_pcie_register_event *reg)
{
	if (phandle)
		return phandle->register_event(reg);

	return ep_pcie_core_register_event(reg);
}
EXPORT_SYMBOL(ep_pcie_register_event);

int ep_pcie_deregister_event(struct ep_pcie_hw *phandle)
{
	if (phandle)
		return phandle->deregister_event();

	pr_err("ep_pcie:%s: the input driver handle is NULL.",
		__func__);
	return -EINVAL;
}
EXPORT_SYMBOL(ep_pcie_deregister_event);

enum ep_pcie_link_status ep_pcie_get_linkstatus(struct ep_pcie_hw *phandle)
{
	if (phandle)
		return phandle->get_linkstatus();

	pr_err("ep_pcie:%s: the input driver handle is NULL.",
		__func__);
	return -EINVAL;
}
EXPORT_SYMBOL(ep_pcie_get_linkstatus);

int ep_pcie_config_outbound_iatu(struct ep_pcie_hw *phandle,
				struct ep_pcie_iatu entries[],
				u32 num_entries)
{
	if (phandle)
		return phandle->config_outbound_iatu(entries, num_entries);

	pr_err("ep_pcie:%s: the input driver handle is NULL.",
		__func__);
	return -EINVAL;
}
EXPORT_SYMBOL(ep_pcie_config_outbound_iatu);

int ep_pcie_get_msi_config(struct ep_pcie_hw *phandle,
				struct ep_pcie_msi_config *cfg)
{
	if (phandle)
		return phandle->get_msi_config(cfg);

	pr_err("ep_pcie:%s: the input driver handle is NULL.",
		__func__);
	return -EINVAL;
}
EXPORT_SYMBOL(ep_pcie_get_msi_config);

int ep_pcie_trigger_msi(struct ep_pcie_hw *phandle, u32 idx)
{
	if (phandle)
		return phandle->trigger_msi(idx);

	pr_err("ep_pcie:%s: the input driver handle is NULL.",
		__func__);
	return -EINVAL;
}
EXPORT_SYMBOL(ep_pcie_trigger_msi);

int ep_pcie_wakeup_host(struct ep_pcie_hw *phandle)
{
	if (phandle)
		return phandle->wakeup_host();

	pr_err("ep_pcie:%s: the input driver handle is NULL.",
		__func__);
	return -EINVAL;
}
EXPORT_SYMBOL(ep_pcie_wakeup_host);

int ep_pcie_config_db_routing(struct ep_pcie_hw *phandle,
				struct ep_pcie_db_config chdb_cfg,
				struct ep_pcie_db_config erdb_cfg)
{
	if (phandle)
		return phandle->config_db_routing(chdb_cfg, erdb_cfg);

	pr_err("ep_pcie:%s: the input driver handle is NULL.",
		__func__);
	return -EINVAL;
}
EXPORT_SYMBOL(ep_pcie_config_db_routing);

int ep_pcie_enable_endpoint(struct ep_pcie_hw *phandle,
				enum ep_pcie_options opt)
{
	if (phandle)
		return phandle->enable_endpoint(opt);

	pr_err("ep_pcie:%s: the input driver handle is NULL.",
		__func__);
	return -EINVAL;
}
EXPORT_SYMBOL(ep_pcie_enable_endpoint);

int ep_pcie_disable_endpoint(struct ep_pcie_hw *phandle)
{
	if (phandle)
		return phandle->disable_endpoint();

	pr_err("ep_pcie:%s: the input driver handle is NULL.",
		__func__);
	return -EINVAL;
}
EXPORT_SYMBOL(ep_pcie_disable_endpoint);

int ep_pcie_mask_irq_event(struct ep_pcie_hw *phandle,
				enum ep_pcie_irq_event event,
				bool enable)
{
	if (phandle)
		return phandle->mask_irq_event(event, enable);

	pr_err("ep_pcie:%s: the input driver handle is NULL.", __func__);
	return -EINVAL;
}
EXPORT_SYMBOL(ep_pcie_mask_irq_event);
Loading