Merge "ARM: config: msm: Enable BAM config for Pineapple"
This commit is contained in:
commit
fe600bc810
@ -82,6 +82,7 @@ CONFIG_POWER_RESET_QCOM_PON=m
|
||||
CONFIG_POWER_RESET_QCOM_REBOOT_REASON=m
|
||||
CONFIG_PWM_QTI_LPG=m
|
||||
CONFIG_QCOM_AOSS_QMP=m
|
||||
CONFIG_QCOM_BAM_DMA=m
|
||||
CONFIG_QCOM_BWMON=m
|
||||
CONFIG_QCOM_CLK_RPMH=m
|
||||
# CONFIG_QCOM_COINCELL is not set
|
||||
@ -194,6 +195,8 @@ CONFIG_SM_VIDEOCC_PINEAPPLE=m
|
||||
CONFIG_SPI_MSM_GENI=m
|
||||
CONFIG_SPMI_MSM_PMIC_ARB=m
|
||||
CONFIG_SPMI_QTI_GLINK_DEBUG=m
|
||||
CONFIG_SPS=m
|
||||
CONFIG_SPS_SUPPORT_NDP_BAM=y
|
||||
CONFIG_STM=m
|
||||
CONFIG_STM_PROTO_OST=m
|
||||
CONFIG_STM_SOURCE_CONSOLE=m
|
||||
|
@ -4,6 +4,35 @@
|
||||
#
|
||||
menu "Qualcomm SoC drivers"
|
||||
|
||||
config SPS
|
||||
tristate "SPS support"
|
||||
select GENERIC_ALLOCATOR
|
||||
help
|
||||
The SPS (Smart Peripheral Switch) is a DMA engine.
|
||||
It can move data in the following modes:
|
||||
1. Peripheral-to-Peripheral.
|
||||
2. Peripheral-to-Memory.
|
||||
3. Memory-to-Memory.
|
||||
|
||||
config SPS_SUPPORT_BAMDMA
|
||||
bool "SPS supports BAM DMA"
|
||||
depends on SPS
|
||||
help
|
||||
The BAM-DMA is used for Memory-to-Memory transfers.
|
||||
The main use cases is RPC between processors.
|
||||
The BAM-DMA hardware has 2 registers sets:
|
||||
1. A BAM HW like all the peripherals.
|
||||
2. A DMA channel configuration (i.e. channel priority).
|
||||
|
||||
config SPS_SUPPORT_NDP_BAM
|
||||
bool "SPS supports NDP BAM"
|
||||
depends on SPS
|
||||
help
|
||||
No-Data-Path BAM is used to improve BAM performance.
|
||||
NDP BAMs enables peripherals with fast fabric connectivity
|
||||
to do the actual data transfer themselves, instead of the
|
||||
BAM.
|
||||
|
||||
config QCOM_AOSS_QMP
|
||||
tristate "Qualcomm AOSS Driver"
|
||||
depends on ARCH_QCOM || COMPILE_TEST
|
||||
|
@ -65,6 +65,7 @@ obj-$(CONFIG_QCOM_LOGBUF_VENDOR_HOOKS) += qcom_logbuf_vh.o
|
||||
obj-$(CONFIG_QCOM_HUNG_TASK_ENH) += hung_task_enh.o
|
||||
obj-$(CONFIG_QCOM_MEM_OFFLINE) += mem-offline.o
|
||||
obj-$(CONFIG_GH_TLMM_VM_MEM_ACCESS) += gh_tlmm_vm_mem_access.o
|
||||
obj-$(CONFIG_SPS) += sps/
|
||||
obj-$(CONFIG_QCOM_RAMDUMP) += qcom_ramdump.o
|
||||
obj-$(CONFIG_QCOM_ICC_BWMON) += icc-bwmon.o
|
||||
obj-$(CONFIG_QCOM_DCVS) += dcvs/
|
||||
|
5
drivers/soc/qcom/sps/Makefile
Normal file
5
drivers/soc/qcom/sps/Makefile
Normal file
@ -0,0 +1,5 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# Makefile for SPS BAM driver
|
||||
#
|
||||
obj-$(CONFIG_SPS) += sps_drv.o
|
||||
sps_drv-objs := bam.o sps_bam.o sps.o sps_dma.o sps_map.o sps_mem.o sps_rm.o
|
2317
drivers/soc/qcom/sps/bam.c
Normal file
2317
drivers/soc/qcom/sps/bam.c
Normal file
File diff suppressed because it is too large
Load Diff
441
drivers/soc/qcom/sps/bam.h
Normal file
441
drivers/soc/qcom/sps/bam.h
Normal file
@ -0,0 +1,441 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2011-2019, 2021, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
/* Bus-Access-Manager (BAM) Hardware manager functions API. */
|
||||
|
||||
#ifndef _BAM_H_
|
||||
#define _BAM_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/bitops.h>
|
||||
#include "spsi.h"
|
||||
|
||||
/* Pipe mode */
|
||||
enum bam_pipe_mode {
|
||||
BAM_PIPE_MODE_BAM2BAM = 0, /* BAM to BAM */
|
||||
BAM_PIPE_MODE_SYSTEM = 1, /* BAM to/from System Memory */
|
||||
};
|
||||
|
||||
/* Pipe direction */
|
||||
enum bam_pipe_dir {
|
||||
/* The Pipe Reads data from data-fifo or system-memory */
|
||||
BAM_PIPE_CONSUMER = 0,
|
||||
/* The Pipe Writes data to data-fifo or system-memory */
|
||||
BAM_PIPE_PRODUCER = 1,
|
||||
};
|
||||
|
||||
/* Stream mode Type */
|
||||
enum bam_stream_mode {
|
||||
BAM_STREAM_MODE_DISABLE = 0,
|
||||
BAM_STREAM_MODE_ENABLE = 1,
|
||||
};
|
||||
|
||||
/* NWD written Type */
|
||||
enum bam_write_nwd {
|
||||
BAM_WRITE_NWD_DISABLE = 0,
|
||||
BAM_WRITE_NWD_ENABLE = 1,
|
||||
};
|
||||
|
||||
|
||||
/* Enable Type */
|
||||
enum bam_enable {
|
||||
BAM_DISABLE = 0,
|
||||
BAM_ENABLE = 1,
|
||||
};
|
||||
|
||||
/* Pipe timer mode */
|
||||
enum bam_pipe_timer_mode {
|
||||
BAM_PIPE_TIMER_ONESHOT = 0,
|
||||
BAM_PIPE_TIMER_PERIODIC = 1,
|
||||
};
|
||||
|
||||
struct transfer_descriptor {
|
||||
u32 addr; /* Buffer physical address */
|
||||
u32 size:16; /* Buffer size in bytes */
|
||||
u32 flags:16; /* Flag bitmask (see SPS_IOVEC_FLAG_ #defines) */
|
||||
} __packed;
|
||||
|
||||
/* BAM pipe initialization parameters */
|
||||
struct bam_pipe_parameters {
|
||||
u16 event_threshold;
|
||||
u32 pipe_irq_mask;
|
||||
enum bam_pipe_dir dir;
|
||||
enum bam_pipe_mode mode;
|
||||
enum bam_write_nwd write_nwd;
|
||||
phys_addr_t desc_base; /* Physical address of descriptor FIFO */
|
||||
u32 desc_size; /* Size (bytes) of descriptor FIFO */
|
||||
u32 lock_group; /* The lock group this pipe belongs to */
|
||||
enum bam_stream_mode stream_mode;
|
||||
u32 ee; /* BAM execution environment index */
|
||||
|
||||
/* The following are only valid if mode is BAM2BAM */
|
||||
u32 peer_phys_addr;
|
||||
u32 peer_pipe;
|
||||
phys_addr_t data_base; /* Physical address of data FIFO */
|
||||
u32 data_size; /* Size (bytes) of data FIFO */
|
||||
bool dummy_peer;
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize a BAM device
|
||||
*
|
||||
* This function initializes a BAM device.
|
||||
*
|
||||
* @base - BAM virtual base address.
|
||||
*
|
||||
* @ee - BAM execution environment index
|
||||
*
|
||||
* @summing_threshold - summing threshold (global for all pipes)
|
||||
*
|
||||
* @irq_mask - error interrupts mask
|
||||
*
|
||||
* @version - return BAM hardware version
|
||||
*
|
||||
* @num_pipes - return number of pipes
|
||||
*
|
||||
* @options - BAM configuration options
|
||||
*
|
||||
* @return 0 on success, negative value on error
|
||||
*
|
||||
*/
|
||||
int bam_init(void *base,
|
||||
u32 ee,
|
||||
u16 summing_threshold,
|
||||
u32 irq_mask, u32 *version,
|
||||
u32 *num_pipes, u32 options);
|
||||
|
||||
/**
|
||||
* Initialize BAM device security execution environment
|
||||
*
|
||||
* @base - BAM virtual base address.
|
||||
*
|
||||
* @ee - BAM execution environment index
|
||||
*
|
||||
* @vmid - virtual master identifier
|
||||
*
|
||||
* @pipe_mask - bit mask of pipes to assign to EE
|
||||
*
|
||||
* @return 0 on success, negative value on error
|
||||
*
|
||||
*/
|
||||
int bam_security_init(void *base, u32 ee, u32 vmid, u32 pipe_mask);
|
||||
|
||||
/**
|
||||
* Check a BAM device
|
||||
*
|
||||
* This function verifies that a BAM device is enabled and gathers
|
||||
* the hardware configuration.
|
||||
*
|
||||
* @base - BAM virtual base address.
|
||||
*
|
||||
* @version - return BAM hardware version
|
||||
*
|
||||
* @ee - BAM execution environment index
|
||||
*
|
||||
* @num_pipes - return number of pipes
|
||||
*
|
||||
* @return 0 on success, negative value on error
|
||||
*
|
||||
*/
|
||||
int bam_check(void *base, u32 *version, u32 ee, u32 *num_pipes);
|
||||
|
||||
/**
|
||||
* Disable a BAM device
|
||||
*
|
||||
* This function disables a BAM device.
|
||||
*
|
||||
* @base - BAM virtual base address.
|
||||
*
|
||||
* @ee - BAM execution environment index
|
||||
*
|
||||
*/
|
||||
void bam_exit(void *base, u32 ee);
|
||||
|
||||
/**
|
||||
* This function prints BAM register content
|
||||
* including TEST_BUS and PIPE register content.
|
||||
*
|
||||
* @base - BAM virtual base address.
|
||||
*
|
||||
* @ee - BAM execution environment index
|
||||
*/
|
||||
void bam_output_register_content(void *base, u32 ee);
|
||||
|
||||
|
||||
/**
|
||||
* Get BAM IRQ source and clear global IRQ status
|
||||
*
|
||||
* This function gets BAM IRQ source.
|
||||
* Clear global IRQ status if it is non-zero.
|
||||
*
|
||||
* @base - BAM virtual base address.
|
||||
*
|
||||
* @ee - BAM execution environment index
|
||||
*
|
||||
* @mask - active pipes mask.
|
||||
*
|
||||
* @case - callback case.
|
||||
*
|
||||
* @return IRQ status
|
||||
*
|
||||
*/
|
||||
u32 bam_check_irq_source(void *base, u32 ee, u32 mask,
|
||||
enum sps_callback_case *cb_case);
|
||||
|
||||
|
||||
/**
|
||||
* Initialize a BAM pipe
|
||||
*
|
||||
* This function initializes a BAM pipe.
|
||||
*
|
||||
* @base - BAM virtual base address.
|
||||
*
|
||||
* @pipe - pipe index
|
||||
*
|
||||
* @param - bam pipe parameters.
|
||||
*
|
||||
* @ee - BAM execution environment index
|
||||
*
|
||||
* @return 0 on success, negative value on error
|
||||
*
|
||||
*/
|
||||
int bam_pipe_init(void *base, u32 pipe, struct bam_pipe_parameters *param,
|
||||
u32 ee);
|
||||
|
||||
/**
|
||||
* Reset the BAM pipe
|
||||
*
|
||||
* This function resets the BAM pipe.
|
||||
*
|
||||
* @base - BAM virtual base address.
|
||||
*
|
||||
* @pipe - pipe index
|
||||
*
|
||||
* @ee - BAM execution environment index
|
||||
*
|
||||
*/
|
||||
void bam_pipe_exit(void *base, u32 pipe, u32 ee);
|
||||
|
||||
/**
|
||||
* Enable a BAM pipe
|
||||
*
|
||||
* This function enables a BAM pipe.
|
||||
*
|
||||
* @base - BAM virtual base address.
|
||||
*
|
||||
* @pipe - pipe index
|
||||
*
|
||||
*/
|
||||
void bam_pipe_enable(void *base, u32 pipe);
|
||||
|
||||
/**
|
||||
* Disable a BAM pipe
|
||||
*
|
||||
* This function disables a BAM pipe.
|
||||
*
|
||||
* @base - BAM virtual base address.
|
||||
*
|
||||
* @pipe - pipe index
|
||||
*
|
||||
*/
|
||||
void bam_pipe_disable(void *base, u32 pipe);
|
||||
|
||||
/**
|
||||
* Get a BAM pipe enable state
|
||||
*
|
||||
* This function determines if a BAM pipe is enabled.
|
||||
*
|
||||
* @base - BAM virtual base address.
|
||||
*
|
||||
* @pipe - pipe index
|
||||
*
|
||||
* @return true if enabled, false if disabled
|
||||
*
|
||||
*/
|
||||
int bam_pipe_is_enabled(void *base, u32 pipe);
|
||||
|
||||
/**
|
||||
* Configure interrupt for a BAM pipe
|
||||
*
|
||||
* This function configures the interrupt for a BAM pipe.
|
||||
*
|
||||
* @base - BAM virtual base address.
|
||||
*
|
||||
* @pipe - pipe index
|
||||
*
|
||||
* @irq_en - enable or disable interrupt
|
||||
*
|
||||
* @src_mask - interrupt source mask, set regardless of whether
|
||||
* interrupt is disabled
|
||||
*
|
||||
* @ee - BAM execution environment index
|
||||
*
|
||||
*/
|
||||
void bam_pipe_set_irq(void *base, u32 pipe, enum bam_enable irq_en,
|
||||
u32 src_mask, u32 ee);
|
||||
|
||||
/**
|
||||
* Configure a BAM pipe for satellite MTI use
|
||||
*
|
||||
* This function configures a BAM pipe for satellite MTI use.
|
||||
*
|
||||
* @base - BAM virtual base address.
|
||||
*
|
||||
* @pipe - pipe index
|
||||
*
|
||||
* @irq_gen_addr - physical address written to generate MTI
|
||||
*
|
||||
* @ee - BAM execution environment index
|
||||
*
|
||||
*/
|
||||
void bam_pipe_satellite_mti(void *base, u32 pipe, u32 irq_gen_addr, u32 ee);
|
||||
|
||||
/**
|
||||
* Configure MTI for a BAM pipe
|
||||
*
|
||||
* This function configures the interrupt for a BAM pipe.
|
||||
*
|
||||
* @base - BAM virtual base address.
|
||||
*
|
||||
* @pipe - pipe index
|
||||
*
|
||||
* @irq_en - enable or disable interrupt
|
||||
*
|
||||
* @src_mask - interrupt source mask, set regardless of whether
|
||||
* interrupt is disabled
|
||||
*
|
||||
* @irq_gen_addr - physical address written to generate MTI
|
||||
*
|
||||
*/
|
||||
void bam_pipe_set_mti(void *base, u32 pipe, enum bam_enable irq_en,
|
||||
u32 src_mask, u32 irq_gen_addr);
|
||||
|
||||
/**
|
||||
* Get and Clear BAM pipe IRQ status
|
||||
*
|
||||
* This function gets and clears BAM pipe IRQ status.
|
||||
*
|
||||
* @base - BAM virtual base address.
|
||||
*
|
||||
* @pipe - pipe index
|
||||
*
|
||||
* @return IRQ status
|
||||
*
|
||||
*/
|
||||
u32 bam_pipe_get_and_clear_irq_status(void *base, u32 pipe);
|
||||
|
||||
/**
|
||||
* Set write offset for a BAM pipe
|
||||
*
|
||||
* This function sets the write offset for a BAM pipe. This is
|
||||
* the offset that is maintained by software in system mode.
|
||||
*
|
||||
* @base - BAM virtual base address.
|
||||
*
|
||||
* @pipe - pipe index
|
||||
*
|
||||
* @next_write - descriptor FIFO write offset
|
||||
*
|
||||
*/
|
||||
void bam_pipe_set_desc_write_offset(void *base, u32 pipe, u32 next_write);
|
||||
|
||||
/**
|
||||
* Get write offset for a BAM pipe
|
||||
*
|
||||
* This function gets the write offset for a BAM pipe. This is
|
||||
* the offset that is maintained by the pipe's peer pipe or by software.
|
||||
*
|
||||
* @base - BAM virtual base address.
|
||||
*
|
||||
* @pipe - pipe index
|
||||
*
|
||||
* @return descriptor FIFO write offset
|
||||
*
|
||||
*/
|
||||
u32 bam_pipe_get_desc_write_offset(void *base, u32 pipe);
|
||||
|
||||
/**
|
||||
* Get read offset for a BAM pipe
|
||||
*
|
||||
* This function gets the read offset for a BAM pipe. This is
|
||||
* the offset that is maintained by the pipe in system mode.
|
||||
*
|
||||
* @base - BAM virtual base address.
|
||||
*
|
||||
* @pipe - pipe index
|
||||
*
|
||||
* @return descriptor FIFO read offset
|
||||
*
|
||||
*/
|
||||
u32 bam_pipe_get_desc_read_offset(void *base, u32 pipe);
|
||||
|
||||
/**
|
||||
* Configure inactivity timer count for a BAM pipe
|
||||
*
|
||||
* This function configures the inactivity timer count for a BAM pipe.
|
||||
*
|
||||
* @base - BAM virtual base address.
|
||||
*
|
||||
* @pipe - pipe index
|
||||
*
|
||||
* @mode - timer operating mode
|
||||
*
|
||||
* @timeout_count - timeout count
|
||||
*
|
||||
*/
|
||||
void bam_pipe_timer_config(void *base, u32 pipe,
|
||||
enum bam_pipe_timer_mode mode,
|
||||
u32 timeout_count);
|
||||
|
||||
/**
|
||||
* Reset inactivity timer for a BAM pipe
|
||||
*
|
||||
* This function resets the inactivity timer count for a BAM pipe.
|
||||
*
|
||||
* @base - BAM virtual base address.
|
||||
*
|
||||
* @pipe - pipe index
|
||||
*
|
||||
*/
|
||||
void bam_pipe_timer_reset(void *base, u32 pipe);
|
||||
|
||||
/**
|
||||
* Get inactivity timer count for a BAM pipe
|
||||
*
|
||||
* This function gets the inactivity timer count for a BAM pipe.
|
||||
*
|
||||
* @base - BAM virtual base address.
|
||||
*
|
||||
* @pipe - pipe index
|
||||
*
|
||||
* @return inactivity timer count
|
||||
*
|
||||
*/
|
||||
u32 bam_pipe_timer_get_count(void *base, u32 pipe);
|
||||
|
||||
/*
|
||||
* bam_pipe_check_zlt - Check if the last desc is ZLT.
|
||||
* @base: BAM virtual address
|
||||
* @pipe: pipe index
|
||||
*
|
||||
* This function checks if the last desc in the desc FIFO is a ZLT desc.
|
||||
*
|
||||
* @return true if the last desc in the desc FIFO is a ZLT desc. Otherwise
|
||||
* return false.
|
||||
*/
|
||||
bool bam_pipe_check_zlt(void *base, u32 pipe);
|
||||
|
||||
/*
|
||||
* bam_pipe_check_pipe_empty - Check if desc FIFO is empty.
|
||||
* @base: BAM virtual address
|
||||
* @pipe: pipe index
|
||||
*
|
||||
* This function checks if the desc FIFO of this pipe is empty.
|
||||
*
|
||||
* @return true if desc FIFO is empty. Otherwise return false.
|
||||
*/
|
||||
bool bam_pipe_check_pipe_empty(void *base, u32 pipe);
|
||||
#endif /* _BAM_H_ */
|
2938
drivers/soc/qcom/sps/sps.c
Normal file
2938
drivers/soc/qcom/sps/sps.c
Normal file
File diff suppressed because it is too large
Load Diff
2503
drivers/soc/qcom/sps/sps_bam.c
Normal file
2503
drivers/soc/qcom/sps/sps_bam.c
Normal file
File diff suppressed because it is too large
Load Diff
608
drivers/soc/qcom/sps/sps_bam.h
Normal file
608
drivers/soc/qcom/sps/sps_bam.h
Normal file
@ -0,0 +1,608 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2011-2019, 2021, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
/*
|
||||
* Function and data structure declarations for SPS BAM handling.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _SPSBAM_H_
|
||||
#define _SPSBAM_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#include "spsi.h"
|
||||
|
||||
#define BAM_HANDLE_INVALID 0
|
||||
|
||||
#define to_sps_bam_dev(x) \
|
||||
container_of((x), struct sps_bam, base)
|
||||
|
||||
enum bam_irq {
|
||||
BAM_DEV_IRQ_RDY_TO_SLEEP = 0x00000001,
|
||||
BAM_DEV_IRQ_HRESP_ERROR = 0x00000002,
|
||||
BAM_DEV_IRQ_ERROR = 0x00000004,
|
||||
BAM_DEV_IRQ_TIMER = 0x00000010,
|
||||
};
|
||||
|
||||
/* Pipe interrupt mask */
|
||||
enum bam_pipe_irq {
|
||||
/* BAM finishes descriptor which has INT bit selected */
|
||||
BAM_PIPE_IRQ_DESC_INT = 0x00000001,
|
||||
/* Inactivity timer Expires */
|
||||
BAM_PIPE_IRQ_TIMER = 0x00000002,
|
||||
/* Wakeup peripheral (i.e. USB) */
|
||||
BAM_PIPE_IRQ_WAKE = 0x00000004,
|
||||
/* Producer - no free space for adding a descriptor */
|
||||
/* Consumer - no descriptors for processing */
|
||||
BAM_PIPE_IRQ_OUT_OF_DESC = 0x00000008,
|
||||
/* Pipe Error interrupt */
|
||||
BAM_PIPE_IRQ_ERROR = 0x00000010,
|
||||
/* End-Of-Transfer */
|
||||
BAM_PIPE_IRQ_EOT = 0x00000020,
|
||||
/* Pipe RESET unsuccessful */
|
||||
BAM_PIPE_IRQ_RST_ERROR = 0x00000040,
|
||||
/* Errorneous Hresponse by AHB MASTER */
|
||||
BAM_PIPE_IRQ_HRESP_ERROR = 0x00000080,
|
||||
};
|
||||
|
||||
/* Halt Type */
|
||||
enum bam_halt {
|
||||
BAM_HALT_OFF = 0,
|
||||
BAM_HALT_ON = 1,
|
||||
};
|
||||
|
||||
/* Threshold values of the DMA channels */
|
||||
enum bam_dma_thresh_dma {
|
||||
BAM_DMA_THRESH_512 = 0x3,
|
||||
BAM_DMA_THRESH_256 = 0x2,
|
||||
BAM_DMA_THRESH_128 = 0x1,
|
||||
BAM_DMA_THRESH_64 = 0x0,
|
||||
};
|
||||
|
||||
/* Weight values of the DMA channels */
|
||||
enum bam_dma_weight_dma {
|
||||
BAM_DMA_WEIGHT_HIGH = 7,
|
||||
BAM_DMA_WEIGHT_MED = 3,
|
||||
BAM_DMA_WEIGHT_LOW = 1,
|
||||
BAM_DMA_WEIGHT_DEFAULT = BAM_DMA_WEIGHT_LOW,
|
||||
BAM_DMA_WEIGHT_DISABLE = 0,
|
||||
};
|
||||
|
||||
|
||||
/* Invalid pipe index value */
|
||||
#define SPS_BAM_PIPE_INVALID ((u32)(-1))
|
||||
|
||||
/* Parameters for sps_bam_pipe_connect() */
|
||||
struct sps_bam_connect_param {
|
||||
/* which end point must be initialized */
|
||||
enum sps_mode mode;
|
||||
|
||||
/* OR'd connection end point options (see SPS_O defines) */
|
||||
u32 options;
|
||||
|
||||
/* SETPEND/MTI interrupt generation parameters */
|
||||
u32 irq_gen_addr;
|
||||
u32 irq_gen_data;
|
||||
|
||||
};
|
||||
|
||||
/* Event registration struct */
|
||||
struct sps_bam_event_reg {
|
||||
/* Client's event object handle */
|
||||
struct completion *xfer_done;
|
||||
void (*callback)(struct sps_event_notify *notify);
|
||||
|
||||
/* Event trigger mode */
|
||||
enum sps_trigger mode;
|
||||
|
||||
/* User pointer that will be provided in event payload data */
|
||||
void *user;
|
||||
|
||||
};
|
||||
|
||||
/* Descriptor FIFO cache entry */
|
||||
struct sps_bam_desc_cache {
|
||||
struct sps_iovec iovec;
|
||||
void *user; /* User pointer registered with this transfer */
|
||||
};
|
||||
|
||||
/* Forward declaration */
|
||||
struct sps_bam;
|
||||
|
||||
/* System mode control */
|
||||
struct sps_bam_sys_mode {
|
||||
/* Descriptor FIFO control */
|
||||
u8 *desc_buf; /* Descriptor FIFO for BAM pipe */
|
||||
u32 desc_offset; /* Next new descriptor to be written to hardware */
|
||||
u32 acked_offset; /* Next descriptor to be retired by software */
|
||||
|
||||
/* Descriptor cache control (!no_queue only) */
|
||||
u8 *desc_cache; /* Software cache of descriptor FIFO contents */
|
||||
u32 cache_offset; /* Next descriptor to be cached (ack_xfers only) */
|
||||
|
||||
/* User pointers associated with cached descriptors */
|
||||
void **user_ptrs;
|
||||
|
||||
/* Event handling */
|
||||
struct sps_bam_event_reg event_regs[SPS_EVENT_INDEX(SPS_EVENT_MAX)];
|
||||
struct list_head events_q;
|
||||
|
||||
struct sps_q_event event; /* Temp storage for event creation */
|
||||
int no_queue; /* Whether events are queued */
|
||||
int ack_xfers; /* Whether client must ACK all descriptors */
|
||||
int handler_eot; /* Whether EOT handling is in progress (debug) */
|
||||
|
||||
/* Statistics */
|
||||
#ifdef SPS_BAM_STATISTICS
|
||||
u32 desc_wr_count;
|
||||
u32 desc_rd_count;
|
||||
u32 user_ptrs_count;
|
||||
u32 user_found;
|
||||
u32 int_flags;
|
||||
u32 eot_flags;
|
||||
u32 callback_events;
|
||||
u32 wait_events;
|
||||
u32 queued_events;
|
||||
u32 get_events;
|
||||
u32 get_iovecs;
|
||||
#endif /* SPS_BAM_STATISTICS */
|
||||
};
|
||||
|
||||
/* BAM pipe descriptor */
|
||||
struct sps_pipe {
|
||||
struct list_head list;
|
||||
|
||||
/* Client state */
|
||||
u32 client_state;
|
||||
struct sps_bam *bam;
|
||||
struct sps_connect connect;
|
||||
const struct sps_connection *map;
|
||||
|
||||
/* Pipe parameters */
|
||||
u32 state;
|
||||
u32 pipe_index;
|
||||
u32 pipe_index_mask;
|
||||
u32 irq_mask;
|
||||
int polled;
|
||||
int hybrid;
|
||||
bool late_eot;
|
||||
u32 irq_gen_addr;
|
||||
enum sps_mode mode;
|
||||
u32 num_descs; /* Size (number of elements) of descriptor FIFO */
|
||||
u32 desc_size; /* Size (bytes) of descriptor FIFO */
|
||||
int wake_up_is_one_shot; /* Whether WAKEUP event is a one-shot or not */
|
||||
|
||||
/* System mode control */
|
||||
struct sps_bam_sys_mode sys;
|
||||
|
||||
bool disconnecting;
|
||||
};
|
||||
|
||||
/* BAM device descriptor */
|
||||
struct sps_bam {
|
||||
struct list_head list;
|
||||
|
||||
/* BAM device properties, including connection defaults */
|
||||
struct sps_bam_props props;
|
||||
|
||||
/* BAM device state */
|
||||
u32 state;
|
||||
struct mutex lock;
|
||||
void __iomem *base; /* BAM virtual base address */
|
||||
u32 version;
|
||||
spinlock_t isr_lock;
|
||||
spinlock_t connection_lock;
|
||||
unsigned long irqsave_flags;
|
||||
|
||||
/* Pipe state */
|
||||
u32 pipe_active_mask;
|
||||
u32 pipe_remote_mask;
|
||||
struct sps_pipe *pipes[BAM_MAX_PIPES];
|
||||
struct list_head pipes_q;
|
||||
|
||||
/* Statistics */
|
||||
u32 irq_from_disabled_pipe;
|
||||
u32 event_trigger_failures;
|
||||
|
||||
void *ipc_log0;
|
||||
void *ipc_log1;
|
||||
void *ipc_log2;
|
||||
void *ipc_log3;
|
||||
void *ipc_log4;
|
||||
|
||||
u32 ipc_loglevel;
|
||||
|
||||
/* Desc cache pointers */
|
||||
u8 *desc_cache_pointers[BAM_MAX_PIPES];
|
||||
};
|
||||
|
||||
/**
|
||||
* BAM driver initialization
|
||||
*
|
||||
* This function initializes the BAM driver.
|
||||
*
|
||||
* @options - driver options bitflags (see SPS_OPT_*)
|
||||
*
|
||||
* @return 0 on success, negative value on error
|
||||
*
|
||||
*/
|
||||
int sps_bam_driver_init(u32 options);
|
||||
|
||||
/**
|
||||
* BAM device initialization
|
||||
*
|
||||
* This function initializes a BAM device.
|
||||
*
|
||||
* @dev - pointer to BAM device descriptor
|
||||
*
|
||||
* @return 0 on success, negative value on error
|
||||
*
|
||||
*/
|
||||
int sps_bam_device_init(struct sps_bam *dev);
|
||||
|
||||
/**
|
||||
* BAM device de-initialization
|
||||
*
|
||||
* This function de-initializes a BAM device.
|
||||
*
|
||||
* @dev - pointer to BAM device descriptor
|
||||
*
|
||||
* @return 0 on success, negative value on error
|
||||
*
|
||||
*/
|
||||
int sps_bam_device_de_init(struct sps_bam *dev);
|
||||
|
||||
/**
|
||||
* BAM device reset
|
||||
*
|
||||
* This Function resets a BAM device.
|
||||
*
|
||||
* @dev - pointer to BAM device descriptor
|
||||
*
|
||||
* @return 0 on success, negative value on error
|
||||
*
|
||||
*/
|
||||
int sps_bam_reset(struct sps_bam *dev);
|
||||
|
||||
/**
|
||||
* BAM device enable
|
||||
*
|
||||
* This function enables a BAM device.
|
||||
*
|
||||
* @dev - pointer to BAM device descriptor
|
||||
*
|
||||
* @return 0 on success, negative value on error
|
||||
*
|
||||
*/
|
||||
int sps_bam_enable(struct sps_bam *dev);
|
||||
|
||||
/**
|
||||
* BAM device disable
|
||||
*
|
||||
* This Function disables a BAM device.
|
||||
*
|
||||
* @dev - pointer to BAM device descriptor
|
||||
*
|
||||
* @return 0 on success, negative value on error
|
||||
*
|
||||
*/
|
||||
int sps_bam_disable(struct sps_bam *dev);
|
||||
|
||||
/**
|
||||
* Allocate a BAM pipe
|
||||
*
|
||||
* This function allocates a BAM pipe.
|
||||
*
|
||||
* @dev - pointer to BAM device descriptor
|
||||
*
|
||||
* @pipe_index - client-specified pipe index, or SPS_BAM_PIPE_INVALID if
|
||||
* any available pipe is acceptable
|
||||
*
|
||||
* @return - allocated pipe index, or SPS_BAM_PIPE_INVALID on error
|
||||
*
|
||||
*/
|
||||
u32 sps_bam_pipe_alloc(struct sps_bam *dev, u32 pipe_index);
|
||||
|
||||
/**
|
||||
* Free a BAM pipe
|
||||
*
|
||||
* This function frees a BAM pipe.
|
||||
*
|
||||
* @dev - pointer to BAM device descriptor
|
||||
*
|
||||
* @pipe_index - pipe index
|
||||
*
|
||||
*/
|
||||
void sps_bam_pipe_free(struct sps_bam *dev, u32 pipe_index);
|
||||
|
||||
/**
|
||||
* Establish BAM pipe connection
|
||||
*
|
||||
* This function establishes a connection for a BAM pipe (end point).
|
||||
*
|
||||
* @client - pointer to client pipe state struct
|
||||
*
|
||||
* @params - connection parameters
|
||||
*
|
||||
* @return 0 on success, negative value on error
|
||||
*
|
||||
*/
|
||||
int sps_bam_pipe_connect(struct sps_pipe *client,
|
||||
const struct sps_bam_connect_param *params);
|
||||
|
||||
/**
|
||||
* Disconnect a BAM pipe connection
|
||||
*
|
||||
* This function disconnects a connection for a BAM pipe (end point).
|
||||
*
|
||||
* @dev - pointer to BAM device descriptor
|
||||
*
|
||||
* @pipe_index - pipe index
|
||||
*
|
||||
* @return 0 on success, negative value on error
|
||||
*
|
||||
*/
|
||||
int sps_bam_pipe_disconnect(struct sps_bam *dev, u32 pipe_index);
|
||||
|
||||
/**
|
||||
* Set BAM pipe parameters
|
||||
*
|
||||
* This function sets parameters for a BAM pipe.
|
||||
*
|
||||
* @dev - pointer to BAM device descriptor
|
||||
*
|
||||
* @pipe_index - pipe index
|
||||
*
|
||||
* @options - bitflag options (see SPS_O_*)
|
||||
*
|
||||
* @return 0 on success, negative value on error
|
||||
*
|
||||
*/
|
||||
int sps_bam_pipe_set_params(struct sps_bam *dev, u32 pipe_index, u32 options);
|
||||
|
||||
/**
|
||||
* Enable a BAM pipe
|
||||
*
|
||||
* This function enables a BAM pipe. Note that this function
|
||||
* is separate from the pipe connect function to allow proper
|
||||
* sequencing of consumer enable followed by producer enable.
|
||||
*
|
||||
* @dev - pointer to BAM device descriptor
|
||||
*
|
||||
* @pipe_index - pipe index
|
||||
*
|
||||
* @return 0 on success, negative value on error
|
||||
*
|
||||
*/
|
||||
int sps_bam_pipe_enable(struct sps_bam *dev, u32 pipe_index);
|
||||
|
||||
/**
|
||||
* Disable a BAM pipe
|
||||
*
|
||||
* This function disables a BAM pipe.
|
||||
*
|
||||
* @dev - pointer to BAM device descriptor
|
||||
*
|
||||
* @pipe_index - pipe index
|
||||
*
|
||||
* @return 0 on success, negative value on error
|
||||
*
|
||||
*/
|
||||
int sps_bam_pipe_disable(struct sps_bam *dev, u32 pipe_index);
|
||||
|
||||
/**
|
||||
* Register an event for a BAM pipe
|
||||
*
|
||||
* This function registers an event for a BAM pipe.
|
||||
*
|
||||
* @dev - pointer to BAM device descriptor
|
||||
*
|
||||
* @pipe_index - pipe index
|
||||
*
|
||||
* @reg - pointer to event registration struct
|
||||
*
|
||||
* @return 0 on success, negative value on error
|
||||
*
|
||||
*/
|
||||
int sps_bam_pipe_reg_event(struct sps_bam *dev, u32 pipe_index,
|
||||
struct sps_register_event *reg);
|
||||
|
||||
/**
|
||||
* Submit a transfer of a single buffer to a BAM pipe
|
||||
*
|
||||
* This function submits a transfer of a single buffer to a BAM pipe.
|
||||
*
|
||||
* @dev - pointer to BAM device descriptor
|
||||
*
|
||||
* @pipe_index - pipe index
|
||||
*
|
||||
* @addr - physical address of buffer to transfer
|
||||
*
|
||||
* @size - number of bytes to transfer
|
||||
*
|
||||
* @user - user pointer to register for event
|
||||
*
|
||||
* @flags - descriptor flags (see SPS_IOVEC_FLAG defines)
|
||||
*
|
||||
* @return 0 on success, negative value on error
|
||||
*
|
||||
*/
|
||||
int sps_bam_pipe_transfer_one(struct sps_bam *dev, u32 pipe_index, u32 addr,
|
||||
u32 size, void *user, u32 flags);
|
||||
|
||||
/**
|
||||
* Submit a transfer to a BAM pipe
|
||||
*
|
||||
* This function submits a transfer to a BAM pipe.
|
||||
*
|
||||
* @dev - pointer to BAM device descriptor
|
||||
*
|
||||
* @pipe_index - pipe index
|
||||
*
|
||||
* @transfer - pointer to transfer struct
|
||||
*
|
||||
* @return 0 on success, negative value on error
|
||||
*
|
||||
*/
|
||||
int sps_bam_pipe_transfer(struct sps_bam *dev, u32 pipe_index,
|
||||
struct sps_transfer *transfer);
|
||||
|
||||
/**
|
||||
* Get a BAM pipe event
|
||||
*
|
||||
* This function polls for a BAM pipe event.
|
||||
*
|
||||
* @dev - pointer to BAM device descriptor
|
||||
*
|
||||
* @pipe_index - pipe index
|
||||
*
|
||||
* @notify - pointer to event notification struct
|
||||
*
|
||||
* @return 0 on success, negative value on error
|
||||
*
|
||||
*/
|
||||
int sps_bam_pipe_get_event(struct sps_bam *dev, u32 pipe_index,
|
||||
struct sps_event_notify *notify);
|
||||
|
||||
/**
|
||||
* Get processed I/O vector
|
||||
*
|
||||
* This function fetches the next processed I/O vector.
|
||||
*
|
||||
* @dev - pointer to BAM device descriptor
|
||||
*
|
||||
* @pipe_index - pipe index
|
||||
*
|
||||
* @iovec - Pointer to I/O vector struct (output).
|
||||
* This struct will be zeroed if there are no more processed I/O vectors.
|
||||
*
|
||||
* @return 0 on success, negative value on error
|
||||
*/
|
||||
int sps_bam_pipe_get_iovec(struct sps_bam *dev, u32 pipe_index,
|
||||
struct sps_iovec *iovec);
|
||||
|
||||
/**
|
||||
* Determine whether a BAM pipe descriptor FIFO is empty
|
||||
*
|
||||
* This function returns the empty state of a BAM pipe descriptor FIFO.
|
||||
*
|
||||
* The pipe mutex must be locked before calling this function.
|
||||
*
|
||||
* @dev - pointer to BAM device descriptor
|
||||
*
|
||||
* @pipe_index - pipe index
|
||||
*
|
||||
* @empty - pointer to client's empty status word (boolean)
|
||||
*
|
||||
* @return 0 on success, negative value on error
|
||||
*
|
||||
*/
|
||||
int sps_bam_pipe_is_empty(struct sps_bam *dev, u32 pipe_index, u32 *empty);
|
||||
|
||||
/**
|
||||
* Get number of free slots in a BAM pipe descriptor FIFO
|
||||
*
|
||||
* This function returns the number of free slots in a BAM pipe descriptor FIFO.
|
||||
*
|
||||
* The pipe mutex must be locked before calling this function.
|
||||
*
|
||||
* @dev - pointer to BAM device descriptor
|
||||
*
|
||||
* @pipe_index - pipe index
|
||||
*
|
||||
* @count - pointer to count status
|
||||
*
|
||||
* @return 0 on success, negative value on error
|
||||
*
|
||||
*/
|
||||
int sps_bam_get_free_count(struct sps_bam *dev, u32 pipe_index, u32 *count);
|
||||
|
||||
/**
|
||||
* Set BAM pipe to satellite ownership
|
||||
*
|
||||
* This function sets the BAM pipe to satellite ownership.
|
||||
*
|
||||
* @dev - pointer to BAM device descriptor
|
||||
*
|
||||
* @pipe_index - pipe index
|
||||
*
|
||||
* @return 0 on success, negative value on error
|
||||
*
|
||||
*/
|
||||
int sps_bam_set_satellite(struct sps_bam *dev, u32 pipe_index);
|
||||
|
||||
/**
|
||||
* Perform BAM pipe timer control
|
||||
*
|
||||
* This function performs BAM pipe timer control operations.
|
||||
*
|
||||
* @dev - pointer to BAM device descriptor
|
||||
*
|
||||
* @pipe_index - pipe index
|
||||
*
|
||||
* @timer_ctrl - Pointer to timer control specification
|
||||
*
|
||||
* @timer_result - Pointer to buffer for timer operation result.
|
||||
* This argument can be NULL if no result is expected for the operation.
|
||||
* If non-NULL, the current timer value will always provided.
|
||||
*
|
||||
* @return 0 on success, negative value on error
|
||||
*
|
||||
*/
|
||||
int sps_bam_pipe_timer_ctrl(struct sps_bam *dev, u32 pipe_index,
|
||||
struct sps_timer_ctrl *timer_ctrl,
|
||||
struct sps_timer_result *timer_result);
|
||||
|
||||
|
||||
/**
|
||||
* Get the number of unused descriptors in the descriptor FIFO
|
||||
* of a pipe
|
||||
*
|
||||
* @dev - pointer to BAM device descriptor
|
||||
*
|
||||
* @pipe_index - pipe index
|
||||
*
|
||||
* @desc_num - number of unused descriptors
|
||||
*
|
||||
*/
|
||||
int sps_bam_pipe_get_unused_desc_num(struct sps_bam *dev, u32 pipe_index,
|
||||
u32 *desc_num);
|
||||
|
||||
/*
|
||||
* sps_bam_check_irq - check IRQ of a BAM device.
|
||||
* @dev - pointer to BAM device descriptor
|
||||
*
|
||||
* This function checks any pending interrupt of a BAM device.
|
||||
*
|
||||
* Return: 0 on success, negative value on error
|
||||
*/
|
||||
int sps_bam_check_irq(struct sps_bam *dev);
|
||||
|
||||
/*
|
||||
* sps_bam_pipe_pending_desc - checking pending descriptor.
|
||||
* @dev: BAM device handle
|
||||
* @pipe_index: pipe index
|
||||
*
|
||||
* This function checks if a pipe of a BAM has any pending descriptor.
|
||||
*
|
||||
* @return true if there is any desc pending
|
||||
*/
|
||||
bool sps_bam_pipe_pending_desc(struct sps_bam *dev, u32 pipe_index);
|
||||
|
||||
/*
|
||||
* sps_bam_pipe_inject_zlt - inject a ZLT with EOT.
|
||||
* @dev: BAM device handle
|
||||
* @pipe_index: pipe index
|
||||
*
|
||||
* This function injects a ZLT with EOT for a pipe of a BAM.
|
||||
*
|
||||
* Return: 0 on success, negative value on error
|
||||
*/
|
||||
int sps_bam_pipe_inject_zlt(struct sps_bam *dev, u32 pipe_index);
|
||||
#endif /* _SPSBAM_H_ */
|
95
drivers/soc/qcom/sps/sps_core.h
Normal file
95
drivers/soc/qcom/sps/sps_core.h
Normal file
@ -0,0 +1,95 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2011, 2013, 2015-2019, 2021, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
/*
|
||||
* Function and data structure declarations.
|
||||
*/
|
||||
|
||||
#ifndef _SPS_CORE_H_
|
||||
#define _SPS_CORE_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/list.h>
|
||||
|
||||
#include "spsi.h"
|
||||
#include "sps_bam.h"
|
||||
|
||||
/* Connection state definitions */
|
||||
#define SPS_STATE_DEF(x) ('S' | ('P' << 8) | ('S' << 16) | ((x) << 24))
|
||||
#define IS_SPS_STATE_OK(x) \
|
||||
(((x)->client_state & 0x00ffffff) == SPS_STATE_DEF(0))
|
||||
|
||||
/* Configuration indicating satellite connection */
|
||||
#define SPS_CONFIG_SATELLITE 0x11111111
|
||||
|
||||
/* Client connection state */
|
||||
#define SPS_STATE_DISCONNECT 0
|
||||
#define SPS_STATE_ALLOCATE SPS_STATE_DEF(1)
|
||||
#define SPS_STATE_CONNECT SPS_STATE_DEF(2)
|
||||
#define SPS_STATE_ENABLE SPS_STATE_DEF(3)
|
||||
#define SPS_STATE_DISABLE SPS_STATE_DEF(4)
|
||||
|
||||
|
||||
/**
|
||||
* Find the BAM device from the handle
|
||||
*
|
||||
* This function finds a BAM device in the BAM registration list that
|
||||
* matches the specified device handle.
|
||||
*
|
||||
* @h - device handle of the BAM
|
||||
*
|
||||
* @return - pointer to the BAM device struct, or NULL on error
|
||||
*
|
||||
*/
|
||||
struct sps_bam *sps_h2bam(unsigned long h);
|
||||
|
||||
/**
|
||||
* Initialize resource manager module
|
||||
*
|
||||
* This function initializes the resource manager module.
|
||||
*
|
||||
* @rm - pointer to resource manager struct
|
||||
*
|
||||
* @options - driver options bitflags (see SPS_OPT_*)
|
||||
*
|
||||
* @return 0 on success, negative value on error
|
||||
*
|
||||
*/
|
||||
int sps_rm_init(struct sps_rm *rm, u32 options);
|
||||
|
||||
/**
|
||||
* De-initialize resource manager module
|
||||
*
|
||||
* This function de-initializes the resource manager module.
|
||||
*
|
||||
*/
|
||||
void sps_rm_de_init(void);
|
||||
|
||||
/**
|
||||
* Initialize client state context
|
||||
*
|
||||
* This function initializes a client state context struct.
|
||||
*
|
||||
* @connect - pointer to client connection state struct
|
||||
*
|
||||
*/
|
||||
void sps_rm_config_init(struct sps_connect *connect);
|
||||
|
||||
/**
|
||||
* Process connection state change
|
||||
*
|
||||
* This function processes a connection state change.
|
||||
*
|
||||
* @pipe - pointer to pipe context
|
||||
*
|
||||
* @state - new state for connection
|
||||
*
|
||||
* @return 0 on success, negative value on error
|
||||
*
|
||||
*/
|
||||
int sps_rm_state_change(struct sps_pipe *pipe, u32 state);
|
||||
|
||||
#endif /* _SPS_CORE_H_ */
|
921
drivers/soc/qcom/sps/sps_dma.c
Normal file
921
drivers/soc/qcom/sps/sps_dma.c
Normal file
@ -0,0 +1,921 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2011-2013, 2015, 2017-2019, 2021, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
/* BAM-DMA Manager. */
|
||||
|
||||
#ifdef CONFIG_SPS_SUPPORT_BAMDMA
|
||||
|
||||
#include <linux/export.h>
|
||||
#include <linux/memory.h>
|
||||
|
||||
#include "spsi.h"
|
||||
#include "bam.h"
|
||||
#include "sps_bam.h"
|
||||
#include "sps_core.h"
|
||||
|
||||
/**
|
||||
* registers
|
||||
*/
|
||||
|
||||
#define DMA_ENBL (0x00000000)
|
||||
#ifdef CONFIG_SPS_SUPPORT_NDP_BAM
|
||||
#define DMA_REVISION (0x00000004)
|
||||
#define DMA_CONFIG (0x00000008)
|
||||
#define DMA_CHNL_CONFIG(n) (0x00001000 + 4096 * (n))
|
||||
#else
|
||||
#define DMA_CHNL_CONFIG(n) (0x00000004 + 4 * (n))
|
||||
#define DMA_CONFIG (0x00000040)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* masks
|
||||
*/
|
||||
|
||||
/* DMA_CHNL_confign */
|
||||
#ifdef CONFIG_SPS_SUPPORT_NDP_BAM
|
||||
#define DMA_CHNL_PRODUCER_PIPE_ENABLED 0x40000
|
||||
#define DMA_CHNL_CONSUMER_PIPE_ENABLED 0x20000
|
||||
#endif
|
||||
#define DMA_CHNL_HALT_DONE 0x10000
|
||||
#define DMA_CHNL_HALT 0x1000
|
||||
#define DMA_CHNL_ENABLE 0x100
|
||||
#define DMA_CHNL_ACT_THRESH 0x30
|
||||
#define DMA_CHNL_WEIGHT 0x7
|
||||
|
||||
/* DMA_CONFIG */
|
||||
#define TESTBUS_SELECT 0x3
|
||||
|
||||
/**
|
||||
*
|
||||
* Write register with debug info.
|
||||
*
|
||||
* @base - bam base virtual address.
|
||||
* @offset - register offset.
|
||||
* @val - value to write.
|
||||
*
|
||||
*/
|
||||
static inline void dma_write_reg(void *base, u32 offset, u32 val)
|
||||
{
|
||||
iowrite32(val, base + offset);
|
||||
SPS_DBG(sps, "sps:bamdma: write reg 0x%x w_val 0x%x\n", offset, val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write register masked field with debug info.
|
||||
*
|
||||
* @base - bam base virtual address.
|
||||
* @offset - register offset.
|
||||
* @mask - register bitmask.
|
||||
* @val - value to write.
|
||||
*
|
||||
*/
|
||||
static inline void dma_write_reg_field(void *base, u32 offset,
|
||||
const u32 mask, u32 val)
|
||||
{
|
||||
unsigned long lmask = mask;
|
||||
u32 shift = find_first_bit(&lmask, 32);
|
||||
u32 tmp = ioread32(base + offset);
|
||||
|
||||
tmp &= ~mask; /* clear written bits */
|
||||
val = tmp | (val << shift);
|
||||
iowrite32(val, base + offset);
|
||||
SPS_DBG(sps, "sps:bamdma: write reg 0x%x w_val 0x%x\n", offset, val);
|
||||
}
|
||||
|
||||
/* Round max number of pipes to nearest multiple of 2 */
|
||||
#define DMA_MAX_PIPES ((BAM_MAX_PIPES / 2) * 2)
|
||||
|
||||
/* Maximum number of BAM-DMAs supported */
|
||||
#define MAX_BAM_DMA_DEVICES 1
|
||||
|
||||
/* Maximum number of BAMs that will be registered */
|
||||
#define MAX_BAM_DMA_BAMS 1
|
||||
|
||||
/* Pipe enable check values */
|
||||
#define DMA_PIPES_STATE_DIFF 0
|
||||
#define DMA_PIPES_BOTH_DISABLED 1
|
||||
#define DMA_PIPES_BOTH_ENABLED 2
|
||||
|
||||
/* Even pipe is tx/dest/input/write, odd pipe is rx/src/output/read */
|
||||
#define DMA_PIPE_IS_DEST(p) (((p) & 1) == 0)
|
||||
#define DMA_PIPE_IS_SRC(p) (((p) & 1) != 0)
|
||||
|
||||
/* BAM DMA pipe state */
|
||||
enum bamdma_pipe_state {
|
||||
PIPE_INACTIVE = 0,
|
||||
PIPE_ACTIVE
|
||||
};
|
||||
|
||||
/* BAM DMA channel state */
|
||||
enum bamdma_chan_state {
|
||||
DMA_CHAN_STATE_FREE = 0,
|
||||
DMA_CHAN_STATE_ALLOC_EXT, /* Client allocation */
|
||||
DMA_CHAN_STATE_ALLOC_INT /* Internal (resource mgr) allocation */
|
||||
};
|
||||
|
||||
struct bamdma_chan {
|
||||
/* Allocation state */
|
||||
enum bamdma_chan_state state;
|
||||
|
||||
/* BAM DMA channel configuration parameters */
|
||||
u32 threshold;
|
||||
enum sps_dma_priority priority;
|
||||
|
||||
/* HWIO channel configuration parameters */
|
||||
enum bam_dma_thresh_dma thresh;
|
||||
enum bam_dma_weight_dma weight;
|
||||
|
||||
};
|
||||
|
||||
/* BAM DMA device state */
|
||||
struct bamdma_device {
|
||||
/* BAM-DMA device state */
|
||||
int enabled;
|
||||
int local;
|
||||
|
||||
/* BAM device state */
|
||||
struct sps_bam *bam;
|
||||
|
||||
/* BAM handle, for deregistration */
|
||||
unsigned long h;
|
||||
|
||||
/* BAM DMA device virtual mapping */
|
||||
void *virt_addr;
|
||||
int virtual_mapped;
|
||||
phys_addr_t phys_addr;
|
||||
void *hwio;
|
||||
|
||||
/* BAM DMA pipe/channel state */
|
||||
u32 num_pipes;
|
||||
enum bamdma_pipe_state pipes[DMA_MAX_PIPES];
|
||||
struct bamdma_chan chans[DMA_MAX_PIPES / 2];
|
||||
|
||||
};
|
||||
|
||||
/* BAM-DMA devices */
|
||||
static struct bamdma_device bam_dma_dev[MAX_BAM_DMA_DEVICES];
|
||||
static struct mutex bam_dma_lock;
|
||||
|
||||
/*
|
||||
* The BAM DMA module registers all BAMs in the BSP properties, but only
|
||||
* uses the first BAM-DMA device for allocations. References to the others
|
||||
* are stored in the following data array.
|
||||
*/
|
||||
static int num_bams;
|
||||
static unsigned long bam_handles[MAX_BAM_DMA_BAMS];
|
||||
|
||||
/**
|
||||
* Find BAM-DMA device
|
||||
*
|
||||
* This function finds the BAM-DMA device associated with the BAM handle.
|
||||
*
|
||||
* @h - BAM handle
|
||||
*
|
||||
* @return - pointer to BAM-DMA device, or NULL on error
|
||||
*
|
||||
*/
|
||||
static struct bamdma_device *sps_dma_find_device(unsigned long h)
|
||||
{
|
||||
return &bam_dma_dev[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* BAM DMA device enable
|
||||
*
|
||||
* This function enables a BAM DMA device and the associated BAM.
|
||||
*
|
||||
* @dev - pointer to BAM DMA device context
|
||||
*
|
||||
* @return 0 on success, negative value on error
|
||||
*
|
||||
*/
|
||||
static int sps_dma_device_enable(struct bamdma_device *dev)
|
||||
{
|
||||
if (dev->enabled)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* If the BAM-DMA device is locally controlled then enable BAM-DMA
|
||||
* device
|
||||
*/
|
||||
if (dev->local)
|
||||
dma_write_reg(dev->virt_addr, DMA_ENBL, 1);
|
||||
|
||||
/* Enable BAM device */
|
||||
if (sps_bam_enable(dev->bam)) {
|
||||
SPS_ERR(sps, "sps:Failed to enable BAM DMA's BAM: %pa\n",
|
||||
&dev->phys_addr);
|
||||
return SPS_ERROR;
|
||||
}
|
||||
|
||||
dev->enabled = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* BAM DMA device enable
|
||||
*
|
||||
* This function initializes a BAM DMA device.
|
||||
*
|
||||
* @dev - pointer to BAM DMA device context
|
||||
*
|
||||
* @return 0 on success, negative value on error
|
||||
*
|
||||
*/
|
||||
static int sps_dma_device_disable(struct bamdma_device *dev)
|
||||
{
|
||||
u32 pipe_index;
|
||||
|
||||
if (!dev->enabled)
|
||||
return 0;
|
||||
|
||||
/* Do not disable if channels active */
|
||||
for (pipe_index = 0; pipe_index < dev->num_pipes; pipe_index++) {
|
||||
if (dev->pipes[pipe_index] != PIPE_INACTIVE)
|
||||
break;
|
||||
}
|
||||
|
||||
if (pipe_index < dev->num_pipes) {
|
||||
SPS_ERR(sps,
|
||||
"sps:Fail to disable BAM-DMA %pa:channels are active\n",
|
||||
&dev->phys_addr);
|
||||
return SPS_ERROR;
|
||||
}
|
||||
|
||||
dev->enabled = false;
|
||||
|
||||
/* Disable BAM device */
|
||||
if (sps_bam_disable(dev->bam)) {
|
||||
SPS_ERR(sps,
|
||||
"sps:Fail to disable BAM-DMA BAM:%pa\n",
|
||||
&dev->phys_addr);
|
||||
return SPS_ERROR;
|
||||
}
|
||||
|
||||
/* Is the BAM-DMA device locally controlled? */
|
||||
if (dev->local)
|
||||
/* Disable BAM-DMA device */
|
||||
dma_write_reg(dev->virt_addr, DMA_ENBL, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize BAM DMA device
|
||||
*
|
||||
*/
|
||||
int sps_dma_device_init(unsigned long h)
|
||||
{
|
||||
struct bamdma_device *dev;
|
||||
struct sps_bam_props *props;
|
||||
int result = SPS_ERROR;
|
||||
|
||||
mutex_lock(&bam_dma_lock);
|
||||
|
||||
/* Find a free BAM-DMA device slot */
|
||||
dev = NULL;
|
||||
if (bam_dma_dev[0].bam != NULL) {
|
||||
SPS_ERR(sps,
|
||||
"sps:%s:BAM-DMA BAM device is already initialized\n",
|
||||
__func__);
|
||||
goto exit_err;
|
||||
} else {
|
||||
dev = &bam_dma_dev[0];
|
||||
}
|
||||
|
||||
/* Record BAM */
|
||||
memset(dev, 0, sizeof(*dev));
|
||||
dev->h = h;
|
||||
dev->bam = sps_h2bam(h);
|
||||
|
||||
if (dev->bam == NULL) {
|
||||
SPS_ERR(sps,
|
||||
"sps:%s:BAM-DMA BAM device is not found from the handle\n",
|
||||
__func__);
|
||||
goto exit_err;
|
||||
}
|
||||
|
||||
/* Map the BAM DMA device into virtual space, if necessary */
|
||||
props = &dev->bam->props;
|
||||
dev->phys_addr = props->periph_phys_addr;
|
||||
if (props->periph_virt_addr != NULL) {
|
||||
dev->virt_addr = props->periph_virt_addr;
|
||||
dev->virtual_mapped = false;
|
||||
} else {
|
||||
if (props->periph_virt_size == 0) {
|
||||
SPS_ERR(sps,
|
||||
"sps:Unable to map BAM DMA IO memory: %pa %x\n",
|
||||
&dev->phys_addr, props->periph_virt_size);
|
||||
goto exit_err;
|
||||
}
|
||||
|
||||
dev->virt_addr = ioremap(dev->phys_addr,
|
||||
props->periph_virt_size);
|
||||
if (dev->virt_addr == NULL) {
|
||||
SPS_ERR(sps,
|
||||
"sps:Unable to map BAM DMA IO memory: %pa %x\n",
|
||||
&dev->phys_addr, props->periph_virt_size);
|
||||
goto exit_err;
|
||||
}
|
||||
dev->virtual_mapped = true;
|
||||
}
|
||||
dev->hwio = (void *) dev->virt_addr;
|
||||
|
||||
/* Is the BAM-DMA device locally controlled? */
|
||||
if ((props->manage & SPS_BAM_MGR_DEVICE_REMOTE) == 0) {
|
||||
SPS_DBG3(sps, "sps:BAM-DMA is controlled locally: %pa\n",
|
||||
&dev->phys_addr);
|
||||
dev->local = true;
|
||||
} else {
|
||||
SPS_DBG3(sps, "sps:BAM-DMA is controlled remotely: %pa\n",
|
||||
&dev->phys_addr);
|
||||
dev->local = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable the BAM DMA and determine the number of pipes/channels.
|
||||
* Leave the BAM-DMA enabled, since it is always a shared device.
|
||||
*/
|
||||
if (sps_dma_device_enable(dev))
|
||||
goto exit_err;
|
||||
|
||||
dev->num_pipes = dev->bam->props.num_pipes;
|
||||
|
||||
result = 0;
|
||||
exit_err:
|
||||
if (result) {
|
||||
if (dev != NULL) {
|
||||
if (dev->virtual_mapped)
|
||||
iounmap(dev->virt_addr);
|
||||
|
||||
dev->bam = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&bam_dma_lock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* De-initialize BAM DMA device
|
||||
*
|
||||
*/
|
||||
int sps_dma_device_de_init(unsigned long h)
|
||||
{
|
||||
struct bamdma_device *dev;
|
||||
u32 pipe_index;
|
||||
u32 chan;
|
||||
int result = 0;
|
||||
|
||||
mutex_lock(&bam_dma_lock);
|
||||
|
||||
dev = sps_dma_find_device(h);
|
||||
if (dev == NULL) {
|
||||
SPS_ERR(sps, "sps:BAM-DMA: not registered: %pK\n", (void *)h);
|
||||
result = SPS_ERROR;
|
||||
goto exit_err;
|
||||
}
|
||||
|
||||
/* Check for channel leaks */
|
||||
for (chan = 0; chan < dev->num_pipes / 2; chan++) {
|
||||
if (dev->chans[chan].state != DMA_CHAN_STATE_FREE) {
|
||||
SPS_ERR(sps, "sps:BAM-DMA: channel not free: %d\n",
|
||||
chan);
|
||||
result = SPS_ERROR;
|
||||
dev->chans[chan].state = DMA_CHAN_STATE_FREE;
|
||||
}
|
||||
}
|
||||
for (pipe_index = 0; pipe_index < dev->num_pipes; pipe_index++) {
|
||||
if (dev->pipes[pipe_index] != PIPE_INACTIVE) {
|
||||
SPS_ERR(sps, "sps:BAM-DMA: pipe not inactive: %d\n",
|
||||
pipe_index);
|
||||
result = SPS_ERROR;
|
||||
dev->pipes[pipe_index] = PIPE_INACTIVE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Disable BAM and BAM-DMA */
|
||||
if (sps_dma_device_disable(dev))
|
||||
result = SPS_ERROR;
|
||||
|
||||
dev->h = BAM_HANDLE_INVALID;
|
||||
dev->bam = NULL;
|
||||
if (dev->virtual_mapped)
|
||||
iounmap(dev->virt_addr);
|
||||
|
||||
exit_err:
|
||||
mutex_unlock(&bam_dma_lock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize BAM DMA module
|
||||
*
|
||||
*/
|
||||
int sps_dma_init(const struct sps_bam_props *bam_props)
|
||||
{
|
||||
struct sps_bam_props props;
|
||||
const struct sps_bam_props *bam_reg;
|
||||
unsigned long h;
|
||||
|
||||
/* Init local data */
|
||||
memset(&bam_dma_dev, 0, sizeof(bam_dma_dev));
|
||||
num_bams = 0;
|
||||
memset(bam_handles, 0, sizeof(bam_handles));
|
||||
|
||||
/* Create a mutex to control access to the BAM-DMA devices */
|
||||
mutex_init(&bam_dma_lock);
|
||||
|
||||
/* Are there any BAM DMA devices? */
|
||||
if (bam_props == NULL)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Registers all BAMs in the BSP properties, but only uses the first
|
||||
* BAM-DMA device for allocations.
|
||||
*/
|
||||
if (bam_props->phys_addr) {
|
||||
/* Force multi-EE option for all BAM-DMAs */
|
||||
bam_reg = bam_props;
|
||||
if ((bam_props->options & SPS_BAM_OPT_BAMDMA) &&
|
||||
(bam_props->manage & SPS_BAM_MGR_MULTI_EE) == 0) {
|
||||
SPS_DBG(sps,
|
||||
"sps:Setting multi-EE options for BAM-DMA: %pa\n",
|
||||
&bam_props->phys_addr);
|
||||
props = *bam_props;
|
||||
props.manage |= SPS_BAM_MGR_MULTI_EE;
|
||||
bam_reg = &props;
|
||||
}
|
||||
|
||||
/* Register the BAM */
|
||||
if (sps_register_bam_device(bam_reg, &h)) {
|
||||
SPS_ERR(sps,
|
||||
"sps:Fail to register BAM-DMA BAM device: phys %pa\n",
|
||||
&bam_props->phys_addr);
|
||||
return SPS_ERROR;
|
||||
}
|
||||
|
||||
/* Record the BAM so that it may be deregistered later */
|
||||
if (num_bams < MAX_BAM_DMA_BAMS) {
|
||||
bam_handles[num_bams] = h;
|
||||
num_bams++;
|
||||
} else {
|
||||
SPS_ERR(sps, "sps:BAM-DMA: BAM limit exceeded: %d\n",
|
||||
num_bams);
|
||||
return SPS_ERROR;
|
||||
}
|
||||
} else {
|
||||
SPS_ERR(sps,
|
||||
"sps:%s:BAM-DMA phys_addr is zero\n",
|
||||
__func__);
|
||||
return SPS_ERROR;
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* De-initialize BAM DMA module
|
||||
*
|
||||
*/
|
||||
void sps_dma_de_init(void)
|
||||
{
|
||||
int n;
|
||||
|
||||
/* De-initialize the BAM devices */
|
||||
for (n = 0; n < num_bams; n++)
|
||||
sps_deregister_bam_device(bam_handles[n]);
|
||||
|
||||
/* Clear local data */
|
||||
memset(&bam_dma_dev, 0, sizeof(bam_dma_dev));
|
||||
num_bams = 0;
|
||||
memset(bam_handles, 0, sizeof(bam_handles));
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate a BAM DMA channel
|
||||
*
|
||||
*/
|
||||
int sps_alloc_dma_chan(const struct sps_alloc_dma_chan *alloc,
|
||||
struct sps_dma_chan *chan_info)
|
||||
{
|
||||
struct bamdma_device *dev;
|
||||
struct bamdma_chan *chan;
|
||||
u32 pipe_index;
|
||||
enum bam_dma_thresh_dma thresh = (enum bam_dma_thresh_dma) 0;
|
||||
enum bam_dma_weight_dma weight = (enum bam_dma_weight_dma) 0;
|
||||
int result = SPS_ERROR;
|
||||
|
||||
if (alloc == NULL || chan_info == NULL) {
|
||||
SPS_ERR(sps,
|
||||
"sps:%s:invalid parameters\n", __func__);
|
||||
return SPS_ERROR;
|
||||
}
|
||||
|
||||
/* Translate threshold and priority to hwio values */
|
||||
if (alloc->threshold != SPS_DMA_THRESHOLD_DEFAULT) {
|
||||
if (alloc->threshold >= 512)
|
||||
thresh = BAM_DMA_THRESH_512;
|
||||
else if (alloc->threshold >= 256)
|
||||
thresh = BAM_DMA_THRESH_256;
|
||||
else if (alloc->threshold >= 128)
|
||||
thresh = BAM_DMA_THRESH_128;
|
||||
else
|
||||
thresh = BAM_DMA_THRESH_64;
|
||||
}
|
||||
|
||||
weight = alloc->priority;
|
||||
|
||||
if ((u32)alloc->priority > (u32)BAM_DMA_WEIGHT_HIGH) {
|
||||
SPS_ERR(sps, "sps:BAM-DMA: invalid priority: %x\n",
|
||||
alloc->priority);
|
||||
return SPS_ERROR;
|
||||
}
|
||||
|
||||
mutex_lock(&bam_dma_lock);
|
||||
|
||||
dev = sps_dma_find_device(alloc->dev);
|
||||
if (dev == NULL) {
|
||||
SPS_ERR(sps, "sps:BAM-DMA: invalid BAM handle: %pK\n",
|
||||
(void *)alloc->dev);
|
||||
goto exit_err;
|
||||
}
|
||||
|
||||
/* Search for a free set of pipes */
|
||||
for (pipe_index = 0, chan = dev->chans;
|
||||
pipe_index < dev->num_pipes; pipe_index += 2, chan++) {
|
||||
if (chan->state == DMA_CHAN_STATE_FREE) {
|
||||
/* Just check pipes for safety */
|
||||
if (dev->pipes[pipe_index] != PIPE_INACTIVE ||
|
||||
dev->pipes[pipe_index + 1] != PIPE_INACTIVE) {
|
||||
SPS_ERR(sps,
|
||||
"sps:BAM-DMA: channel %d state error:%d %d\n",
|
||||
pipe_index / 2, dev->pipes[pipe_index],
|
||||
dev->pipes[pipe_index + 1]);
|
||||
goto exit_err;
|
||||
}
|
||||
break; /* Found free pipe */
|
||||
}
|
||||
}
|
||||
|
||||
if (pipe_index >= dev->num_pipes) {
|
||||
SPS_ERR(sps, "sps:BAM-DMA: no free channel num_pipes = %d\n",
|
||||
dev->num_pipes);
|
||||
goto exit_err;
|
||||
}
|
||||
|
||||
chan->state = DMA_CHAN_STATE_ALLOC_EXT;
|
||||
|
||||
/* Store config values for use when pipes are activated */
|
||||
chan = &dev->chans[pipe_index / 2];
|
||||
chan->threshold = alloc->threshold;
|
||||
chan->thresh = thresh;
|
||||
chan->priority = alloc->priority;
|
||||
chan->weight = weight;
|
||||
|
||||
SPS_DBG3(sps, "sps:%s. pipe %d\n", __func__, pipe_index);
|
||||
|
||||
/* Report allocated pipes to client */
|
||||
chan_info->dev = dev->h;
|
||||
/* Dest/input/write pipex */
|
||||
chan_info->dest_pipe_index = pipe_index;
|
||||
/* Source/output/read pipe */
|
||||
chan_info->src_pipe_index = pipe_index + 1;
|
||||
|
||||
result = 0;
|
||||
exit_err:
|
||||
mutex_unlock(&bam_dma_lock);
|
||||
|
||||
return result;
|
||||
}
|
||||
EXPORT_SYMBOL(sps_alloc_dma_chan);
|
||||
|
||||
/**
|
||||
* Free a BAM DMA channel
|
||||
*
|
||||
*/
|
||||
int sps_free_dma_chan(struct sps_dma_chan *chan)
|
||||
{
|
||||
struct bamdma_device *dev;
|
||||
u32 pipe_index;
|
||||
int result = 0;
|
||||
|
||||
if (chan == NULL) {
|
||||
SPS_ERR(sps,
|
||||
"sps:%s:chan is NULL\n", __func__);
|
||||
return SPS_ERROR;
|
||||
}
|
||||
|
||||
mutex_lock(&bam_dma_lock);
|
||||
|
||||
dev = sps_dma_find_device(chan->dev);
|
||||
if (dev == NULL) {
|
||||
SPS_ERR(sps, "sps:BAM-DMA: invalid BAM handle: %pK\n",
|
||||
(void *)chan->dev);
|
||||
result = SPS_ERROR;
|
||||
goto exit_err;
|
||||
}
|
||||
|
||||
/* Verify the pipe indices */
|
||||
pipe_index = chan->dest_pipe_index;
|
||||
if (pipe_index >= dev->num_pipes || ((pipe_index & 1)) ||
|
||||
(pipe_index + 1) != chan->src_pipe_index) {
|
||||
SPS_ERR(sps,
|
||||
"sps:%s. Invalid pipe indices num_pipes=%d dest=%d src=%d\n",
|
||||
__func__, dev->num_pipes,
|
||||
chan->dest_pipe_index,
|
||||
chan->src_pipe_index);
|
||||
result = SPS_ERROR;
|
||||
goto exit_err;
|
||||
}
|
||||
|
||||
/* Are both pipes inactive? */
|
||||
if (dev->chans[pipe_index / 2].state != DMA_CHAN_STATE_ALLOC_EXT ||
|
||||
dev->pipes[pipe_index] != PIPE_INACTIVE ||
|
||||
dev->pipes[pipe_index + 1] != PIPE_INACTIVE) {
|
||||
SPS_ERR(sps,
|
||||
"sps:BAM-DMA: attempt to free active chan %d: %d %d\n",
|
||||
pipe_index / 2, dev->pipes[pipe_index],
|
||||
dev->pipes[pipe_index + 1]);
|
||||
result = SPS_ERROR;
|
||||
goto exit_err;
|
||||
}
|
||||
|
||||
/* Free the channel */
|
||||
dev->chans[pipe_index / 2].state = DMA_CHAN_STATE_FREE;
|
||||
|
||||
exit_err:
|
||||
mutex_unlock(&bam_dma_lock);
|
||||
|
||||
return result;
|
||||
}
|
||||
EXPORT_SYMBOL(sps_free_dma_chan);
|
||||
|
||||
/**
|
||||
* Activate a BAM DMA pipe
|
||||
*
|
||||
* This function activates a BAM DMA pipe.
|
||||
*
|
||||
* @dev - pointer to BAM-DMA device descriptor
|
||||
*
|
||||
* @pipe_index - pipe index
|
||||
*
|
||||
* @return 0 on success, negative value on error
|
||||
*
|
||||
*/
|
||||
static u32 sps_dma_check_pipes(struct bamdma_device *dev, u32 pipe_index)
|
||||
{
|
||||
u32 pipe_in;
|
||||
u32 pipe_out;
|
||||
int enabled_in;
|
||||
int enabled_out;
|
||||
u32 check;
|
||||
|
||||
pipe_in = pipe_index & ~1;
|
||||
pipe_out = pipe_in + 1;
|
||||
enabled_in = bam_pipe_is_enabled(&dev->bam->base, pipe_in);
|
||||
enabled_out = bam_pipe_is_enabled(&dev->bam->base, pipe_out);
|
||||
|
||||
if (!enabled_in && !enabled_out)
|
||||
check = DMA_PIPES_BOTH_DISABLED;
|
||||
else if (enabled_in && enabled_out)
|
||||
check = DMA_PIPES_BOTH_ENABLED;
|
||||
else
|
||||
check = DMA_PIPES_STATE_DIFF;
|
||||
|
||||
return check;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate a BAM DMA pipe
|
||||
*
|
||||
*/
|
||||
int sps_dma_pipe_alloc(void *bam_arg, u32 pipe_index, enum sps_mode dir)
|
||||
{
|
||||
struct sps_bam *bam = bam_arg;
|
||||
struct bamdma_device *dev;
|
||||
struct bamdma_chan *chan;
|
||||
u32 channel;
|
||||
int result = SPS_ERROR;
|
||||
|
||||
if (bam == NULL) {
|
||||
SPS_ERR(sps, "%s\n", "sps:BAM context is NULL");
|
||||
return SPS_ERROR;
|
||||
}
|
||||
|
||||
/* Check pipe direction */
|
||||
if ((DMA_PIPE_IS_DEST(pipe_index) && dir != SPS_MODE_DEST) ||
|
||||
(DMA_PIPE_IS_SRC(pipe_index) && dir != SPS_MODE_SRC)) {
|
||||
SPS_ERR(sps, "sps:BAM-DMA: wrong dir for BAM %pa pipe %d\n",
|
||||
&bam->props.phys_addr, pipe_index);
|
||||
return SPS_ERROR;
|
||||
}
|
||||
|
||||
mutex_lock(&bam_dma_lock);
|
||||
|
||||
dev = sps_dma_find_device((unsigned long) bam);
|
||||
if (dev == NULL) {
|
||||
SPS_ERR(sps, "sps:BAM-DMA: invalid BAM: %pa\n",
|
||||
&bam->props.phys_addr);
|
||||
goto exit_err;
|
||||
}
|
||||
if (pipe_index >= dev->num_pipes) {
|
||||
SPS_ERR(sps, "sps:BAM-DMA: BAM %pa invalid pipe: %d\n",
|
||||
&bam->props.phys_addr, pipe_index);
|
||||
goto exit_err;
|
||||
}
|
||||
if (dev->pipes[pipe_index] != PIPE_INACTIVE) {
|
||||
SPS_ERR(sps, "sps:BAM-DMA: BAM %pa pipe %d already active\n",
|
||||
&bam->props.phys_addr, pipe_index);
|
||||
goto exit_err;
|
||||
}
|
||||
|
||||
/* Mark pipe active */
|
||||
dev->pipes[pipe_index] = PIPE_ACTIVE;
|
||||
|
||||
/* If channel is not allocated, make an internal allocation */
|
||||
channel = pipe_index / 2;
|
||||
chan = &dev->chans[channel];
|
||||
if (chan->state != DMA_CHAN_STATE_ALLOC_EXT &&
|
||||
chan->state != DMA_CHAN_STATE_ALLOC_INT) {
|
||||
chan->state = DMA_CHAN_STATE_ALLOC_INT;
|
||||
}
|
||||
|
||||
result = 0;
|
||||
exit_err:
|
||||
mutex_unlock(&bam_dma_lock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable a BAM DMA pipe
|
||||
*
|
||||
*/
|
||||
int sps_dma_pipe_enable(void *bam_arg, u32 pipe_index)
|
||||
{
|
||||
struct sps_bam *bam = bam_arg;
|
||||
struct bamdma_device *dev;
|
||||
struct bamdma_chan *chan;
|
||||
u32 channel;
|
||||
int result = SPS_ERROR;
|
||||
|
||||
SPS_DBG3(sps, "sps:%s pipe %d\n", __func__, pipe_index);
|
||||
|
||||
mutex_lock(&bam_dma_lock);
|
||||
|
||||
dev = sps_dma_find_device((unsigned long) bam);
|
||||
if (dev == NULL) {
|
||||
SPS_ERR(sps, "sps:%s:BAM-DMA: invalid BAM\n", __func__);
|
||||
goto exit_err;
|
||||
}
|
||||
if (pipe_index >= dev->num_pipes) {
|
||||
SPS_ERR(sps, "sps:BAM-DMA: BAM %pa invalid pipe: %d\n",
|
||||
&bam->props.phys_addr, pipe_index);
|
||||
goto exit_err;
|
||||
}
|
||||
if (dev->pipes[pipe_index] != PIPE_ACTIVE) {
|
||||
SPS_ERR(sps, "sps:BAM-DMA: BAM %pa pipe %d not active\n",
|
||||
&bam->props.phys_addr, pipe_index);
|
||||
goto exit_err;
|
||||
}
|
||||
|
||||
/*
|
||||
* The channel must be enabled when the dest/input/write pipe
|
||||
* is enabled
|
||||
*/
|
||||
if (DMA_PIPE_IS_DEST(pipe_index)) {
|
||||
/* Configure and enable the channel */
|
||||
channel = pipe_index / 2;
|
||||
chan = &dev->chans[channel];
|
||||
|
||||
if (chan->threshold != SPS_DMA_THRESHOLD_DEFAULT)
|
||||
dma_write_reg_field(dev->virt_addr,
|
||||
DMA_CHNL_CONFIG(channel),
|
||||
DMA_CHNL_ACT_THRESH,
|
||||
chan->thresh);
|
||||
|
||||
if (chan->priority != SPS_DMA_PRI_DEFAULT)
|
||||
dma_write_reg_field(dev->virt_addr,
|
||||
DMA_CHNL_CONFIG(channel),
|
||||
DMA_CHNL_WEIGHT,
|
||||
chan->weight);
|
||||
|
||||
dma_write_reg_field(dev->virt_addr,
|
||||
DMA_CHNL_CONFIG(channel),
|
||||
DMA_CHNL_ENABLE, 1);
|
||||
}
|
||||
|
||||
result = 0;
|
||||
exit_err:
|
||||
mutex_unlock(&bam_dma_lock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deactivate a BAM DMA pipe
|
||||
*
|
||||
* This function deactivates a BAM DMA pipe.
|
||||
*
|
||||
* @dev - pointer to BAM-DMA device descriptor
|
||||
*
|
||||
* @bam - pointer to BAM device descriptor
|
||||
*
|
||||
* @pipe_index - pipe index
|
||||
*
|
||||
* @return 0 on success, negative value on error
|
||||
*
|
||||
*/
|
||||
static int sps_dma_deactivate_pipe_atomic(struct bamdma_device *dev,
|
||||
struct sps_bam *bam,
|
||||
u32 pipe_index)
|
||||
{
|
||||
u32 channel;
|
||||
|
||||
if (dev->bam != bam)
|
||||
return SPS_ERROR;
|
||||
if (pipe_index >= dev->num_pipes)
|
||||
return SPS_ERROR;
|
||||
if (dev->pipes[pipe_index] != PIPE_ACTIVE)
|
||||
return SPS_ERROR; /* Pipe is not active */
|
||||
|
||||
SPS_DBG3(sps, "sps:BAM-DMA: deactivate pipe %d\n", pipe_index);
|
||||
|
||||
/* Mark pipe inactive */
|
||||
dev->pipes[pipe_index] = PIPE_INACTIVE;
|
||||
|
||||
/*
|
||||
* Channel must be reset when either pipe is disabled, so just always
|
||||
* reset regardless of other pipe's state
|
||||
*/
|
||||
channel = pipe_index / 2;
|
||||
dma_write_reg_field(dev->virt_addr, DMA_CHNL_CONFIG(channel),
|
||||
DMA_CHNL_ENABLE, 0);
|
||||
|
||||
/* If the peer pipe is also inactive, reset the channel */
|
||||
if (sps_dma_check_pipes(dev, pipe_index) == DMA_PIPES_BOTH_DISABLED) {
|
||||
/* Free channel if allocated internally */
|
||||
if (dev->chans[channel].state == DMA_CHAN_STATE_ALLOC_INT)
|
||||
dev->chans[channel].state = DMA_CHAN_STATE_FREE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free a BAM DMA pipe
|
||||
*
|
||||
*/
|
||||
int sps_dma_pipe_free(void *bam_arg, u32 pipe_index)
|
||||
{
|
||||
struct bamdma_device *dev;
|
||||
struct sps_bam *bam = bam_arg;
|
||||
int result;
|
||||
|
||||
mutex_lock(&bam_dma_lock);
|
||||
|
||||
dev = sps_dma_find_device((unsigned long) bam);
|
||||
if (dev == NULL) {
|
||||
SPS_ERR(sps, "sps:%s:BAM-DMA: invalid BAM\n", __func__);
|
||||
result = SPS_ERROR;
|
||||
goto exit_err;
|
||||
}
|
||||
|
||||
result = sps_dma_deactivate_pipe_atomic(dev, bam, pipe_index);
|
||||
|
||||
exit_err:
|
||||
mutex_unlock(&bam_dma_lock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the BAM handle for BAM-DMA.
|
||||
*
|
||||
* The BAM handle should be use as source/destination in the sps_connect().
|
||||
*
|
||||
* @return bam handle on success, zero on error
|
||||
*/
|
||||
unsigned long sps_dma_get_bam_handle(void)
|
||||
{
|
||||
return (unsigned long)bam_dma_dev[0].bam;
|
||||
}
|
||||
EXPORT_SYMBOL(sps_dma_get_bam_handle);
|
||||
|
||||
/**
|
||||
* Free the BAM handle for BAM-DMA.
|
||||
*
|
||||
*/
|
||||
void sps_dma_free_bam_handle(unsigned long h)
|
||||
{
|
||||
}
|
||||
EXPORT_SYMBOL(sps_dma_free_bam_handle);
|
||||
|
||||
#endif /* CONFIG_SPS_SUPPORT_BAMDMA */
|
132
drivers/soc/qcom/sps/sps_map.c
Normal file
132
drivers/soc/qcom/sps/sps_map.c
Normal file
@ -0,0 +1,132 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2011-2013, 2015, 2017-2019, 2021, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
/**
|
||||
* Connection mapping table management for SPS device driver.
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/memory.h>
|
||||
|
||||
#include "spsi.h"
|
||||
|
||||
/* Module state */
|
||||
struct sps_map_state {
|
||||
const struct sps_map *maps;
|
||||
u32 num_maps;
|
||||
u32 options;
|
||||
};
|
||||
|
||||
static struct sps_map_state sps_maps;
|
||||
|
||||
/**
|
||||
* Initialize connection mapping module
|
||||
*
|
||||
*/
|
||||
int sps_map_init(const struct sps_map *map_props, u32 options)
|
||||
{
|
||||
const struct sps_map *maps;
|
||||
|
||||
/* Are there any connection mappings? */
|
||||
memset(&sps_maps, 0, sizeof(sps_maps));
|
||||
if (map_props == NULL)
|
||||
return 0;
|
||||
|
||||
/* Init the module state */
|
||||
sps_maps.maps = map_props;
|
||||
sps_maps.options = options;
|
||||
for (maps = sps_maps.maps;; maps++, sps_maps.num_maps++)
|
||||
if (maps->src.periph_class == SPS_CLASS_INVALID &&
|
||||
maps->src.periph_phy_addr == SPS_ADDR_INVALID)
|
||||
break;
|
||||
|
||||
SPS_DBG(sps, "sps: %d mappings\n", sps_maps.num_maps);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* De-initialize connection mapping module
|
||||
*
|
||||
*/
|
||||
void sps_map_de_init(void)
|
||||
{
|
||||
memset(&sps_maps, 0, sizeof(sps_maps));
|
||||
}
|
||||
|
||||
/**
|
||||
* Find matching connection mapping
|
||||
*
|
||||
*/
|
||||
int sps_map_find(struct sps_connect *connect)
|
||||
{
|
||||
const struct sps_map *map;
|
||||
u32 i;
|
||||
void *desc;
|
||||
void *data;
|
||||
|
||||
/* Are there any connection mappings? */
|
||||
if (sps_maps.num_maps == 0)
|
||||
return SPS_ERROR;
|
||||
|
||||
/* Search the mapping table for a match to the specified connection */
|
||||
for (i = sps_maps.num_maps, map = sps_maps.maps;
|
||||
i > 0; i--, map++)
|
||||
if (map->src.periph_class == (u32) connect->source &&
|
||||
map->dest.periph_class == (u32) connect->destination
|
||||
&& map->config == (u32) connect->config)
|
||||
break;
|
||||
|
||||
if (i == 0)
|
||||
return SPS_ERROR;
|
||||
|
||||
/*
|
||||
* Before modifying client parameter struct, perform all
|
||||
* operations that might fail
|
||||
*/
|
||||
desc = spsi_get_mem_ptr(map->desc_base);
|
||||
if (desc == NULL) {
|
||||
SPS_ERR(sps,
|
||||
"sps:Cannot get virt addr for I/O buffer: %pa\n",
|
||||
&map->desc_base);
|
||||
return SPS_ERROR;
|
||||
}
|
||||
|
||||
if (map->data_size > 0 && map->data_base != SPS_ADDR_INVALID) {
|
||||
data = spsi_get_mem_ptr(map->data_base);
|
||||
if (data == NULL) {
|
||||
SPS_ERR(sps,
|
||||
"sps:Can't get virt addr for I/O buffer: %pa\n",
|
||||
&map->data_base);
|
||||
return SPS_ERROR;
|
||||
}
|
||||
} else {
|
||||
data = NULL;
|
||||
}
|
||||
|
||||
/* Copy mapping values to client parameter struct */
|
||||
if (connect->source != SPS_DEV_HANDLE_MEM)
|
||||
connect->src_pipe_index = map->src.pipe_index;
|
||||
|
||||
if (connect->destination != SPS_DEV_HANDLE_MEM)
|
||||
connect->dest_pipe_index = map->dest.pipe_index;
|
||||
|
||||
if (connect->mode == SPS_MODE_SRC)
|
||||
connect->event_thresh = map->src.event_thresh;
|
||||
else
|
||||
connect->event_thresh = map->dest.event_thresh;
|
||||
|
||||
connect->desc.size = map->desc_size;
|
||||
connect->desc.phys_base = map->desc_base;
|
||||
connect->desc.base = desc;
|
||||
if (map->data_size > 0 && map->data_base != SPS_ADDR_INVALID) {
|
||||
connect->data.size = map->data_size;
|
||||
connect->data.phys_base = map->data_base;
|
||||
connect->data.base = data;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
39
drivers/soc/qcom/sps/sps_map.h
Normal file
39
drivers/soc/qcom/sps/sps_map.h
Normal file
@ -0,0 +1,39 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2011, 2013, 2016-2019, 2021, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
/* SPS driver mapping table data declarations. */
|
||||
|
||||
|
||||
#ifndef _SPS_MAP_H_
|
||||
#define _SPS_MAP_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
/* End point parameters */
|
||||
struct sps_map_end_point {
|
||||
u32 periph_class; /* Peripheral device enumeration class */
|
||||
phys_addr_t periph_phy_addr; /* Peripheral base address */
|
||||
u32 pipe_index; /* Pipe index */
|
||||
u32 event_thresh; /* Pipe event threshold */
|
||||
};
|
||||
|
||||
/* Mapping connection descriptor */
|
||||
struct sps_map {
|
||||
/* Source end point parameters */
|
||||
struct sps_map_end_point src;
|
||||
|
||||
/* Destination end point parameters */
|
||||
struct sps_map_end_point dest;
|
||||
|
||||
/* Resource parameters */
|
||||
u32 config; /* Configuration (stream) identifier */
|
||||
phys_addr_t desc_base; /* Physical address of descriptor FIFO */
|
||||
u32 desc_size; /* Size (bytes) of descriptor FIFO */
|
||||
phys_addr_t data_base; /* Physical address of data FIFO */
|
||||
u32 data_size; /* Size (bytes) of data FIFO */
|
||||
|
||||
};
|
||||
|
||||
#endif /* _SPS_MAP_H_ */
|
164
drivers/soc/qcom/sps/sps_mem.c
Normal file
164
drivers/soc/qcom/sps/sps_mem.c
Normal file
@ -0,0 +1,164 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2011, 2013, 2015, 2017-2019, 2021, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
/**
|
||||
* Pipe-Memory allocation/free management.
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/genalloc.h>
|
||||
#include <linux/errno.h>
|
||||
|
||||
#include "sps_bam.h"
|
||||
#include "spsi.h"
|
||||
|
||||
static phys_addr_t iomem_phys;
|
||||
static void *iomem_virt;
|
||||
static u32 iomem_size;
|
||||
static u32 iomem_offset;
|
||||
static struct gen_pool *pool;
|
||||
static u32 nid = 0xaa;
|
||||
|
||||
/* Debug */
|
||||
static u32 total_alloc;
|
||||
static u32 total_free;
|
||||
|
||||
/**
|
||||
* Translate physical to virtual address
|
||||
*
|
||||
*/
|
||||
void *spsi_get_mem_ptr(phys_addr_t phys_addr)
|
||||
{
|
||||
void *virt = NULL;
|
||||
|
||||
if ((phys_addr >= iomem_phys) &&
|
||||
(phys_addr < (iomem_phys + iomem_size))) {
|
||||
virt = (u8 *) iomem_virt + (phys_addr - iomem_phys);
|
||||
} else {
|
||||
virt = phys_to_virt(phys_addr);
|
||||
SPS_ERR(sps, "sps:%s.invalid phys addr=0x%pa\n",
|
||||
__func__, &phys_addr);
|
||||
}
|
||||
return virt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate I/O (pipe) memory
|
||||
*
|
||||
*/
|
||||
phys_addr_t sps_mem_alloc_io(u32 bytes)
|
||||
{
|
||||
phys_addr_t phys_addr = SPS_ADDR_INVALID;
|
||||
unsigned long virt_addr = 0;
|
||||
|
||||
virt_addr = gen_pool_alloc(pool, bytes);
|
||||
if (virt_addr) {
|
||||
iomem_offset = virt_addr - (uintptr_t) iomem_virt;
|
||||
phys_addr = iomem_phys + iomem_offset;
|
||||
total_alloc += bytes;
|
||||
} else {
|
||||
SPS_ERR(sps, "sps:gen_pool_alloc %d bytes fail\n", bytes);
|
||||
return SPS_ADDR_INVALID;
|
||||
}
|
||||
|
||||
SPS_DBG3(sps, "sps:%s.phys=%pa.virt=0x%pK.size=0x%x\n",
|
||||
__func__, &phys_addr, (void *)virt_addr, bytes);
|
||||
|
||||
return phys_addr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free I/O memory
|
||||
*
|
||||
*/
|
||||
void sps_mem_free_io(phys_addr_t phys_addr, u32 bytes)
|
||||
{
|
||||
unsigned long virt_addr = 0;
|
||||
|
||||
iomem_offset = phys_addr - iomem_phys;
|
||||
virt_addr = (uintptr_t) iomem_virt + iomem_offset;
|
||||
|
||||
SPS_DBG3(sps, "sps:%s.phys=%pa.virt=0x%pK.size=0x%x\n",
|
||||
__func__, &phys_addr, (void *)virt_addr, bytes);
|
||||
|
||||
gen_pool_free(pool, virt_addr, bytes);
|
||||
total_free += bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize driver memory module
|
||||
*
|
||||
*/
|
||||
int sps_mem_init(phys_addr_t pipemem_phys_base, u32 pipemem_size)
|
||||
{
|
||||
int res;
|
||||
|
||||
/* 2^8=128. The desc-fifo and data-fifo minimal allocation. */
|
||||
int min_alloc_order = 8;
|
||||
|
||||
if ((d_type == 0) || (d_type == 2) || imem) {
|
||||
iomem_phys = pipemem_phys_base;
|
||||
iomem_size = pipemem_size;
|
||||
|
||||
if (iomem_phys == 0) {
|
||||
SPS_ERR(sps, "sps:%s:Invalid Pipe-Mem address\n",
|
||||
__func__);
|
||||
return SPS_ERROR;
|
||||
}
|
||||
iomem_virt = ioremap(iomem_phys, iomem_size);
|
||||
if (!iomem_virt) {
|
||||
SPS_ERR(sps,
|
||||
"sps:%s:Failed to IO map pipe memory\n",
|
||||
__func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
iomem_offset = 0;
|
||||
SPS_DBG(sps,
|
||||
"sps:%s.iomem_phys=%pa,iomem_virt=0x%pK\n",
|
||||
__func__, &iomem_phys, iomem_virt);
|
||||
}
|
||||
|
||||
pool = gen_pool_create(min_alloc_order, nid);
|
||||
|
||||
if (!pool) {
|
||||
SPS_ERR(sps, "sps:%s:Failed to create a new memory pool\n",
|
||||
__func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if ((d_type == 0) || (d_type == 2) || imem) {
|
||||
res = gen_pool_add(pool, (uintptr_t)iomem_virt,
|
||||
iomem_size, nid);
|
||||
if (res)
|
||||
return res;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* De-initialize driver memory module
|
||||
*
|
||||
*/
|
||||
int sps_mem_de_init(void)
|
||||
{
|
||||
if (iomem_virt != NULL) {
|
||||
gen_pool_destroy(pool);
|
||||
pool = NULL;
|
||||
iounmap(iomem_virt);
|
||||
iomem_virt = NULL;
|
||||
}
|
||||
|
||||
if (total_alloc == total_free)
|
||||
return 0;
|
||||
|
||||
SPS_ERR(sps, "sps:%s:some memory not free\n", __func__);
|
||||
return SPS_ERROR;
|
||||
}
|
870
drivers/soc/qcom/sps/sps_rm.c
Normal file
870
drivers/soc/qcom/sps/sps_rm.c
Normal file
@ -0,0 +1,870 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2011-2015, 2017-2019, 2021, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
/* Resource management for the SPS device driver. */
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/memory.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include "spsi.h"
|
||||
#include "sps_core.h"
|
||||
|
||||
/* Max BAM FIFO sizes */
|
||||
#define SPSRM_MAX_DESC_FIFO_SIZE 0xffff
|
||||
#define SPSRM_MAX_DATA_FIFO_SIZE 0xffff
|
||||
|
||||
/* Connection control struct pointer */
|
||||
static struct sps_rm *sps_rm;
|
||||
|
||||
/**
|
||||
* Initialize resource manager module
|
||||
*/
|
||||
int sps_rm_init(struct sps_rm *rm, u32 options)
|
||||
{
|
||||
/* Set the resource manager state struct pointer */
|
||||
sps_rm = rm;
|
||||
|
||||
/* Initialize the state struct */
|
||||
INIT_LIST_HEAD(&sps_rm->connections_q);
|
||||
mutex_init(&sps_rm->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize client state context
|
||||
*
|
||||
*/
|
||||
void sps_rm_config_init(struct sps_connect *connect)
|
||||
{
|
||||
memset(connect, SPSRM_CLEAR, sizeof(*connect));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove reference to connection mapping
|
||||
*
|
||||
* This function removes a reference from a connection mapping struct.
|
||||
*
|
||||
* @map - pointer to connection mapping struct
|
||||
*
|
||||
*/
|
||||
static void sps_rm_remove_ref(struct sps_connection *map)
|
||||
{
|
||||
/* Free this connection */
|
||||
map->refs--;
|
||||
if (map->refs <= 0) {
|
||||
if (map->client_src != NULL || map->client_dest != NULL)
|
||||
SPS_ERR(sps,
|
||||
"sps:%s:Failed to allocate connection struct\n",
|
||||
__func__);
|
||||
|
||||
list_del(&map->list);
|
||||
kfree(map);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare map to connect parameters
|
||||
*
|
||||
* This function compares client connect parameters to an allocated
|
||||
* connection mapping.
|
||||
*
|
||||
* @pipe - client context for SPS connection end point
|
||||
*
|
||||
* @return - true if match, false otherwise
|
||||
*
|
||||
*/
|
||||
static int sps_rm_map_match(const struct sps_connect *cfg,
|
||||
const struct sps_connection *map)
|
||||
{
|
||||
if (cfg->source != map->src.dev ||
|
||||
cfg->destination != map->dest.dev)
|
||||
return false;
|
||||
|
||||
if (cfg->src_pipe_index != SPSRM_CLEAR &&
|
||||
cfg->src_pipe_index != map->src.pipe_index)
|
||||
return false;
|
||||
|
||||
if (cfg->dest_pipe_index != SPSRM_CLEAR &&
|
||||
cfg->dest_pipe_index != map->dest.pipe_index)
|
||||
return false;
|
||||
|
||||
if (cfg->config != map->config)
|
||||
return false;
|
||||
|
||||
if (cfg->desc.size != SPSRM_CLEAR) {
|
||||
if (cfg->desc.size != map->desc.size)
|
||||
return false;
|
||||
|
||||
if (cfg->desc.phys_base != (SPSRM_CLEAR|SPSRM_ADDR_CLR) &&
|
||||
cfg->desc.base != (void *)(SPSRM_CLEAR|SPSRM_ADDR_CLR) &&
|
||||
(cfg->desc.phys_base != map->desc.phys_base ||
|
||||
cfg->desc.base != map->desc.base)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (cfg->data.size != SPSRM_CLEAR) {
|
||||
if (cfg->data.size != map->data.size)
|
||||
return false;
|
||||
|
||||
if (cfg->data.phys_base != (SPSRM_CLEAR|SPSRM_ADDR_CLR) &&
|
||||
cfg->data.base != (void *)(SPSRM_CLEAR|SPSRM_ADDR_CLR) &&
|
||||
(cfg->data.phys_base != map->data.phys_base ||
|
||||
cfg->data.base != map->data.base))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find unconnected mapping
|
||||
*
|
||||
* This function finds an allocated a connection mapping.
|
||||
*
|
||||
* @pipe - client context for SPS connection end point
|
||||
*
|
||||
* @return - pointer to allocated connection mapping, or NULL if not found
|
||||
*
|
||||
*/
|
||||
static struct sps_connection *find_unconnected(struct sps_pipe *pipe)
|
||||
{
|
||||
struct sps_connect *cfg = &pipe->connect;
|
||||
struct sps_connection *map;
|
||||
|
||||
/* Has this connection already been allocated? */
|
||||
list_for_each_entry(map, &sps_rm->connections_q, list) {
|
||||
if (sps_rm_map_match(cfg, map))
|
||||
if ((cfg->mode == SPS_MODE_SRC
|
||||
&& map->client_src == NULL)
|
||||
|| (cfg->mode != SPS_MODE_SRC
|
||||
&& map->client_dest == NULL))
|
||||
return map; /* Found */
|
||||
}
|
||||
|
||||
return NULL; /* Not Found */
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign connection to client
|
||||
*
|
||||
* This function assigns a connection to a client.
|
||||
*
|
||||
* @pipe - client context for SPS connection end point
|
||||
*
|
||||
* @map - connection mapping
|
||||
*
|
||||
* @return 0 on success, negative value on error
|
||||
*
|
||||
*/
|
||||
static int sps_rm_assign(struct sps_pipe *pipe,
|
||||
struct sps_connection *map)
|
||||
{
|
||||
struct sps_connect *cfg = &pipe->connect;
|
||||
unsigned long desc_iova = 0;
|
||||
unsigned long data_iova = 0;
|
||||
|
||||
/* Check ownership and BAM */
|
||||
if ((cfg->mode == SPS_MODE_SRC && map->client_src != NULL) ||
|
||||
(cfg->mode != SPS_MODE_SRC && map->client_dest != NULL)) {
|
||||
SPS_ERR(sps,
|
||||
"sps:%s:The end point is already connected\n",
|
||||
__func__);
|
||||
return SPS_ERROR;
|
||||
}
|
||||
|
||||
/* Check whether this end point is a BAM (not memory) */
|
||||
if ((cfg->mode == SPS_MODE_SRC && map->src.bam == NULL) ||
|
||||
(cfg->mode != SPS_MODE_SRC && map->dest.bam == NULL)) {
|
||||
SPS_ERR(sps, "sps:%s:The end point is empty\n", __func__);
|
||||
return SPS_ERROR;
|
||||
}
|
||||
|
||||
/* Record the connection assignment */
|
||||
if (cfg->mode == SPS_MODE_SRC) {
|
||||
map->client_src = pipe;
|
||||
pipe->bam = map->src.bam;
|
||||
pipe->pipe_index = map->src.pipe_index;
|
||||
if (pipe->connect.event_thresh != SPSRM_CLEAR)
|
||||
map->src.event_threshold = pipe->connect.event_thresh;
|
||||
if (pipe->connect.lock_group != SPSRM_CLEAR)
|
||||
map->src.lock_group = pipe->connect.lock_group;
|
||||
} else {
|
||||
map->client_dest = pipe;
|
||||
pipe->bam = map->dest.bam;
|
||||
pipe->pipe_index = map->dest.pipe_index;
|
||||
if (pipe->connect.event_thresh != SPSRM_CLEAR)
|
||||
map->dest.event_threshold =
|
||||
pipe->connect.event_thresh;
|
||||
if (pipe->connect.lock_group != SPSRM_CLEAR)
|
||||
map->dest.lock_group = pipe->connect.lock_group;
|
||||
}
|
||||
pipe->map = map;
|
||||
|
||||
SPS_DBG(pipe->bam, "sps:%s.bam %pa.pipe_index=%d\n",
|
||||
__func__, BAM_ID(pipe->bam), pipe->pipe_index);
|
||||
|
||||
/* Copy parameters to client connect state */
|
||||
pipe->connect.src_pipe_index = map->src.pipe_index;
|
||||
pipe->connect.dest_pipe_index = map->dest.pipe_index;
|
||||
|
||||
/*
|
||||
* The below assignment to connect.desc and connect.data will
|
||||
* overwrite the previous values given by the first client
|
||||
* in a BAM-to-BAM connection. Prevent that since the IOVAs
|
||||
* may be different for the same physical buffers if the
|
||||
* BAMs use different SMMUs.
|
||||
*/
|
||||
if (pipe->bam->props.options & SPS_BAM_SMMU_EN) {
|
||||
desc_iova = pipe->connect.desc.iova;
|
||||
data_iova = pipe->connect.data.iova;
|
||||
}
|
||||
pipe->connect.desc = map->desc;
|
||||
pipe->connect.data = map->data;
|
||||
if (pipe->bam->props.options & SPS_BAM_SMMU_EN) {
|
||||
pipe->connect.desc.iova = desc_iova;
|
||||
pipe->connect.data.iova = data_iova;
|
||||
}
|
||||
|
||||
pipe->client_state = SPS_STATE_ALLOCATE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free connection mapping resources
|
||||
*
|
||||
* This function frees a connection mapping resources.
|
||||
*
|
||||
* @pipe - client context for SPS connection end point
|
||||
*
|
||||
*/
|
||||
static void sps_rm_free_map_rsrc(struct sps_connection *map)
|
||||
{
|
||||
struct sps_bam *bam;
|
||||
|
||||
if (map->client_src != NULL || map->client_dest != NULL)
|
||||
return;
|
||||
|
||||
if (map->alloc_src_pipe != SPS_BAM_PIPE_INVALID) {
|
||||
bam = map->src.bam;
|
||||
sps_bam_pipe_free(bam, map->src.pipe_index);
|
||||
|
||||
/* Is this a BAM-DMA pipe? */
|
||||
#ifdef CONFIG_SPS_SUPPORT_BAMDMA
|
||||
if ((bam->props.options & SPS_BAM_OPT_BAMDMA))
|
||||
/* Deallocate and free the BAM-DMA channel */
|
||||
sps_dma_pipe_free(bam, map->src.pipe_index);
|
||||
#endif
|
||||
map->alloc_src_pipe = SPS_BAM_PIPE_INVALID;
|
||||
map->src.pipe_index = SPS_BAM_PIPE_INVALID;
|
||||
}
|
||||
if (map->alloc_dest_pipe != SPS_BAM_PIPE_INVALID) {
|
||||
bam = map->dest.bam;
|
||||
sps_bam_pipe_free(bam, map->dest.pipe_index);
|
||||
|
||||
/* Is this a BAM-DMA pipe? */
|
||||
#ifdef CONFIG_SPS_SUPPORT_BAMDMA
|
||||
if ((bam->props.options & SPS_BAM_OPT_BAMDMA)) {
|
||||
/* Deallocate the BAM-DMA channel */
|
||||
sps_dma_pipe_free(bam, map->dest.pipe_index);
|
||||
}
|
||||
#endif
|
||||
map->alloc_dest_pipe = SPS_BAM_PIPE_INVALID;
|
||||
map->dest.pipe_index = SPS_BAM_PIPE_INVALID;
|
||||
}
|
||||
if (map->alloc_desc_base != SPS_ADDR_INVALID) {
|
||||
sps_mem_free_io(map->alloc_desc_base, map->desc.size);
|
||||
|
||||
map->alloc_desc_base = SPS_ADDR_INVALID;
|
||||
map->desc.phys_base = SPS_ADDR_INVALID;
|
||||
}
|
||||
if (map->alloc_data_base != SPS_ADDR_INVALID) {
|
||||
sps_mem_free_io(map->alloc_data_base, map->data.size);
|
||||
|
||||
map->alloc_data_base = SPS_ADDR_INVALID;
|
||||
map->data.phys_base = SPS_ADDR_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Init connection mapping from client connect
|
||||
*
|
||||
* This function initializes a connection mapping from the client's
|
||||
* connect parameters.
|
||||
*
|
||||
* @map - connection mapping struct
|
||||
*
|
||||
* @cfg - client connect parameters
|
||||
*
|
||||
* @return - pointer to allocated connection mapping, or NULL on error
|
||||
*
|
||||
*/
|
||||
static void sps_rm_init_map(struct sps_connection *map,
|
||||
const struct sps_connect *cfg)
|
||||
{
|
||||
/* Clear the connection mapping struct */
|
||||
memset(map, 0, sizeof(*map));
|
||||
map->desc.phys_base = SPS_ADDR_INVALID;
|
||||
map->data.phys_base = SPS_ADDR_INVALID;
|
||||
map->alloc_desc_base = SPS_ADDR_INVALID;
|
||||
map->alloc_data_base = SPS_ADDR_INVALID;
|
||||
map->alloc_src_pipe = SPS_BAM_PIPE_INVALID;
|
||||
map->alloc_dest_pipe = SPS_BAM_PIPE_INVALID;
|
||||
|
||||
/* Copy client required parameters */
|
||||
map->src.dev = cfg->source;
|
||||
map->dest.dev = cfg->destination;
|
||||
map->desc.size = cfg->desc.size;
|
||||
map->data.size = cfg->data.size;
|
||||
map->config = cfg->config;
|
||||
|
||||
/* Did client specify descriptor FIFO? */
|
||||
if (map->desc.size != SPSRM_CLEAR &&
|
||||
cfg->desc.phys_base != (SPSRM_CLEAR|SPSRM_ADDR_CLR) &&
|
||||
cfg->desc.base != (void *)(SPSRM_CLEAR|SPSRM_ADDR_CLR))
|
||||
map->desc = cfg->desc;
|
||||
|
||||
/* Did client specify data FIFO? */
|
||||
if (map->data.size != SPSRM_CLEAR &&
|
||||
cfg->data.phys_base != (SPSRM_CLEAR|SPSRM_ADDR_CLR) &&
|
||||
cfg->data.base != (void *)(SPSRM_CLEAR|SPSRM_ADDR_CLR))
|
||||
map->data = cfg->data;
|
||||
|
||||
/* Did client specify source pipe? */
|
||||
if (cfg->src_pipe_index != SPSRM_CLEAR)
|
||||
map->src.pipe_index = cfg->src_pipe_index;
|
||||
else
|
||||
map->src.pipe_index = SPS_BAM_PIPE_INVALID;
|
||||
|
||||
|
||||
/* Did client specify destination pipe? */
|
||||
if (cfg->dest_pipe_index != SPSRM_CLEAR)
|
||||
map->dest.pipe_index = cfg->dest_pipe_index;
|
||||
else
|
||||
map->dest.pipe_index = SPS_BAM_PIPE_INVALID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new connection mapping
|
||||
*
|
||||
* This function creates a new connection mapping.
|
||||
*
|
||||
* @pipe - client context for SPS connection end point
|
||||
*
|
||||
* @return - pointer to allocated connection mapping, or NULL on error
|
||||
*
|
||||
*/
|
||||
static struct sps_connection *sps_rm_create(struct sps_pipe *pipe)
|
||||
{
|
||||
struct sps_connection *map;
|
||||
struct sps_bam *bam;
|
||||
u32 desc_size;
|
||||
u32 data_size;
|
||||
enum sps_mode dir;
|
||||
int success = false;
|
||||
|
||||
/* Allocate new connection */
|
||||
map = kzalloc(sizeof(*map), GFP_KERNEL);
|
||||
if (map == NULL) {
|
||||
SPS_ERR(sps,
|
||||
"sps:%s:Failed to allocate connection struct\n",
|
||||
__func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Initialize connection struct */
|
||||
sps_rm_init_map(map, &pipe->connect);
|
||||
dir = pipe->connect.mode;
|
||||
|
||||
/* Use a do/while() loop to avoid a "goto" */
|
||||
success = false;
|
||||
/* Get BAMs */
|
||||
map->src.bam = sps_h2bam(map->src.dev);
|
||||
if (map->src.bam == NULL) {
|
||||
if (map->src.dev != SPS_DEV_HANDLE_MEM) {
|
||||
SPS_ERR(sps, "sps:Invalid BAM handle: %pK\n",
|
||||
(void *)(&map->src.dev));
|
||||
goto exit_err;
|
||||
}
|
||||
map->src.pipe_index = SPS_BAM_PIPE_INVALID;
|
||||
}
|
||||
|
||||
if (!(pipe->connect.options & SPS_O_DUMMY_PEER)) {
|
||||
map->dest.bam = sps_h2bam(map->dest.dev);
|
||||
if (map->dest.bam == NULL) {
|
||||
if (map->dest.dev != SPS_DEV_HANDLE_MEM) {
|
||||
SPS_ERR(sps,
|
||||
"sps:Invalid BAM handle: %pK",
|
||||
(void *)(&map->dest.dev));
|
||||
goto exit_err;
|
||||
}
|
||||
map->dest.pipe_index = SPS_BAM_PIPE_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check the BAM device for the pipe */
|
||||
if ((dir == SPS_MODE_SRC && map->src.bam == NULL) ||
|
||||
(dir != SPS_MODE_SRC && map->dest.bam == NULL)) {
|
||||
SPS_ERR(sps, "sps:Invalid BAM endpt: dir %d src %pK dest %pK\n",
|
||||
dir, (void *)(&map->src.dev), (void *)(&map->dest.dev));
|
||||
goto exit_err;
|
||||
}
|
||||
|
||||
/* Allocate pipes and copy BAM parameters */
|
||||
if (map->src.bam != NULL) {
|
||||
/* Allocate the pipe */
|
||||
bam = map->src.bam;
|
||||
map->alloc_src_pipe = sps_bam_pipe_alloc(bam,
|
||||
map->src.pipe_index);
|
||||
if (map->alloc_src_pipe == SPS_BAM_PIPE_INVALID)
|
||||
goto exit_err;
|
||||
map->src.pipe_index = map->alloc_src_pipe;
|
||||
|
||||
/* Is this a BAM-DMA pipe? */
|
||||
#ifdef CONFIG_SPS_SUPPORT_BAMDMA
|
||||
if ((bam->props.options & SPS_BAM_OPT_BAMDMA)) {
|
||||
int rc;
|
||||
/* Allocate the BAM-DMA channel */
|
||||
rc = sps_dma_pipe_alloc(bam, map->src.pipe_index,
|
||||
SPS_MODE_SRC);
|
||||
if (rc) {
|
||||
SPS_ERR(bam,
|
||||
"sps:Failed to alloc BAM-DMA pipe: %d\n",
|
||||
map->src.pipe_index);
|
||||
goto exit_err;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
map->src.bam_phys = bam->props.phys_addr;
|
||||
map->src.event_threshold = bam->props.event_threshold;
|
||||
}
|
||||
if (map->dest.bam != NULL) {
|
||||
/* Allocate the pipe */
|
||||
bam = map->dest.bam;
|
||||
map->alloc_dest_pipe = sps_bam_pipe_alloc(bam,
|
||||
map->dest.pipe_index);
|
||||
if (map->alloc_dest_pipe == SPS_BAM_PIPE_INVALID)
|
||||
goto exit_err;
|
||||
|
||||
map->dest.pipe_index = map->alloc_dest_pipe;
|
||||
|
||||
/* Is this a BAM-DMA pipe? */
|
||||
#ifdef CONFIG_SPS_SUPPORT_BAMDMA
|
||||
if ((bam->props.options & SPS_BAM_OPT_BAMDMA)) {
|
||||
int rc;
|
||||
/* Allocate the BAM-DMA channel */
|
||||
rc = sps_dma_pipe_alloc(bam, map->dest.pipe_index,
|
||||
SPS_MODE_DEST);
|
||||
if (rc) {
|
||||
SPS_ERR(bam,
|
||||
"sps:Failed to alloc BAM-DMA pipe: %d\n",
|
||||
map->dest.pipe_index);
|
||||
goto exit_err;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
map->dest.bam_phys = bam->props.phys_addr;
|
||||
map->dest.event_threshold =
|
||||
bam->props.event_threshold;
|
||||
}
|
||||
|
||||
/* Get default FIFO sizes */
|
||||
desc_size = 0;
|
||||
data_size = 0;
|
||||
if (map->src.bam != NULL) {
|
||||
bam = map->src.bam;
|
||||
desc_size = bam->props.desc_size;
|
||||
data_size = bam->props.data_size;
|
||||
}
|
||||
if (map->dest.bam != NULL) {
|
||||
bam = map->dest.bam;
|
||||
if (bam->props.desc_size > desc_size)
|
||||
desc_size = bam->props.desc_size;
|
||||
if (bam->props.data_size > data_size)
|
||||
data_size = bam->props.data_size;
|
||||
}
|
||||
|
||||
/* Set FIFO sizes */
|
||||
if (map->desc.size == SPSRM_CLEAR)
|
||||
map->desc.size = desc_size;
|
||||
if (map->src.bam != NULL && map->dest.bam != NULL) {
|
||||
/* BAM-to-BAM requires data FIFO */
|
||||
if (map->data.size == SPSRM_CLEAR)
|
||||
map->data.size = data_size;
|
||||
} else {
|
||||
if (!(pipe->connect.options & SPS_O_DUMMY_PEER))
|
||||
map->data.size = 0;
|
||||
}
|
||||
if (map->desc.size > SPSRM_MAX_DESC_FIFO_SIZE) {
|
||||
SPS_ERR(sps, "sps:Invalid desc FIFO size: 0x%x\n",
|
||||
map->desc.size);
|
||||
goto exit_err;
|
||||
}
|
||||
if (map->src.bam != NULL && map->dest.bam != NULL &&
|
||||
map->data.size > SPSRM_MAX_DATA_FIFO_SIZE) {
|
||||
SPS_ERR(sps, "sps:Invalid data FIFO size: 0x%x\n",
|
||||
map->data.size);
|
||||
goto exit_err;
|
||||
}
|
||||
|
||||
/* Allocate descriptor FIFO if necessary */
|
||||
if (map->desc.size && map->desc.phys_base == SPS_ADDR_INVALID) {
|
||||
map->alloc_desc_base = sps_mem_alloc_io(map->desc.size);
|
||||
if (map->alloc_desc_base == SPS_ADDR_INVALID) {
|
||||
SPS_ERR(sps, "sps:I/O memory allocation failure:0x%x\n",
|
||||
map->desc.size);
|
||||
goto exit_err;
|
||||
}
|
||||
map->desc.phys_base = map->alloc_desc_base;
|
||||
map->desc.base = spsi_get_mem_ptr(map->desc.phys_base);
|
||||
if (map->desc.base == NULL) {
|
||||
SPS_ERR(sps,
|
||||
"sps:Cannot get virt addr for I/O buffer:%pa\n",
|
||||
&map->desc.phys_base);
|
||||
goto exit_err;
|
||||
}
|
||||
}
|
||||
|
||||
/* Allocate data FIFO if necessary */
|
||||
if (map->data.size && map->data.phys_base == SPS_ADDR_INVALID) {
|
||||
map->alloc_data_base = sps_mem_alloc_io(map->data.size);
|
||||
if (map->alloc_data_base == SPS_ADDR_INVALID) {
|
||||
SPS_ERR(sps, "sps:I/O memory allocation failure:0x%x\n",
|
||||
map->data.size);
|
||||
goto exit_err;
|
||||
}
|
||||
map->data.phys_base = map->alloc_data_base;
|
||||
map->data.base = spsi_get_mem_ptr(map->data.phys_base);
|
||||
if (map->data.base == NULL) {
|
||||
SPS_ERR(sps,
|
||||
"sps:Cannot get virt addr for I/O buffer:%pa\n",
|
||||
&map->data.phys_base);
|
||||
goto exit_err;
|
||||
}
|
||||
}
|
||||
|
||||
/* Attempt to assign this connection to the client */
|
||||
if (sps_rm_assign(pipe, map)) {
|
||||
SPS_ERR(sps,
|
||||
"sps:%s:failed to assign a connection to the client\n",
|
||||
__func__);
|
||||
goto exit_err;
|
||||
}
|
||||
|
||||
/* Initialization was successful */
|
||||
success = true;
|
||||
exit_err:
|
||||
|
||||
/* If initialization failed, free resources */
|
||||
if (!success) {
|
||||
sps_rm_free_map_rsrc(map);
|
||||
kfree(map);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free connection mapping
|
||||
*
|
||||
* This function frees a connection mapping.
|
||||
*
|
||||
* @pipe - client context for SPS connection end point
|
||||
*
|
||||
* @return 0 on success, negative value on error
|
||||
*
|
||||
*/
|
||||
static int sps_rm_free(struct sps_pipe *pipe)
|
||||
{
|
||||
struct sps_connection *map = (void *)pipe->map;
|
||||
struct sps_connect *cfg = &pipe->connect;
|
||||
|
||||
mutex_lock(&sps_rm->lock);
|
||||
|
||||
/* Free this connection */
|
||||
if (cfg->mode == SPS_MODE_SRC)
|
||||
map->client_src = NULL;
|
||||
else
|
||||
map->client_dest = NULL;
|
||||
|
||||
pipe->map = NULL;
|
||||
pipe->client_state = SPS_STATE_DISCONNECT;
|
||||
sps_rm_free_map_rsrc(map);
|
||||
|
||||
sps_rm_remove_ref(map);
|
||||
|
||||
mutex_unlock(&sps_rm->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate an SPS connection end point
|
||||
*
|
||||
* This function allocates resources and initializes a BAM connection.
|
||||
*
|
||||
* @pipe - client context for SPS connection end point
|
||||
*
|
||||
* @return 0 on success, negative value on error
|
||||
*
|
||||
*/
|
||||
static int sps_rm_alloc(struct sps_pipe *pipe)
|
||||
{
|
||||
struct sps_connection *map;
|
||||
int result = SPS_ERROR;
|
||||
|
||||
if (pipe->connect.sps_reserved != SPSRM_CLEAR) {
|
||||
/*
|
||||
* Client did not call sps_get_config() to init
|
||||
* struct sps_connect, so only use legacy members.
|
||||
*/
|
||||
unsigned long source = pipe->connect.source;
|
||||
unsigned long destination = pipe->connect.destination;
|
||||
enum sps_mode mode = pipe->connect.mode;
|
||||
u32 config = pipe->connect.config;
|
||||
|
||||
memset(&pipe->connect, SPSRM_CLEAR,
|
||||
sizeof(pipe->connect));
|
||||
pipe->connect.source = source;
|
||||
pipe->connect.destination = destination;
|
||||
pipe->connect.mode = mode;
|
||||
pipe->connect.config = config;
|
||||
}
|
||||
if (pipe->connect.config == SPSRM_CLEAR)
|
||||
pipe->connect.config = SPS_CONFIG_DEFAULT;
|
||||
|
||||
/*
|
||||
* If configuration is not default, then client is specifying a
|
||||
* connection mapping. Find a matching mapping, or fail.
|
||||
* If a match is found, the client's Connect struct will be updated
|
||||
* with all the mapping's values.
|
||||
*/
|
||||
if (pipe->connect.config != SPS_CONFIG_DEFAULT) {
|
||||
if (sps_map_find(&pipe->connect)) {
|
||||
SPS_ERR(sps,
|
||||
"sps:%s:Failed to find connection mapping\n",
|
||||
__func__);
|
||||
return SPS_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_lock(&sps_rm->lock);
|
||||
/* Check client state */
|
||||
if (IS_SPS_STATE_OK(pipe)) {
|
||||
SPS_ERR(sps,
|
||||
"sps:%s:Client connection already allocated\n",
|
||||
__func__);
|
||||
goto exit_err;
|
||||
}
|
||||
|
||||
/* Are the connection resources already allocated? */
|
||||
map = find_unconnected(pipe);
|
||||
if (map != NULL) {
|
||||
/* Attempt to assign this connection to the client */
|
||||
if (sps_rm_assign(pipe, map))
|
||||
/* Assignment failed, so must allocate new */
|
||||
map = NULL;
|
||||
}
|
||||
|
||||
/* Allocate a new connection if necessary */
|
||||
if (map == NULL) {
|
||||
map = sps_rm_create(pipe);
|
||||
if (map == NULL) {
|
||||
SPS_ERR(sps,
|
||||
"sps:%s:Failed to allocate connection\n",
|
||||
__func__);
|
||||
goto exit_err;
|
||||
}
|
||||
list_add_tail(&map->list, &sps_rm->connections_q);
|
||||
}
|
||||
|
||||
/* Add the connection to the allocated queue */
|
||||
map->refs++;
|
||||
|
||||
/* Initialization was successful */
|
||||
result = 0;
|
||||
exit_err:
|
||||
mutex_unlock(&sps_rm->lock);
|
||||
|
||||
if (result)
|
||||
return SPS_ERROR;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect an SPS connection end point
|
||||
*
|
||||
* This function frees resources and de-initializes a BAM connection.
|
||||
*
|
||||
* @pipe - client context for SPS connection end point
|
||||
*
|
||||
* @return 0 on success, negative value on error
|
||||
*
|
||||
*/
|
||||
static int sps_rm_disconnect(struct sps_pipe *pipe)
|
||||
{
|
||||
sps_rm_free(pipe);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process connection state change
|
||||
*
|
||||
* This function processes a connection state change.
|
||||
*
|
||||
* @pipe - pointer to client context
|
||||
*
|
||||
* @state - new state for connection
|
||||
*
|
||||
* @return 0 on success, negative value on error
|
||||
*
|
||||
*/
|
||||
int sps_rm_state_change(struct sps_pipe *pipe, u32 state)
|
||||
{
|
||||
int auto_enable = false;
|
||||
int result;
|
||||
|
||||
/* Allocate the pipe */
|
||||
if (pipe->client_state == SPS_STATE_DISCONNECT &&
|
||||
state == SPS_STATE_ALLOCATE) {
|
||||
if (sps_rm_alloc(pipe)) {
|
||||
SPS_ERR(pipe->bam,
|
||||
"sps:Fail to allocate resource for BAM 0x%pK pipe %d\n",
|
||||
pipe->bam, pipe->pipe_index);
|
||||
return SPS_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/* Configure the pipe */
|
||||
if (pipe->client_state == SPS_STATE_ALLOCATE &&
|
||||
state == SPS_STATE_CONNECT) {
|
||||
/* Connect the BAM pipe */
|
||||
struct sps_bam_connect_param params;
|
||||
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
params.mode = pipe->connect.mode;
|
||||
if (pipe->connect.options != SPSRM_CLEAR) {
|
||||
params.options = pipe->connect.options;
|
||||
params.irq_gen_addr = pipe->connect.irq_gen_addr;
|
||||
params.irq_gen_data = pipe->connect.irq_gen_data;
|
||||
}
|
||||
result = sps_bam_pipe_connect(pipe, ¶ms);
|
||||
if (result) {
|
||||
SPS_ERR(pipe->bam,
|
||||
"sps:Failed to connect BAM 0x%pK pipe %d\n",
|
||||
pipe->bam, pipe->pipe_index);
|
||||
return SPS_ERROR;
|
||||
}
|
||||
pipe->client_state = SPS_STATE_CONNECT;
|
||||
|
||||
/* Set auto-enable for system-mode connections */
|
||||
if (pipe->connect.source == SPS_DEV_HANDLE_MEM ||
|
||||
pipe->connect.destination == SPS_DEV_HANDLE_MEM) {
|
||||
if (pipe->map->desc.size != 0 &&
|
||||
pipe->map->desc.phys_base != SPS_ADDR_INVALID)
|
||||
auto_enable = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Enable the pipe data flow */
|
||||
if (pipe->client_state == SPS_STATE_CONNECT &&
|
||||
!(state == SPS_STATE_DISABLE
|
||||
|| state == SPS_STATE_DISCONNECT)
|
||||
&& (state == SPS_STATE_ENABLE || auto_enable
|
||||
|| (pipe->connect.options & SPS_O_AUTO_ENABLE))) {
|
||||
result = sps_bam_pipe_enable(pipe->bam, pipe->pipe_index);
|
||||
if (result) {
|
||||
SPS_ERR(pipe->bam,
|
||||
"sps:Failed to set BAM %pa pipe %d flow on\n",
|
||||
&pipe->bam->props.phys_addr,
|
||||
pipe->pipe_index);
|
||||
return SPS_ERROR;
|
||||
}
|
||||
|
||||
/* Is this a BAM-DMA pipe? */
|
||||
#ifdef CONFIG_SPS_SUPPORT_BAMDMA
|
||||
if ((pipe->bam->props.options & SPS_BAM_OPT_BAMDMA)) {
|
||||
/* Activate the BAM-DMA channel */
|
||||
result = sps_dma_pipe_enable(pipe->bam,
|
||||
pipe->pipe_index);
|
||||
if (result) {
|
||||
SPS_ERR(pipe->bam,
|
||||
"sps:Failed to activate BAM-DMA pipe: %d\n",
|
||||
pipe->pipe_index);
|
||||
return SPS_ERROR;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
pipe->client_state = SPS_STATE_ENABLE;
|
||||
}
|
||||
|
||||
/* Disable the pipe data flow */
|
||||
if (pipe->client_state == SPS_STATE_ENABLE &&
|
||||
(state == SPS_STATE_DISABLE || state == SPS_STATE_DISCONNECT)) {
|
||||
result = sps_bam_pipe_disable(pipe->bam, pipe->pipe_index);
|
||||
if (result) {
|
||||
SPS_ERR(pipe->bam,
|
||||
"sps:Failed to set BAM %pa pipe %d flow off\n",
|
||||
&pipe->bam->props.phys_addr,
|
||||
pipe->pipe_index);
|
||||
return SPS_ERROR;
|
||||
}
|
||||
pipe->client_state = SPS_STATE_CONNECT;
|
||||
}
|
||||
|
||||
/* Disconnect the BAM pipe */
|
||||
if (pipe->client_state == SPS_STATE_CONNECT &&
|
||||
state == SPS_STATE_DISCONNECT) {
|
||||
struct sps_connection *map;
|
||||
struct sps_bam *bam = pipe->bam;
|
||||
unsigned long flags;
|
||||
u32 pipe_index;
|
||||
|
||||
if (pipe->connect.mode == SPS_MODE_SRC)
|
||||
pipe_index = pipe->map->src.pipe_index;
|
||||
else
|
||||
pipe_index = pipe->map->dest.pipe_index;
|
||||
|
||||
if (bam->props.irq > 0)
|
||||
synchronize_irq(bam->props.irq);
|
||||
|
||||
spin_lock_irqsave(&bam->isr_lock, flags);
|
||||
pipe->disconnecting = true;
|
||||
spin_unlock_irqrestore(&bam->isr_lock, flags);
|
||||
result = sps_bam_pipe_disconnect(pipe->bam, pipe_index);
|
||||
if (result) {
|
||||
SPS_ERR(pipe->bam,
|
||||
"sps:Failed to disconnect BAM %pa pipe %d\n",
|
||||
&pipe->bam->props.phys_addr,
|
||||
pipe->pipe_index);
|
||||
return SPS_ERROR;
|
||||
}
|
||||
|
||||
/* Clear map state */
|
||||
map = (void *)pipe->map;
|
||||
if (pipe->connect.mode == SPS_MODE_SRC)
|
||||
map->client_src = NULL;
|
||||
else if (pipe->connect.mode == SPS_MODE_DEST)
|
||||
map->client_dest = NULL;
|
||||
|
||||
sps_rm_disconnect(pipe);
|
||||
|
||||
/* Clear the client state */
|
||||
pipe->map = NULL;
|
||||
pipe->bam = NULL;
|
||||
pipe->client_state = SPS_STATE_DISCONNECT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
527
drivers/soc/qcom/sps/spsi.h
Normal file
527
drivers/soc/qcom/sps/spsi.h
Normal file
@ -0,0 +1,527 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2011-2021, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
/**
|
||||
* Smart-Peripheral-Switch (SPS) internal API.
|
||||
*/
|
||||
|
||||
#ifndef _SPSI_H_
|
||||
#define _SPSI_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/ratelimit.h>
|
||||
#include <linux/ipc_logging.h>
|
||||
|
||||
#include <linux/msm-sps.h>
|
||||
|
||||
#include "sps_map.h"
|
||||
|
||||
#if defined(CONFIG_PHYS_ADDR_T_64BIT) || defined(CONFIG_ARM_LPAE)
|
||||
#define SPS_LPAE (true)
|
||||
#else
|
||||
#define SPS_LPAE (false)
|
||||
#endif
|
||||
|
||||
#define BAM_MAX_PIPES 31
|
||||
#define BAM_MAX_P_LOCK_GROUP_NUM 31
|
||||
|
||||
/* Adjust for offset of struct sps_q_event */
|
||||
#define SPS_EVENT_INDEX(e) ((e) - 1)
|
||||
#define SPS_ERROR -1
|
||||
|
||||
/* BAM identifier used in log messages */
|
||||
#define BAM_ID(dev) (&(dev)->props.phys_addr)
|
||||
|
||||
/* "Clear" value for the connection parameter struct */
|
||||
#define SPSRM_CLEAR 0xccccccccUL
|
||||
#define SPSRM_ADDR_CLR \
|
||||
((sizeof(int) == sizeof(long)) ? 0 : (SPSRM_CLEAR << 32))
|
||||
|
||||
#define MAX_MSG_LEN 80
|
||||
#define SPS_IPC_LOGPAGES 10
|
||||
#define SPS_IPC_REG_DUMP_FACTOR 3
|
||||
#define SPS_IPC_DEFAULT_LOGLEVEL 3
|
||||
#define SPS_IPC_MAX_LOGLEVEL 4
|
||||
|
||||
/* Connection mapping control struct */
|
||||
struct sps_rm {
|
||||
struct list_head connections_q;
|
||||
struct mutex lock;
|
||||
};
|
||||
|
||||
/* SPS driver state struct */
|
||||
struct sps_drv {
|
||||
struct class *dev_class;
|
||||
dev_t dev_num;
|
||||
struct device *dev;
|
||||
struct clk *pmem_clk;
|
||||
struct clk *bamdma_clk;
|
||||
struct clk *dfab_clk;
|
||||
|
||||
int is_ready;
|
||||
|
||||
/* Platform data */
|
||||
phys_addr_t pipemem_phys_base;
|
||||
u32 pipemem_size;
|
||||
phys_addr_t bamdma_bam_phys_base;
|
||||
u32 bamdma_bam_size;
|
||||
phys_addr_t bamdma_dma_phys_base;
|
||||
u32 bamdma_dma_size;
|
||||
u32 bamdma_irq;
|
||||
u32 bamdma_restricted_pipes;
|
||||
|
||||
/* Driver options bitflags (see SPS_OPT_*) */
|
||||
u32 options;
|
||||
|
||||
/* Mutex to protect BAM and connection queues */
|
||||
struct mutex lock;
|
||||
|
||||
/* BAM devices */
|
||||
struct list_head bams_q;
|
||||
|
||||
char *hal_bam_version;
|
||||
|
||||
/* Connection control state */
|
||||
struct sps_rm connection_ctrl;
|
||||
|
||||
void *ipc_log0;
|
||||
void *ipc_log1;
|
||||
void *ipc_log2;
|
||||
void *ipc_log3;
|
||||
void *ipc_log4;
|
||||
|
||||
u32 ipc_loglevel;
|
||||
};
|
||||
|
||||
extern struct sps_drv *sps;
|
||||
extern u32 d_type;
|
||||
extern bool enhd_pipe;
|
||||
extern bool imem;
|
||||
extern enum sps_bam_type bam_type;
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
extern u8 debugfs_record_enabled;
|
||||
extern u8 logging_option;
|
||||
extern u8 debug_level_option;
|
||||
extern u8 print_limit_option;
|
||||
|
||||
#define SPS_IPC(idx, dev, msg, ...) do { \
|
||||
if (dev) { \
|
||||
if (idx == 0) \
|
||||
ipc_log_string((dev)->ipc_log0, \
|
||||
"%s: " msg, __func__, ##__VA_ARGS__); \
|
||||
else if (idx == 1) \
|
||||
ipc_log_string((dev)->ipc_log1, \
|
||||
"%s: " msg, __func__, ##__VA_ARGS__); \
|
||||
else if (idx == 2) \
|
||||
ipc_log_string((dev)->ipc_log2, \
|
||||
"%s: " msg, __func__, ##__VA_ARGS__); \
|
||||
else if (idx == 3) \
|
||||
ipc_log_string((dev)->ipc_log3, \
|
||||
"%s: " msg, __func__, ##__VA_ARGS__); \
|
||||
else if (idx == 4) \
|
||||
ipc_log_string((dev)->ipc_log4, \
|
||||
"%s: " msg, __func__, ##__VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
#define SPS_DUMP(msg, ...) do { \
|
||||
SPS_IPC(4, sps, msg, ##__VA_ARGS__); \
|
||||
if (sps) { \
|
||||
if (sps->ipc_log4 == NULL) \
|
||||
pr_info("%s: " msg, __func__, ##__VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
#define SPS_ERR(dev, msg, ...) do { \
|
||||
if (logging_option != 1) { \
|
||||
if (unlikely(print_limit_option > 2)) \
|
||||
pr_err_ratelimited( \
|
||||
"%s: " msg, __func__, ##__VA_ARGS__); \
|
||||
else \
|
||||
pr_err("%s: " msg, __func__, ##__VA_ARGS__); \
|
||||
} \
|
||||
SPS_IPC(3, dev, msg, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
#define SPS_INFO(dev, msg, ...) do { \
|
||||
if (logging_option != 1) { \
|
||||
if (unlikely(print_limit_option > 1)) \
|
||||
pr_info_ratelimited( \
|
||||
"%s: " msg, __func__, ##__VA_ARGS__); \
|
||||
else \
|
||||
pr_info("%s: " msg, __func__, ##__VA_ARGS__); \
|
||||
} \
|
||||
SPS_IPC(3, dev, msg, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
#define SPS_DBG(dev, msg, ...) do { \
|
||||
if ((unlikely(logging_option > 1)) \
|
||||
&& (unlikely(debug_level_option > 3))) {\
|
||||
if (unlikely(print_limit_option > 0)) \
|
||||
pr_info_ratelimited( \
|
||||
"%s: " msg, __func__, ##__VA_ARGS__); \
|
||||
else \
|
||||
pr_info("%s: " msg, __func__, ##__VA_ARGS__); \
|
||||
} else \
|
||||
pr_debug("%s: " msg, __func__, ##__VA_ARGS__); \
|
||||
if (dev) { \
|
||||
if ((dev)->ipc_loglevel <= 0) \
|
||||
SPS_IPC(0, dev, msg, ##__VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
#define SPS_DBG1(dev, msg, ...) do { \
|
||||
if ((unlikely(logging_option > 1)) \
|
||||
&& (unlikely(debug_level_option > 2))) {\
|
||||
if (unlikely(print_limit_option > 0)) \
|
||||
pr_info_ratelimited( \
|
||||
"%s: " msg, __func__, ##__VA_ARGS__); \
|
||||
else \
|
||||
pr_info("%s: " msg, __func__, ##__VA_ARGS__); \
|
||||
} else \
|
||||
pr_debug("%s: " msg, __func__, ##__VA_ARGS__); \
|
||||
if (dev) { \
|
||||
if ((dev)->ipc_loglevel <= 1) \
|
||||
SPS_IPC(1, dev, msg, ##__VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
#define SPS_DBG2(dev, msg, ...) do { \
|
||||
if ((unlikely(logging_option > 1)) \
|
||||
&& (unlikely(debug_level_option > 1))) {\
|
||||
if (unlikely(print_limit_option > 0)) \
|
||||
pr_info_ratelimited( \
|
||||
"%s: " msg, __func__, ##__VA_ARGS__); \
|
||||
else \
|
||||
pr_info("%s: " msg, __func__, ##__VA_ARGS__); \
|
||||
} else \
|
||||
pr_debug("%s: " msg, __func__, ##__VA_ARGS__); \
|
||||
if (dev) { \
|
||||
if ((dev)->ipc_loglevel <= 2) \
|
||||
SPS_IPC(2, dev, msg, ##__VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
#define SPS_DBG3(dev, msg, ...) do { \
|
||||
if ((unlikely(logging_option > 1)) \
|
||||
&& (unlikely(debug_level_option > 0))) {\
|
||||
if (unlikely(print_limit_option > 0)) \
|
||||
pr_info_ratelimited( \
|
||||
"%s: " msg, __func__, ##__VA_ARGS__); \
|
||||
else \
|
||||
pr_info("%s: " msg, __func__, ##__VA_ARGS__); \
|
||||
} else \
|
||||
pr_debug("%s: " msg, __func__, ##__VA_ARGS__); \
|
||||
if (dev) { \
|
||||
if ((dev)->ipc_loglevel <= 3) \
|
||||
SPS_IPC(3, dev, msg, ##__VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
#else
|
||||
#define SPS_DBG3(dev, msg, args...) pr_debug(msg, ##args)
|
||||
#define SPS_DBG2(dev, msg, args...) pr_debug(msg, ##args)
|
||||
#define SPS_DBG1(dev, msg, args...) pr_debug(msg, ##args)
|
||||
#define SPS_DBG(dev, msg, args...) pr_debug(msg, ##args)
|
||||
#define SPS_INFO(dev, msg, args...) pr_info(msg, ##args)
|
||||
#define SPS_ERR(dev, msg, args...) pr_err(msg, ##args)
|
||||
#define SPS_DUMP(msg, args...) pr_info(msg, ##args)
|
||||
#endif
|
||||
|
||||
/* End point parameters */
|
||||
struct sps_conn_end_pt {
|
||||
unsigned long dev; /* Device handle of BAM */
|
||||
phys_addr_t bam_phys; /* Physical address of BAM. */
|
||||
u32 pipe_index; /* Pipe index */
|
||||
u32 event_threshold; /* Pipe event threshold */
|
||||
u32 lock_group; /* The lock group this pipe belongs to */
|
||||
void *bam;
|
||||
};
|
||||
|
||||
/* Connection bookkeeping descriptor struct */
|
||||
struct sps_connection {
|
||||
struct list_head list;
|
||||
|
||||
/* Source end point parameters */
|
||||
struct sps_conn_end_pt src;
|
||||
|
||||
/* Destination end point parameters */
|
||||
struct sps_conn_end_pt dest;
|
||||
|
||||
/* Resource parameters */
|
||||
struct sps_mem_buffer desc; /* Descriptor FIFO */
|
||||
struct sps_mem_buffer data; /* Data FIFO (BAM-to-BAM mode only) */
|
||||
u32 config; /* Client specified connection configuration */
|
||||
|
||||
/* Connection state */
|
||||
void *client_src;
|
||||
void *client_dest;
|
||||
int refs; /* Reference counter */
|
||||
|
||||
/* Dynamically allocated resources, if required */
|
||||
u32 alloc_src_pipe; /* Source pipe index */
|
||||
u32 alloc_dest_pipe; /* Destination pipe index */
|
||||
/* Physical address of descriptor FIFO */
|
||||
phys_addr_t alloc_desc_base;
|
||||
phys_addr_t alloc_data_base; /* Physical address of data FIFO */
|
||||
};
|
||||
|
||||
/* Event bookkeeping descriptor struct */
|
||||
struct sps_q_event {
|
||||
struct list_head list;
|
||||
/* Event payload data */
|
||||
struct sps_event_notify notify;
|
||||
};
|
||||
|
||||
/* Memory heap statistics */
|
||||
struct sps_mem_stats {
|
||||
u32 base_addr;
|
||||
u32 size;
|
||||
u32 blocks_used;
|
||||
u32 bytes_used;
|
||||
u32 max_bytes_used;
|
||||
};
|
||||
|
||||
enum sps_bam_type {
|
||||
SPS_BAM_LEGACY,
|
||||
SPS_BAM_NDP,
|
||||
SPS_BAM_NDP_4K
|
||||
};
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
/* record debug info for debugfs */
|
||||
void sps_debugfs_record(const char *msg);
|
||||
#endif
|
||||
|
||||
/* output the content of BAM-level registers */
|
||||
void print_bam_reg(void *virt_addr);
|
||||
|
||||
/* output the content of BAM pipe registers */
|
||||
void print_bam_pipe_reg(void *virt_addr, u32 pipe_index);
|
||||
|
||||
/* output the content of selected BAM-level registers */
|
||||
void print_bam_selected_reg(void *virt_addr, u32 pipe_index);
|
||||
|
||||
/* output the content of selected BAM pipe registers */
|
||||
void print_bam_pipe_selected_reg(void *virt_addr, u32 pipe_index);
|
||||
|
||||
/* output descriptor FIFO of a pipe */
|
||||
void print_bam_pipe_desc_fifo(void *virt_addr, u32 pipe_index, u32 option);
|
||||
|
||||
/* output BAM_TEST_BUS_REG */
|
||||
void print_bam_test_bus_reg(void *base, u32 tb_sel);
|
||||
|
||||
/* halt and un-halt a pipe */
|
||||
void bam_pipe_halt(void *base, u32 pipe, bool halt);
|
||||
|
||||
/**
|
||||
* Translate physical to virtual address
|
||||
*
|
||||
* This Function translates physical to virtual address.
|
||||
*
|
||||
* @phys_addr - physical address to translate
|
||||
*
|
||||
* @return virtual memory pointer
|
||||
*
|
||||
*/
|
||||
void *spsi_get_mem_ptr(phys_addr_t phys_addr);
|
||||
|
||||
/**
|
||||
* Allocate I/O (pipe) memory
|
||||
*
|
||||
* This function allocates target I/O (pipe) memory.
|
||||
*
|
||||
* @bytes - number of bytes to allocate
|
||||
*
|
||||
* @return physical address of allocated memory, or SPS_ADDR_INVALID on error
|
||||
*/
|
||||
phys_addr_t sps_mem_alloc_io(u32 bytes);
|
||||
|
||||
/**
|
||||
* Free I/O (pipe) memory
|
||||
*
|
||||
* This function frees target I/O (pipe) memory.
|
||||
*
|
||||
* @phys_addr - physical address of memory to free
|
||||
*
|
||||
* @bytes - number of bytes to free.
|
||||
*/
|
||||
void sps_mem_free_io(phys_addr_t phys_addr, u32 bytes);
|
||||
|
||||
/**
|
||||
* Find matching connection mapping
|
||||
*
|
||||
* This function searches for a connection mapping that matches the
|
||||
* parameters supplied by the client. If a match is found, the client's
|
||||
* parameter struct is updated with the values specified in the mapping.
|
||||
*
|
||||
* @connect - pointer to client connection parameters
|
||||
*
|
||||
* @return 0 if match is found, negative value otherwise
|
||||
*
|
||||
*/
|
||||
int sps_map_find(struct sps_connect *connect);
|
||||
|
||||
/**
|
||||
* Allocate a BAM DMA pipe
|
||||
*
|
||||
* This function allocates a BAM DMA pipe, and is intended to be called
|
||||
* internally from the BAM resource manager. Allocation implies that
|
||||
* the pipe has been referenced by a client Connect() and is in use.
|
||||
*
|
||||
* BAM DMA is permissive with activations, and allows a pipe to be allocated
|
||||
* with or without a client-initiated allocation. This allows the client to
|
||||
* specify exactly which pipe should be used directly through the Connect() API.
|
||||
* sps_dma_alloc_chan() does not allow the client to specify the pipes/channel.
|
||||
*
|
||||
* @bam - pointer to BAM device descriptor
|
||||
*
|
||||
* @pipe_index - pipe index
|
||||
*
|
||||
* @dir - pipe direction
|
||||
*
|
||||
* @return 0 on success, negative value on error
|
||||
*/
|
||||
int sps_dma_pipe_alloc(void *bam, u32 pipe_index, enum sps_mode dir);
|
||||
|
||||
/**
|
||||
* Enable a BAM DMA pipe
|
||||
*
|
||||
* This function enables the channel associated with a BAM DMA pipe, and
|
||||
* is intended to be called internally from the BAM resource manager.
|
||||
* Enable must occur *after* the pipe has been enabled so that proper
|
||||
* sequencing between pipe and DMA channel enables can be enforced.
|
||||
*
|
||||
* @bam - pointer to BAM device descriptor
|
||||
*
|
||||
* @pipe_index - pipe index
|
||||
*
|
||||
* @return 0 on success, negative value on error
|
||||
*
|
||||
*/
|
||||
int sps_dma_pipe_enable(void *bam, u32 pipe_index);
|
||||
|
||||
/**
|
||||
* Free a BAM DMA pipe
|
||||
*
|
||||
* This function disables and frees a BAM DMA pipe, and is intended to be
|
||||
* called internally from the BAM resource manager. This must occur *after*
|
||||
* the pipe has been disabled/reset so that proper sequencing between pipe and
|
||||
* DMA channel resets can be enforced.
|
||||
*
|
||||
* @bam_arg - pointer to BAM device descriptor
|
||||
*
|
||||
* @pipe_index - pipe index
|
||||
*
|
||||
* @return 0 on success, negative value on error
|
||||
*
|
||||
*/
|
||||
int sps_dma_pipe_free(void *bam, u32 pipe_index);
|
||||
|
||||
/**
|
||||
* Initialize driver memory module
|
||||
*
|
||||
* This function initializes the driver memory module.
|
||||
*
|
||||
* @pipemem_phys_base - Pipe-Memory physical base.
|
||||
*
|
||||
* @pipemem_size - Pipe-Memory size.
|
||||
*
|
||||
* @return 0 on success, negative value on error
|
||||
*
|
||||
*/
|
||||
int sps_mem_init(phys_addr_t pipemem_phys_base, u32 pipemem_size);
|
||||
|
||||
/**
|
||||
* De-initialize driver memory module
|
||||
*
|
||||
* This function de-initializes the driver memory module.
|
||||
*
|
||||
* @return 0 on success, negative value on error
|
||||
*
|
||||
*/
|
||||
int sps_mem_de_init(void);
|
||||
|
||||
/**
|
||||
* Initialize BAM DMA module
|
||||
*
|
||||
* This function initializes the BAM DMA module.
|
||||
*
|
||||
* @bam_props - pointer to BAM DMA devices BSP configuration properties
|
||||
*
|
||||
* @return 0 on success, negative value on error
|
||||
*
|
||||
*/
|
||||
int sps_dma_init(const struct sps_bam_props *bam_props);
|
||||
|
||||
/**
|
||||
* De-initialize BAM DMA module
|
||||
*
|
||||
* This function de-initializes the SPS BAM DMA module.
|
||||
*
|
||||
*/
|
||||
void sps_dma_de_init(void);
|
||||
|
||||
/**
|
||||
* Initialize BAM DMA device
|
||||
*
|
||||
* This function initializes a BAM DMA device.
|
||||
*
|
||||
* @h - BAM handle
|
||||
*
|
||||
* @return 0 on success, negative value on error
|
||||
*
|
||||
*/
|
||||
int sps_dma_device_init(unsigned long h);
|
||||
|
||||
/**
|
||||
* De-initialize BAM DMA device
|
||||
*
|
||||
* This function de-initializes a BAM DMA device.
|
||||
*
|
||||
* @h - BAM handle
|
||||
*
|
||||
* @return 0 on success, negative value on error
|
||||
*
|
||||
*/
|
||||
int sps_dma_device_de_init(unsigned long h);
|
||||
|
||||
/**
|
||||
* Initialize connection mapping module
|
||||
*
|
||||
* This function initializes the SPS connection mapping module.
|
||||
*
|
||||
* @map_props - pointer to connection mapping BSP configuration properties
|
||||
*
|
||||
* @options - driver options bitflags (see SPS_OPT_*)
|
||||
*
|
||||
* @return 0 on success, negative value on error
|
||||
*
|
||||
*/
|
||||
|
||||
int sps_map_init(const struct sps_map *map_props, u32 options);
|
||||
|
||||
/**
|
||||
* De-initialize connection mapping module
|
||||
*
|
||||
* This function de-initializes the SPS connection mapping module.
|
||||
*
|
||||
*/
|
||||
void sps_map_de_init(void);
|
||||
|
||||
/*
|
||||
* bam_pipe_reset - reset a BAM pipe.
|
||||
* @base: BAM virtual address
|
||||
* @pipe: pipe index
|
||||
*
|
||||
* This function resets a BAM pipe.
|
||||
*/
|
||||
void bam_pipe_reset(void *base, u32 pipe);
|
||||
|
||||
/*
|
||||
* bam_disable_pipe - disable a BAM pipe.
|
||||
* @base: BAM virtual address
|
||||
* @pipe: pipe index
|
||||
*
|
||||
* This function disables a BAM pipe.
|
||||
*/
|
||||
void bam_disable_pipe(void *base, u32 pipe);
|
||||
#endif /* _SPSI_H_ */
|
1635
include/linux/msm-sps.h
Normal file
1635
include/linux/msm-sps.h
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user