// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2015, Sony Mobile Communications AB. * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. */ #include <linux/interrupt.h> #include <linux/list.h> #include <linux/io.h> #include <linux/of.h> #include <linux/irq.h> #include <linux/irqdomain.h> #include <linux/mailbox_client.h> #include <linux/mfd/syscon.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/pm_wakeirq.h> #include <linux/regmap.h> #include <linux/seq_file.h> #include <linux/soc/qcom/smem.h> #include <linux/soc/qcom/smem_state.h> #include <linux/spinlock.h> /* * The Shared Memory Point to Point (SMP2P) protocol facilitates communication * of a single 32-bit value between two processors. Each value has a single * writer (the local side) and a single reader (the remote side). Values are * uniquely identified in the system by the directed edge (local processor ID * to remote processor ID) and a string identifier. * * Each processor is responsible for creating the outgoing SMEM items and each * item is writable by the local processor and readable by the remote * processor. By using two separate SMEM items that are single-reader and * single-writer, SMP2P does not require any remote locking mechanisms. * * The driver uses the Linux GPIO and interrupt framework to expose a virtual * GPIO for each outbound entry and a virtual interrupt controller for each * inbound entry. */ #define SMP2P_MAX_ENTRY … #define SMP2P_MAX_ENTRY_NAME … #define SMP2P_FEATURE_SSR_ACK … #define SMP2P_FLAGS_RESTART_DONE_BIT … #define SMP2P_FLAGS_RESTART_ACK_BIT … #define SMP2P_MAGIC … #define SMP2P_ALL_FEATURES … /** * struct smp2p_smem_item - in memory communication structure * @magic: magic number * @version: version - must be 1 * @features: features flag - currently unused * @local_pid: processor id of sending end * @remote_pid: processor id of receiving end * @total_entries: number of entries - always SMP2P_MAX_ENTRY * @valid_entries: number of allocated entries * @flags: * @entries: individual communication entries * @entries.name: name of the entry * @entries.value: content of the entry */ struct smp2p_smem_item { … } __packed; /** * struct smp2p_entry - driver context matching one entry * @node: list entry to keep track of allocated entries * @smp2p: reference to the device driver context * @name: name of the entry, to match against smp2p_smem_item * @value: pointer to smp2p_smem_item entry value * @last_value: last handled value * @domain: irq_domain for inbound entries * @irq_enabled:bitmap to track enabled irq bits * @irq_rising: bitmap to mark irq bits for rising detection * @irq_falling:bitmap to mark irq bits for falling detection * @state: smem state handle * @lock: spinlock to protect read-modify-write of the value */ struct smp2p_entry { … }; #define SMP2P_INBOUND … #define SMP2P_OUTBOUND … /** * struct qcom_smp2p - device driver context * @dev: device driver handle * @in: pointer to the inbound smem item * @out: pointer to the outbound smem item * @smem_items: ids of the two smem items * @valid_entries: already scanned inbound entries * @ssr_ack_enabled: SMP2P_FEATURE_SSR_ACK feature is supported and was enabled * @ssr_ack: current cached state of the local ack bit * @negotiation_done: whether negotiating finished * @local_pid: processor id of the inbound edge * @remote_pid: processor id of the outbound edge * @ipc_regmap: regmap for the outbound ipc * @ipc_offset: offset within the regmap * @ipc_bit: bit in regmap@offset to kick to signal remote processor * @mbox_client: mailbox client handle * @mbox_chan: apcs ipc mailbox channel handle * @inbound: list of inbound entries * @outbound: list of outbound entries */ struct qcom_smp2p { … }; static void qcom_smp2p_kick(struct qcom_smp2p *smp2p) { … } static bool qcom_smp2p_check_ssr(struct qcom_smp2p *smp2p) { … } static void qcom_smp2p_do_ssr_ack(struct qcom_smp2p *smp2p) { … } static void qcom_smp2p_negotiate(struct qcom_smp2p *smp2p) { … } static void qcom_smp2p_notify_in(struct qcom_smp2p *smp2p) { … } /** * qcom_smp2p_intr() - interrupt handler for incoming notifications * @irq: unused * @data: smp2p driver context * * Handle notifications from the remote side to handle newly allocated entries * or any changes to the state bits of existing entries. * * Return: %IRQ_HANDLED */ static irqreturn_t qcom_smp2p_intr(int irq, void *data) { … } static void smp2p_mask_irq(struct irq_data *irqd) { … } static void smp2p_unmask_irq(struct irq_data *irqd) { … } static int smp2p_set_irq_type(struct irq_data *irqd, unsigned int type) { … } static void smp2p_irq_print_chip(struct irq_data *irqd, struct seq_file *p) { … } static struct irq_chip smp2p_irq_chip = …; static int smp2p_irq_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) { … } static const struct irq_domain_ops smp2p_irq_ops = …; static int qcom_smp2p_inbound_entry(struct qcom_smp2p *smp2p, struct smp2p_entry *entry, struct device_node *node) { … } static int smp2p_update_bits(void *data, u32 mask, u32 value) { … } static const struct qcom_smem_state_ops smp2p_state_ops = …; static int qcom_smp2p_outbound_entry(struct qcom_smp2p *smp2p, struct smp2p_entry *entry, struct device_node *node) { … } static int qcom_smp2p_alloc_outbound_item(struct qcom_smp2p *smp2p) { … } static int smp2p_parse_ipc(struct qcom_smp2p *smp2p) { … } static int qcom_smp2p_probe(struct platform_device *pdev) { … } static void qcom_smp2p_remove(struct platform_device *pdev) { … } static const struct of_device_id qcom_smp2p_of_match[] = …; MODULE_DEVICE_TABLE(of, qcom_smp2p_of_match); static struct platform_driver qcom_smp2p_driver = …; module_platform_driver(…) …; MODULE_DESCRIPTION(…) …; MODULE_LICENSE(…) …;