DivestOS/Patches/Linux_CVEs/CVE-2015-0573/ANY/0001.patch
2017-11-07 17:32:46 -05:00

12988 lines
385 KiB
Diff
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

From e20f20aaed6b6d2fd1667bad9be9ef35103a51df Mon Sep 17 00:00:00 2001
From: Liron Kuch <lkuch@codeaurora.org>
Date: Sun, 6 Sep 2015 11:19:39 +0300
Subject: msm: broadcast: Remove unused TSC and TSPP2 drivers
TSC and TSPP2 were HW blocks in MPQ8092 target which is
no longer supported. Remove TSC and TSPP2 drivers to
eliminate unused code.
Change-Id: Ibb55ae0d15b33ba5855bde69e78925d23def3c6b
Signed-off-by: Liron Kuch <lkuch@codeaurora.org>
---
Documentation/arm/msm/tsc.txt | 398 --
Documentation/arm/msm/tspp2.txt | 497 --
drivers/media/platform/msm/broadcast/Makefile | 2 -
drivers/media/platform/msm/broadcast/tsc.c | 3450 ----------
drivers/media/platform/msm/broadcast/tspp2.c | 8578 -------------------------
5 files changed, 12925 deletions(-)
delete mode 100644 Documentation/arm/msm/tsc.txt
delete mode 100644 Documentation/arm/msm/tspp2.txt
delete mode 100644 drivers/media/platform/msm/broadcast/tsc.c
delete mode 100644 drivers/media/platform/msm/broadcast/tspp2.c
diff --git a/Documentation/arm/msm/tsc.txt b/Documentation/arm/msm/tsc.txt
deleted file mode 100644
index 11e74a2..0000000
--- a/Documentation/arm/msm/tsc.txt
+++ /dev/null
@@ -1,398 +0,0 @@
-Introduction
-============
-
-TSC Driver
-
-The TSC (Transport Stream Controller) is a hardware block used in products such
-as smart TVs, Set-top boxes and digital media adapters, and is responsible for
-two main functionalities:
-
-1. Mux function: enabling the routing of MPEG-2 transport streams (TS) received
-from terrestrial/cable/satelite in order to support the different topologies of
-the end product, as it may be deployed in many different topologies.
-In addition, the active topology may change according to various factors such as
-broadcast technology and/or conditional access system.
-
-2. CI function: acting as a common interface, complying with both PC Card and
-CI/+ specifications.
-
-The TSC driver has two different interfaces, one for each function.
-
-Hardware description
-====================
-The TSC HW contains the TSC core, and uses the VBIF unit (IOMMU) which is part
-of the broadcast subsystem HW.
-
-Mux function:
--------------
-The TSC can receive transport streams from:
-a. Two Transport Stream Interfaces (TSIFs) 0 or 1, connected to two external
-demods or to external bridge.
-b. One TSIF from an integrated demod.
-
-The TSC can route TS from any of the above TSIFs to an external CICAM, using a
-software configurable mux.
-The TSC can route TS from any of the above TSIFs, and TS received from the CI
-Conditional Access Mudule (CICAM) to two TSIF outputs (0 or 1), using two
-software configurable muexes.
-The CICAM input and outputs are also managed via two additional TSIFs: TSIF-out
-to the CAM, and TSIF-in from the CAM.
-
-CI function:
-------------
-The common interface is composed of:
-1. Card detection logic: the TSC notifies the SW of any change in the card
-detection status (via HW interrupt).
-
-2. Control interface used to send/receive the CI messages (APDUs), supporting
-data transmission in two formats:
-a. Single byte transactions: to/from the attribute memory space of the CAM and
- the command area of the CAM.
-b. Buffer transactions: to/from the command area of the CAM, using a
- configurable buffer size of 1k bytes-64k bytes. This enables transferring
- large chunks of data between the CAM and applications.
- The data buffer resides in the external memory and the interface to the
- memory is done through BCSS VBIF.
-The TSC uses PCMCIA interface to interact with the CAM.
-
-The following diagram provides an overview of the TSC HW:
-+-------------------------------------------------------------------------+
-| |
-| +------------------------------+ |
-| +-----------+ | TSC Core --. | |
-| |Ext. TSIF 0+------------+------------>| \ | +-----------+ |
-| +-----------+ | +-----|------------>|Mux)----->TSPP TSIF 0| |
-| +-----------+ | | +--|------------>| / | +-----------+ |
-| |Ext. TSIF 1+------| | | +->--' | |
-| +-----------+ | | | | | --. | |
-| | | | +----------|->| \ | +-----------+ |
-| +-----------+ | +--|--|-+--------|->|Mux)----->TSPP TSIF 1| |
-| |Int. TSIF +---------+--|-|-+------|->| / | +-----------+ |
-| +-----------+ | | | | +->--' | |
-| | | | | | | |
-| | | | | | | |
-| |+------+(v-v-v--) | +-----+| |
-| ||Card | \ Mux / | |CI/+ +---Data-Interface--+ |
-| ||detect| `---' | +----++| | |
-| |+-^-^--+ | | | | | |
-| +--|-|-------|-------|-------|-+ +------+----+ |
-| | | | | | | VBIF | |
-| | | +-----v--+ +--+----+ | | | |
-| | | |TSIF-Out| |TSIF-In| | +-----------+ |
-| | | +-----+--+ +--^----+ | |
-| | | | | | |
-| ++-+-------v-------+-------++ |
-| | CICAM | |
-| | | |
-| +---------------------------+ |
-+-------------------------------------------------------------------------+
-
-Software description
-====================
-The TSC Linux kernel driver manages the TSC core. It is a standard Linux
-platform device driver. It can be configured as a loadable or built-in kernel
-module. The driver is supported only in platforms that contain the TSC HW.
-
-The TSC driver uses ION driver to control the IOMMU and map user-allocated
-buffers to the TSC IOMMU domain.
-
-The driver provides an abstraction of the TSC HW functionality for user-space
-clients via two separate interfaces: tsc_mux and tsc_ci. These interfaces may
-be used by upper layers to utilize the TSC HW for routing the TS and supporting
-the Common Interface specification.
-
-Driver initialization
----------------------
-The driver's probe function is invoked if there is a matching device tree node.
-The probe function gets the required memory resources (i.e., register address
-spaces) and maps them to kernel space for the driver's use.
-The probe function also requests the required IRQs, GPIOs and clocks, and gets
-the TSC IOMMU domain. The probe function also disables the TSIFs input.
-Finally, the function creates two character device drivers: "tsc_mux","tsc_ci".
-
-See API description in interface section.
-
-Data paths
------------
-The TSC does not process the TS data received from the TSIFs. It just manages
-the routing of that data.
-
-Control paths - Mux function
-----------------------------
-Example for routing the TS from external demod TSIF 0 to the CAM, and from the
-CAM to TSIF 1 of the TSPP:
-
-struct tsc_route tsif_cam = {TSC_SOURCE_EXTERNAL0, TSC_DEST_CICAM};
-struct tsc_route cam_tspp = {TSC_SOURCE_CICAM, TSC_DEST_TSPP1};
-int mux_fd, ret;
-enum tsc_source tsif0 = TSC_SOURCE_EXTERNAL0;
-enum tsc_source cam = TSC_SOURCE_CICAM;
-
-/* opening Mux char device */
-mux_fd = open("/dev/tsc_mux0");
-
-/* Configure the CAM mux to route TS from external demod TSIF 0: */
-ret = ioctl(mux_fd, TSC_CONFIG_ROUTE, &tsif_cam);
-
-/* Configure the TSPP TSIF 1 mux to route TS from CAM: */
-ret = ioctl(mux_fd, TSC_CONFIG_ROUTE, &cam_tspp);
-
-/* Enabling the external demod TSIF 0, and the CAM TSIF-in and TSIF-out */
-ret = ioctl(mux_fd, TSC_ENABLE_INPUT, &tsif0);
-ret = ioctl(mux_fd, TSC_ENABLE_INPUT, &cam);
-
-close(mux_fd);
-
-Control paths - CI function
----------------------------
-Example for writing a buffer to the CAM command area:
-
-Assumptions:
-1. The user allocated a buffer using ION driver and wrote to that buffer.
-Also, retrieved the ion fd of that buffer and saved it to:
-int buffer_fd;
-2. The user already performed buffer size negotiation with the CAM according to
-CI/+ specification, and had set the CAM size register with the buffer size. This
-size is saved to: int size;
-3. The user decided about the time the user wants to wait for the data
-transmission.
-struct tsc_buffer_mode buff_params = {buffer_fd, size, timeout};
-int ret;
-
-/* Perform a blocking write buffer transaction for at most timeout */
-ret = ioctl(fd, TSC_WRITE_CAM_BUFFER, &buff_params);
-/* ret indicate whether the transaction succeeded */
-
-Example for SW reset to the CAM (according to CI/+ specification):
-struct single_byte_mode cmd_params = {1, RS bit set, timeout};
-struct single_byte_mode stat_params = {1, not initialize, timeout};
-int ci_fd, ret;
-u8 data;
-
-/* opening CI char device */
-ci_fd = open("/dev/tsc_ci0");
-
-/* Setting the RS bit of the CAM command register */
-ret = ioctl(ci_fd, TSC_WRITE_CAM_IO, &cmd_params);
-
-/* Polling the FR bit of the CAM status register */
-ret = ioctl(ci_fd, TSC_READ_CAM_IO, &stat_params);
-data = stat_params.data;
-while (data & FR_BIT_MASK) {
- ret = ioctl(ci_fd, TSC_READ_CAM_IO, &stat_params);
- data = stat_params.data;
-}
-
-close(ci_fd);
-
-Design
-======
-The TSC driver is a regular Linux platform driver designed to support the
-TSC HW available on specific SoCs.
-
-The driver provides two user-space APIs: tsc_mux that allows the client full
-control over the configuration of the TS routing, and tsc_ci that enables the
-client to implement the Common Interface in front of the CAM. It does so while
-encapsulating HW implementation details that are not relevant to the clients.
-
-The driver enforces HW restrictions and checks for input parameters
-validity, providing a success or failure return value for each API function:
-0 upon success or negative value on failure. Errno parameter is set to indicate
-the failure reason.
-However, the driver does not enforce any high-level policy with regard to the
-correct use of the TSC HW for various use-cases.
-
-Power Management
-================
-The TSC driver prevents the CPU from sleeping while the HW is active by using
-wakeup_source API. When there are no open devices the driver releases the wakeup
-source. In a similar manner, the driver enables the HW clocks only when needed.
-
-SMP/multi-core
-==============
-The driver uses a spinlock to protect accesses to its internal databases,
-for synchronization between user control API and kernel interrupt handlers.
-
-The driver uses a mutex for all the Mux operations to synchronize access to the
-routing internal databases. The driver uses another mutex for all the CI
-operations to synchronize data sent and received to and from the CAM.
-
-Security
-========
-Although the TSC is the bridge the external conditional access module, it has no
-security aspects. Any protection which is needed is performed by the upper
-layers. For example, the messages which are written to the CAM are encrypted.
-Thus the TSC accesses only non-protected, HLOS accessible memory regions.
-
-Performance
-===========
-Control operations are not considered as performance critical.
-Most of the control operations are assumed to be fairly uncommon.
-
-Interface
-=========
-Kernel-space API
-----------------
-The TSC driver does not provide any kernel-space API, only a user-space API.
-
-User-space API
-----------------
-Open: upper layer can open tsc_mux device and/or tsc_ci device.
-Release: close the device and release all the allocated resources.
-Poll: two different functions- one for Mux, one for CI. The Mux poll wait for
-rate mismatch interrupt. The CI poll waits for card detection HW interrupt.
-The rate mismatch interrupt is not cleared in the interrupt handler because it
-will signal again all the time. Therefore it is cleared via a specific ioctl
-that upper layer can use after the problem is solved. Additionally, the
-interrupt is cleared when the card is removed.
-ioctl: two functions, one for mux and one for ci. The ioctl are specified below.
-
-TSC Mux - routing the TS:
--------------------------
-enum tsc_source {
- TSC_SOURCE_EXTERNAL0,
- TSC_SOURCE_EXTERNAL1,
- TSC_SOURCE_INTERNAL,
- TSC_SOURCE_CICAM
-};
-enum tsc_dest {
- TSC_DEST_TSPP0,
- TSC_DEST_TSPP1,
- TSC_DSET_CICAM
-};
-
-struct tsc_route {
- enum tsc_source source;
- enum tsc_dest dest;
-};
-
-#define TSC_CONFIG_ROUTE _IOW(TSC_IOCTL_BASE, 0, struct tsc_tspp_route)
-#define TSC_ENABLE_INPUT _IOW(TSC_IOCTL_BASE, 1, enum tsc_source)
-#define TSC_DISABLE_INPUT _IOW(TSC_IOCTL_BASE, 2, enum tsc_source)
-
-These 3 IOCTLs control the 3 muxes that route the TS, and enable/disable the
-TSIFs input.
-
-TSC Mux - configuring the TSIFs:
---------------------------------
-enum tsc_data_type {
- TSC_DATA_TYPE_SERIAL,
- TSC_DATA_TYPE_PARALLEL
-};
-enum tsc_receive_mode {
- TSC_RECEIVE_MODE_START_VALID,
- TSC_RECEIVE_MODE_START_ONLY,
- TSC_RECEIVE_MODE_VALID_ONLY
-};
-
-struct tsc_tsif_params {
- enum tsc_source source;
- enum tsc_receive_mode receive_mode;
- enum tsc_data_type data_type;
- int clock_polarity;
- int data_polarity;
- int start_polarity;
- int valid_polarity;
- int error_polarity;
- int data_swap;
- int set_error;
-};
-
-#define TSC_SET_TSIF_CONFIG _IOW(TSC_IOCTL_BASE, 3, struct tsc_tsif_params)
-
-This IOCTL enables configuring a specific TSIF with all possible configurations.
-
-TSC Mux - clearing rate mismatch interrupt
-------------------------------------------
-
-#define TSC_CLEAR_RATE_MISMATCH_IRQ _IO(TSC_IOCTL_BASE, 4)
-
-This IOCTL is used for clearing the interrupt, which is not done automatically
-by the driver.
-
-TSC CI - CAM configuration:
----------------------------
-enum tsc_cam_personality {
- TSC_CICAM_PERSONALITY_CI,
- TSC_CICAM_PERSONALITY_CIPLUS,
- TSC_CICAM_PERSONALITY_PCCARD,
- TSC_CICAM_PERSONALITY_DISABLE
-};
-enum tsc_card_status {
- TSC_CARD_STATUS_NOT_DETECTED,
- TSC_CARD_STATUS_DETECTED,
- TSC_CARD_STATUS_FAILURE
-};
-
-#define TSC_CICAM_SET_CLOCK _IOW(TSC_IOCTL_BASE, 5, int)
-This IOCTL sets the clock rate of the TS from the TSC to the CAM
-
-#define TSC_CAM_RESET _IO(TSC_IOCTL_BASE, 6)
-This IOCTL performs HW reset to the CAM
-
-#define TSC_CICAM_PERSONALITY_CHANGE \
- _IOW(TSC_IOCTL_BASE, 7, enum tsc_cam_personality)
-This IOCTL configures the PCMCIA pins according to the specified card type.
-
-#define TSC_GET_CARD_STATUS _IOR(TSC_IOCTL_BASE, 8, enum tsc_card_status)
-This IOCTL queries the card detection pins and returns their status.
-
-TSC CI - Data transactions:
----------------------------
-struct tsc_single_byte_mode {
- u16 address;
- u8 data;
- int timeout; /* in msec */
-};
-struct tsc_buffer_mode {
- int buffer_fd;
- u16 buffer_size;
- int timeout; /* in msec */
-};
-
-#define TSC_READ_CAM_MEMORY \
- _IOWR(TSC_IOCTL_BASE, 9, struct tsc_single_byte_mode)
-#define TSC_WRITE_CAM_MEMORY \
- _IOW(TSC_IOCTL_BASE, 10, struct tsc_single_byte_mode)
-#define TSC_READ_CAM_IO \
- _IOWR(TSC_IOCTL_BASE, 11, struct tsc_single_byte_mode)
-#define TSC_WRITE_CAM_IO \
- _IOW(TSC_IOCTL_BASE, 12, struct tsc_single_byte_mode)
-#define TSC_READ_CAM_BUFFER \
- _IOWR(TSC_IOCTL_BASE, 13, struct tsc_buffer_mode)
-#define TSC_WRITE_CAM_BUFFER \
- _IOW(TSC_IOCTL_BASE, 14, struct tsc_buffer_mode)
-
-These IOCTLs performs a read/write data transaction of the requested type.
-
-Driver parameters
-=================
-The TSC module receives one parameter:
-tsc_iommu_bypass - 0 for using the VBIF, 1 for not using it. Not using the VBIF
-is a debug configuration.
-
-Config options
-==============
-To enable the driver, set CONFIG_TSC to y (built-in) or m (kernel module)
-in the kernel configuration menu.
-
-Dependencies
-============
-The TSC driver uses the ION driver for IOMMU registration and buffer
-mapping to BCSS VBIF.
-
-User space utilities
-====================
-None.
-
-Other
-=====
-None.
-
-Known issues
-============
-None.
-
-To do
-=====
-None.
diff --git a/Documentation/arm/msm/tspp2.txt b/Documentation/arm/msm/tspp2.txt
deleted file mode 100644
index 006c688..0000000
--- a/Documentation/arm/msm/tspp2.txt
+++ /dev/null
@@ -1,497 +0,0 @@
-Introduction
-============
-
-TSPP2 Driver
-
-The TSPP2 (Transport Stream Packet Processor v2) is a hardware accelerator
-designed to process MPEG-2 Transport Stream (TS) data. It can be used to
-process broadcast TV services. The TSPP2 HW processes the TS packets, offloads
-the host CPU and supports the real-time processing requirements of such
-services.
-
-TS data can be received either from TSIF (Transport Stream Interface) input
-or from memory input, to support playing live broadcasts as well as
-playback from memory. Recording is also supported.
-
-TSPP2 is a significantly different HW unit than the TSPP unit described in
-Documentation/arm/msm/tspp.txt. The functionality is enhanced and the HW
-design is different.
-
-Hardware description
-====================
-The TSPP2 HW contains the TSPP2 core, a BAM (Bus Access Manager, used for DMA
-operations) unit, and a VBIF unit (IOMMU).
-
-The TSPP2 HW supports:
-a. Up to two TSIF inputs and up to eight memory inputs.
-b. Various TS packet sizes (188/192 bytes) and formats (timestamp location).
-c. PID filtering.
-d. Raw transmit operation for section filtering or recording.
-e. Full PES and separated PES transmit operation for audio and video playback.
-f. Decryption and re-encryption operations for secure transport streams.
-g. PCR extraction.
-h. Indexing - identifying patterns in video streams.
-
-The following diagram provides an overview of the TSPP2 HW:
-+------------------------------------------------------------------+
-| |
-| +-------------+ +--------------------+ |
-| | TSIF 0 +---> TSPP2 Core | |
-| +-------------+ | | |
-| | +---------------+ | |
-| +-------------+ | | | | |
-| | TSIF 1 +---> | Source 0 | | |
-| +-------------+ | | | | |
-| | | | | |
-| | | | | |
-| | | +------------+| | +--------------+ |
-| | | | Filter 0 +|---------> BAM pipe 3 | |
-| | | +------------+| | +--------------+ |
-| | | +------------+| | +--------------+ |
-| +-------------+ | | | Filter 1 +|---------> BAM pipe 4 | |
-| | BAM pipe 0 +---> | +------------+| | +--------------+ |
-| +-------------+ | | | | | |
-| +-------------+ | +---------------+ | +--------------+ |
-| | BAM pipe 1 +--->--------------------|----| | |
-| +-------------+ | | | VBIF | |
-| +-------------+ | | | IOMMU | |
-| | BAM pipe 2 +--->--------------------|----| | |
-| +-------------+ +--------------------+ +--------------+ |
-+------------------------------------------------------------------+
-
-A source is configured to have either a TSIF input (TSIF 0 or 1) or a
-memory input (a BAM pipe). One or more filters are attached to the source.
-Each filter has a 13-bit PID and mask values to perform the PID filtering.
-Additionally, one or more operations are added to each filter to achieve the
-required functionality. Each operation has specific parameters. The operation's
-output is usually placed in an output pipe.
-
-The TSPP HW uses its own virtual address space, mapping memory buffer addresses
-using the VBIF IOMMU.
-
-Software description
-====================
-The TSPP2 Linux kernel driver manages the TSPP2 core. The TSPP2 driver utilizes
-the SPS driver to configure and manage the BAM unit, which is used to perform
-DMA operations and move TS data to/from system memory.
-
-The TSPP2 driver uses the ION driver to control the IOMMU and map user-allocated
-buffers to the TSPP2 IOMMU domain.
-
-The TSPP2 is a standard Linux platform device driver. It can be configured as a
-loadable or built-in kernel module. The driver is supported only in platforms
-that contain the TSPP2 HW.
-
-The driver provides an abstraction of the TSPP2 HW functionality for
-kernel-space clients. For example, the dvb/demux kernel driver, which provides
-an API for upper layers to perform TS de-multiplexing (including PID filtering,
-recording, indexing etc.), uses the TSPP2 driver to utilize the TSPP2 HW and
-offload the CPU, instead of doing all the required processing in SW.
-
-For further information please refer to Documentation/dvb/qcom-mpq.txt.
-
-Terminology
------------
-This section describes some of the software "objects" implemented by the driver.
-
-a. TSPP2 device: an instance of the TSPP2 device representing the TSPP2 HW and
-its capabilities. The client identifies a device instance according to a
-device ID.
-
-b. Indexing table: A TSPP2 device contains 4 indexing tables. These tables are
-used to identify patterns in the video stream and report on them.
-The client identifies an indexing table according to a table ID.
-
-c. Pipe: a BAM pipe used for DMA operations. The TSPP2 HW has a BAM unit with
-31 pipes. A pipe contains a memory buffer and a corresponding descriptor ring,
-and is used as the output for TSPP2 data (e.g. PES payload, PES headers,
-indexing information etc.). For memory inputs, a pipe is used as the input
-buffer where data can be written to for TSPP2 processing. BAM Pipes are
-managed by the TSPP2 driver using the SPS driver which controls BAM HW. The
-client is responsible for buffer memory allocation, and can control many
-BAM-related pipe parameters.
-
-d. Source: a source object represents data "stream" from the TS input,
-through the filters and operations that perform the processing on the TS data,
-until the output. A source has the following properties:
- - Either a TSIF or a memory input.
- - For memory input: an input pipe.
- - Source-related configuration (e.g., packet size and format).
- - One or more PID filters. Each filter contains operations.
- - One or more output pipes.
-The client is responsible to configure the source object as needed using the
-appropriate API. The client identifies a source using a source handle, which
-the driver provides when opening a source for use.
-
-e. Filter: a filter object represents a PID filter which is used to get only the
-TS packets with specific PIDs and filter out all other TS packets in the stream.
-The client adds filters to the source object to define the processing of data.
-Each filter has a 13-bit PID value and bit-mask, so a filter can be used to
-get TS packets with various PID values. Note, however, that it is highly
-recommended to use each filter with a unique PID (i.e., 0x1FFF mask), and it is
-mandatory that the PIDs handled by each source's filters are mutually exclusive
-(i.e., the client must not configure two filters in the same source that handle
-the same PID values). A filter has up to 16 operations that instruct the TSPP2
-HW how to process the data. The client identifies a filter using a filter
-handle, which the driver provides when opening a filter for use.
-
-f. Operation: an operation object represents a basic building block describing
-how data is processed. Operations are added to a filter and are performed on
-the data received by this filter, in the order they were added. One or more
-operations may be required to achieve the desired functionality. For example,
-a "section filtering" functionality requires a raw transmit operation, while a
-"recording" functionality requires a raw transmit operations as well as an
-indexing operation (to support trick modes).
-
-Driver initialization
----------------------
-The driver's probe function is invoked if there is a matching device tree node
-(or platform device). The probe function gets the required memory resources
-(i.e., register address spaces) and maps them to kernel space for the
-driver's use. The probe function also request the required IRQs and gets the
-TSPP2 IOMMU domain. Finally, the probe function resets all HW registers to
-appropriate default values, and resets all the required software structures.
-
-See API description in Interface section.
-
-Usage examples
---------------
-
-Section filtering example - opening a Raw filter with data from TSIF0:
-----------------------------------------------------------------------
-u32 dev_id = 0;
-u32 src_handle;
-u32 pipe_handle;
-u32 filter_handle;
-u32 iova;
-u32 vaddress;
-struct tspp2_config cfg = {...};
-struct tspp2_pipe_config_params pipe_config;
-struct tspp2_pipe_pull_mode_params pull_params = {0, 0};
-struct tspp2_operation raw_op;
-struct sps_event_notify event;
-struct sps_iovec desc;
-
-/* Open TSPP2 device for use */
-tspp2_device_open(dev_id);
-
-/* Set global configuration */
-tspp2_config_set(dev_id, &cfg);
-
-/* Open source with TSIF0 input */
-tspp2_src_open(dev_id, TSPP2_INPUT_TSIF0, &src_handle);
-
-/* Set parsing options if needed, for example: */
-tspp2_src_parsing_option_set(src_handle,
- TSPP2_SRC_PARSING_OPT_CHECK_CONTINUITY, 1);
-
-/* Assume normal sync byte, assume no need for scrambling configuration */
-
-/* Set packet size and format: */
-tspp2_src_packet_format_set(src_handle, TSPP2_PACKET_FORMAT_188_RAW);
-
-/* Since this is TSIF input, flow control is in push mode */
-
-/* Allocate memory for output pipe via ION not shown here */
-
-/* Open an output pipe for use */
-pipe_config.ion_client = ...
-pipe_config.buffer_handle = ...
-pipe_config.buffer_size = ...
-pipe_config.pipe_mode = TSPP2_SRC_PIPE_OUTPUT;
-pipe_config.sps_cfg.descriptor_size = 188;
-pipe_config.sps_cfg.setting = (SPS_O_AUTO_ENABLE | SPS_O_HYBRID |
- SPS_O_OUT_OF_DESC | SPS_O_ACK_TRANSFERS);
-pipe_config.sps_cfg.wakeup_events = SPS_O_OUT_OF_DESC;
-pipe_config.sps_cfg.callback = ...
-pipe_config.sps_cfg.user_info = ...
-tspp2_pipe_open(dev_id, &pipe_config, &iova, &pipe_handle);
-
-/* Attache the pipe to the source */
-tspp2_src_pipe_attach(src_handle, pipe_handle, &pull_params);
-/* Open a filter for PID 13 */
-tspp2_filter_open(src_handle, 13, 0x1FFF, &filter_handle);
-
-/* Add a raw transmit operation */
-raw_op.type = TSPP2_OP_RAW_TRANSMIT;
-raw_op.params.raw_transmit.input = TSPP2_OP_BUFFER_A;
-raw_op.params.raw_transmit.timestamp_mode = TSPP2_OP_TIMESTAMP_NONE;
-raw_op.params.raw_transmit.skip_ts_packets_with_errors = 0;
-raw_op.params.raw_transmit.output_pipe_handle = pipe_handle;
-tspp2_filter_operations_add(filter_handle, &raw_op, 1);
-
-/* Enable filter and source to start getting data */
-tspp2_filter_enable(filter_handle);
-tspp2_source_enable(src_handle);
-
-/*
- * Data path: poll pipe (or get notifications from pipe via
- * registered callback).
- */
-tspp2_pipe_last_address_used_get(pipe_handle, &vaddress);
-
-/* Process data... */
-
-/* Get and release descriptors: */
-tspp2_pipe_descriptor_get(pipe_handle, &desc);
-tspp2_pipe_descriptor_put(pipe_handle, desc.addr, desc.size, ...);
-
-/* Teardown: */
-tspp2_src_disable(src_handle);
-tspp2_filter_disable(filter_handle);
-tspp2_filter_close(filter_handle);
-tspp2_src_pipe_detach(src_handle, pipe_handle);
-tspp2_pipe_close(pipe_handle);
-tspp2_src_close(src_handle);
-tspp2_device_close(dev_id);
-
-Debug facilities
-----------------
-The TSPP2 driver supports several debug facilities via debugfs:
-a. Ability to read the status of TSIF and TSPP2 HW registers via debugfs.
-b. Ability to print HW statistics, error and performance counters via debugfs.
-c. Ability to print SW status via debugfs.
-
-Design
-======
-The TSPP2 driver is a regular Linux platform driver designed to support the
-TSPP2 HW available on specific Qualcomm SoCs.
-
-The driver provides an extensive kernel-space API to allow the client full
-control over the configuration of the TSPP2 HW, while encapsulating HW
-implementation details that are not relevant to the client.
-
-The driver enforces HW restrictions and checks for input parameters
-validity, providing a success or failure return value for each API function.
-However, the driver does not enforce any high-level policy with regard to the
-correct use of the TSPP2 HW for various use-cases.
-
-Power Management
-================
-The TSPP2 driver prevents the CPU from sleeping while the HW is active by
-using the wakeup_source API. When the HW is not active (i.e., no sources
-configured), the driver indicates it is ready for system suspend by invoking
-__pm_relax(). When the HW needs to be active (i.e., a source has been opened and
-enabled), the driver invokes __pm_stay_awake().
-
-In a similar manner, the driver enables the HW clocks only when needed.
-The TSPP2 HW manages power saving automatically when the HW is not used.
-No SW involvement is required.
-
-SMP/multi-core
-==============
-The driver uses a mutex for mutual exclusion between kernel API calls.
-A spinlock is used to protect accesses to its internal databases which can be
-performed both from interrupt handler context and from API context.
-
-Security
-========
-None.
-
-Performance
-===========
-Control operations are not considered as performance critical.
-Most of the control operations are assumed to be fairly uncommon.
-Data-path operations involve only getting descriptors from the pipe and
-releasing them back to the pipe for reuse.
-
-Interface
-=========
-Kernel-space API
-----------------
-
-Control path API
--------------------
-
-TSPP2 device open / close API:
-------------------------------
-int tspp2_device_open(u32 dev_id);
-
-int tspp2_device_close(u32 dev_id);
-
-Global configuration for the TSPP2 device:
-------------------------------------------
-int tspp2_config_set(u32 dev_id, const struct tspp2_config *cfg);
- Set device global configuration.
-
-int tspp2_config_get(u32 dev_id, struct tspp2_config *cfg);
- Get current device global configuration.
-
-Configure Indexing Tables:
---------------------------
-int tspp2_indexing_prefix_set(u32 dev_id, u8 table_id, u32 value, u32 mask);
- Set prefix value and mask of an indexing table.
-
-int tspp2_indexing_patterns_add(u32 dev_id, u8 table_id, const u32 *values,
- const u32 *masks, u8 patterns_num);
- Add patterns to an indexing table.
-
-int tspp2_indexing_patterns_clear(u32 dev_id, u8 table_id);
- Clear all patterns of an indexing table
-
-Opening and closing Pipes:
---------------------------
-int tspp2_pipe_open(u32 dev_id, const struct tspp2_pipe_config_params *cfg,
- u32 *iova, u32 *pipe_handle);
- Open a pipe for use.
-
-int tspp2_pipe_close(u32 pipe_handle);
- Close an opened pipe.
-
-Source configuration:
----------------------
-int tspp2_src_open(u32 dev_id, enum tspp2_src_input input, u32 *src_handle);
- Open a new source for use.
-
-int tspp2_src_close(u32 src_handle);
- Close an opened source.
-
-int tspp2_src_parsing_option_set(u32 src_handle,
- enum tspp2_src_parsing_option option, int value);
- Set source parsing configuration option.
-
-int tspp2_src_parsing_option_get(u32 src_handle,
- enum tspp2_src_parsing_option option, int *value);
- Get source parsing configuration option.
-
-int tspp2_src_sync_byte_config_set(u32 src_handle, int check_sync_byte,
- u8 sync_byte_value);
- Set source sync byte configuration.
-
-int tspp2_src_sync_byte_config_get(u32 src_handle, int *check_sync_byte,
- u8 *sync_byte_value);
- Get source sync byte configuration.
-
-int tspp2_src_scrambling_config_set(u32 src_handle,
- const struct tspp2_src_scrambling_config *cfg);
- Set source scrambling configuration.
-
-int tspp2_src_scrambling_config_get(u32 src_handle,
- struct tspp2_src_scrambling_config *cfg);
- Get source scrambling configuration.
-
-int tspp2_src_packet_format_set(u32 src_handle,
- enum tspp2_packet_format format);
- Set source packet size and format.
-
-int tspp2_src_pipe_attach(u32 src_handle, u32 pipe_handle,
- const struct tspp2_pipe_pull_mode_params *cfg);
- Attach a pipe to a source.
-
-int tspp2_src_pipe_detach(u32 src_handle, u32 pipe_handle);
- Detach a pipe from a source.
-
-int tspp2_src_enable(u32 src_handle);
- Enable source (start using it).
-
-int tspp2_src_disable(u32 src_handle);
- Disable source (stop using it).
-
-int tspp2_src_filters_clear(u32 src_handle);
- Clear all filters from a source.
-
-Filter and Operation configuration:
------------------------------------
-int tspp2_filter_open(u32 src_handle, u16 pid, u16 mask, u32 *filter_handle);
- Open a new filter and add it to a source.
-
-int tspp2_filter_close(u32 filter_handle);
- Close a filter.
-
-int tspp2_filter_enable(u32 filter_handle);
- Enable a filter.
-
-int tspp2_filter_disable(u32 filter_handle);
- Disable a filter.
-
-int tspp2_filter_operations_set(u32 filter_handle,
- const struct tspp2_operation *ops, u8 operations_num);
- Set (add or update) operations to a filter.
-
-int tspp2_filter_operations_clear(u32 filter_handle);
- Clear all operations from a filter.
-
-int tspp2_filter_current_scrambling_bits_get(u32 filter_handle,
- u8 *scrambling_bits_value);
- Get the current scrambling bits.
-
-Events notifications registration:
-----------------------------------
-int tspp2_global_event_notification_register(u32 dev_id,
- u32 global_event_bitmask,
- void (*callback)(void *cookie),
- void *cookie);
- Get notified on a global event.
-
-int tspp2_src_event_notification_register(u32 src_handle,
- u32 src_event_bitmask,
- void (*callback)(void *cookie),
- void *cookie);
- Get notified on a source event.
-
-int tspp2_filter_event_notification_register(u32 filter_handle,
- u32 filter_event_bitmask,
- void (*callback)(void *cookie),
- void *cookie);
- Get notified on a filter event.
-
-Data path API
-----------------
-int tspp2_pipe_descriptor_get(u32 pipe_handle, struct sps_iovec *desc);
- Get a data descriptor from a pipe.
-
-int tspp2_pipe_descriptor_put(u32 pipe_handle, u32 addr,
- u32 size, u32 flags);
- Put (release) a descriptor for reuse by the pipe.
-
-int tspp2_pipe_last_address_used_get(u32 pipe_handle, u32 *address);
- Get the last address the TSPP2 used.
-
-int tspp2_data_write(u32 src_handle, u32 offset, u32 size);
- Write (feed) data to a source.
-
-User-space API
---------------
-The TSPP2 driver does not provide any user-space API, only a kernel-space API.
-The dvb/demux driver, which utilizes the TSPP2 driver (and HW), provides an
-extensive user-space API, allowing upper layers to achieve complex demuxing
-functionality.
-
-For further information please refer to Documentation/dvb/qcom-mpq.txt.
-
-Driver parameters
-=================
-The TSPP2 driver supports the following module parameter:
-tspp2_iommu_bypass: Bypass VBIF/IOMMU and use physical buffer addresses
-instead. This is mostly useful for debug purposes if something is wrong with
-the IOMMU configuration. Default is false.
-
-Platform-dependent parameters (e.g., IRQ numbers) are provided to the driver
-via the device tree mechanism or the platform device data mechanism.
-
-Config options
-==============
-To enable the driver, set CONFIG_TSPP2 to y (built-in) or m (kernel module)
-in the kernel configuration menu.
-
-Dependencies
-============
-a. The TSPP2 driver uses the SPS driver to control the BAM unit.
-b. The TSPP2 driver uses the ION driver for IOMMU registration and buffer
-mapping. The client is responsible to allocate memory buffers via ION.
-
-User space utilities
-====================
-None.
-
-Other
-=====
-None.
-
-Known issues
-============
-None.
-
-To do
-=====
-None.
diff --git a/drivers/media/platform/msm/broadcast/Makefile b/drivers/media/platform/msm/broadcast/Makefile
index 1233d6d..5e72b0d 100644
--- a/drivers/media/platform/msm/broadcast/Makefile
+++ b/drivers/media/platform/msm/broadcast/Makefile
@@ -3,9 +3,7 @@
#
obj-$(CONFIG_TSPP) += tspp.o
-obj-$(CONFIG_TSPP2) += tspp2.o
obj-$(CONFIG_CI_BRIDGE_SPI) += ci-bridge-spi.o
-obj-$(CONFIG_TSC) += tsc.o
obj-$(CONFIG_ENSIGMA_UCCP_330) += ensigma_uccp330.o
obj-$(CONFIG_DEMOD_WRAPPER) += demod_wrapper.o
diff --git a/drivers/media/platform/msm/broadcast/tsc.c b/drivers/media/platform/msm/broadcast/tsc.c
deleted file mode 100644
index ec3142e..0000000
--- a/drivers/media/platform/msm/broadcast/tsc.c
+++ /dev/null
@@ -1,3450 +0,0 @@
-/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/tsc.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/device.h> /* Device drivers need this */
-#include <linux/cdev.h> /* Char device drivers need that */
-#include <linux/kernel.h> /* for KERN_INFO */
-#include <linux/fs.h>
-#include <linux/completion.h> /* for completion signaling after interrupts */
-#include <linux/uaccess.h> /* for copy from/to user in the ioctls */
-#include <linux/msm_iommu_domains.h>
-#include <linux/mutex.h>
-#include <linux/of.h> /* parsing device tree data */
-#include <linux/of_gpio.h>
-#include <linux/of_irq.h>
-#include <mach/gpio.h> /* gpios definitions */
-#include <linux/pinctrl/consumer.h> /* pinctrl API */
-#include <linux/clk.h>
-#include <linux/wait.h> /* wait() macros, sleeping */
-#include <linux/sched.h> /* Externally defined globals */
-#include <linux/poll.h> /* poll() file op */
-#include <linux/io.h> /* IO macros */
-#include <linux/bitops.h>
-#include <linux/msm_ion.h> /* ion_map_iommu */
-#include <linux/iommu.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h> /* kfree, kzalloc */
-#include <linux/debugfs.h> /* debugfs support */
-#include <linux/pm_runtime.h> /* debugfs support */
-#include <linux/pm_wakeup.h> /* debugfs support */
-#include <linux/regulator/consumer.h> /* gdsc */
-#include <linux/msm-bus.h> /* bus client */
-#include <linux/delay.h> /* usleep function */
-/* TODO: include <linux/mpq_standby_if.h> after MCU is mainlined */
-
-/*
- * General defines
- */
-#define TEST_BIT(pos, number) (number & (1 << pos))
-#define CLEAR_BIT(pos, number) (number &= ~(1 << pos))
-#define SET_BIT(pos, number) (number |= 1 << pos)
-
-/*
- * extract bits [@b0:@b1] (inclusive) from the value @x
- * it should be @b0 <= @b1, or result is incorrect
- */
-static inline u32 GETL_BITS(u32 x, int b0, int b1)
-{
- return (x >> b0) & ((1 << (b1 - b0 + 1)) - 1);
-}
-
-/* Bypass VBIF/IOMMU for debug and bring-up purposes */
-static int tsc_iommu_bypass; /* defualt=0 using iommu */
-module_param(tsc_iommu_bypass, int, S_IRUGO | S_IWUSR | S_IWGRP);
-
-/* The rate of the clock that control TS from TSC to the CAM */
-#define CICAM_CLK_RATE_12MHZ 12000000
-#define CICAM_CLK_RATE_9MHZ 8971962
-#define CICAM_CLK_RATE_7MHZ 7218045
-/* Rates for TSC serial and parallel clocks */
-#define TSC_SER_CLK_RATE 192000000
-#define TSC_PAR_CLK_RATE 24000000
-
-/* CICAM address space according to CI specification */
-#define CICAM_MAX_ADDRESS 3
-
-/*
- * TSC register offsets
- */
-#define TSC_HW_VERSION (0x0)
-#define TSC_MUX_CFG (0x4) /* Muxs config */
-#define TSC_IN_IFC_EXT (0x8) /* External demods tsifs */
-#define TSC_IN_IFC_CFG_INT (0xc) /* internal demods and
- cicam tsif config */
-#define TSC_FSM_STATE (0x50) /* Read FSM state */
-#define TSC_FSM_STATE_MASK (0x54) /* Config FSM state */
-#define TSC_CAM_CMD (0x1000)/* Config cam commands */
-#define TSC_CAM_RD_DATA (0x1004)/* read data for single-mode
- byte */
-#define TSC_STAT (0x1008)/* Interrupts status */
-#define TSC_IRQ_ENA (0x100C)/* Enable interrupts */
-#define TSC_IRQ_CLR (0x1010)/* Clear interrupts */
-#define TSC_CIP_CFG (0x1014)/* Enable HW polling */
-#define TSC_CD_STAT (0x1020)/* Card pins status */
-#define TSC_RD_BUFF_ADDR (0x1024)/* Vbif address for read
- buffer */
-#define TSC_WR_BUFF_ADDR (0x1028)/* Vbif address for write
- buffer */
-#define TSC_FALSE_CD (0x102C)/* Counter of false card
- detection */
-#define TSC_FALSE_CD_CLR (0x1030)/* Clear false cd counter */
-#define TSC_RESP_ERR (0x1034)/* State of read/write buffer
- error */
-#define TSC_CICAM_TSIF (0x1038)/* Enable tsif (tsc->cam) */
-
-
-/*
- * Registers structure definitions
- */
-
-/* TSC_MUX_CFG */
-#define MUX_EXTERNAL_DEMOD_0 0
-#define MUX_EXTERNAL_DEMOD_1 1
-#define MUX_INTERNAL_DEMOD 2
-#define MUX_CICAM 3
-#define MUX0_OFFS 0
-#define MUX1_OFFS 2
-#define MUX_CAM_OFFS 4
-
-/* TSC_IN_IFC_EXT and TSC_IN_IFC_CFG_INT*/
-#define TSIF_INPUT_ENABLE 0
-#define TSIF_INPUT_DISABLE 1
-
-#define TSIF_CLK_POL_OFFS 0
-#define TSIF_DATA_POL_OFFS 1
-#define TSIF_START_POL_OFFS 2
-#define TSIF_VALID_POL_OFFS 3
-#define TSIF_ERROR_POL_OFFS 4
-#define TSIF_SER_PAR_OFFS 5
-#define TSIF_REC_MODE_OFFS 6
-#define TSIF_DATA_SWAP_OFFS 8
-#define TSIF_DISABLE_OFFS 9
-#define TSIF_ERR_INSERT_OFFS 10
-
-/* TSC_FSM_STATE and TSC_FSM_STATE_MASK*/
-#define FSM_STATE_BUFFER_BEG 0
-#define FSM_STATE_BUFFER_END 3
-#define FSM_STATE_POLL_BEG 8
-#define FSM_STATE_POLL_END 10
-#define FSM_STATE_BYTE_BEG 12
-#define FSM_STATE_BYTE_END 13
-#define FSM_STATE_MEM_WR_BEG 16
-#define FSM_STATE_MEM_WR_END 17
-#define FSM_STATE_MEM_RD_BEG 20
-#define FSM_STATE_MEM_RD_END 21
-#define FSM_STATE_IO_RD_BEG 24
-#define FSM_STATE_IO_RD_END 25
-#define FSM_STATE_IO_WR_BEG 28
-#define FSM_STATE_IO_WR_END 29
-
-/* TSC_CAM_CMD */
-#define MEMORY_TRANSACTION 0
-#define IO_TRANSACTION 1
-#define WRITE_TRANSACTION 0
-#define READ_TRANSACTION 1
-#define SINGLE_BYTE_MODE 0
-#define BUFFER_MODE 1
-
-#define CAM_CMD_ADDR_SIZE_OFFS 0
-#define CAM_CMD_WR_DATA_OFFS 16
-#define CAM_CMD_IO_MEM_OFFS 24
-#define CAM_CMD_RD_WR_OFFS 25
-#define CAM_CMD_BUFF_MODE_OFFS 26
-#define CAM_CMD_ABORT 27
-
-/* TSC_STAT, TSC_IRQ_ENA and TSC_IRQ_CLR */
-#define CAM_IRQ_EOT_OFFS 0
-#define CAM_IRQ_POLL_OFFS 1
-#define CAM_IRQ_RATE_MISMATCH_OFFS 2
-#define CAM_IRQ_ERR_OFFS 3
-#define CAM_IRQ_ABORTED_OFFS 4
-
-/* TSC_CD_STAT */
-#define TSC_CD_STAT_INSERT 0x00
-#define TSC_CD_STAT_ERROR1 0x01
-#define TSC_CD_STAT_ERROR2 0x02
-#define TSC_CD_STAT_REMOVE 0x03
-
-#define TSC_CD_BEG 0
-#define TSC_CD_END 1
-
-/* TSC_CICAM_TSIF */
-#define TSC_CICAM_TSIF_OE_OFFS 0
-
-/* Data structures */
-
-/**
- * enum transaction_state - states for the transacation interrupt reason
- */
-enum transaction_state {
- BEFORE_TRANSACTION = 0,
- TRANSACTION_SUCCESS = 1,
- TRANSACTION_ERROR = -1,
- TRANSACTION_CARD_REMOVED = -2
-};
-
-/**
-* enum pcmcia_state - states for the pcmcia pinctrl states
-* Note: the numbers here corresponds to the numbers of enum tsc_cam_personality
-* in tsc.h file.
-*/
-enum pcmcia_state {
- PCMCIA_STATE_DISABLE = 0,
- PCMCIA_STATE_CI_CARD = 1,
- PCMCIA_STATE_CI_PLUS = 2,
- PCMCIA_STATE_PC_CARD = 3
-};
-
-/**
- * struct iommu_info - manage all the iommu information
- *
- * @group: TSC IOMMU group.
- * @domain: TSC IOMMU domain.
- * @domain_num: TSC IOMMU domain number.
- * @partition_num: TSC iommu partition number.
- * @ion_client: TSC IOMMU client.
- * @iommu_group_name TSC IOMMU group name.
- */
-struct iommu_info {
- struct iommu_group *group;
- struct iommu_domain *domain;
- int domain_num;
- int partition_num;
- struct ion_client *ion_client;
- const char *iommu_group_name;
-};
-
-/**
- * struct pinctrl_current_state - represent which TLMM pins currently active
- *
- * @ts0: true if TS-in 0 is active, false otherwise.
- * @ts1: true if TS-in 1 is active, false otherwise.
- * @pcmcia_state: Represent the pcmcia pins state.
- */
-struct pinctrl_current_state {
- bool ts0;
- bool ts1;
- enum pcmcia_state pcmcia_state;
-};
-/**
- * struct pinctrl_info - manage all the pinctrl information
- *
- * @pinctrl: TSC pinctrl state holder.
- * @disable: pinctrl state to disable all the pins.
- * @ts0: pinctrl state to activate TS-in 0 alone.
- * @ts1: pinctrl state to activate TS-in 1 alone.
- * @dual_ts: pinctrl state to activate both TS-in.
- * @pc_card: pinctrl state to activate pcmcia upon card insertion.
- * @ci_card: pinctrl state to activate pcmcia after personality
- * change to CI card.
- * @ci_plus: pinctrl state to activate pcmcia after personality
- * change to CI+ card.
- * @ts0_pc_card: pinctrl state to activate TS-in 0 and pcmcia upon card
- * insertion.
- * @ts0_ci_card: pinctrl state to activate TS-in 0 and pcmcia after
- * personality change to CI card.
- * @ts0_ci_plus: pinctrl state to activate TS-in 0 and pcmcia after
- * personality change to CI+ card.
- * @ts1_pc_card: pinctrl state to activate TS-in 1 and pcmcia upon card
- * insertion.
- * @ts1_ci_card: pinctrl state to activate TS-in 1 and pcmcia after
- * personality change to CI card.
- * @ts1_ci_plus: pinctrl state to activate TS-in 1 and pcmcia after
- * personality change to CI+ card.
- * @dual_ts_pc_card: pinctrl state to activate both TS-in and pcmcia upon
- * card insertion.
- * @dual_ts_ci_card: pinctrl state to activate both TS-in and pcmcia after
- * personality change to CI card.
- * @dual_ts_ci_plus: pinctrl state to activate both TS-in and pcmcia after
- * personality change to CI+ card.
- * @is_ts0: true if ts0 pinctrl states exist in device tree, false
- * otherwise.
- * @is_ts1: true if ts1 pinctrl states exist in device tree, false
- * otherwise.
- * @is_pcmcia: true if pcmcia pinctrl states exist in device tree,
- * false otherwise.
- * @curr_state: the current state of the TLMM pins.
- */
-struct pinctrl_info {
- struct pinctrl *pinctrl;
- struct pinctrl_state *disable;
- struct pinctrl_state *ts0;
- struct pinctrl_state *ts1;
- struct pinctrl_state *dual_ts;
- struct pinctrl_state *pc_card;
- struct pinctrl_state *ci_card;
- struct pinctrl_state *ci_plus;
- struct pinctrl_state *ts0_pc_card;
- struct pinctrl_state *ts0_ci_card;
- struct pinctrl_state *ts0_ci_plus;
- struct pinctrl_state *ts1_pc_card;
- struct pinctrl_state *ts1_ci_card;
- struct pinctrl_state *ts1_ci_plus;
- struct pinctrl_state *dual_ts_pc_card;
- struct pinctrl_state *dual_ts_ci_card;
- struct pinctrl_state *dual_ts_ci_plus;
- bool is_ts0;
- bool is_ts1;
- bool is_pcmcia;
- struct pinctrl_current_state curr_state;
-};
-
-/**
- * struct tsc_mux_chdev - TSC Mux character device
- *
- * @cdev: TSC Mux cdev.
- * @mutex: A mutex for mutual exclusion between Mux API calls.
- * @poll_queue: Waiting queue for rate mismatch interrupt.
- * @spinlock: A spinlock to protect accesses to
- * data structures that happen from APIs and ISRs.
- * @rate_interrupt: A flag indicating if rate mismatch interrupt received.
- */
-struct tsc_mux_chdev {
- struct cdev cdev;
- struct mutex mutex;
- wait_queue_head_t poll_queue;
- spinlock_t spinlock;
- bool rate_interrupt;
-};
-
-/**
- * struct tsc_ci_chdev - TSC CI character device
- *
- * @cdev: TSC CI cdev.
- * @mutex: A mutex for mutual exclusion between CI API calls.
- * @poll_queue: Waiting queue for card detection interrupt.
- * @spinlock: A spinlock to protect accesses to data structures that
- * happen from APIs and ISRs.
- * @transaction_complete: A completion struct indicating end of data
- * transaction.
- * @transaction_finish: A completion struct indicating data transaction func
- * has finished.
- * @transaction_state: flag indicating the reason for transaction end.
- * @ci_card_status: The last card status received by the upper layer.
- * @data_busy: true when the device is in the middle of data
- * transaction operation, false otherwise.
- */
-struct tsc_ci_chdev {
- struct cdev cdev;
- struct mutex mutex;
- wait_queue_head_t poll_queue;
- spinlock_t spinlock;
- struct completion transaction_complete;
- struct completion transaction_finish;
- enum transaction_state transaction_state;
- enum tsc_card_status card_status;
- bool data_busy;
-};
-
-/**
- * struct tsc_device - TSC device
- *
- * @pdev: TSC platform device.
- * @device_mux: Mux device for sysfs and /dev entry.
- * @device_ci: CI device for sysfs and /dev entry.
- * @mux_chdev: TSC Mux character device instance.
- * @ci_chdev: TSC CI character device instance.
- * @mux_device_number: TSC Mux major number.
- * @ci_device_number: TSC CI major number.
- * @num_mux_opened: A counter to ensure 1 TSC Mux character device.
- * @num_ci_opened: A counter to ensure 1 TSC CI character device.
- * @num_device_open: A counter to synch init of power and bus voting.
- * @mutex: Global mutex to to synch init of power and bus voting.
- * @base: Base memory address for the TSC registers.
- * @card_detection_irq: Interrupt No. of the card detection interrupt.
- * @cam_cmd_irq: Interrupt No. of the cam cmd interrupt.
- * @iommu_info: TSC IOMMU parameters.
- * @ahb_clk: The clock for accessing the TSC registers.
- * @ci_clk: The clock for TSC internal logic.
- * @ser_clk: The clock for synchronizing serial TS input.
- * @par_clk: The clock for synchronizing parallel TS input.
- * @cicam_ts_clk: The clock for pushing TS data into the cicam.
- * @tspp2_core_clk: The clock for enabling the TSPP2.
- * @vbif_tspp2_clk: The clock for accessing the VBIF.
- * @vbif_ahb_clk: The clock for VBIF AHB.
- * @vbif_axi_clk: The clock for VBIF AXI.
- * @gdsc: The Broadcast GDSC.
- * @bus_client: The TSC bus client.
- * @pinctrl_info: TSC pinctrl parameters.
- * @reset_cam_gpio: GPIO No. for CAM HW reset.
- * @hw_card_status: The card status as reflected by the HW registers.
- * @card_power: True if the card is powered up, false otherwise.
- * @debugfs_entry: TSC device debugfs entry.
- */
-struct tsc_device {
- struct platform_device *pdev;
- struct device *device_mux;
- struct device *device_ci;
- struct tsc_mux_chdev mux_chdev;
- struct tsc_ci_chdev ci_chdev;
- dev_t mux_device_number;
- dev_t ci_device_number;
- int num_mux_opened;
- int num_ci_opened;
- int num_device_open;
- struct mutex mutex;
- void __iomem *base;
- unsigned int card_detection_irq;
- unsigned int cam_cmd_irq;
- struct iommu_info iommu_info;
- struct clk *ahb_clk;
- struct clk *ci_clk;
- struct clk *ser_clk;
- struct clk *par_clk;
- struct clk *cicam_ts_clk;
- struct clk *tspp2_core_clk;
- struct clk *vbif_tspp2_clk;
- struct clk *vbif_ahb_clk;
- struct clk *vbif_axi_clk;
- struct regulator *gdsc;
- uint32_t bus_client;
- struct pinctrl_info pinctrl_info;
- int reset_cam_gpio;
- enum tsc_card_status hw_card_status;
- bool card_power;
- struct dentry *debugfs_entry;
-};
-
-/* Global TSC device class */
-static struct class *tsc_class;
-
-/* Global TSC device database */
-static struct tsc_device *tsc_device;
-
-/************************** Debugfs Support **************************/
-/* debugfs entries */
-#define TSC_S_RW (S_IRUGO | S_IWUSR)
-
-struct debugfs_entry {
- const char *name;
- mode_t mode;
- int offset;
-};
-
-static const struct debugfs_entry tsc_regs_32[] = {
- {"tsc_hw_version", S_IRUGO, TSC_HW_VERSION},
- {"tsc_mux", TSC_S_RW, TSC_MUX_CFG},
- {"tsif_external_demods", TSC_S_RW, TSC_IN_IFC_EXT},
- {"tsif_internal_demod_cam", TSC_S_RW, TSC_IN_IFC_CFG_INT},
- {"tsc_fsm_state", S_IRUGO, TSC_FSM_STATE},
- {"tsc_fsm_state_mask", TSC_S_RW, TSC_FSM_STATE_MASK},
- {"tsc_cam_cmd", TSC_S_RW, TSC_CAM_CMD},
- {"tsc_rd_buff_addr", TSC_S_RW, TSC_RD_BUFF_ADDR},
- {"tsc_wr_buff_addr", TSC_S_RW, TSC_WR_BUFF_ADDR},
-};
-
-static const struct debugfs_entry tsc_regs_16[] = {
- {"tsc_false_cd_counter", S_IRUGO, TSC_FALSE_CD},
- {"tsc_cicam_tsif", TSC_S_RW, TSC_CICAM_TSIF},
-};
-
-static const struct debugfs_entry tsc_regs_8[] = {
- {"tsc_cam_rd_data", S_IRUGO, TSC_CAM_RD_DATA},
- {"tsc_irq_stat", S_IRUGO, TSC_STAT},
- {"tsc_irq_ena", TSC_S_RW, TSC_IRQ_ENA},
- {"tsc_irq_clr", TSC_S_RW, TSC_IRQ_CLR},
- {"tsc_ena_hw_poll", TSC_S_RW, TSC_CIP_CFG},
- {"tsc_card_stat", TSC_S_RW, TSC_CD_STAT},
- {"tsc_false_cd_counter_clr", TSC_S_RW, TSC_FALSE_CD_CLR},
- {"tsc_last_error_resp", S_IRUGO, TSC_RESP_ERR},
-};
-
-/* debugfs settings */
-static int debugfs_iomem_set(void *data, u64 val)
-{
- if (mutex_lock_interruptible(&tsc_device->mutex))
- return -ERESTARTSYS;
-
- if (!tsc_device->num_device_open) {
- mutex_unlock(&tsc_device->mutex);
- return -ENXIO;
- }
-
- mutex_unlock(&tsc_device->mutex);
-
- writel_relaxed(val, data);
- wmb();
-
- return 0;
-}
-
-static int debugfs_iomem_get(void *data, u64 *val)
-{
- if (mutex_lock_interruptible(&tsc_device->mutex))
- return -ERESTARTSYS;
-
- if (!tsc_device->num_device_open) {
- mutex_unlock(&tsc_device->mutex);
- return -ENXIO;
- }
-
- mutex_unlock(&tsc_device->mutex);
-
- *val = readl_relaxed(data);
-
- return 0;
-}
-
-DEFINE_SIMPLE_ATTRIBUTE(fops_iomem_x32, debugfs_iomem_get,
- debugfs_iomem_set, "0x%08llX");
-DEFINE_SIMPLE_ATTRIBUTE(fops_iomem_x16, debugfs_iomem_get,
- debugfs_iomem_set, "0x%04llX");
-DEFINE_SIMPLE_ATTRIBUTE(fops_iomem_x8, debugfs_iomem_get,
- debugfs_iomem_set, "0x%02llX");
-
-/**
- * tsc_debugfs_init() - TSC device debugfs initialization.
- */
-static void tsc_debugfs_init(void)
-{
- int i;
- struct dentry *dentry;
- void __iomem *base = tsc_device->base;
-
- tsc_device->debugfs_entry = debugfs_create_dir("tsc", NULL);
- if (!tsc_device->debugfs_entry)
- return;
- dentry = debugfs_create_dir("regs", tsc_device->debugfs_entry);
- if (dentry) {
- for (i = 0; i < ARRAY_SIZE(tsc_regs_32); i++) {
- debugfs_create_file(
- tsc_regs_32[i].name,
- tsc_regs_32[i].mode,
- dentry,
- base + tsc_regs_32[i].offset,
- &fops_iomem_x32);
- }
- for (i = 0; i < ARRAY_SIZE(tsc_regs_16); i++) {
- debugfs_create_file(
- tsc_regs_16[i].name,
- tsc_regs_16[i].mode,
- dentry,
- base + tsc_regs_16[i].offset,
- &fops_iomem_x16);
- }
- for (i = 0; i < ARRAY_SIZE(tsc_regs_8); i++) {
- debugfs_create_file(
- tsc_regs_8[i].name,
- tsc_regs_8[i].mode,
- dentry,
- base + tsc_regs_8[i].offset,
- &fops_iomem_x8);
- }
- }
-}
-
-/**
- * tsc_debugfs_exit() - TSC device debugfs teardown.
- */
-static void tsc_debugfs_exit(void)
-{
- debugfs_remove_recursive(tsc_device->debugfs_entry);
- tsc_device->debugfs_entry = NULL;
-}
-
-/**
- * tsc_update_hw_card_status() - Update the hw_status according to the HW reg.
- *
- * Read the register indicating the card status (inserted, removed, error) and
- * update the tsc_device->hw_card_status accordingly.
- */
-static void tsc_update_hw_card_status(void)
-{
- u32 cd_reg, card_status = 0;
-
- cd_reg = readl_relaxed(tsc_device->base + TSC_CD_STAT);
- card_status = GETL_BITS(cd_reg, TSC_CD_BEG, TSC_CD_END);
- switch (card_status) {
- case TSC_CD_STAT_INSERT:
- tsc_device->hw_card_status = TSC_CARD_STATUS_DETECTED;
- break;
- case TSC_CD_STAT_ERROR1:
- case TSC_CD_STAT_ERROR2:
- tsc_device->hw_card_status = TSC_CARD_STATUS_FAILURE;
- break;
- case TSC_CD_STAT_REMOVE:
- tsc_device->hw_card_status = TSC_CARD_STATUS_NOT_DETECTED;
- break;
- }
-}
-
-/**
- * tsc_card_power_down() - power down card interface upon removal.
- *
- * Power down the card by disable VPP, disable pins in the TLMM, assert the
- * reset line and disable the level-shifters. This function assumes the spinlock
- * of ci device is already taken.
- *
- * Return 0 on finish, error value if interrupted while acquiring a mutex.
- */
-static int tsc_card_power_down(void)
-{
- int ret = 0;
- struct pinctrl_info *ppinctrl = &tsc_device->pinctrl_info;
- struct pinctrl_current_state *pcurr_state = &ppinctrl->curr_state;
- int reset_gpio = tsc_device->reset_cam_gpio;
- u32 reg = 0;
-
- /* Clearing CAM TSIF OE to disable I/O CAM transactions */
- CLEAR_BIT(TSC_CICAM_TSIF_OE_OFFS, reg);
- writel_relaxed(reg, tsc_device->base + TSC_CICAM_TSIF);
-
- /* Assert the reset line */
- ret = gpio_direction_output(reset_gpio, 1); /* assert */
- if (ret != 0)
- pr_err("%s: Failed to assert the reset CAM GPIO\n", __func__);
-
- /* Disable all the level-shifters */
- /* TODO: call mpq_standby_pcmcia_master0_set(0) after MCU mainlined */
- if (ret != 0)
- pr_err("%s: error disable master0 level-shifters. ret value = %d\n",
- __func__, ret);
- /* TODO: call mpq_standby_pcmcia_master1_set(1) after MCU mainlined */
- if (ret != 0)
- pr_err("%s: error disable master1 level-shifters. ret value = %d\n",
- __func__, ret);
-
- /* Power-down the card */
- /* TODO: call mpq_standby_pcmcia_vpp_set(1) after MCU mainlined */
- if (ret != 0)
- pr_err("%s: error disabling VPP. ret value = %d\n", __func__,
- ret);
- /* Wait 10msec until VPP become stable */
- usleep(10000);
-
- /* Disable pins in the TLMM */
- if (mutex_lock_interruptible(&tsc_device->mutex))
- return -ERESTARTSYS;
-
- if (pcurr_state->ts0 && pcurr_state->ts1)
- ret = pinctrl_select_state(ppinctrl->pinctrl,
- ppinctrl->dual_ts);
- else if (pcurr_state->ts0 && !pcurr_state->ts1)
- ret = pinctrl_select_state(ppinctrl->pinctrl,
- ppinctrl->ts0);
- else if (!pcurr_state->ts0 && pcurr_state->ts1)
- ret = pinctrl_select_state(ppinctrl->pinctrl,
- ppinctrl->ts1);
- else
- ret = pinctrl_select_state(ppinctrl->pinctrl,
- ppinctrl->disable);
- if (ret != 0)
- pr_err("%s: error changing PCMCIA pins upon card removal. ret value = %d\n",
- __func__, ret);
- else
- pcurr_state->pcmcia_state = PCMCIA_STATE_DISABLE;
-
- mutex_unlock(&tsc_device->mutex);
-
- return 0;
-}
-
-/**
- * tsc_card_power_up() - power up card interface upon insertion.
- *
- * Power up the card by open VPP, enable pins in the TLMM, deassert the reset
- * line and enable the level-shifters. This function assumes the spinlock of ci
- * device is already taken.
- *
- * Return 0 on success, error value otherwise.
- */
-static int tsc_card_power_up(void)
-{
- int ret = 0;
- struct pinctrl_info *ppinctrl = &tsc_device->pinctrl_info;
- struct pinctrl_current_state *pcurr_state = &ppinctrl->curr_state;
- int reset_gpio = tsc_device->reset_cam_gpio;
-
- /* Power-up the card */
- /* TODO: call mpq_standby_pcmcia_vpp_set(1) after MCU mainlined */
- if (ret != 0) {
- pr_err("%s: error setting VPP. ret value = %d\n", __func__,
- ret);
- return ret;
- }
- /* Wait 10msec until VPP become stable */
- usleep(10000);
-
- /* Enable pins in the TLMM */
- if (mutex_lock_interruptible(&tsc_device->mutex))
- return -ERESTARTSYS;
-
- if (pcurr_state->ts0 && pcurr_state->ts1)
- ret = pinctrl_select_state(ppinctrl->pinctrl,
- ppinctrl->dual_ts_pc_card);
- else if (pcurr_state->ts0 && !pcurr_state->ts1)
- ret = pinctrl_select_state(ppinctrl->pinctrl,
- ppinctrl->ts0_pc_card);
- else if (!pcurr_state->ts0 && pcurr_state->ts1)
- ret = pinctrl_select_state(ppinctrl->pinctrl,
- ppinctrl->ts1_pc_card);
- else
- ret = pinctrl_select_state(ppinctrl->pinctrl,
- ppinctrl->pc_card);
- if (ret != 0) {
- pr_err("%s: error changing PCMCIA pins upon card insertion. ret value = %d\n",
- __func__, ret);
- mutex_unlock(&tsc_device->mutex);
- goto err;
- } else {
- pcurr_state->pcmcia_state = PCMCIA_STATE_PC_CARD;
- }
- mutex_unlock(&tsc_device->mutex);
-
- /* Release the reset line */
- ret = gpio_direction_output(reset_gpio, 0); /* Deassert */
- if (ret != 0) {
- pr_err("%s: Failed to deassert the reset CAM GPIO\n", __func__);
- goto err;
- }
-
- /* Enable level-shifters for all pins */
- /* TODO: call mpq_standby_pcmcia_master0_set(0) after MCU mainlined */
- if (ret != 0) {
- pr_err("%s: error setting master0 level-shifters. ret value = %d\n",
- __func__, ret);
- goto err;
- }
- /* TODO: call mpq_standby_pcmcia_master1_set(0) after MCU mainlined */
- if (ret != 0) {
- pr_err("%s: error setting master1 level-shifters. ret value = %d\n",
- __func__, ret);
- goto err;
- }
-
- /* Wait 20msec at the end of the power-up sequence */
- usleep(20000);
-
- return ret;
-
-err:
- tsc_card_power_down();
- return ret;
-}
-
-/************************** Interrupt handlers **************************/
-/**
- * tsc_card_detect_irq_thread_handler() - TSC card detect interrupt handler.
- *
- * @irq: Interrupt number.
- * @dev: TSC device.
- *
- * The handler is executed on a thread context, not in the interrupt context
- * (can take a mutex and sleep).
- * Read the card detection status from the register and initiate a power-up/down
- * sequence accordingly. The sequence will occur only if a change is needed in
- * the current power state.
- *
- */
-static irqreturn_t tsc_card_detect_irq_thread_handler(int irq, void *dev)
-{
- int ret = 0;
- struct tsc_ci_chdev *tsc_ci;
- unsigned long flags = 0;
-
- tsc_ci = &tsc_device->ci_chdev;
-
- mutex_lock(&tsc_ci->mutex);
-
- tsc_update_hw_card_status();
-
- /* waking-up ci poll queue */
- wake_up_interruptible(&tsc_ci->poll_queue);
-
- /* If in the middle of a data transaction- aborting the transaction */
- if (tsc_ci->data_busy && tsc_device->hw_card_status ==
- TSC_CARD_STATUS_NOT_DETECTED) {
- spin_lock_irqsave(&tsc_ci->spinlock, flags);
- tsc_ci->transaction_state = TRANSACTION_CARD_REMOVED;
- spin_unlock_irqrestore(&tsc_ci->spinlock, flags);
- complete_all(&tsc_ci->transaction_complete);
- }
-
- if (tsc_device->hw_card_status == TSC_CARD_STATUS_DETECTED &&
- !tsc_device->card_power) {
- ret = tsc_card_power_up();
- if (ret != 0)
- pr_err("%s: card power-up failed\n", __func__);
- else
- tsc_device->card_power = true;
- } else if (tsc_device->hw_card_status == TSC_CARD_STATUS_NOT_DETECTED &&
- tsc_device->card_power) {
- tsc_card_power_down();
- /*
- * In case something failed during the power down, the sequence
- * continue and the status of the card power is considered as
- * powered down.
- */
- tsc_device->card_power = false;
- }
-
- mutex_unlock(&tsc_ci->mutex);
-
- return IRQ_HANDLED;
-}
-
-/**
- * tsc_cam_cmd_irq_handler() - TSC CAM interrupt handler.
- *
- * @irq: Interrupt number.
- * @dev: TSC device.
- *
- * Handle TSC CAM HW interrupt. Handle the CAM transaction interrupts by waking
- * up the completion sync object, handle rate mismatch interrupt by waking-up
- * the TSC Mux poll wait-queue and clear the interrupts received.
- *
- * Return IRQ_HANDLED.
- */
-static irqreturn_t tsc_cam_cmd_irq_handler(int irq, void *dev)
-{
- struct tsc_ci_chdev *tsc_ci;
- struct tsc_mux_chdev *tsc_mux;
- unsigned long flags;
- u32 stat_reg, ena_reg;
-
- tsc_ci = &tsc_device->ci_chdev;
- tsc_mux = &tsc_device->mux_chdev;
-
- stat_reg = readl_relaxed(tsc_device->base + TSC_STAT);
-
- /* Handling transaction interrupts */
- if (TEST_BIT(CAM_IRQ_ERR_OFFS, stat_reg) ||
- TEST_BIT(CAM_IRQ_EOT_OFFS, stat_reg)) {
- spin_lock_irqsave(&tsc_ci->spinlock, flags);
-
- if (TEST_BIT(CAM_IRQ_EOT_OFFS, stat_reg))
- tsc_ci->transaction_state = TRANSACTION_SUCCESS;
- else
- tsc_ci->transaction_state = TRANSACTION_ERROR;
-
- spin_unlock_irqrestore(&tsc_ci->spinlock, flags);
- complete_all(&tsc_ci->transaction_complete);
- }
-
- /* Handling rate mismatch interrupt */
- if (TEST_BIT(CAM_IRQ_RATE_MISMATCH_OFFS, stat_reg)) {
- spin_lock_irqsave(&tsc_mux->spinlock, flags);
-
- /* Disabling rate mismatch interrupt */
- ena_reg = readl_relaxed(tsc_device->base + TSC_IRQ_ENA);
- CLEAR_BIT(CAM_IRQ_RATE_MISMATCH_OFFS, ena_reg);
- writel_relaxed(ena_reg, tsc_device->base + TSC_IRQ_ENA);
-
- /* Setting internal flag for poll */
- tsc_mux->rate_interrupt = true;
-
- spin_unlock_irqrestore(&tsc_mux->spinlock, flags);
- /* waking-up mux poll queue */
- wake_up_interruptible(&tsc_mux->poll_queue);
- }
-
- /* Clearing all the interrupts received */
- writel_relaxed(stat_reg, tsc_device->base + TSC_IRQ_CLR);
-
- /*
- * Before returning IRQ_HANDLED to the generic interrupt handling
- * framework need to make sure all operations including clearing of
- * interrupt status registers in the hardware is performed.
- * Thus a barrier after clearing the interrupt status register
- * is required to guarantee that the interrupt status register has
- * really been cleared by the time we return from this handler.
- */
- wmb();
-
- return IRQ_HANDLED;
-}
-
-/************************** Internal functions **************************/
-
-/**
- * tsc_set_cicam_clk() - Setting the rate of the TS from the TSC to the CAM
- *
- * @arg: The argument received from the user-space via set rate IOCTL.
- * It is the value of the requested rate in MHz.
- *
- * Setting the rate of the cicam_ts_clk clock, with one of the valid clock
- * frequencies. The arg value given is rounded to the nearest frequency.
- *
- * Return 0 on success, error value otherwise.
- */
-static int tsc_set_cicam_clk(unsigned long arg)
-{
- int ret;
-
- if (arg <= 8)
- ret = clk_set_rate(tsc_device->cicam_ts_clk,
- CICAM_CLK_RATE_7MHZ);
- else if (arg <= 11)
- ret = clk_set_rate(tsc_device->cicam_ts_clk,
- CICAM_CLK_RATE_9MHZ);
- else
- ret = clk_set_rate(tsc_device->cicam_ts_clk,
- CICAM_CLK_RATE_12MHZ);
- return ret;
-}
-
-/**
- * tsc_enable_rate_irq() - Enabling the rate mismatch interrupt.
- *
- * @tsc_mux: TSC Mux device.
- *
- * Setting the bit of this interrupt in the register that controls which
- * interrupts are enabled.
- */
-static void tsc_enable_rate_irq(struct tsc_mux_chdev *tsc_mux)
-{
- unsigned long flags;
- u32 ena_reg = 0;
-
- spin_lock_irqsave(&tsc_mux->spinlock, flags);
-
- /* Setting the bit to start receiving rate mismatch interrupt again */
- ena_reg = readl_relaxed(tsc_device->base + TSC_IRQ_ENA);
- SET_BIT(CAM_IRQ_RATE_MISMATCH_OFFS, ena_reg);
- writel_relaxed(ena_reg, tsc_device->base + TSC_IRQ_ENA);
-
- spin_unlock_irqrestore(&tsc_mux->spinlock, flags);
-}
-
-/**
- * tsc_config_tsif() - Modifying TSIF configuration.
- *
- * @tsc_mux: TSC Mux device.
- * @tsif_params: TSIF parameters received from the user-space via IOCTL.
- *
- * Update the specified TSIF parameters according to the values in tsif_params.
- * The update is done by modifying a HW register.
- *
- * Return 0 on success, error value otherwise.
- */
-static int tsc_config_tsif(struct tsc_mux_chdev *tsc_mux,
- struct tsc_tsif_params *tsif_params)
-{
- int ret = 0;
- u32 reg;
- int reg_internal_offs;
- u32 reg_addr_offs;
-
- switch (tsif_params->source) {
- case TSC_SOURCE_EXTERNAL0:
- reg_internal_offs = 0;
- reg_addr_offs = TSC_IN_IFC_EXT;
- break;
- case TSC_SOURCE_EXTERNAL1:
- reg_internal_offs = 16;
- reg_addr_offs = TSC_IN_IFC_EXT;
- break;
- case TSC_SOURCE_INTERNAL:
- reg_internal_offs = 0;
- reg_addr_offs = TSC_IN_IFC_CFG_INT;
- break;
- case TSC_SOURCE_CICAM:
- reg_internal_offs = 16;
- reg_addr_offs = TSC_IN_IFC_CFG_INT;
- break;
- default:
- pr_err("%s: unidentified source parameter\n", __func__);
- ret = -EINVAL;
- goto err;
- }
-
-
- reg = readl_relaxed(tsc_device->base + reg_addr_offs);
-
- /* Modifying TSIF settings in the register value */
- (tsif_params->clock_polarity ?
- SET_BIT((reg_internal_offs + TSIF_CLK_POL_OFFS), reg) :
- CLEAR_BIT((reg_internal_offs + TSIF_CLK_POL_OFFS), reg));
- (tsif_params->data_polarity ?
- SET_BIT(((reg_internal_offs + TSIF_DATA_POL_OFFS)), reg) :
- CLEAR_BIT((reg_internal_offs + TSIF_DATA_POL_OFFS), reg));
- (tsif_params->start_polarity ?
- SET_BIT((reg_internal_offs + TSIF_START_POL_OFFS), reg) :
- CLEAR_BIT((reg_internal_offs + TSIF_START_POL_OFFS), reg));
- (tsif_params->valid_polarity ?
- SET_BIT((reg_internal_offs + TSIF_VALID_POL_OFFS), reg) :
- CLEAR_BIT((reg_internal_offs + TSIF_VALID_POL_OFFS), reg));
- (tsif_params->error_polarity ?
- SET_BIT((reg_internal_offs + TSIF_ERROR_POL_OFFS), reg) :
- CLEAR_BIT((reg_internal_offs + TSIF_ERROR_POL_OFFS), reg));
- (tsif_params->data_type ?
- SET_BIT((reg_internal_offs + TSIF_SER_PAR_OFFS), reg) :
- CLEAR_BIT((reg_internal_offs + TSIF_SER_PAR_OFFS), reg));
- reg &= ~(0x3 << TSIF_REC_MODE_OFFS);
- reg |= (tsif_params->receive_mode << TSIF_REC_MODE_OFFS);
- (tsif_params->data_swap ?
- SET_BIT((reg_internal_offs + TSIF_DATA_SWAP_OFFS), reg) :
- CLEAR_BIT((reg_internal_offs + TSIF_DATA_SWAP_OFFS), reg));
- (tsif_params->set_error ?
- SET_BIT((reg_internal_offs + TSIF_ERR_INSERT_OFFS), reg) :
- CLEAR_BIT((reg_internal_offs + TSIF_ERR_INSERT_OFFS), reg));
-
- /* Writing the new settings to the register */
- writel_relaxed(reg, tsc_device->base + reg_addr_offs);
-
-err:
- return ret;
-}
-
-/**
- * tsc_suspend_ts_pins() - Suspend TS-in pins
- *
- * @source: The TSIF to configure.
- *
- * Config the TLMM pins of a TSIF as TS-in pins in sleep state according to
- * the current pinctrl configuration of the other pins.
- *
- * Return 0 on success, error value otherwise.
- */
-static int tsc_suspend_ts_pins(enum tsc_source source)
-{
- int ret = 0;
- struct pinctrl_info *ppinctrl = &tsc_device->pinctrl_info;
- struct pinctrl_current_state *pcurr_state = &ppinctrl->curr_state;
-
- if (mutex_lock_interruptible(&tsc_device->mutex))
- return -ERESTARTSYS;
-
- if (source == TSC_SOURCE_EXTERNAL0) {
- if (!ppinctrl->is_ts0) {
- pr_err("%s: No TS0-in pinctrl definitions were found in the TSC devicetree\n",
- __func__);
- mutex_unlock(&tsc_device->mutex);
- return -EPERM;
- }
-
- /* Transition from current pinctrl state to curr + ts0 sleep */
- switch (pcurr_state->pcmcia_state) {
- case PCMCIA_STATE_DISABLE:
- if (pcurr_state->ts1)
- ret = pinctrl_select_state(ppinctrl->pinctrl,
- ppinctrl->ts1);
- else
- ret = pinctrl_select_state(ppinctrl->pinctrl,
- ppinctrl->disable);
- break;
- case PCMCIA_STATE_PC_CARD:
- if (pcurr_state->ts1)
- ret = pinctrl_select_state(ppinctrl->pinctrl,
- ppinctrl->ts1_pc_card);
- else
- ret = pinctrl_select_state(ppinctrl->pinctrl,
- ppinctrl->pc_card);
- break;
- case PCMCIA_STATE_CI_CARD:
- if (pcurr_state->ts1)
- ret = pinctrl_select_state(ppinctrl->pinctrl,
- ppinctrl->ts1_ci_card);
- else
- ret = pinctrl_select_state(ppinctrl->pinctrl,
- ppinctrl->ci_card);
- break;
- case PCMCIA_STATE_CI_PLUS:
- if (pcurr_state->ts1)
- ret = pinctrl_select_state(ppinctrl->pinctrl,
- ppinctrl->ts1_ci_plus);
- else
- ret = pinctrl_select_state(ppinctrl->pinctrl,
- ppinctrl->ci_plus);
- break;
- }
- } else { /* source == TSC_SOURCE_EXTERNAL1 */
- if (!ppinctrl->is_ts1) {
- pr_err("%s: No TS1-in pinctrl definitions were found in the TSC devicetree\n",
- __func__);
- mutex_unlock(&tsc_device->mutex);
- return -EPERM;
- }
-
- /* Transition from current pinctrl state to curr + ts1 sleep */
- switch (pcurr_state->pcmcia_state) {
- case PCMCIA_STATE_DISABLE:
- if (pcurr_state->ts0)
- ret = pinctrl_select_state(ppinctrl->pinctrl,
- ppinctrl->ts0);
- else
- ret = pinctrl_select_state(ppinctrl->pinctrl,
- ppinctrl->disable);
- break;
- case PCMCIA_STATE_PC_CARD:
- if (pcurr_state->ts0)
- ret = pinctrl_select_state(ppinctrl->pinctrl,
- ppinctrl->ts0_pc_card);
- else
- ret = pinctrl_select_state(ppinctrl->pinctrl,
- ppinctrl->pc_card);
- break;
- case PCMCIA_STATE_CI_CARD:
- if (pcurr_state->ts0)
- ret = pinctrl_select_state(ppinctrl->pinctrl,
- ppinctrl->ts0_ci_card);
- else
- ret = pinctrl_select_state(ppinctrl->pinctrl,
- ppinctrl->ci_card);
- break;
- case PCMCIA_STATE_CI_PLUS:
- if (pcurr_state->ts0)
- ret = pinctrl_select_state(ppinctrl->pinctrl,
- ppinctrl->ts0_ci_plus);
- else
- ret = pinctrl_select_state(ppinctrl->pinctrl,
- ppinctrl->ci_plus);
- break;
- }
- }
-
- if (ret != 0) {
- pr_err("%s: error disabling TS-in pins. ret value = %d\n",
- __func__, ret);
- mutex_unlock(&tsc_device->mutex);
- return -EINVAL;
- }
-
- /* Update the current pinctrl state in the internal struct */
- if (source == TSC_SOURCE_EXTERNAL0)
- pcurr_state->ts0 = false;
- else
- pcurr_state->ts1 = false;
-
- mutex_unlock(&tsc_device->mutex);
-
- return 0;
-}
-
-/**
- * tsc_activate_ts_pins() - Activate TS-in pins
- *
- * @source: The TSIF to configure.
- *
- * Config the TLMM pins of a TSIF as TS-in pins in active state according to
- * the current pinctrl configuration of the other pins
- *
- * Return 0 on success, error value otherwise.
- */
-static int tsc_activate_ts_pins(enum tsc_source source)
-{
- int ret = 0;
- struct pinctrl_info *ppinctrl = &tsc_device->pinctrl_info;
- struct pinctrl_current_state *pcurr_state = &ppinctrl->curr_state;
-
- if (mutex_lock_interruptible(&tsc_device->mutex))
- return -ERESTARTSYS;
-
- if (source == TSC_SOURCE_EXTERNAL0) {
- if (!ppinctrl->is_ts0) {
- pr_err("%s: No TS0-in pinctrl definitions were found in the TSC devicetree\n",
- __func__);
- mutex_unlock(&tsc_device->mutex);
- return -EPERM;
- }
-
- /* Transition from current pinctrl state to curr + ts0 active */
- switch (pcurr_state->pcmcia_state) {
- case PCMCIA_STATE_DISABLE:
- if (pcurr_state->ts1)
- ret = pinctrl_select_state(ppinctrl->pinctrl,
- ppinctrl->dual_ts);
- else
- ret = pinctrl_select_state(ppinctrl->pinctrl,
- ppinctrl->ts0);
- break;
- case PCMCIA_STATE_PC_CARD:
- if (pcurr_state->ts1)
- ret = pinctrl_select_state(ppinctrl->pinctrl,
- ppinctrl->dual_ts_pc_card);
- else
- ret = pinctrl_select_state(ppinctrl->pinctrl,
- ppinctrl->ts0_pc_card);
- break;
- case PCMCIA_STATE_CI_CARD:
- if (pcurr_state->ts1)
- ret = pinctrl_select_state(ppinctrl->pinctrl,
- ppinctrl->dual_ts_ci_card);
- else
- ret = pinctrl_select_state(ppinctrl->pinctrl,
- ppinctrl->ts0_ci_card);
- break;
- case PCMCIA_STATE_CI_PLUS:
- if (pcurr_state->ts1)
- ret = pinctrl_select_state(ppinctrl->pinctrl,
- ppinctrl->dual_ts_ci_plus);
- else
- ret = pinctrl_select_state(ppinctrl->pinctrl,
- ppinctrl->ts0_ci_plus);
- break;
- }
- } else { /* source == TSC_SOURCE_EXTERNAL1 */
- if (!ppinctrl->is_ts1) {
- pr_err("%s: No TS1-in pinctrl definitions were found in the TSC devicetree\n",
- __func__);
- mutex_unlock(&tsc_device->mutex);
- return -EPERM;
- }
-
- /* Transition from current pinctrl state to curr + ts1 active */
- switch (pcurr_state->pcmcia_state) {
- case PCMCIA_STATE_DISABLE:
- if (pcurr_state->ts0)
- ret = pinctrl_select_state(ppinctrl->pinctrl,
- ppinctrl->dual_ts);
- else
- ret = pinctrl_select_state(ppinctrl->pinctrl,
- ppinctrl->ts1);
- break;
- case PCMCIA_STATE_PC_CARD:
- if (pcurr_state->ts0)
- ret = pinctrl_select_state(ppinctrl->pinctrl,
- ppinctrl->dual_ts_pc_card);
- else
- ret = pinctrl_select_state(ppinctrl->pinctrl,
- ppinctrl->ts1_pc_card);
- break;
- case PCMCIA_STATE_CI_CARD:
- if (pcurr_state->ts0)
- ret = pinctrl_select_state(ppinctrl->pinctrl,
- ppinctrl->dual_ts_ci_card);
- else
- ret = pinctrl_select_state(ppinctrl->pinctrl,
- ppinctrl->ts1_ci_card);
- break;
- case PCMCIA_STATE_CI_PLUS:
- if (pcurr_state->ts0)
- ret = pinctrl_select_state(ppinctrl->pinctrl,
- ppinctrl->dual_ts_ci_plus);
- else
- ret = pinctrl_select_state(ppinctrl->pinctrl,
- ppinctrl->ts1_ci_plus);
- break;
- }
- }
-
- if (ret != 0) {
- pr_err("%s: error activating TS-in pins. ret value = %d\n",
- __func__, ret);
- mutex_unlock(&tsc_device->mutex);
- return -EINVAL;
- }
-
- /* Update the current pinctrl state in the internal struct */
- if (source == TSC_SOURCE_EXTERNAL0)
- pcurr_state->ts0 = true;
- else
- pcurr_state->ts1 = true;
-
- mutex_unlock(&tsc_device->mutex);
-
- return 0;
-}
-
-/**
- * tsc_enable_disable_tsif() - Enable/disable a TSIF.
- *
- * @tsc_mux: TSC Mux device.
- * @source: The TSIF to enable or disable.
- * @operation: The operation to perform: 0- enable, 1- disable.
- *
- * Enable or disable the specified TSIF, which consequently will block the TS
- * flowing through this TSIF. The update is done by modifying a HW register.
- *
- * Return 0 on success, error value otherwise.
- */
-static int tsc_enable_disable_tsif(struct tsc_mux_chdev *tsc_mux,
- enum tsc_source source, int operation)
-{
- int ret = 0;
- u32 reg;
- u32 addr_offs;
- int reg_offs;
- int curr_disable_state;
-
- switch (source) {
- case TSC_SOURCE_EXTERNAL0:
- reg_offs = 0;
- addr_offs = TSC_IN_IFC_EXT;
- break;
- case TSC_SOURCE_EXTERNAL1:
- reg_offs = 16;
- addr_offs = TSC_IN_IFC_EXT;
- break;
- case TSC_SOURCE_INTERNAL:
- reg_offs = 0;
- addr_offs = TSC_IN_IFC_CFG_INT;
- break;
- case TSC_SOURCE_CICAM:
- reg_offs = 16;
- addr_offs = TSC_IN_IFC_CFG_INT;
- break;
- default:
- pr_err("%s: unidentified source parameter\n", __func__);
- ret = -EINVAL;
- return ret;
- }
-
- /* Reading the current enable/disable state from the register */
- reg = readl_relaxed(tsc_device->base + addr_offs);
- curr_disable_state = GETL_BITS(reg, TSIF_DISABLE_OFFS + reg_offs,
- TSIF_DISABLE_OFFS + reg_offs);
- /* If the current state equals the new state- return success */
- if (curr_disable_state == operation)
- return ret;
-
- if (operation == TSIF_INPUT_DISABLE) {
- if (source == TSC_SOURCE_EXTERNAL0 ||
- source == TSC_SOURCE_EXTERNAL1) {
- /* Disabling the TS-in pins in the TLMM */
- ret = tsc_suspend_ts_pins(source);
- if (ret != 0) {
- pr_err("%s: Error suspending TS-in pins",
- __func__);
- return ret;
- }
- }
- SET_BIT((reg_offs + TSIF_DISABLE_OFFS), reg);
- } else {
- if (source == TSC_SOURCE_EXTERNAL0 ||
- source == TSC_SOURCE_EXTERNAL1) {
- /* Enabling the TS-in pins in the TLMM */
- ret = tsc_activate_ts_pins(source);
- if (ret != 0) {
- pr_err("%s: Error activating TS-in pins",
- __func__);
- return ret;
- }
- }
- CLEAR_BIT((reg_offs + TSIF_DISABLE_OFFS), reg);
- }
-
- /* Writing back to the reg the enable/disable of the TSIF */
- writel_relaxed(reg, tsc_device->base + addr_offs);
-
- return ret;
-}
-
-/**
- * tsc_route_mux() - Configuring one of the TSC muxes.
- *
- * @tsc_mux: TSC Mux device.
- * @source: The requested TS source to be selected by the mux.
- * @dest: The requested mux.
- *
- * Configuring the specified mux to pass the TS indicated by the src parameter.
- * The update is done by modifying a HW register.
- *
- * Return 0 on success, error value otherwise.
- */
-static int tsc_route_mux(struct tsc_mux_chdev *tsc_mux, enum tsc_source source,
- enum tsc_dest dest)
-{
- int ret = 0;
- u32 mux_cfg_reg;
- int src_val;
-
- switch (source) {
- case TSC_SOURCE_EXTERNAL0:
- src_val = MUX_EXTERNAL_DEMOD_0;
- break;
- case TSC_SOURCE_EXTERNAL1:
- src_val = MUX_EXTERNAL_DEMOD_1;
- break;
- case TSC_SOURCE_INTERNAL:
- src_val = MUX_INTERNAL_DEMOD;
- break;
- case TSC_SOURCE_CICAM:
- src_val = MUX_CICAM;
- break;
- default:
- pr_err("%s: unidentified source parameter\n", __func__);
- ret = -EINVAL;
- goto err;
- }
-
- /* Reading the current muxes state, to change only the requested mux */
- mux_cfg_reg = readl_relaxed(tsc_device->base + TSC_MUX_CFG);
-
- switch (dest) {
- case TSC_DEST_TSPP0:
- mux_cfg_reg &= ~(0x3 << MUX0_OFFS);
- mux_cfg_reg |= (src_val << MUX0_OFFS);
- break;
- case TSC_DEST_TSPP1:
- mux_cfg_reg &= ~(0x3 << MUX1_OFFS);
- mux_cfg_reg |= (src_val << MUX1_OFFS);
- break;
- case TSC_DEST_CICAM:
- if (src_val == TSC_SOURCE_CICAM) {
- pr_err("%s: Error: CICAM cannot be source and dest\n",
- __func__);
- ret = -EINVAL;
- goto err;
- }
- mux_cfg_reg &= ~(0x3 << MUX_CAM_OFFS);
- mux_cfg_reg |= (src_val << MUX_CAM_OFFS);
- break;
- default:
- pr_err("%s: unidentified dest parameter\n", __func__);
- ret = -EINVAL;
- goto err;
- }
-
- writel_relaxed(mux_cfg_reg, tsc_device->base + TSC_MUX_CFG);
-
-err:
- return ret;
-}
-
-/**
- * is_tsc_idle() - Checking if TSC is idle.
- *
- * @tsc_ci: TSC CI device.
- *
- * Reading the TSC state-machine register and checking if the TSC is busy in
- * one of the operations reflected by this register.
- *
- * Return true if the TSC is idle and false if it's busy.
- */
-static bool is_tsc_idle(struct tsc_ci_chdev *tsc_ci)
-{
- u32 fsm_reg;
-
- fsm_reg = readl_relaxed(tsc_device->base + TSC_FSM_STATE);
- if (GETL_BITS(fsm_reg, FSM_STATE_BUFFER_BEG, FSM_STATE_BUFFER_END) ||
- GETL_BITS(fsm_reg, FSM_STATE_POLL_BEG, FSM_STATE_POLL_END) ||
- GETL_BITS(fsm_reg, FSM_STATE_BYTE_BEG, FSM_STATE_BYTE_END) ||
- GETL_BITS(fsm_reg, FSM_STATE_MEM_WR_BEG,
- FSM_STATE_MEM_WR_END) ||
- GETL_BITS(fsm_reg, FSM_STATE_MEM_RD_BEG,
- FSM_STATE_MEM_RD_END) ||
- GETL_BITS(fsm_reg, FSM_STATE_IO_RD_BEG, FSM_STATE_IO_RD_END) ||
- GETL_BITS(fsm_reg, FSM_STATE_IO_WR_BEG, FSM_STATE_IO_WR_END) ||
- tsc_ci->data_busy)
- return false;
-
- tsc_ci->data_busy = true;
-
- return true;
-}
-
-
-/**
- * tsc_power_on_buff_mode_clocks() - power-on the TSPP2 and VBIF clocks.
- *
- * Power-on the TSPP2 and the VBIF clocks required for buffer mode transaction.
- *
- * Return 0 on success, error value otherwise.
- */
-static int tsc_power_on_buff_mode_clocks(void)
-{
- int ret = 0;
-
- ret = clk_prepare_enable(tsc_device->tspp2_core_clk);
- if (ret != 0) {
- pr_err("%s: Can't start tspp2_core_clk", __func__);
- goto err_tspp2;
- }
- ret = clk_prepare_enable(tsc_device->vbif_tspp2_clk);
- if (ret != 0) {
- pr_err("%s: Can't start vbif_tspp2_clk", __func__);
- goto err_vbif_tspp2;
- }
- ret = clk_prepare_enable(tsc_device->vbif_ahb_clk);
- if (ret != 0) {
- pr_err("%s: Can't start vbif_ahb_clk", __func__);
- goto err_vbif_ahb;
- }
- ret = clk_prepare_enable(tsc_device->vbif_axi_clk);
- if (ret != 0) {
- pr_err("%s: Can't start vbif_axi_clk", __func__);
- goto err_vbif_axi;
- }
-
- return ret;
-
-err_vbif_axi:
- clk_disable_unprepare(tsc_device->vbif_ahb_clk);
-err_vbif_ahb:
- clk_disable_unprepare(tsc_device->vbif_tspp2_clk);
-err_vbif_tspp2:
- clk_disable_unprepare(tsc_device->tspp2_core_clk);
-err_tspp2:
- return ret;
-}
-
-/**
- * tsc_power_off_buff_mode_clocks() - power-off the SPP2 and VBIF clocks.
- *
- * Power-off the TSPP2 and the VBIF clocks required for buffer mode transaction.
- */
-static void tsc_power_off_buff_mode_clocks(void)
-{
- clk_disable_unprepare(tsc_device->vbif_axi_clk);
- clk_disable_unprepare(tsc_device->vbif_ahb_clk);
- clk_disable_unprepare(tsc_device->tspp2_core_clk);
- clk_disable_unprepare(tsc_device->vbif_tspp2_clk);
-}
-
-/**
- * tsc_config_cam_data_transaction() - Configuring a new data transaction.
- *
- * @addr_size: The value for the address_size register field- address when
- * using single byte-mode, and size when using buffer mode.
- * @wr_data: the value for the wr_data register field- data to write to the
- * cam when using single byte mode.
- * @io_mem: The value for the io_mem register field- 1 for IO transaction,
- * 0 for memory transaction.
- * @read_write: The value for the read_write register field- 1 for read
- * transaction, 0 for write transaction.
- * @buff_mode: The value for the buff_mode register field- 1 for buffer mode,
- * 0 for single byte mode.
- *
- * Configuring the cam cmd register with the specified parameters, to initiate
- * data transaction with the cam.
- */
-static void tsc_config_cam_data_transaction(u16 addr_size,
- u8 wr_data,
- uint io_mem,
- uint read_write,
- uint buff_mode)
-{
- u32 cam_cmd_reg = 0;
-
- cam_cmd_reg |= (addr_size << CAM_CMD_ADDR_SIZE_OFFS);
- cam_cmd_reg |= (wr_data << CAM_CMD_WR_DATA_OFFS);
- cam_cmd_reg |= (io_mem << CAM_CMD_IO_MEM_OFFS);
- cam_cmd_reg |= (read_write << CAM_CMD_RD_WR_OFFS);
- cam_cmd_reg |= (buff_mode << CAM_CMD_BUFF_MODE_OFFS);
- writel_relaxed(cam_cmd_reg, tsc_device->base + TSC_CAM_CMD);
-}
-
-/**
- * tsc_data_transaction() - Blocking function that manage the data transactions.
- *
- * @tsc_ci: TSC CI device.
- * @io_mem: The value for the io_mem register field- 1 for IO transaction,
- * 0 for memory transaction.
- * @read_write: The value for the read_write register field- 1 for read
- * transaction, 0 for write transaction.
- * @buff_mode: The value for the buff_mode register field- 1 for buffer mode,
- * 0 for single byte mode.
- * @arg: The argument received from the user-space via a data transaction
- * IOCTL. It is from one of the two following types:
- * "struct tsc_single_byte_mode" and "struct tsc_buffer_mode".
- *
- * Receiving the transaction paramters from the user-space. Configure the HW
- * registers to initiate a data transaction with the cam. Wait for an
- * interrupt indicating the transaction is over and return the the data read
- * from the cam in case of single-byte read transaction.
- *
- * Return 0 on success, error value otherwise.
- */
-static int tsc_data_transaction(struct tsc_ci_chdev *tsc_ci, uint io_mem,
- uint read_write, uint buff_mode, unsigned long arg)
-{
- struct tsc_single_byte_mode arg_byte;
- struct tsc_buffer_mode arg_buff;
- u16 addr_size;
- u8 wr_data;
- uint timeout;
- u32 cam_cmd_reg;
- struct ion_handle *ion_handle = NULL;
- ion_phys_addr_t iova = 0;
- unsigned long buffer_size = 0;
- unsigned long flags = 0;
- int ret = 0;
-
- if (!arg)
- return -EINVAL;
-
- /* make sure the tsc is in idle state before configuring the cam */
- if (!is_tsc_idle(tsc_ci)) {
- ret = -EBUSY;
- goto finish;
- }
-
- INIT_COMPLETION(tsc_ci->transaction_finish);
-
- /* copying data from the ioctl parameter */
- if (buff_mode == SINGLE_BYTE_MODE) {
- if (copy_from_user(&arg_byte, (void *)arg,
- sizeof(struct tsc_single_byte_mode))) {
- ret = -EFAULT;
- goto err_copy_arg;
- }
- addr_size = arg_byte.address;
- if (IO_TRANSACTION == io_mem &&
- addr_size > CICAM_MAX_ADDRESS) {
- pr_err("%s: wrong address parameter: %d\n", __func__,
- addr_size);
- ret = -EFAULT;
- goto err_copy_arg;
- }
- wr_data = arg_byte.data;
- timeout = arg_byte.timeout;
- } else {
- if (copy_from_user(&arg_buff, (void *)arg,
- sizeof(struct tsc_buffer_mode))) {
- ret = -EFAULT;
- goto err_copy_arg;
- }
- addr_size = arg_buff.buffer_size;
- if (!addr_size) {
- pr_err("%s: size parameter is 0\n", __func__);
- ret = -EFAULT;
- goto err_copy_arg;
- }
- wr_data = 0;
- timeout = arg_buff.timeout;
-
- /* import ion handle from the ion fd passed from user-space */
- ion_handle = ion_import_dma_buf
- (tsc_device->iommu_info.ion_client, arg_buff.buffer_fd);
- if (IS_ERR_OR_NULL(ion_handle)) {
- pr_err("%s: get_ION_handle failed\n", __func__);
- ret = -EIO;
- goto err_ion_handle;
- }
-
- /*
- * mapping the ion handle to the VBIF and get the virtual
- * address
- */
- ret = ion_map_iommu(tsc_device->iommu_info.ion_client,
- ion_handle, tsc_device->iommu_info.domain_num,
- tsc_device->iommu_info.partition_num, SZ_4K,
- 0, &iova, &buffer_size, 0, 0);
-
- if (ret != 0) {
- pr_err("%s: get_ION_kernel physical addr fail\n",
- __func__);
- goto err_ion_map;
- }
-
- /*
- * writing the buffer virtual address to the register for buffer
- * address of buffer mode
- */
- if (read_write == READ_TRANSACTION)
- writel_relaxed(iova,
- tsc_device->base + TSC_RD_BUFF_ADDR);
- else /* write transaction */
- writel_relaxed(iova,
- tsc_device->base + TSC_WR_BUFF_ADDR);
- }
-
- /* configuring the cam command register */
- tsc_config_cam_data_transaction(addr_size, wr_data, io_mem, read_write,
- buff_mode);
-
- /*
- * This function assume the mutex is locked before calling the function,
- * so mutex has to be unlocked before going to sleep when waiting for
- * the transaction.
- */
- mutex_unlock(&tsc_ci->mutex);
- /* waiting for EOT interrupt or timeout */
- if (!wait_for_completion_timeout(&tsc_ci->transaction_complete,
- msecs_to_jiffies(timeout))) {
- pr_err("%s: Error: wait for transaction timed-out\n", __func__);
- ret = -ETIMEDOUT;
- mutex_lock(&tsc_ci->mutex);
- /* Aborting the transaction if it's buffer mode */
- if (buff_mode) {
- cam_cmd_reg = readl_relaxed(tsc_device->base +
- TSC_CAM_CMD);
- SET_BIT(CAM_CMD_ABORT, cam_cmd_reg);
- writel_relaxed(cam_cmd_reg, tsc_device->base +
- TSC_CAM_CMD);
- }
- goto finish;
- }
- mutex_lock(&tsc_ci->mutex);
-
- /* Checking if transaction ended with error */
- spin_lock_irqsave(&tsc_ci->spinlock, flags);
- if (tsc_ci->transaction_state == TRANSACTION_ERROR) {
- tsc_ci->transaction_state = BEFORE_TRANSACTION;
- spin_unlock_irqrestore(&tsc_ci->spinlock, flags);
- pr_err("%s: Transaction error\n", __func__);
- ret = -EBADE; /* Invalid exchange error code */
- goto finish;
- } else if (tsc_ci->transaction_state == TRANSACTION_CARD_REMOVED) {
- tsc_ci->transaction_state = BEFORE_TRANSACTION;
- spin_unlock_irqrestore(&tsc_ci->spinlock, flags);
- pr_err("%s: Card was removed during the transaction. Aborting\n",
- __func__);
- ret = -ECONNABORTED;
- /* Aborting the transaction if it's buffer mode */
- if (buff_mode) {
- cam_cmd_reg = readl_relaxed(tsc_device->base +
- TSC_CAM_CMD);
- SET_BIT(CAM_CMD_ABORT, cam_cmd_reg);
- writel_relaxed(cam_cmd_reg, tsc_device->base +
- TSC_CAM_CMD);
- }
- goto finish;
- }
-
- /* reseting the argument after reading the interrupt type */
- tsc_ci->transaction_state = BEFORE_TRANSACTION;
- spin_unlock_irqrestore(&tsc_ci->spinlock, flags);
-
- /*
- * Only on case of read single byte operation, we need to copy the data
- * to the arg data field
- */
- if (buff_mode == SINGLE_BYTE_MODE && read_write == READ_TRANSACTION)
- ret = put_user(readl_relaxed(tsc_device->base +
- TSC_CAM_RD_DATA),
- &((struct tsc_single_byte_mode *)arg)->data);
-
-finish:
- if (iova != 0)
- ion_unmap_iommu(tsc_device->iommu_info.ion_client, ion_handle,
- tsc_device->iommu_info.domain_num,
- tsc_device->iommu_info.partition_num);
-err_ion_map:
- if (!IS_ERR_OR_NULL(ion_handle))
- ion_free(tsc_device->iommu_info.ion_client, ion_handle);
-err_ion_handle:
-err_copy_arg:
- tsc_ci->data_busy = false;
- INIT_COMPLETION(tsc_ci->transaction_complete);
- complete_all(&tsc_ci->transaction_finish);
- return ret;
-}
-
-/**
- * tsc_personality_change() - change the PCMCIA pins state.
- *
- * @pcmcia_state: The new state of the PCMCIA pins.
- *
- * Configure the TLMM pins of the PCMCIA according to received state and
- * the current pinctrl configuration of the other pins. This function assums the
- * PCMCIA pinctrl definitions were successfully parsed from the devicetree (this
- * check is done at open device).
- *
- * Return 0 on success, error value otherwise.
- */
-static int tsc_personality_change(enum tsc_cam_personality pcmcia_state)
-{
- int ret = 0;
- struct pinctrl_info *ppinctrl = &tsc_device->pinctrl_info;
- struct pinctrl_current_state *pcurr_state = &ppinctrl->curr_state;
- u32 reg = 0;
-
- if (mutex_lock_interruptible(&tsc_device->mutex))
- return -ERESTARTSYS;
-
- if (pcmcia_state == (enum tsc_cam_personality)pcurr_state->pcmcia_state)
- goto exit;
-
- /* Transition from current pinctrl state to curr + new pcmcia state */
- switch (pcmcia_state) {
- case TSC_CICAM_PERSONALITY_CI:
- if (pcurr_state->ts0 && pcurr_state->ts1)
- ret = pinctrl_select_state(ppinctrl->pinctrl,
- ppinctrl->dual_ts_ci_card);
- else if (pcurr_state->ts0 && !pcurr_state->ts1)
- ret = pinctrl_select_state(ppinctrl->pinctrl,
- ppinctrl->ts0_ci_card);
- else if (!pcurr_state->ts0 && pcurr_state->ts1)
- ret = pinctrl_select_state(ppinctrl->pinctrl,
- ppinctrl->ts1_ci_card);
- else
- ret = pinctrl_select_state(ppinctrl->pinctrl,
- ppinctrl->ci_card);
- break;
- case TSC_CICAM_PERSONALITY_CIPLUS:
- if (pcurr_state->ts0 && pcurr_state->ts1)
- ret = pinctrl_select_state(ppinctrl->pinctrl,
- ppinctrl->dual_ts_ci_plus);
- else if (pcurr_state->ts0 && !pcurr_state->ts1)
- ret = pinctrl_select_state(ppinctrl->pinctrl,
- ppinctrl->ts0_ci_plus);
- else if (!pcurr_state->ts0 && pcurr_state->ts1)
- ret = pinctrl_select_state(ppinctrl->pinctrl,
- ppinctrl->ts1_ci_plus);
- else
- ret = pinctrl_select_state(ppinctrl->pinctrl,
- ppinctrl->ci_plus);
- break;
- case TSC_CICAM_PERSONALITY_DISABLE:
- if (pcurr_state->ts0 && pcurr_state->ts1)
- ret = pinctrl_select_state(ppinctrl->pinctrl,
- ppinctrl->dual_ts);
- else if (pcurr_state->ts0 && !pcurr_state->ts1)
- ret = pinctrl_select_state(ppinctrl->pinctrl,
- ppinctrl->ts0);
- else if (!pcurr_state->ts0 && pcurr_state->ts1)
- ret = pinctrl_select_state(ppinctrl->pinctrl,
- ppinctrl->ts1);
- else
- ret = pinctrl_select_state(ppinctrl->pinctrl,
- ppinctrl->disable);
- break;
- default:
- pr_err("%s: Wrong personality parameter\n", __func__);
- ret = -EINVAL;
- goto exit;
- }
-
- if (ret != 0) {
- pr_err("%s: error changing PCMCIA pins. ret value = %d\n",
- __func__, ret);
- ret = -EINVAL;
- goto exit;
- }
-
- /* Update the current pcmcia state in the internal struct */
- pcurr_state->pcmcia_state = (enum pcmcia_state)pcmcia_state;
-
- /*
- * Setting CAM TSIF OE to enable I/O transactions for CI/+ cards
- * or clearing it when moving to disable state
- */
- if (TSC_CICAM_PERSONALITY_CI == pcmcia_state ||
- TSC_CICAM_PERSONALITY_CIPLUS == pcmcia_state) {
- SET_BIT(TSC_CICAM_TSIF_OE_OFFS, reg);
- writel_relaxed(reg, tsc_device->base + TSC_CICAM_TSIF);
- } else {
- CLEAR_BIT(TSC_CICAM_TSIF_OE_OFFS, reg);
- writel_relaxed(reg, tsc_device->base + TSC_CICAM_TSIF);
- }
-
-exit:
- mutex_unlock(&tsc_device->mutex);
- return ret;
-}
-
-/**
- * tsc_reset_cam() - HW reset to the CAM.
- *
- * Toggle the reset pin of the pcmcia to make a HW reset.
- * This function assumes that pinctrl_select_state was already called on the
- * reset pin with its active state (happens during personality change).
- *
- * Return 0 on success, error value otherwise.
- */
-static int tsc_reset_cam(void)
-{
- int ret;
- int reset_gpio = tsc_device->reset_cam_gpio;
-
- /* Toggle the GPIO to create a reset pulse */
- ret = gpio_direction_output(reset_gpio, 0); /* Make sure it's 0 */
- if (ret != 0)
- goto err;
-
- ret = gpio_direction_output(reset_gpio, 1); /* Assert */
- if (ret != 0)
- goto err;
-
- /*
- * Waiting to enable the CAM to process the assertion before the
- * deassertion. 1ms is needed for this processing.
- */
- usleep(1000);
-
- ret = gpio_direction_output(reset_gpio, 0); /* Deassert */
- if (ret != 0)
- goto err;
-
- return 0;
-err:
- pr_err("%s: Failed writing to reset cam GPIO\n", __func__);
- return ret;
-}
-
-/**
- * tsc_reset_registers() - Reset the TSC registers.
- *
- * Write specific reset values to the TSC registers, managed by the driver.
- */
-static void tsc_reset_registers(void)
-{
- /* Reset state - all mux transfer ext. demod 0 */
- writel_relaxed(0x00000000, tsc_device->base + TSC_MUX_CFG);
-
- /* Disabling TSIFs inputs, putting polarity to normal, data as serial */
- writel_relaxed(0x02000200, tsc_device->base + TSC_IN_IFC_EXT);
- writel_relaxed(0x02000200, tsc_device->base + TSC_IN_IFC_CFG_INT);
-
- /* Reseting TSC_FSM_STATE_MASK to represent all the states but poll */
- writel_relaxed(0x3333300F, tsc_device->base + TSC_FSM_STATE_MASK);
-
- /* Clearing all the CAM interrupt */
- writel_relaxed(0x1F, tsc_device->base + TSC_IRQ_CLR);
-
- /* Disabling all cam interrupts (enable is done at - open) */
- writel_relaxed(0x00, tsc_device->base + TSC_IRQ_ENA);
-
- /* Disabling HW polling */
- writel_relaxed(0x00, tsc_device->base + TSC_CIP_CFG);
-
- /* Reset state - address for read/write buffer */
- writel_relaxed(0x00000000, tsc_device->base + TSC_RD_BUFF_ADDR);
- writel_relaxed(0x00000000, tsc_device->base + TSC_WR_BUFF_ADDR);
-
- /* Clearing false cd counter */
- writel_relaxed(0x01, tsc_device->base + TSC_FALSE_CD_CLR);
- writel_relaxed(0x00, tsc_device->base + TSC_FALSE_CD_CLR);
-
- /* Disabling TSIF out to cicam and IO read/write with the CAM */
- writel_relaxed(0x00000000, tsc_device->base + TSC_CICAM_TSIF);
-}
-
-/**
- * tsc_disable_tsifs() - Disable all the TSC Tsifs.
- *
- * Disable the TSIFs of the ext. demods, the int. demod and the cam on both
- * directions.
- */
-static void tsc_disable_tsifs(void)
-{
- u32 reg;
-
- /* Ext. TSIFs */
- reg = readl_relaxed(tsc_device->base + TSC_IN_IFC_EXT);
- SET_BIT(TSIF_DISABLE_OFFS, reg);
- SET_BIT((TSIF_DISABLE_OFFS + 16), reg);
- writel_relaxed(reg, tsc_device->base + TSC_IN_IFC_EXT);
-
- /* Int. TSIF and TSIF-in from the CAM */
- reg = readl_relaxed(tsc_device->base + TSC_IN_IFC_CFG_INT);
- SET_BIT(TSIF_DISABLE_OFFS, reg);
- SET_BIT((TSIF_DISABLE_OFFS + 16), reg);
- writel_relaxed(reg, tsc_device->base + TSC_IN_IFC_CFG_INT);
-}
-
-/**
- * tsc_power_on_clocks() - power-on the TSC clocks.
- *
- * Power-on the TSC clocks required for Mux and/or CI operations.
- *
- * Return 0 on success, error value otherwise.
- */
-static int tsc_power_on_clocks(void)
-{
- int ret = 0;
- unsigned long rate_in_hz = 0;
-
- /* Enabling the clocks */
- ret = clk_prepare_enable(tsc_device->ahb_clk);
- if (ret != 0) {
- pr_err("%s: Can't start tsc_ahb_clk", __func__);
- return ret;
- }
-
- /* We need to set the rate of ci clock before enabling it */
- rate_in_hz = clk_round_rate(tsc_device->ci_clk, 1);
- if (clk_set_rate(tsc_device->ci_clk, rate_in_hz)) {
- pr_err("%s: Failed to set rate to tsc_ci clock\n", __func__);
- goto err;
- }
-
- ret = clk_prepare_enable(tsc_device->ci_clk);
- if (ret != 0) {
- pr_err("%s: Can't start tsc_ci_clk", __func__);
- goto err;
- }
-
- return ret;
-err:
- clk_disable_unprepare(tsc_device->ahb_clk);
- return ret;
-}
-
-/**
- * tsc_power_off_clocks() - power-off the TSC clocks.
- *
- * Power-off the TSC clocks required for Mux and/or CI operations.
- */
-static void tsc_power_off_clocks(void)
-{
- clk_disable_unprepare(tsc_device->ahb_clk);
- clk_disable_unprepare(tsc_device->ci_clk);
-}
-
-/**
- * tsc_mux_power_on_clocks() - power-on the TSC Mux clocks.
- *
- * Power-on the TSC clocks required only for Mux operations, and not for CI.
- *
- * Return 0 on success, error value otherwise.
- */
-static int tsc_mux_power_on_clocks(void)
-{
- int ret = 0;
-
- /* Setting the cicam clock rate */
- ret = clk_set_rate(tsc_device->cicam_ts_clk, CICAM_CLK_RATE_7MHZ);
- if (ret != 0) {
- pr_err("%s: Can't set rate for tsc_cicam_ts_clk", __func__);
- goto err_set_rate;
- }
-
- /* Setting the TSC serial clock rate */
- ret = clk_set_rate(tsc_device->ser_clk, TSC_SER_CLK_RATE);
- if (ret != 0) {
- pr_err("%s: Can't set rate for tsc serial clock", __func__);
- goto err_set_rate;
- }
-
- /* Setting the TSC parallel clock rate */
- ret = clk_set_rate(tsc_device->par_clk, TSC_PAR_CLK_RATE);
- if (ret != 0) {
- pr_err("%s: Can't set rate for tsc parallel clock", __func__);
- goto err_set_rate;
- }
-
- /* Enabling the clocks */
- ret = clk_prepare_enable(tsc_device->ser_clk);
- if (ret != 0) {
- pr_err("%s: Can't start tsc_ser_clk", __func__);
- goto err_ser_clk;
- }
- ret = clk_prepare_enable(tsc_device->par_clk);
- if (ret != 0) {
- pr_err("%s: Can't start tsc_par_clk", __func__);
- goto err_par_clk;
- }
- ret = clk_prepare_enable(tsc_device->cicam_ts_clk);
- if (ret != 0) {
- pr_err("%s: Can't start tsc_cicam_ts_clk", __func__);
- goto err_cicam_ts_clk;
- }
-
- return ret;
-
-err_cicam_ts_clk:
- clk_disable_unprepare(tsc_device->par_clk);
-err_par_clk:
- clk_disable_unprepare(tsc_device->ser_clk);
-err_ser_clk:
-err_set_rate:
- return ret;
-}
-
-/**
- * tsc_mux_power_off_clocks() - power-off the TSC Mux clocks.
- *
- * Power-off the TSC clocks required only for Mux operations, and not for CI.
- */
-static void tsc_mux_power_off_clocks(void)
-{
- clk_disable_unprepare(tsc_device->ser_clk);
- clk_disable_unprepare(tsc_device->par_clk);
- clk_disable_unprepare(tsc_device->cicam_ts_clk);
-}
-
-/**
- * tsc_device_power_up() - Power init done by the first device opened.
- *
- * Check if it's the first device and enable the GDSC,power-on the TSC clocks
- * required for both Mux and CI, Vote for the bus and reset the registers to a
- * known default values.
- *
- * Return 0 on success, error value otherwise.
- */
-static int tsc_device_power_up(void)
-{
- int ret = 0;
-
- if (mutex_lock_interruptible(&tsc_device->mutex))
- return -ERESTARTSYS;
-
- if (tsc_device->num_device_open > 0)
- goto not_first_device;
-
- /* Enable the GDSC */
- ret = regulator_enable(tsc_device->gdsc);
- if (ret != 0) {
- pr_err("%s: Failed to enable regulator\n", __func__);
- goto err_regulator;
- }
-
- /* Power-on the clocks needed by Mux and CI */
- ret = tsc_power_on_clocks();
- if (ret != 0)
- goto err_power_clocks;
-
- /* Voting for bus bandwidth */
- if (tsc_device->bus_client) {
- ret = msm_bus_scale_client_update_request
- (tsc_device->bus_client, 1);
- if (ret) {
- pr_err("%s: Can't enable bus\n", __func__);
- goto err_bus;
- }
- }
-
- /* Reset the TSC TLMM pins to a default state */
- ret = pinctrl_select_state(tsc_device->pinctrl_info.pinctrl,
- tsc_device->pinctrl_info.disable);
- if (ret != 0) {
- pr_err("%s: Failed to disable the TLMM pins\n", __func__);
- goto err_pinctrl;
- }
- /* Update the current pinctrl state in the internal struct */
- tsc_device->pinctrl_info.curr_state.ts0 = false;
- tsc_device->pinctrl_info.curr_state.ts1 = false;
- tsc_device->pinctrl_info.curr_state.pcmcia_state =
- TSC_CICAM_PERSONALITY_DISABLE;
-
- /* Reset TSC registers to a default known state */
- tsc_reset_registers();
-
-not_first_device:
- tsc_device->num_device_open++;
- mutex_unlock(&tsc_device->mutex);
- return ret;
-
-err_pinctrl:
- if (tsc_device->bus_client)
- msm_bus_scale_client_update_request(tsc_device->bus_client, 0);
-err_bus:
- tsc_power_off_clocks();
-err_power_clocks:
- regulator_disable(tsc_device->gdsc);
-err_regulator:
- mutex_unlock(&tsc_device->mutex);
- return ret;
-}
-
-/**
- * tsc_device_power_off() - Power off done by the last device closed.
- *
- * Check if it's the last device and unvote the bus, power-off the TSC clocks
- * required for both Mux and CI, disable the TLMM pins and disable the GDSC.
- */
-static void tsc_device_power_off(void)
-{
- mutex_lock(&tsc_device->mutex);
-
- if (tsc_device->num_device_open > 1)
- goto not_last_device;
-
- pinctrl_select_state(tsc_device->pinctrl_info.pinctrl,
- tsc_device->pinctrl_info.disable);
- if (tsc_device->bus_client)
- msm_bus_scale_client_update_request(tsc_device->bus_client, 0);
-
- tsc_power_off_clocks();
- regulator_disable(tsc_device->gdsc);
-
-not_last_device:
- tsc_device->num_device_open--;
- mutex_unlock(&tsc_device->mutex);
-}
-
-
-/************************** TSC file operations **************************/
-/**
- * tsc_mux_open() - init the TSC Mux char device.
- *
- * @inode: The inode associated with the TSC Mux device.
- * @flip: The file pointer associated with the TSC Mux device.
- *
- * Enables only one open Mux device.
- * Init all the data structures and vote for all the power resources needed.
- * Manage reference counters for initiating resources upon first open.
- *
- * Return 0 on success, error value otherwise.
- */
-static int tsc_mux_open(struct inode *inode, struct file *filp)
-{
- struct tsc_mux_chdev *tsc_mux;
- int ret = 0;
- u32 ena_reg;
-
- if (mutex_lock_interruptible(&tsc_device->mux_chdev.mutex))
- return -ERESTARTSYS;
-
- if (tsc_device->num_mux_opened > 0) {
- pr_err("%s: Too many devices open\n", __func__);
- mutex_unlock(&tsc_device->mux_chdev.mutex);
- return -EMFILE;
- }
- tsc_device->num_mux_opened++;
-
- tsc_mux = container_of(inode->i_cdev, struct tsc_mux_chdev, cdev);
- filp->private_data = tsc_mux;
-
- /* Init all resources if it's the first device (checked inside) */
- ret = tsc_device_power_up();
- if (ret != 0)
- goto err_first_device;
-
- /* Power-on the Mux clocks */
- ret = tsc_mux_power_on_clocks();
- if (ret != 0)
- goto err_mux_clocks;
-
- /* Init TSC Mux args */
- spin_lock_init(&tsc_mux->spinlock);
- init_waitqueue_head(&tsc_mux->poll_queue);
- tsc_mux->rate_interrupt = false;
-
- /* Enabling TSC Mux cam interrupt of rate mismatch */
- ena_reg = readl_relaxed(tsc_device->base + TSC_IRQ_ENA);
- SET_BIT(CAM_IRQ_RATE_MISMATCH_OFFS, ena_reg);
- writel_relaxed(ena_reg, tsc_device->base + TSC_IRQ_ENA);
-
- mutex_unlock(&tsc_device->mux_chdev.mutex);
-
- return ret;
-
-err_mux_clocks:
- /* De-init all resources if it's the only device (checked inside) */
- tsc_device_power_off();
-err_first_device:
- tsc_device->num_mux_opened--;
- mutex_unlock(&tsc_device->mux_chdev.mutex);
- return ret;
-}
-
-/**
- * tsc_ci_open() - init the TSC CI char device.
- *
- * @inode: The inode associated with the TSC Mux device.
- * @flip: The file pointer associated with the TSC Mux device.
- *
- * Enables only one open CI device.
- * Init all the data structures and vote for all the power resources needed.
- * Manage reference counters for initiating resources upon first open.
- *
- * Return 0 on success, error value otherwise.
- */
-static int tsc_ci_open(struct inode *inode, struct file *filp)
-{
- struct tsc_ci_chdev *tsc_ci;
- int ret = 0;
- u32 ena_reg;
-
- if (mutex_lock_interruptible(&tsc_device->ci_chdev.mutex))
- return -ERESTARTSYS;
-
- if (tsc_device->num_ci_opened > 0) {
- pr_err("%s: Too many devices open\n", __func__);
- mutex_unlock(&tsc_device->ci_chdev.mutex);
- return -EMFILE;
- }
-
- if (!tsc_device->pinctrl_info.is_pcmcia) {
- pr_err("%s: No pcmcia pinctrl definitions were found in the TSC devicetree\n",
- __func__);
- mutex_unlock(&tsc_device->ci_chdev.mutex);
- return -EPERM;
- }
-
- tsc_device->num_ci_opened++;
-
- tsc_ci = container_of(inode->i_cdev, struct tsc_ci_chdev, cdev);
- filp->private_data = tsc_ci;
-
- /* Init all resources if it's the first device (checked inside) */
- ret = tsc_device_power_up();
- if (ret != 0)
- goto err_first_device;
-
- /* powering-up the tspp2 and VBIF clocks */
- ret = tsc_power_on_buff_mode_clocks();
- if (ret != 0)
- goto err_buff_clocks;
-
- /* Request reset CAM GPIO */
- ret = gpio_request(tsc_device->reset_cam_gpio, "tsc_ci_reset");
- if (ret != 0) {
- pr_err("%s: Failed to request reset CAM GPIO\n", __func__);
- goto err_gpio_req;
- }
-
- /* Set the reset line to default "no card" state */
- ret = gpio_direction_output(tsc_device->reset_cam_gpio, 1);
- if (ret != 0) {
- pr_err("%s: Failed to assert the reset CAM GPIO\n", __func__);
- goto err_assert;
- }
-
- /* Attach the iommu group to support the required memory mapping */
- if (!tsc_iommu_bypass) {
- ret = iommu_attach_group(tsc_device->iommu_info.domain,
- tsc_device->iommu_info.group);
- if (ret != 0) {
- pr_err("%s: iommu_attach_group failed\n", __func__);
- goto err_iommu_attach;
- }
- }
-
- /* Init TSC CI args */
- spin_lock_init(&tsc_ci->spinlock);
- init_waitqueue_head(&tsc_ci->poll_queue);
- tsc_ci->transaction_state = BEFORE_TRANSACTION;
- tsc_ci->data_busy = false;
- tsc_device->card_power = false;
-
- /*
- * Init hw card status flag according to the pins' state.
- * No need to protect from interrupt because the handler is not
- * registred yet.
- */
- tsc_update_hw_card_status();
- tsc_ci->card_status = tsc_device->hw_card_status;
-
- /* If a card is already inserted - need to power up the card */
- if (tsc_device->hw_card_status == TSC_CARD_STATUS_DETECTED) {
- ret = tsc_card_power_up();
- if (ret != 0)
- pr_err("%s: card power-up failed\n", __func__);
- else
- tsc_device->card_power = true;
- }
-
- /* Enabling the TSC CI cam interrupts: EOT and Err */
- ena_reg = readl_relaxed(tsc_device->base + TSC_IRQ_ENA);
- SET_BIT(CAM_IRQ_EOT_OFFS, ena_reg);
- SET_BIT(CAM_IRQ_ERR_OFFS, ena_reg);
- writel_relaxed(ena_reg, tsc_device->base + TSC_IRQ_ENA);
-
- /* Registering the CAM cmd interrupt handler */
- ret = request_irq(tsc_device->cam_cmd_irq, tsc_cam_cmd_irq_handler,
- IRQF_SHARED, dev_name(&tsc_device->pdev->dev),
- tsc_device);
- if (ret) {
- pr_err("%s: failed to request TSC IRQ %d : %d",
- __func__, tsc_device->cam_cmd_irq, ret);
- goto err_cam_irq;
- }
-
- /*
- * Registering the card detect interrupt handler (this interrupt is
- * enabled by default, right after this registration)
- */
- ret = request_threaded_irq(tsc_device->card_detection_irq,
- NULL, tsc_card_detect_irq_thread_handler,
- IRQF_ONESHOT | IRQF_TRIGGER_RISING,
- dev_name(&tsc_device->pdev->dev), tsc_device);
- if (ret) {
- pr_err("%s: failed to request TSC IRQ %d : %d",
- __func__, tsc_device->card_detection_irq, ret);
- goto err_card_irq;
- }
-
- mutex_unlock(&tsc_device->ci_chdev.mutex);
-
- return ret;
-
-err_card_irq:
- free_irq(tsc_device->cam_cmd_irq, tsc_device);
-err_cam_irq:
- if (!tsc_iommu_bypass)
- iommu_detach_group(tsc_device->iommu_info.domain,
- tsc_device->iommu_info.group);
-err_iommu_attach:
- gpio_free(tsc_device->reset_cam_gpio);
-err_assert:
-err_gpio_req:
- tsc_power_off_buff_mode_clocks();
-err_buff_clocks:
- /* De-init all resources if it's the only device (checked inside) */
- tsc_device_power_off();
-err_first_device:
- tsc_device->num_ci_opened--;
- mutex_unlock(&tsc_device->ci_chdev.mutex);
- return ret;
-}
-
-/**
- * tsc_mux_release() - Release and close the TSC Mux char device.
- *
- * @inode: The inode associated with the TSC Mux device.
- * @flip: The file pointer associated with the TSC Mux device.
- *
- * Release all the resources allocated for the Mux device and unvote power
- * resources.
- *
- * Return 0 on success, error value otherwise.
- */
-static int tsc_mux_release(struct inode *inode, struct file *filp)
-{
- struct tsc_mux_chdev *tsc_mux;
- u32 ena_reg;
-
- tsc_mux = filp->private_data;
- if (!tsc_mux)
- return -EINVAL;
-
- mutex_lock(&tsc_mux->mutex);
-
- tsc_mux_power_off_clocks();
-
- /* Disable the TSIFs */
- tsc_disable_tsifs();
- /* Disabling rate mismatch interrupt */
- ena_reg = readl_relaxed(tsc_device->base + TSC_IRQ_ENA);
- CLEAR_BIT(CAM_IRQ_RATE_MISMATCH_OFFS, ena_reg);
- writel_relaxed(ena_reg, tsc_device->base + TSC_IRQ_ENA);
-
- tsc_device_power_off();
-
- tsc_device->num_mux_opened--;
- mutex_unlock(&tsc_mux->mutex);
-
- return 0;
-}
-
-/**
- * tsc_ci_release() - Release and close the TSC CI char device.
- *
- * @inode: The inode associated with the TSC CI device.
- * @flip: The file pointer associated with the TSC CI device.
- *
- * Release all the resources allocated for the CI device and unvote power
- * resources.
- *
- * Return 0 on success, error value otherwise.
- */
-static int tsc_ci_release(struct inode *inode, struct file *filp)
-{
- struct tsc_ci_chdev *tsc_ci;
- u32 ena_reg;
- int ret;
-
- tsc_ci = filp->private_data;
- if (!tsc_ci)
- return -EINVAL;
-
- mutex_lock(&tsc_ci->mutex);
-
- /* If in the middle of a data transaction- wake-up completion */
- if (tsc_ci->data_busy) {
- /* Closing the device is similar in behavior to card removal */
- tsc_ci->transaction_state = TRANSACTION_CARD_REMOVED;
- mutex_unlock(&tsc_ci->mutex);
- complete_all(&tsc_ci->transaction_complete);
- wait_for_completion(&tsc_ci->transaction_finish);
- mutex_lock(&tsc_ci->mutex);
- }
-
- /* clearing EOT and ERR interrupts */
- ena_reg = readl_relaxed(tsc_device->base + TSC_IRQ_ENA);
- CLEAR_BIT(CAM_IRQ_EOT_OFFS, ena_reg);
- CLEAR_BIT(CAM_IRQ_ERR_OFFS, ena_reg);
- writel_relaxed(ena_reg, tsc_device->base + TSC_IRQ_ENA);
-
- /* Cancel the interrupt handlers registration */
- free_irq(tsc_device->card_detection_irq, tsc_device);
- free_irq(tsc_device->cam_cmd_irq, tsc_device);
-
- /* power down the card interface if it's currently powered up */
- if (tsc_device->hw_card_status == TSC_CARD_STATUS_DETECTED &&
- tsc_device->card_power) {
- ret = tsc_card_power_down();
- if (ret != 0)
- pr_err("%s: card power-down failed\n", __func__);
- }
-
- if (!tsc_iommu_bypass)
- iommu_detach_group(tsc_device->iommu_info.domain,
- tsc_device->iommu_info.group);
-
- gpio_free(tsc_device->reset_cam_gpio);
-
- tsc_power_off_buff_mode_clocks();
- tsc_device_power_off();
-
- tsc_device->num_ci_opened--;
- mutex_unlock(&tsc_ci->mutex);
-
- return 0;
-}
-
-/**
- * tsc_mux_poll() - Perform polling on a designated wait-queue.
- *
- * @flip: The file pointer associated with the TSC Mux device.
- * @p: The poll-table struct of the kernel.
- *
- * Add the TSC Mux wait-queue to the poll-table. Poll until a rate mismatch
- * interrupt is received.
- *
- * Return 0 on success, error value otherwise.
- */
-static unsigned int tsc_mux_poll(struct file *filp, struct poll_table_struct *p)
-{
- unsigned long flags;
- unsigned int mask = 0;
- struct tsc_mux_chdev *tsc_mux;
-
- tsc_mux = filp->private_data;
- if (!tsc_mux)
- return -EINVAL;
-
- /* register the wait queue for rate mismatch interrupt */
- poll_wait(filp, &tsc_mux->poll_queue, p);
-
- /* Setting the mask upon rate mismatch irq and clearing the flag */
- spin_lock_irqsave(&tsc_mux->spinlock, flags);
- if (tsc_mux->rate_interrupt) {
- mask = POLLPRI;
- tsc_mux->rate_interrupt = false;
- }
- spin_unlock_irqrestore(&tsc_mux->spinlock, flags);
-
- return mask;
-}
-
-/**
- * tsc_ci_poll() - Perform polling on a designated wait-queue.
- *
- * @flip: The file pointer associated with the TSC CI device.
- * @p: The poll-table struct of the kernel.
- *
- * Add the TSC Mux wait-queue to the poll-table. Poll until a card detection
- * interrupt is received.
- *
- * Return 0 on success, error value otherwise.
- */
-static unsigned int tsc_ci_poll(struct file *filp, struct poll_table_struct *p)
-{
- unsigned int mask = 0;
-
- struct tsc_ci_chdev *tsc_ci = filp->private_data;
- if (!tsc_ci)
- return -EINVAL;
-
- /* Register the wait queue for card detection interrupt */
- poll_wait(filp, &tsc_ci->poll_queue, p);
-
- /* Setting the mask upon card detect irq and update ci card state */
- if (mutex_lock_interruptible(&tsc_ci->mutex))
- return -ERESTARTSYS;
- if (tsc_ci->card_status != tsc_device->hw_card_status) {
- mask = POLLPRI;
- tsc_ci->card_status = tsc_device->hw_card_status;
- }
- mutex_unlock(&tsc_ci->mutex);
-
- return mask;
-}
-
-/**
- * tsc_mux_ioctl() - Handle IOCTLs sent from user-space application.
- *
- * @flip: The file pointer associated with the TSC Mux device.
- * @cmd: The IOCTL code sent
- * @arg: The IOCTL argument (if the IOCTL receives an argument)
- *
- * Verify the validity of the IOCTL sent and handle it by updating the
- * appropriate register or calling a function that handle the IOCTL operation.
- *
- * Return 0 on success, error value otherwise.
- */
-static long tsc_mux_ioctl(struct file *filp,
- unsigned int cmd,
- unsigned long arg)
-{
- int ret = 0;
- struct tsc_mux_chdev *tsc_mux;
- struct tsc_route tsc_route;
- struct tsc_tsif_params tsif_params;
-
- tsc_mux = filp->private_data;
- if (!tsc_mux)
- return -EINVAL;
-
- if (mutex_lock_interruptible(&tsc_mux->mutex))
- return -ERESTARTSYS;
-
- switch (cmd) {
- case TSC_CONFIG_ROUTE:
- if (!arg || copy_from_user(&tsc_route, (void *)arg,
- sizeof(struct tsc_route))) {
- ret = -EFAULT;
- goto err;
- }
- ret = tsc_route_mux(tsc_mux, tsc_route.source, tsc_route.dest);
- break;
- case TSC_ENABLE_INPUT:
- ret = tsc_enable_disable_tsif(tsc_mux, arg, TSIF_INPUT_ENABLE);
- break;
- case TSC_DISABLE_INPUT:
- ret = tsc_enable_disable_tsif(tsc_mux, arg, TSIF_INPUT_DISABLE);
- break;
- case TSC_SET_TSIF_CONFIG:
- if (!arg || copy_from_user(&tsif_params, (void *)arg,
- sizeof(struct tsc_tsif_params))) {
- ret = -EFAULT;
- goto err;
- }
- ret = tsc_config_tsif(tsc_mux, &tsif_params);
- break;
- case TSC_CLEAR_RATE_MISMATCH_IRQ:
- tsc_enable_rate_irq(tsc_mux);
- break;
- case TSC_CICAM_SET_CLOCK:
- ret = tsc_set_cicam_clk(arg);
- break;
- default:
- ret = -EINVAL;
- pr_err("%s: Unknown ioctl %i", __func__, cmd);
- }
-
-err:
- mutex_unlock(&tsc_mux->mutex);
- return ret;
-}
-
-/**
- * tsc_ci_ioctl() - Handle IOCTLs sent from user-space application.
- *
- * @flip: The file pointer associated with the TSC CI device.
- * @cmd: The IOCTL code sent
- * @arg: The IOCTL argument (if the IOCTL receives an argument)
- *
- * Verify the validity of the IOCTL sent and handle it by updating the
- * appropriate register or calling a function that handle the IOCTL operation.
- *
- * Return 0 on success, error value otherwise.
- */
-static long tsc_ci_ioctl(struct file *filp,
- unsigned int cmd,
- unsigned long arg)
-{
- int ret = 0;
- struct tsc_ci_chdev *tsc_ci;
- unsigned long flags;
-
- tsc_ci = filp->private_data;
- if (!tsc_ci)
- return -EINVAL;
-
- if (mutex_lock_interruptible(&tsc_ci->mutex))
- return -ERESTARTSYS;
-
- switch (cmd) {
-
- case TSC_CAM_RESET:
- ret = tsc_reset_cam();
- break;
- case TSC_CICAM_PERSONALITY_CHANGE:
- ret = tsc_personality_change(arg);
- break;
- case TSC_GET_CARD_STATUS:
- spin_lock_irqsave(&tsc_ci->spinlock, flags);
- tsc_ci->card_status = tsc_device->hw_card_status;
- ret = __put_user(tsc_ci->card_status,
- (enum tsc_card_status __user *)arg);
- spin_unlock_irqrestore(&tsc_ci->spinlock, flags);
- break;
- case TSC_READ_CAM_MEMORY:
- ret = tsc_data_transaction(tsc_ci, MEMORY_TRANSACTION,
- READ_TRANSACTION, SINGLE_BYTE_MODE, arg);
- break;
- case TSC_WRITE_CAM_MEMORY:
- ret = tsc_data_transaction(tsc_ci, MEMORY_TRANSACTION,
- WRITE_TRANSACTION, SINGLE_BYTE_MODE, arg);
- break;
- case TSC_READ_CAM_IO:
- ret = tsc_data_transaction(tsc_ci, IO_TRANSACTION,
- READ_TRANSACTION, SINGLE_BYTE_MODE, arg);
- break;
- case TSC_WRITE_CAM_IO:
- ret = tsc_data_transaction(tsc_ci, IO_TRANSACTION,
- WRITE_TRANSACTION, SINGLE_BYTE_MODE, arg);
- break;
- case TSC_READ_CAM_BUFFER:
- ret = tsc_data_transaction(tsc_ci, IO_TRANSACTION,
- READ_TRANSACTION, BUFFER_MODE, arg);
- break;
- case TSC_WRITE_CAM_BUFFER:
- ret = tsc_data_transaction(tsc_ci, IO_TRANSACTION,
- WRITE_TRANSACTION, BUFFER_MODE, arg);
- break;
- default:
- ret = -EINVAL;
- pr_err("%s: Unknown ioctl %i\n", __func__, cmd);
- }
-
- mutex_unlock(&tsc_ci->mutex);
- return ret;
-}
-
-/************************** Probe helper-functions **************************/
-/**
- * tsc_init_char_driver() - Initialize a character driver.
- *
- * @pcdev: A pointer to the cdev structure to initialize.
- * @pfops: A pointer to the file_operations for this device.
- * @device_number: A pointer that will store the device number.
- * @device: A pointer that will store the new device upon success.
- * @name: A string for the device's name.
- *
- * Create a new character device driver inside the TSC class. The new device
- * is created under "/dev/<name>0".
- *
- * Return 0 on success, error value otherwise.
- */
-static int tsc_init_char_driver(struct cdev *pcdev,
- const struct file_operations *pfops,
- dev_t *pdevice_number,
- struct device *pdevice,
- const char *name)
-{
- int ret = 0;
-
- /* Allocate device number for the char device driver */
- ret = alloc_chrdev_region(pdevice_number, 0, 1, name);
- if (ret) {
- pr_err("%s: alloc_chrdev_region failed: %d\n", name, ret);
- goto err_devrgn;
- }
-
- /* initializing the char device structures with file operations */
- cdev_init(pcdev, pfops);
- pcdev->owner = THIS_MODULE;
-
- /* adding the char device structures to the VFS */
- ret = cdev_add(pcdev, *pdevice_number, 1);
- if (ret != 0) {
- pr_err("%s%d: cdev_add failed\n", name, MINOR(*pdevice_number));
- goto err_cdev_add;
- }
-
- /* create the char devices under "/dev/" and register them to sysfs */
- pdevice = device_create(tsc_class, NULL, pcdev->dev, NULL, "%s%d", name,
- MINOR(*pdevice_number));
- if (IS_ERR(pdevice)) {
- pr_err("%s%d device_create failed\n", name,
- MINOR(*pdevice_number));
- ret = PTR_ERR(pdevice); /* PTR_ERR return -ENOMEM */
- goto err_device_create;
- }
-
- return ret;
-
-err_device_create:
- cdev_del(pcdev);
-err_cdev_add:
- unregister_chrdev_region(*pdevice_number, 1);
-err_devrgn:
- return ret;
-}
-
-/**
- * tsc_get_pinctrl() - Get the TSC pinctrl definitions.
- *
- * @pdev: A pointer to the TSC platform device.
- *
- * Get the pinctrl states' handles from the device tree. The function doesn't
- * enforce wrong pinctrl definitions, i.e. it's the client's responsibility to
- * define all the necessary states for the board being used.
- *
- * Return 0 on success, error value otherwise.
- */
-static int tsc_get_pinctrl(struct platform_device *pdev)
-{
- struct pinctrl *pinctrl;
-
- pinctrl = devm_pinctrl_get(&pdev->dev);
- if (IS_ERR(pinctrl)) {
- pr_err("%s: Unable to get pinctrl handle\n", __func__);
- return -EINVAL;
- }
- tsc_device->pinctrl_info.pinctrl = pinctrl;
-
- /* get all the states handles */
- tsc_device->pinctrl_info.disable =
- pinctrl_lookup_state(pinctrl, "disable");
- tsc_device->pinctrl_info.ts0 =
- pinctrl_lookup_state(pinctrl, "ts-in-0");
- tsc_device->pinctrl_info.ts1 =
- pinctrl_lookup_state(pinctrl, "ts-in-1");
- tsc_device->pinctrl_info.dual_ts =
- pinctrl_lookup_state(pinctrl, "dual-ts");
- tsc_device->pinctrl_info.pc_card =
- pinctrl_lookup_state(pinctrl, "pc-card");
- tsc_device->pinctrl_info.ci_card =
- pinctrl_lookup_state(pinctrl, "ci-card");
- tsc_device->pinctrl_info.ci_plus =
- pinctrl_lookup_state(pinctrl, "ci-plus");
- tsc_device->pinctrl_info.ts0_pc_card =
- pinctrl_lookup_state(pinctrl, "ts-in-0-pc-card");
- tsc_device->pinctrl_info.ts0_ci_card =
- pinctrl_lookup_state(pinctrl, "ts-in-0-ci-card");
- tsc_device->pinctrl_info.ts0_ci_plus =
- pinctrl_lookup_state(pinctrl, "ts-in-0-ci-plus");
- tsc_device->pinctrl_info.ts1_pc_card =
- pinctrl_lookup_state(pinctrl, "ts-in-1-pc-card");
- tsc_device->pinctrl_info.ts1_ci_card =
- pinctrl_lookup_state(pinctrl, "ts-in-1-ci-card");
- tsc_device->pinctrl_info.ts1_ci_plus =
- pinctrl_lookup_state(pinctrl, "ts-in-1-ci-plus");
- tsc_device->pinctrl_info.dual_ts_pc_card =
- pinctrl_lookup_state(pinctrl, "dual-ts-pc-card");
- tsc_device->pinctrl_info.dual_ts_ci_card =
- pinctrl_lookup_state(pinctrl, "dual-ts-ci-card");
- tsc_device->pinctrl_info.dual_ts_ci_plus =
- pinctrl_lookup_state(pinctrl, "dual-ts-ci-plus");
-
- if (IS_ERR(tsc_device->pinctrl_info.disable)) {
- pr_err("%s: Unable to get pinctrl disable state handle\n",
- __func__);
- return -EINVAL;
- }
-
- /* Basic checks to inquire what pinctrl states are available */
- if (IS_ERR(tsc_device->pinctrl_info.ts0))
- tsc_device->pinctrl_info.is_ts0 = false;
- else
- tsc_device->pinctrl_info.is_ts0 = true;
-
- if (IS_ERR(tsc_device->pinctrl_info.ts1))
- tsc_device->pinctrl_info.is_ts1 = false;
- else
- tsc_device->pinctrl_info.is_ts1 = true;
-
- if (IS_ERR(tsc_device->pinctrl_info.pc_card) ||
- IS_ERR(tsc_device->pinctrl_info.ci_card) ||
- IS_ERR(tsc_device->pinctrl_info.ci_plus))
- tsc_device->pinctrl_info.is_pcmcia = false;
- else
- tsc_device->pinctrl_info.is_pcmcia = true;
-
- return 0;
-}
-
-/**
- * tsc_get_regulator_bus() - Get the TSC regulator and register the bus client.
- *
- * @pdev: A pointer to the TSC platform device.
- *
- * Return 0 on success, error value otherwise.
- */
-static int tsc_get_regulator_bus(struct platform_device *pdev)
-{
- struct msm_bus_scale_pdata *tsc_bus_pdata = NULL;
-
- /* Reading the GDSC info */
- tsc_device->gdsc = devm_regulator_get(&pdev->dev, "vdd");
- if (IS_ERR(tsc_device->gdsc)) {
- dev_err(&pdev->dev, "%s: Failed to get vdd power regulator\n",
- __func__);
- return PTR_ERR(tsc_device->gdsc);
- }
-
- /* Reading the bus platform data */
- tsc_bus_pdata = msm_bus_cl_get_pdata(pdev);
- if (tsc_bus_pdata == NULL) {
- dev_err(&pdev->dev, "%s: Could not find the bus property. Continue anyway...\n",
- __func__);
- }
-
- /* Register the bus client */
- if (tsc_bus_pdata) {
- tsc_device->bus_client =
- msm_bus_scale_register_client(tsc_bus_pdata);
- if (!tsc_device->bus_client) {
- dev_err(&pdev->dev, "%s: Unable to register bus client\n",
- __func__);
- goto err;
- }
- }
-
- return 0;
-err:
- devm_regulator_put(tsc_device->gdsc);
- return -EINVAL;
-}
-
-/**
- * tsc_get_irqs() - Get the TSC IRQ numbers and map the cam irq.
- *
- * @pdev: A pointer to the TSC platform device.
- *
- * Read the irq numbers from the platform device information.
- *
- * Return 0 on success, error value otherwise.
- */
-static int tsc_get_irqs(struct platform_device *pdev)
-{
- int irq;
-
- irq = platform_get_irq_byname(pdev, "cam-cmd");
- if (irq > 0) {
- tsc_device->cam_cmd_irq = irq;
- } else {
- dev_err(&pdev->dev, "%s: Failed to get CAM_CMD IRQ = %d",
- __func__, irq);
- goto err;
- }
-
- irq = platform_get_irq_byname(pdev, "card-detect");
- if (irq > 0) {
- tsc_device->card_detection_irq = irq;
- } else {
- dev_err(&pdev->dev, "%s: Failed to get CARD_DETECT IRQ = %d",
- __func__, irq);
- goto err;
- }
-
- return 0;
-err:
- tsc_device->cam_cmd_irq = 0;
- tsc_device->card_detection_irq = 0;
-
- return -EINVAL;
-}
-
-/**
- * tsc_map_io_memory() - Map memory resources to kernel space.
- *
- * @pdev: A pointer to the TSC platform device.
- *
- * Return 0 on success, error value otherwise.
- */
-static int tsc_map_io_memory(struct platform_device *pdev)
-{
- struct resource *registers_mem;
-
- /* Reading memory resources */
- registers_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
- "tsc-base");
- if (!registers_mem) {
- dev_err(&pdev->dev, "%s: Missing tsc-base MEM resource",
- __func__);
- return -EINVAL;
- }
-
- tsc_device->base = ioremap(registers_mem->start,
- resource_size(registers_mem));
- if (!tsc_device->base) {
- dev_err(&pdev->dev, "%s: ioremap failed", __func__);
- return -ENXIO;
- }
-
- return 0;
-}
-
-/**
- * tsc_clocks_put() - Put the clocks
- */
-static void tsc_clocks_put(void)
-{
- if (tsc_device->ahb_clk)
- clk_put(tsc_device->ahb_clk);
- if (tsc_device->ci_clk)
- clk_put(tsc_device->ci_clk);
- if (tsc_device->ser_clk)
- clk_put(tsc_device->ser_clk);
- if (tsc_device->par_clk)
- clk_put(tsc_device->par_clk);
- if (tsc_device->cicam_ts_clk)
- clk_put(tsc_device->cicam_ts_clk);
- if (tsc_device->tspp2_core_clk)
- clk_put(tsc_device->tspp2_core_clk);
- if (tsc_device->vbif_tspp2_clk)
- clk_put(tsc_device->vbif_tspp2_clk);
- if (tsc_device->vbif_ahb_clk)
- clk_put(tsc_device->vbif_ahb_clk);
- if (tsc_device->vbif_axi_clk)
- clk_put(tsc_device->vbif_axi_clk);
-
- tsc_device->ahb_clk = NULL;
- tsc_device->ci_clk = NULL;
- tsc_device->ser_clk = NULL;
- tsc_device->par_clk = NULL;
- tsc_device->cicam_ts_clk = NULL;
- tsc_device->tspp2_core_clk = NULL;
- tsc_device->vbif_tspp2_clk = NULL;
- tsc_device->vbif_ahb_clk = NULL;
- tsc_device->vbif_axi_clk = NULL;
-}
-
-/**
- * tsc_clocks_get() - Get the TSC clocks
- *
- * @pdev: A pointer to the TSC platform device.
- *
- * Return 0 on success, error value otherwise.
- */
-static int tsc_clocks_get(struct platform_device *pdev)
-{
- int ret = 0;
-
- tsc_device->ahb_clk = clk_get(&pdev->dev, "bcc_tsc_ahb_clk");
- if (IS_ERR(tsc_device->ahb_clk)) {
- pr_err("%s: Failed to get bcc_tsc_ahb_clk\n", __func__);
- ret = PTR_ERR(tsc_device->ahb_clk);
- goto ahb_err;
- }
-
- tsc_device->ci_clk = clk_get(&pdev->dev, "bcc_tsc_ci_clk");
- if (IS_ERR(tsc_device->ci_clk)) {
- pr_err("%s: Failed to get bcc_tsc_ci_clk\n", __func__);
- ret = PTR_ERR(tsc_device->ci_clk);
- goto ci_err;
- }
-
- tsc_device->ser_clk = clk_get(&pdev->dev, "bcc_tsc_ser_clk");
- if (IS_ERR(tsc_device->ser_clk)) {
- pr_err("%s: Failed to get bcc_tsc_ser_clk\n", __func__);
- ret = PTR_ERR(tsc_device->ser_clk);
- goto ser_err;
- }
-
- tsc_device->par_clk = clk_get(&pdev->dev, "bcc_tsc_par_clk");
- if (IS_ERR(tsc_device->par_clk)) {
- pr_err("%s: Failed to get bcc_tsc_par_clk", __func__);
- ret = PTR_ERR(tsc_device->par_clk);
- goto par_err;
- }
-
- tsc_device->cicam_ts_clk = clk_get(&pdev->dev, "bcc_tsc_cicam_ts_clk");
- if (IS_ERR(tsc_device->cicam_ts_clk)) {
- pr_err("%s: Failed to get bcc_tsc_cicam_ts_clk", __func__);
- ret = PTR_ERR(tsc_device->cicam_ts_clk);
- goto cicam_err;
- }
-
- tsc_device->tspp2_core_clk = clk_get(&pdev->dev, "bcc_tspp2_core_clk");
- if (IS_ERR(tsc_device->tspp2_core_clk)) {
- pr_err("%s: Failed to get bcc_tspp2_core_clk", __func__);
- ret = PTR_ERR(tsc_device->tspp2_core_clk);
- goto tspp2_err;
- }
-
- tsc_device->vbif_tspp2_clk = clk_get(&pdev->dev, "bcc_vbif_tspp2_clk");
- if (IS_ERR(tsc_device->vbif_tspp2_clk)) {
- pr_err("%s: Failed to get bcc_vbif_tspp2_clk", __func__);
- ret = PTR_ERR(tsc_device->vbif_tspp2_clk);
- goto vbif_tspp2_err;
- }
-
- tsc_device->vbif_ahb_clk = clk_get(&pdev->dev, "iface_vbif_clk");
- if (IS_ERR(tsc_device->vbif_ahb_clk)) {
- pr_err("%s: Failed to get bcc_vbif_ahb_clk", __func__);
- ret = PTR_ERR(tsc_device->vbif_ahb_clk);
- goto vbif_ahb_err;
- }
-
- tsc_device->vbif_axi_clk = clk_get(&pdev->dev, "vbif_core_clk");
- if (IS_ERR(tsc_device->vbif_axi_clk)) {
- pr_err("%s: Failed to get bcc_vbif_axi_clk", __func__);
- ret = PTR_ERR(tsc_device->vbif_axi_clk);
- goto vbif_axi_err;
- }
-
- return ret;
-
-vbif_axi_err:
- tsc_device->vbif_axi_clk = NULL;
- clk_put(tsc_device->vbif_ahb_clk);
-vbif_ahb_err:
- tsc_device->vbif_ahb_clk = NULL;
- clk_put(tsc_device->vbif_tspp2_clk);
-vbif_tspp2_err:
- tsc_device->vbif_tspp2_clk = NULL;
- clk_put(tsc_device->tspp2_core_clk);
-tspp2_err:
- tsc_device->tspp2_core_clk = NULL;
- clk_put(tsc_device->cicam_ts_clk);
-cicam_err:
- tsc_device->cicam_ts_clk = NULL;
- clk_put(tsc_device->par_clk);
-par_err:
- tsc_device->par_clk = NULL;
- clk_put(tsc_device->ser_clk);
-ser_err:
- tsc_device->ser_clk = NULL;
- clk_put(tsc_device->ci_clk);
-ci_err:
- tsc_device->ci_clk = NULL;
- clk_put(tsc_device->ahb_clk);
-ahb_err:
- tsc_device->ahb_clk = NULL;
- return ret;
-}
-
-/**
- * tsc_free_iommu_info() - Free IOMMU information.
- */
-static void tsc_free_iommu_info(void)
-{
- if (tsc_device->iommu_info.group) {
- iommu_group_put(tsc_device->iommu_info.group);
- tsc_device->iommu_info.group = NULL;
- }
-
- if (tsc_device->iommu_info.ion_client) {
- ion_client_destroy(tsc_device->iommu_info.ion_client);
- tsc_device->iommu_info.ion_client = NULL;
- }
-
- tsc_device->iommu_info.domain = NULL;
- tsc_device->iommu_info.domain_num = -1;
- tsc_device->iommu_info.partition_num = -1;
-}
-
-/**
- * tsc_get_iommu_info() - Get IOMMU information.
- *
- * @pdev: A pointer to the TSC platform device.
- *
- * Return 0 on success, error value otherwise.
- */
-static int tsc_get_iommu_info(struct platform_device *pdev)
-{
- int ret = 0;
-
- /* Create a new ION client used by tsc ci to allocate memory */
- tsc_device->iommu_info.ion_client = msm_ion_client_create("tsc_client");
- if (IS_ERR_OR_NULL(tsc_device->iommu_info.ion_client)) {
- pr_err("%s: error in ion_client_create", __func__);
- ret = PTR_ERR(tsc_device->iommu_info.ion_client);
- if (!ret)
- ret = -ENOMEM;
- tsc_device->iommu_info.ion_client = NULL;
- goto err_client;
- }
-
- /* Find the iommu group by the name obtained from the device tree */
- tsc_device->iommu_info.group =
- iommu_group_find(tsc_device->iommu_info.iommu_group_name);
- if (!tsc_device->iommu_info.group) {
- pr_err("%s: error in iommu_group_find", __func__);
- ret = -EINVAL;
- goto err_group;
- }
-
- /* Get the domain associated with the iommu group */
- tsc_device->iommu_info.domain =
- iommu_group_get_iommudata(tsc_device->iommu_info.group);
- if (IS_ERR_OR_NULL(tsc_device->iommu_info.domain)) {
- pr_err("%s: iommu_group_get_iommudata failed", __func__);
- ret = -EINVAL;
- goto err_domain;
- }
-
- /* Get the domain number */
- tsc_device->iommu_info.domain_num =
- msm_find_domain_no(tsc_device->iommu_info.domain);
-
- return ret;
-
-err_domain:
- iommu_group_put(tsc_device->iommu_info.group);
- tsc_device->iommu_info.group = NULL;
-err_group:
- ion_client_destroy(tsc_device->iommu_info.ion_client);
- tsc_device->iommu_info.ion_client = NULL;
-err_client:
- return ret;
-}
-
-/**
- * tsc_parse_dt() - Parse device-tree data and save it.
- *
- * @pdev: A pointer to the TSC platform device.
- *
- * Return 0 on success, error value otherwise.
- */
-static int tsc_parse_dt(struct platform_device *pdev)
-{
- struct device_node *node = pdev->dev.of_node;
- struct device_node *iommu_pnode;
- int ret;
-
- /* Check that power regulator property exist */
- if (!of_get_property(node, "vdd-supply", NULL)) {
- dev_err(&pdev->dev, "%s: Could not find vdd-supply property\n",
- __func__);
- return -EINVAL;
- }
-
- /* Reading IOMMU group label by obtaining the group's phandle */
- iommu_pnode = of_parse_phandle(node, "qcom,iommu-group", 0);
- if (!iommu_pnode) {
- dev_err(&pdev->dev, "%s: Couldn't find iommu-group property\n",
- __func__);
- return -EINVAL;
- }
- ret = of_property_read_string(iommu_pnode, "label",
- &tsc_device->iommu_info.iommu_group_name);
- of_node_put(iommu_pnode);
- if (ret) {
- dev_err(&pdev->dev, "%s: Couldn't find label property of the IOMMU group, err=%d\n",
- __func__, ret);
- return -EINVAL;
- }
-
- /* Reading IOMMU partition */
- ret = of_property_read_u32(node, "qcom,iommu-partition",
- &tsc_device->iommu_info.partition_num);
- if (ret) {
- dev_err(&pdev->dev, "%s: Couldn't find iommu-partition property, err=%d\n",
- __func__, ret);
- return -EINVAL;
- }
-
- /* Reading reset cam gpio */
- tsc_device->reset_cam_gpio = of_get_named_gpio(node,
- "qcom,tsc-reset-cam-gpio", 0);
- if (tsc_device->reset_cam_gpio < 0) {
- dev_err(&pdev->dev, "%s: Couldn't find qcom,tsc-reset-cam-gpio property\n",
- __func__);
- return -EINVAL;
- }
-
- return 0;
-}
-
-/* TSC Mux file operations */
-static const struct file_operations tsc_mux_fops = {
- .owner = THIS_MODULE,
- .open = tsc_mux_open,
- .poll = tsc_mux_poll,
- .release = tsc_mux_release,
- .unlocked_ioctl = tsc_mux_ioctl,
-};
-
-/* TSC CI file operations */
-static const struct file_operations tsc_ci_fops = {
- .owner = THIS_MODULE,
- .open = tsc_ci_open,
- .poll = tsc_ci_poll,
- .release = tsc_ci_release,
- .unlocked_ioctl = tsc_ci_ioctl,
-};
-
-
-/************************ Device driver probe function ************************/
-static int msm_tsc_probe(struct platform_device *pdev)
-{
- int ret;
-
- tsc_device = kzalloc(sizeof(struct tsc_device), GFP_KERNEL);
- if (!tsc_device) {
- pr_err("%s: Unable to allocate memory for struct\n", __func__);
- return -ENOMEM;
- }
-
- /* get information from device tree */
- if (pdev->dev.of_node) {
- ret = tsc_parse_dt(pdev);
- if (ret != 0) {
- pr_err("%s: devicetree data not available", __func__);
- ret = -EINVAL;
- goto err_dt;
- }
- } else { /* else - devicetree is not found */
- pr_err("%s: devicetree data is missing", __func__);
- ret = -EINVAL;
- goto err_dt;
- }
-
- /* set up references */
- tsc_device->pdev = pdev;
- platform_set_drvdata(pdev, tsc_device);
-
- /* init iommu client, group and domain */
- if (!tsc_iommu_bypass) {
- ret = tsc_get_iommu_info(pdev);
- if (ret != 0)
- return ret;
- }
-
- /* Map clocks */
- ret = tsc_clocks_get(pdev);
- if (ret != 0)
- goto err_clocks_get;
-
- /* map registers memory */
- ret = tsc_map_io_memory(pdev);
- if (ret != 0)
- goto err_map_io;
-
- /* map irqs */
- ret = tsc_get_irqs(pdev);
- if (ret != 0)
- goto err_map_irqs;
-
- /* get regulators and bus */
- ret = tsc_get_regulator_bus(pdev);
- if (ret != 0)
- goto err_get_regulator_bus;
-
- /* get pinctrl */
- ret = tsc_get_pinctrl(pdev);
- if (ret != 0)
- goto err_pinctrl;
-
- /* creating the tsc device's class */
- tsc_class = class_create(THIS_MODULE, "tsc");
- if (IS_ERR(tsc_class)) {
- ret = PTR_ERR(tsc_class);
- pr_err("%s: Error creating class: %d\n", __func__, ret);
- goto err_class;
- }
-
- /* Initialize and register mux char device driver */
- ret = tsc_init_char_driver(&tsc_device->mux_chdev.cdev, &tsc_mux_fops,
- &tsc_device->mux_device_number, tsc_device->device_mux,
- "tsc_mux");
- if (ret != 0)
- goto err_chdev_mux;
-
- /* Initialize and register ci char device drivers */
- ret = tsc_init_char_driver(&tsc_device->ci_chdev.cdev, &tsc_ci_fops,
- &tsc_device->ci_device_number, tsc_device->device_ci,
- "tsc_ci");
- if (ret != 0)
- goto err_chdev_ci;
-
- /* Init char device counters */
- tsc_device->num_device_open = 0;
- tsc_device->num_mux_opened = 0;
- tsc_device->num_ci_opened = 0;
-
- /* Init char device mutexes and completion structs */
- mutex_init(&tsc_device->mux_chdev.mutex);
- mutex_init(&tsc_device->ci_chdev.mutex);
- mutex_init(&tsc_device->mutex);
- init_completion(&tsc_device->ci_chdev.transaction_complete);
- init_completion(&tsc_device->ci_chdev.transaction_finish);
-
- /* Init debugfs support */
- tsc_debugfs_init();
-
- return ret;
-
-err_chdev_ci:
- device_destroy(tsc_class, tsc_device->mux_chdev.cdev.dev);
- cdev_del(&tsc_device->mux_chdev.cdev);
-err_chdev_mux:
- class_destroy(tsc_class);
-err_class:
-err_pinctrl:
- if (tsc_device->bus_client)
- msm_bus_scale_unregister_client(tsc_device->bus_client);
-
- devm_regulator_put(tsc_device->gdsc);
-err_get_regulator_bus:
-err_map_irqs:
- iounmap(tsc_device->base);
-err_map_io:
- tsc_clocks_put();
-err_clocks_get:
- tsc_free_iommu_info();
-err_dt:
- kfree(tsc_device);
-
- return ret;
-}
-
-/*********************** Device driver remove function ***********************/
-static int msm_tsc_remove(struct platform_device *pdev)
-{
- /* Removing debugfs support */
- tsc_debugfs_exit();
-
- /* Destroying the char device mutexes */
- mutex_destroy(&tsc_device->mux_chdev.mutex);
- mutex_destroy(&tsc_device->ci_chdev.mutex);
-
- /* unregistering and deleting the tsc-ci char device driver*/
- device_destroy(tsc_class, tsc_device->ci_chdev.cdev.dev);
- cdev_del(&tsc_device->ci_chdev.cdev);
-
- /* unregistering and deleting the tsc-mux char device driver*/
- device_destroy(tsc_class, tsc_device->mux_chdev.cdev.dev);
- cdev_del(&tsc_device->mux_chdev.cdev);
-
- /* Unregistering the char devices */
- unregister_chrdev_region(tsc_device->ci_device_number, 1);
- unregister_chrdev_region(tsc_device->mux_device_number, 1);
-
- /* Removing the tsc class*/
- class_destroy(tsc_class);
-
- /* Unregister the bus client and the regulator */
- if (tsc_device->bus_client)
- msm_bus_scale_unregister_client(tsc_device->bus_client);
-
- devm_regulator_put(tsc_device->gdsc);
-
- /* Unmapping the io memory */
- iounmap(tsc_device->base);
-
- /* Releasing the clocks */
- tsc_clocks_put();
-
- /* Releasing the iommu info */
- if (!tsc_iommu_bypass)
- tsc_free_iommu_info();
-
- /* Releasing the memory allocated for the TSC device struct */
- kfree(tsc_device);
-
- return 0;
-}
-
-/*********************** Platform driver information ***********************/
-static struct of_device_id msm_match_table[] = {
- {.compatible = "qcom,msm-tsc"},
- {}
-};
-
-static struct platform_driver msm_tsc_driver = {
- .probe = msm_tsc_probe,
- .remove = msm_tsc_remove,
- .driver = {
- .name = "msm_tsc",
- .of_match_table = msm_match_table,
- },
-};
-
-/**
- * tsc_init() - TSC driver module init function.
- *
- * Return 0 on success, error value otherwise.
- */
-static int __init tsc_init(void)
-{
- int ret = 0;
-
- /* register the driver, and check hardware */
- ret = platform_driver_register(&msm_tsc_driver);
- if (ret) {
- pr_err("%s: platform_driver_register failed: %d\n", __func__,
- ret);
- return ret;
- }
-
- return ret;
-}
-
-/**
- * tsc_exit() - TSC driver module exit function.
- */
-static void __exit tsc_exit(void)
-{
- platform_driver_unregister(&msm_tsc_driver);
-}
-
-module_init(tsc_init);
-module_exit(tsc_exit);
-
-MODULE_DESCRIPTION("TSC platform device and two char devs: mux and ci");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/broadcast/tspp2.c b/drivers/media/platform/msm/broadcast/tspp2.c
deleted file mode 100644
index 1f51dca..0000000
--- a/drivers/media/platform/msm/broadcast/tspp2.c
+++ /dev/null
@@ -1,8578 +0,0 @@
-/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/module.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/dma-mapping.h>
-#include <linux/debugfs.h>
-#include <linux/device.h>
-#include <linux/pm_runtime.h>
-#include <linux/pm_wakeup.h>
-#include <linux/platform_device.h>
-#include <linux/msm_ion.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/of.h>
-#include <linux/list.h>
-#include <linux/mutex.h>
-#include <linux/workqueue.h>
-#include <linux/iommu.h>
-#include <linux/qcom_iommu.h>
-#include <linux/msm_iommu_domains.h>
-#include <linux/msm-bus.h>
-#include <mach/msm_tspp2.h>
-#include <linux/clk/msm-clk.h>
-
-#define TSPP2_MODULUS_OP(val, mod) ((val) & ((mod) - 1))
-
-/* General definitions. Note we're reserving one batch. */
-#define TSPP2_NUM_ALL_INPUTS (TSPP2_NUM_TSIF_INPUTS + TSPP2_NUM_MEM_INPUTS)
-#define TSPP2_NUM_CONTEXTS 128
-#define TSPP2_NUM_AVAIL_CONTEXTS 127
-#define TSPP2_NUM_HW_FILTERS 128
-#define TSPP2_NUM_BATCHES 15
-#define TSPP2_FILTERS_PER_BATCH 8
-#define TSPP2_NUM_AVAIL_FILTERS (TSPP2_NUM_HW_FILTERS - TSPP2_FILTERS_PER_BATCH)
-#define TSPP2_NUM_KEYTABLES 32
-#define TSPP2_TSIF_DEF_TIME_LIMIT 15000 /* Number of tsif-ref-clock ticks */
-
-#define TSPP2_NUM_EVENT_WORK_ELEMENTS 256
-
-/*
- * Based on the hardware programming guide, HW requires we wait for up to 2ms
- * before closing the pipes used by the filter.
- * This is required to avoid unexpected pipe reset interrupts.
- */
-#define TSPP2_HW_DELAY_USEC 2000
-
-/*
- * Default source configuration:
- * Sync byte 0x47, check sync byte,
- * Do not monitor scrambling bits,
- * Discard packets with invalid AF,
- * Do not assume duplicates,
- * Do not ignore discontinuity indicator,
- * Check continuity of TS packets.
- */
-#define TSPP2_DEFAULT_SRC_CONFIG 0x47801E49
-
-/*
- * Default memory source configuration:
- * Use 16 batches,
- * Attach last batch to each memory source.
- */
-#define TSPP2_DEFAULT_MEM_SRC_CONFIG 0x80000010
-
-/* Bypass VBIF/IOMMU for debug and bring-up purposes */
-static int tspp2_iommu_bypass;
-module_param(tspp2_iommu_bypass, int, S_IRUGO);
-
-/* Enable Invalid Adaptation Field control bits event */
-static int tspp2_en_invalid_af_ctrl;
-module_param(tspp2_en_invalid_af_ctrl, int, S_IRUGO | S_IWUSR);
-
-/* Enable Invalid Adaptation Field length event */
-static int tspp2_en_invalid_af_length;
-module_param(tspp2_en_invalid_af_length, int, S_IRUGO | S_IWUSR);
-
-/* Enable PES No Sync event */
-static int tspp2_en_pes_no_sync;
-module_param(tspp2_en_pes_no_sync, int, S_IRUGO | S_IWUSR);
-
-/**
- * enum tspp2_operation_opcode - TSPP2 Operation opcode for TSPP2_OPCODE
- */
-enum tspp2_operation_opcode {
- TSPP2_OPCODE_PES_ANALYSIS = 0x03,
- TSPP2_OPCODE_RAW_TRANSMIT = 0x07,
- TSPP2_OPCODE_PES_TRANSMIT = 0x00,
- TSPP2_OPCODE_PCR_EXTRACTION = 0x05,
- TSPP2_OPCODE_CIPHER = 0x01,
- TSPP2_OPCODE_INDEXING = 0x09,
- TSPP2_OPCODE_COPY_PACKET = 0x0B,
- TSPP2_OPCODE_EXIT = 0x0F
-};
-
-/* TSIF Register definitions: */
-#define TSPP2_TSIF_STS_CTL (0x0000)
-#define TSPP2_TSIF_TIME_LIMIT (0x0004)
-#define TSPP2_TSIF_CLK_REF (0x0008)
-#define TSPP2_TSIF_LPBK_FLAGS (0x000C)
-#define TSPP2_TSIF_LPBK_DATA (0x0010)
-#define TSPP2_TSIF_DATA_PORT (0x0100)
-
-/* Bits for TSPP2_TSIF_STS_CTL register */
-#define TSIF_STS_CTL_PKT_WRITE_ERR BIT(30)
-#define TSIF_STS_CTL_PKT_READ_ERR BIT(29)
-#define TSIF_STS_CTL_EN_IRQ BIT(28)
-#define TSIF_STS_CTL_PACK_AVAIL BIT(27)
-#define TSIF_STS_CTL_1ST_PACKET BIT(26)
-#define TSIF_STS_CTL_OVERFLOW BIT(25)
-#define TSIF_STS_CTL_LOST_SYNC BIT(24)
-#define TSIF_STS_CTL_TIMEOUT BIT(23)
-#define TSIF_STS_CTL_INV_SYNC BIT(21)
-#define TSIF_STS_CTL_INV_NULL BIT(20)
-#define TSIF_STS_CTL_INV_ERROR BIT(19)
-#define TSIF_STS_CTL_INV_ENABLE BIT(18)
-#define TSIF_STS_CTL_INV_DATA BIT(17)
-#define TSIF_STS_CTL_INV_CLOCK BIT(16)
-#define TSIF_STS_CTL_PARALLEL BIT(14)
-#define TSIF_STS_CTL_EN_NULL BIT(11)
-#define TSIF_STS_CTL_EN_ERROR BIT(10)
-#define TSIF_STS_CTL_LAST_BIT BIT(9)
-#define TSIF_STS_CTL_EN_TIME_LIM BIT(8)
-#define TSIF_STS_CTL_EN_TCR BIT(7)
-#define TSIF_STS_CTL_TEST_MODE BIT(6)
-#define TSIF_STS_CTL_MODE_2 BIT(5)
-#define TSIF_STS_CTL_EN_DM BIT(4)
-#define TSIF_STS_CTL_STOP BIT(3)
-#define TSIF_STS_CTL_START BIT(0)
-
-/* Indexing Table Register definitions: id = 0..3, n = 0..25 */
-#define TSPP2_INDEX_TABLE_PREFIX(id) (0x6000 + ((id) << 2))
-#define TSPP2_INDEX_TABLE_PREFIX_MASK(id) (0x6010 + ((id) << 2))
-#define TSPP2_INDEX_TABLE_PATTEREN(id, n) (0x3C00 + ((id) << 8) + \
- ((n) << 3))
-#define TSPP2_INDEX_TABLE_MASK(id, n) (0x3C04 + ((id) << 8) + \
- ((n) << 3))
-#define TSPP2_INDEX_TABLE_PARAMS(id) (0x6020 + ((id) << 2))
-
-/* Bits for TSPP2_INDEX_TABLE_PARAMS register */
-#define INDEX_TABLE_PARAMS_PREFIX_SIZE_OFFS 8
-#define INDEX_TABLE_PARAMS_NUM_PATTERNS_OFFS 0
-
-/* Source with memory input register definitions: n = 0..7 */
-#define TSPP2_MEM_INPUT_SRC_CONFIG(n) (0x6040 + ((n) << 2))
-
-/* Bits for TSPP2_MEM_INPUT_SRC_CONFIG register */
-#define MEM_INPUT_SRC_CONFIG_BATCHES_OFFS 16
-#define MEM_INPUT_SRC_CONFIG_INPUT_PIPE_OFFS 8
-#define MEM_INPUT_SRC_CONFIG_16_BATCHES_OFFS 4
-#define MEM_INPUT_SRC_CONFIG_STAMP_SUFFIX_OFFS 2
-#define MEM_INPUT_SRC_CONFIG_STAMP_EN_OFFS 1
-#define MEM_INPUT_SRC_CONFIG_INPUT_EN_OFFS 0
-
-/* Source with TSIF input register definitions: n = 0..1 */
-#define TSPP2_TSIF_INPUT_SRC_CONFIG(n) (0x6060 + ((n) << 2))
-#define TSIF_INPUT_SRC_CONFIG_16_BATCHES_OFFS 4
-
-/* Bits for TSPP2_TSIF_INPUT_SRC_CONFIG register */
-#define TSIF_INPUT_SRC_CONFIG_BATCHES_OFFS 16
-#define TSIF_INPUT_SRC_CONFIG_INPUT_EN_OFFS 0
-
-/* Source with any input register definitions: n = 0..9 */
-#define TSPP2_SRC_DEST_PIPES(n) (0x6070 + ((n) << 2))
-#define TSPP2_SRC_CONFIG(n) (0x6120 + ((n) << 2))
-#define TSPP2_SRC_TOTAL_TSP(n) (0x6600 + ((n) << 2))
-#define TSPP2_SRC_FILTERED_OUT_TSP(n) (0x6630 + ((n) << 2))
-
-/* Bits for TSPP2_SRC_CONFIG register */
-#define SRC_CONFIG_SYNC_BYTE_OFFS 24
-#define SRC_CONFIG_CHECK_SYNC_OFFS 23
-#define SRC_CONFIG_SCRAMBLING_MONITOR_OFFS 13
-#define SRC_CONFIG_VERIFY_PES_START_OFFS 12
-#define SRC_CONFIG_SCRAMBLING3_OFFS 10
-#define SRC_CONFIG_SCRAMBLING2_OFFS 8
-#define SRC_CONFIG_SCRAMBLING1_OFFS 6
-#define SRC_CONFIG_SCRAMBLING0_OFFS 4
-#define SRC_CONFIG_DISCARD_INVALID_AF_OFFS 3
-#define SRC_CONFIG_ASSUME_DUPLICATES_OFFS 2
-#define SRC_CONFIG_IGNORE_DISCONT_OFFS 1
-#define SRC_CONFIG_CHECK_CONT_OFFS 0
-
-/* Context register definitions: n = 0..127 */
-#define TSPP2_PES_CONTEXT0(n) (0x0000 + ((n) << 4))
-#define TSPP2_PES_CONTEXT1(n) (0x0004 + ((n) << 4))
-#define TSPP2_PES_CONTEXT2(n) (0x0008 + ((n) << 4))
-#define TSPP2_PES_CONTEXT3(n) (0x000C + ((n) << 4))
-#define TSPP2_INDEXING_CONTEXT0(n) (0x0800 + ((n) << 3))
-#define TSPP2_INDEXING_CONTEXT1(n) (0x0804 + ((n) << 3))
-#define TSPP2_TSP_CONTEXT(n) (0x5600 + ((n) << 2))
-
-/* Bits for TSPP2_TSP_CONTEXT register */
-#define TSP_CONTEXT_TS_HEADER_SC_OFFS 6
-#define TSP_CONTEXT_PES_HEADER_SC_OFFS 8
-
-/* Operations register definitions: f_idx = 0..127, n = 0..15 */
-#define TSPP2_OPCODE(f_idx, n) (0x1000 + \
- ((f_idx) * (TSPP2_MAX_OPS_PER_FILTER << 2)) + \
- ((n) << 2))
-
-/* Filter register definitions: n = 0..127 */
-#define TSPP2_FILTER_ENTRY0(n) (0x5800 + ((n) << 3))
-#define TSPP2_FILTER_ENTRY1(n) (0x5804 + ((n) << 3))
-
-/* Bits for TSPP2_FILTER_ENTRY0 register */
-#define FILTER_ENTRY0_PID_OFFS 0
-#define FILTER_ENTRY0_MASK_OFFS 13
-#define FILTER_ENTRY0_EN_OFFS 26
-#define FILTER_ENTRY0_CODEC_OFFS 27
-
-/* Bits for TSPP2_FILTER_ENTRY1 register */
-#define FILTER_ENTRY1_CONTEXT_OFFS 0
-
-/* Filter context-based counter register definitions: n = 0..127 */
-#define TSPP2_FILTER_TSP_SYNC_ERROR(n) (0x4000 + ((n) << 2))
-#define TSPP2_FILTER_ERRED_TSP(n) (0x4200 + ((n) << 2))
-#define TSPP2_FILTER_DISCONTINUITIES(n) (0x4400 + ((n) << 2))
-#define TSPP2_FILTER_SCRAMBLING_BITS_DISCARD(n) (0x4600 + ((n) << 2))
-#define TSPP2_FILTER_TSP_TOTAL_NUM(n) (0x4800 + ((n) << 2))
-#define TSPP2_FILTER_DISCONT_INDICATOR(n) (0x4A00 + ((n) << 2))
-#define TSPP2_FILTER_TSP_NO_PAYLOAD(n) (0x4C00 + ((n) << 2))
-#define TSPP2_FILTER_TSP_DUPLICATE(n) (0x4E00 + ((n) << 2))
-#define TSPP2_FILTER_KEY_FETCH_FAILURE(n) (0x5000 + ((n) << 2))
-#define TSPP2_FILTER_DROPPED_PCR(n) (0x5200 + ((n) << 2))
-#define TSPP2_FILTER_PES_ERRORS(n) (0x5400 + ((n) << 2))
-
-/* Pipe register definitions: n = 0..30 */
-#define TSPP2_PIPE_THRESH_CONFIG(n) (0x60A0 + ((n) << 2))
-#define TSPP2_PIPE_LAST_ADDRESS(n) (0x6190 + ((n) << 2))
-#define TSPP2_PIPE_SECURITY 0x6150
-#define TSPP2_DATA_NOT_SENT_ON_PIPE(n) (0x6660 + ((n) << 2))
-
-/* Global register definitions: */
-#define TSPP2_PCR_GLOBAL_CONFIG 0x6160
-#define TSPP2_CLK_TO_PCR_TIME_UNIT 0x6170
-#define TSPP2_DESC_WAIT_TIMEOUT 0x6180
-#define TSPP2_GLOBAL_IRQ_STATUS 0x6300
-#define TSPP2_GLOBAL_IRQ_CLEAR 0x6304
-#define TSPP2_GLOBAL_IRQ_ENABLE 0x6308
-#define TSPP2_KEY_NOT_READY_IRQ_STATUS 0x6310
-#define TSPP2_KEY_NOT_READY_IRQ_CLEAR 0x6314
-#define TSPP2_KEY_NOT_READY_IRQ_ENABLE 0x6318
-#define TSPP2_UNEXPECTED_RST_IRQ_STATUS 0x6320
-#define TSPP2_UNEXPECTED_RST_IRQ_CLEAR 0x6324
-#define TSPP2_UNEXPECTED_RST_IRQ_ENABLE 0x6328
-#define TSPP2_WRONG_PIPE_DIR_IRQ_STATUS 0x6330
-#define TSPP2_WRONG_PIPE_DIR_IRQ_CLEAR 0x6334
-#define TSPP2_WRONG_PIPE_DIR_IRQ_ENABLE 0x6338
-#define TSPP2_QSB_RESPONSE_ERROR_IRQ_STATUS 0x6340
-#define TSPP2_QSB_RESPONSE_ERROR_IRQ_CLEAR 0x6344
-#define TSPP2_QSB_RESPONSE_ERROR_IRQ_ENABLE 0x6348
-#define TSPP2_SRC_TOTAL_TSP_RESET 0x6710
-#define TSPP2_SRC_FILTERED_OUT_TSP_RESET 0x6714
-#define TSPP2_DATA_NOT_SENT_ON_PIPE_RESET 0x6718
-#define TSPP2_VERSION 0x6FFC
-
-/* Bits for TSPP2_GLOBAL_IRQ_CLEAR register */
-#define GLOBAL_IRQ_CLEAR_RESERVED_OFFS 4
-
-/* Bits for TSPP2_VERSION register */
-#define VERSION_MAJOR_OFFS 28
-#define VERSION_MINOR_OFFS 16
-#define VERSION_STEP_OFFS 0
-
-/* Bits for TSPP2_GLOBAL_IRQ_XXX registers */
-#define GLOBAL_IRQ_TSP_INVALID_AF_OFFS 0
-#define GLOBAL_IRQ_TSP_INVALID_LEN_OFFS 1
-#define GLOBAL_IRQ_PES_NO_SYNC_OFFS 2
-#define GLOBAL_IRQ_ENCRYPT_LEVEL_ERR_OFFS 3
-#define GLOBAL_IRQ_KEY_NOT_READY_OFFS 4
-#define GLOBAL_IRQ_UNEXPECTED_RESET_OFFS 5
-#define GLOBAL_IRQ_QSB_RESP_ERR_OFFS 6
-#define GLOBAL_IRQ_WRONG_PIPE_DIR_OFFS 7
-#define GLOBAL_IRQ_SC_GO_HIGH_OFFS 8
-#define GLOBAL_IRQ_SC_GO_LOW_OFFS 9
-#define GLOBAL_IRQ_READ_FAIL_OFFS 16
-#define GLOBAL_IRQ_FC_STALL_OFFS 24
-
-/* Bits for TSPP2_PCR_GLOBAL_CONFIG register */
-#define PCR_GLOBAL_CONFIG_PCR_ON_DISCONT_OFFS 10
-#define PCR_GLOBAL_CONFIG_STC_OFFSET_OFFS 8
-#define PCR_GLOBAL_CONFIG_PCR_INTERVAL_OFFS 0
-#define PCR_GLOBAL_CONFIG_PCR_ON_DISCONT BIT(10)
-#define PCR_GLOBAL_CONFIG_STC_OFFSET (BIT(8)|BIT(9))
-#define PCR_GLOBAL_CONFIG_PCR_INTERVAL 0xFF
-
-/* n = 0..3, each register handles 32 filters */
-#define TSPP2_SC_GO_HIGH_STATUS(n) (0x6350 + ((n) << 2))
-#define TSPP2_SC_GO_HIGH_CLEAR(n) (0x6360 + ((n) << 2))
-#define TSPP2_SC_GO_HIGH_ENABLE(n) (0x6370 + ((n) << 2))
-#define TSPP2_SC_GO_LOW_STATUS(n) (0x6390 + ((n) << 2))
-#define TSPP2_SC_GO_LOW_CLEAR(n) (0x63A0 + ((n) << 2))
-#define TSPP2_SC_GO_LOW_ENABLE(n) (0x63B0 + ((n) << 2))
-
-/* n = 0..3, each register handles 32 contexts */
-#define TSPP2_TSP_CONTEXT_RESET(n) (0x6500 + ((n) << 2))
-#define TSPP2_PES_CONTEXT_RESET(n) (0x6510 + ((n) << 2))
-#define TSPP2_INDEXING_CONTEXT_RESET(n) (0x6520 + ((n) << 2))
-
-/* debugfs entries */
-
-#define TSPP2_S_RW (S_IRUGO | S_IWUSR)
-
-struct debugfs_entry {
- const char *name;
- mode_t mode;
- int offset;
-};
-
-static const struct debugfs_entry tsif_regs[] = {
- {"sts_ctl", TSPP2_S_RW, TSPP2_TSIF_STS_CTL},
- {"time_limit", TSPP2_S_RW, TSPP2_TSIF_TIME_LIMIT},
- {"clk_ref", TSPP2_S_RW, TSPP2_TSIF_CLK_REF},
- {"lpbk_flags", TSPP2_S_RW, TSPP2_TSIF_LPBK_FLAGS},
- {"lpbk_data", TSPP2_S_RW, TSPP2_TSIF_LPBK_DATA},
- {"data_port", S_IRUGO, TSPP2_TSIF_DATA_PORT},
-};
-
-static const struct debugfs_entry tspp2_regs[] = {
- /* Memory input source configuration registers */
- {"mem_input_src_config_0", TSPP2_S_RW, TSPP2_MEM_INPUT_SRC_CONFIG(0)},
- {"mem_input_src_config_1", TSPP2_S_RW, TSPP2_MEM_INPUT_SRC_CONFIG(1)},
- {"mem_input_src_config_2", TSPP2_S_RW, TSPP2_MEM_INPUT_SRC_CONFIG(2)},
- {"mem_input_src_config_3", TSPP2_S_RW, TSPP2_MEM_INPUT_SRC_CONFIG(3)},
- {"mem_input_src_config_4", TSPP2_S_RW, TSPP2_MEM_INPUT_SRC_CONFIG(4)},
- {"mem_input_src_config_5", TSPP2_S_RW, TSPP2_MEM_INPUT_SRC_CONFIG(5)},
- {"mem_input_src_config_6", TSPP2_S_RW, TSPP2_MEM_INPUT_SRC_CONFIG(6)},
- {"mem_input_src_config_7", TSPP2_S_RW, TSPP2_MEM_INPUT_SRC_CONFIG(7)},
- /* TSIF input source configuration registers */
- {"tsif_input_src_config_0", TSPP2_S_RW, TSPP2_TSIF_INPUT_SRC_CONFIG(0)},
- {"tsif_input_src_config_1", TSPP2_S_RW, TSPP2_TSIF_INPUT_SRC_CONFIG(1)},
- /* Source destination pipes association registers */
- {"src_dest_pipes_0", TSPP2_S_RW, TSPP2_SRC_DEST_PIPES(0)},
- {"src_dest_pipes_1", TSPP2_S_RW, TSPP2_SRC_DEST_PIPES(1)},
- {"src_dest_pipes_2", TSPP2_S_RW, TSPP2_SRC_DEST_PIPES(2)},
- {"src_dest_pipes_3", TSPP2_S_RW, TSPP2_SRC_DEST_PIPES(3)},
- {"src_dest_pipes_4", TSPP2_S_RW, TSPP2_SRC_DEST_PIPES(4)},
- {"src_dest_pipes_5", TSPP2_S_RW, TSPP2_SRC_DEST_PIPES(5)},
- {"src_dest_pipes_6", TSPP2_S_RW, TSPP2_SRC_DEST_PIPES(6)},
- {"src_dest_pipes_7", TSPP2_S_RW, TSPP2_SRC_DEST_PIPES(7)},
- {"src_dest_pipes_8", TSPP2_S_RW, TSPP2_SRC_DEST_PIPES(8)},
- {"src_dest_pipes_9", TSPP2_S_RW, TSPP2_SRC_DEST_PIPES(9)},
- /* Source configuration registers */
- {"src_config_0", TSPP2_S_RW, TSPP2_SRC_CONFIG(0)},
- {"src_config_1", TSPP2_S_RW, TSPP2_SRC_CONFIG(1)},
- {"src_config_2", TSPP2_S_RW, TSPP2_SRC_CONFIG(2)},
- {"src_config_3", TSPP2_S_RW, TSPP2_SRC_CONFIG(3)},
- {"src_config_4", TSPP2_S_RW, TSPP2_SRC_CONFIG(4)},
- {"src_config_5", TSPP2_S_RW, TSPP2_SRC_CONFIG(5)},
- {"src_config_6", TSPP2_S_RW, TSPP2_SRC_CONFIG(6)},
- {"src_config_7", TSPP2_S_RW, TSPP2_SRC_CONFIG(7)},
- {"src_config_8", TSPP2_S_RW, TSPP2_SRC_CONFIG(8)},
- {"src_config_9", TSPP2_S_RW, TSPP2_SRC_CONFIG(9)},
- /* Source total TS packets counter registers */
- {"src_total_tsp_0", S_IRUGO, TSPP2_SRC_TOTAL_TSP(0)},
- {"src_total_tsp_1", S_IRUGO, TSPP2_SRC_TOTAL_TSP(1)},
- {"src_total_tsp_2", S_IRUGO, TSPP2_SRC_TOTAL_TSP(2)},
- {"src_total_tsp_3", S_IRUGO, TSPP2_SRC_TOTAL_TSP(3)},
- {"src_total_tsp_4", S_IRUGO, TSPP2_SRC_TOTAL_TSP(4)},
- {"src_total_tsp_5", S_IRUGO, TSPP2_SRC_TOTAL_TSP(5)},
- {"src_total_tsp_6", S_IRUGO, TSPP2_SRC_TOTAL_TSP(6)},
- {"src_total_tsp_7", S_IRUGO, TSPP2_SRC_TOTAL_TSP(7)},
- {"src_total_tsp_8", S_IRUGO, TSPP2_SRC_TOTAL_TSP(8)},
- {"src_total_tsp_9", S_IRUGO, TSPP2_SRC_TOTAL_TSP(9)},
- /* Source total filtered out TS packets counter registers */
- {"src_filtered_out_tsp_0", S_IRUGO, TSPP2_SRC_FILTERED_OUT_TSP(0)},
- {"src_filtered_out_tsp_1", S_IRUGO, TSPP2_SRC_FILTERED_OUT_TSP(1)},
- {"src_filtered_out_tsp_2", S_IRUGO, TSPP2_SRC_FILTERED_OUT_TSP(2)},
- {"src_filtered_out_tsp_3", S_IRUGO, TSPP2_SRC_FILTERED_OUT_TSP(3)},
- {"src_filtered_out_tsp_4", S_IRUGO, TSPP2_SRC_FILTERED_OUT_TSP(4)},
- {"src_filtered_out_tsp_5", S_IRUGO, TSPP2_SRC_FILTERED_OUT_TSP(5)},
- {"src_filtered_out_tsp_6", S_IRUGO, TSPP2_SRC_FILTERED_OUT_TSP(6)},
- {"src_filtered_out_tsp_7", S_IRUGO, TSPP2_SRC_FILTERED_OUT_TSP(7)},
- {"src_filtered_out_tsp_8", S_IRUGO, TSPP2_SRC_FILTERED_OUT_TSP(8)},
- {"src_filtered_out_tsp_9", S_IRUGO, TSPP2_SRC_FILTERED_OUT_TSP(9)},
- /* Global registers */
- {"pipe_security", TSPP2_S_RW, TSPP2_PIPE_SECURITY},
- {"pcr_global_config", TSPP2_S_RW, TSPP2_PCR_GLOBAL_CONFIG},
- {"clk_to_pcr_time_unit", TSPP2_S_RW, TSPP2_CLK_TO_PCR_TIME_UNIT},
- {"desc_wait_timeout", TSPP2_S_RW, TSPP2_DESC_WAIT_TIMEOUT},
- {"global_irq_status", S_IRUGO, TSPP2_GLOBAL_IRQ_STATUS},
- {"global_irq_clear", S_IWUSR, TSPP2_GLOBAL_IRQ_CLEAR},
- {"global_irq_en", TSPP2_S_RW, TSPP2_GLOBAL_IRQ_ENABLE},
- {"key_not_ready_irq_status", S_IRUGO, TSPP2_KEY_NOT_READY_IRQ_STATUS},
- {"key_not_ready_irq_clear", S_IWUSR, TSPP2_KEY_NOT_READY_IRQ_CLEAR},
- {"key_not_ready_irq_en", TSPP2_S_RW, TSPP2_KEY_NOT_READY_IRQ_ENABLE},
- {"unexpected_rst_irq_status", S_IRUGO, TSPP2_UNEXPECTED_RST_IRQ_STATUS},
- {"unexpected_rst_irq_clear", S_IWUSR, TSPP2_UNEXPECTED_RST_IRQ_CLEAR},
- {"unexpected_rst_irq_en", TSPP2_S_RW, TSPP2_UNEXPECTED_RST_IRQ_ENABLE},
- {"wrong_pipe_dir_irq_status", S_IRUGO, TSPP2_WRONG_PIPE_DIR_IRQ_STATUS},
- {"wrong_pipe_dir_irq_clear", S_IWUSR, TSPP2_WRONG_PIPE_DIR_IRQ_CLEAR},
- {"wrong_pipe_dir_irq_en", TSPP2_S_RW, TSPP2_WRONG_PIPE_DIR_IRQ_ENABLE},
- {"qsb_response_error_irq_status", S_IRUGO,
- TSPP2_QSB_RESPONSE_ERROR_IRQ_STATUS},
- {"qsb_response_error_irq_clear", S_IWUSR,
- TSPP2_QSB_RESPONSE_ERROR_IRQ_CLEAR},
- {"qsb_response_error_irq_en", TSPP2_S_RW,
- TSPP2_QSB_RESPONSE_ERROR_IRQ_ENABLE},
- {"src_total_tsp_reset", S_IWUSR, TSPP2_SRC_TOTAL_TSP_RESET},
- {"src_filtered_out_tsp_reset", S_IWUSR,
- TSPP2_SRC_FILTERED_OUT_TSP_RESET},
- {"data_not_sent_on_pipe_reset", S_IWUSR,
- TSPP2_DATA_NOT_SENT_ON_PIPE_RESET},
- {"version", S_IRUGO, TSPP2_VERSION},
- /* Scrambling bits monitoring interrupt registers */
- {"sc_go_high_status_0", S_IRUGO, TSPP2_SC_GO_HIGH_STATUS(0)},
- {"sc_go_high_status_1", S_IRUGO, TSPP2_SC_GO_HIGH_STATUS(1)},
- {"sc_go_high_status_2", S_IRUGO, TSPP2_SC_GO_HIGH_STATUS(2)},
- {"sc_go_high_status_3", S_IRUGO, TSPP2_SC_GO_HIGH_STATUS(3)},
- {"sc_go_high_clear_0", S_IWUSR, TSPP2_SC_GO_HIGH_CLEAR(0)},
- {"sc_go_high_clear_1", S_IWUSR, TSPP2_SC_GO_HIGH_CLEAR(1)},
- {"sc_go_high_clear_2", S_IWUSR, TSPP2_SC_GO_HIGH_CLEAR(2)},
- {"sc_go_high_clear_3", S_IWUSR, TSPP2_SC_GO_HIGH_CLEAR(3)},
- {"sc_go_high_en_0", TSPP2_S_RW, TSPP2_SC_GO_HIGH_ENABLE(0)},
- {"sc_go_high_en_1", TSPP2_S_RW, TSPP2_SC_GO_HIGH_ENABLE(1)},
- {"sc_go_high_en_2", TSPP2_S_RW, TSPP2_SC_GO_HIGH_ENABLE(2)},
- {"sc_go_high_en_3", TSPP2_S_RW, TSPP2_SC_GO_HIGH_ENABLE(3)},
- {"sc_go_low_status_0", S_IRUGO, TSPP2_SC_GO_LOW_STATUS(0)},
- {"sc_go_low_status_1", S_IRUGO, TSPP2_SC_GO_LOW_STATUS(1)},
- {"sc_go_low_status_2", S_IRUGO, TSPP2_SC_GO_LOW_STATUS(2)},
- {"sc_go_low_status_3", S_IRUGO, TSPP2_SC_GO_LOW_STATUS(3)},
- {"sc_go_low_clear_0", S_IWUSR, TSPP2_SC_GO_LOW_CLEAR(0)},
- {"sc_go_low_clear_1", S_IWUSR, TSPP2_SC_GO_LOW_CLEAR(1)},
- {"sc_go_low_clear_2", S_IWUSR, TSPP2_SC_GO_LOW_CLEAR(2)},
- {"sc_go_low_clear_3", S_IWUSR, TSPP2_SC_GO_LOW_CLEAR(3)},
- {"sc_go_low_en_0", TSPP2_S_RW, TSPP2_SC_GO_LOW_ENABLE(0)},
- {"sc_go_low_en_1", TSPP2_S_RW, TSPP2_SC_GO_LOW_ENABLE(1)},
- {"sc_go_low_en_2", TSPP2_S_RW, TSPP2_SC_GO_LOW_ENABLE(2)},
- {"sc_go_low_en_3", TSPP2_S_RW, TSPP2_SC_GO_LOW_ENABLE(3)},
-};
-
-/* Data structures */
-
-/**
- * struct tspp2_tsif_device - TSIF device
- *
- * @base: TSIF device memory base address.
- * @hw_index: TSIF device HW index (0 .. (TSPP2_NUM_TSIF_INPUTS - 1)).
- * @dev: Back pointer to the TSPP2 device.
- * @time_limit: TSIF device time limit
- * (maximum time allowed between each TS packet).
- * @ref_count: TSIF device reference count.
- * @tsif_irq: TSIF device IRQ number.
- * @mode: TSIF mode of operation.
- * @clock_inverse: Invert input clock signal.
- * @data_inverse: Invert input data signal.
- * @sync_inverse: Invert input sync signal.
- * @enable_inverse: Invert input enable signal.
- * @debugfs_entrys: TSIF device debugfs entry.
- * @stat_pkt_write_err: TSIF device packet write error statistics.
- * @stat__pkt_read_err: TSIF device packet read error statistics.
- * @stat_overflow: TSIF device overflow statistics.
- * @stat_lost_sync: TSIF device lost sync statistics.
- * @stat_timeout: TSIF device timeout statistics.
- */
-struct tspp2_tsif_device {
- void __iomem *base;
- u32 hw_index;
- struct tspp2_device *dev;
- u32 time_limit;
- u32 ref_count;
- u32 tsif_irq;
- enum tspp2_tsif_mode mode;
- int clock_inverse;
- int data_inverse;
- int sync_inverse;
- int enable_inverse;
- struct dentry *debugfs_entry;
- u32 stat_pkt_write_err;
- u32 stat_pkt_read_err;
- u32 stat_overflow;
- u32 stat_lost_sync;
- u32 stat_timeout;
-};
-
-/**
- * struct tspp2_indexing_table - Indexing table
- *
- * @prefix_value: 4-byte common prefix value.
- * @prefix_mask: 4-byte prefix mask.
- * @entry_value: An array of 4-byte pattern values.
- * @entry_mask: An array of corresponding 4-byte pattern masks.
- * @num_valid_entries: Number of valid entries in the arrays.
- */
-struct tspp2_indexing_table {
- u32 prefix_value;
- u32 prefix_mask;
- u32 entry_value[TSPP2_NUM_INDEXING_PATTERNS];
- u32 entry_mask[TSPP2_NUM_INDEXING_PATTERNS];
- u16 num_valid_entries;
-};
-
-/**
- * struct tspp2_event_work - Event work information
- *
- * @device: TSPP2 device back-pointer.
- * @callback: Callback to invoke.
- * @cookie: Cookie to pass to the callback.
- * @event_bitmask: A bit mask of events to pass to the callback.
- * @work: The work structure to queue.
- * @link: A list element.
- */
-struct tspp2_event_work {
- struct tspp2_device *device;
- void (*callback)(void *cookie, u32 event_bitmask);
- void *cookie;
- u32 event_bitmask;
- struct work_struct work;
- struct list_head link;
-};
-
-/**
- * struct tspp2_filter - Filter object
- *
- * @opened: A flag to indicate whether the filter is open.
- * @device: Back-pointer to the TSPP2 device the filter
- * belongs to.
- * @batch: The filter batch this filter belongs to.
- * @src: Back-pointer to the source the filter is
- * associated with.
- * @hw_index: The filter's HW index.
- * @pid_value: The filter's 13-bit PID value.
- * @mask: The corresponding 13-bit bitmask.
- * @context: The filter's context ID.
- * @indexing_table_id: The ID of the indexing table this filter uses
- * in case an indexing operation is set.
- * @operations: An array of user-defined operations.
- * @num_user_operations: The number of user-defined operations.
- * @indexing_op_set: A flag to indicate an indexing operation
- * has been set.
- * @raw_op_with_indexing: A flag to indicate a Raw Transmit operation
- * with support_indexing parameter has been set.
- * @pes_analysis_op_set: A flag to indicate a PES Analysis operation
- * has been set.
- * @raw_op_set: A flag to indicate a Raw Transmit operation
- * has been set.
- * @pes_tx_op_set: A flag to indicate a PES Transmit operation
- * has been set.
- * @event_callback: A user callback to invoke when a filter event
- * occurs.
- * @event_cookie: A user cookie to provide to the callback.
- * @event_bitmask: A bit mask of filter events
- * TSPP2_FILTER_EVENT_XXX.
- * @enabled: A flag to indicate whether the filter
- * is enabled.
- * @link: A list element. When the filter is associated
- * with a source, it is added to the source's
- * list of filters.
- */
-struct tspp2_filter {
- int opened;
- struct tspp2_device *device;
- struct tspp2_filter_batch *batch;
- struct tspp2_src *src;
- u16 hw_index;
- u16 pid_value;
- u16 mask;
- u16 context;
- u8 indexing_table_id;
- struct tspp2_operation operations[TSPP2_MAX_OPS_PER_FILTER];
- u8 num_user_operations;
- int indexing_op_set;
- int raw_op_with_indexing;
- int pes_analysis_op_set;
- int raw_op_set;
- int pes_tx_op_set;
- void (*event_callback)(void *cookie, u32 event_bitmask);
- void *event_cookie;
- u32 event_bitmask;
- int enabled;
- struct list_head link;
-};
-
-/**
- * struct tspp2_pipe - Pipe object
- *
- * @opened: A flag to indicate whether the pipe is open.
- * @device: Back-pointer to the TSPP2 device the pipe belongs to.
- * @cfg: Pipe configuration parameters.
- * @sps_pipe: The BAM SPS pipe.
- * @sps_connect_cfg: SPS pipe connection configuration.
- * @sps_event: SPS pipe event registration parameters.
- * @desc_ion_handle: ION handle for the SPS pipe descriptors.
- * @iova: TSPP2 IOMMU-mapped virtual address of the
- * data buffer provided by the user.
- * @hw_index: The pipe's HW index (for register access).
- * @threshold: Pipe threshold.
- * @ref_cnt: Pipe reference count. Incremented when pipe
- * is attached to a source, decremented when it
- * is detached from a source.
- */
-struct tspp2_pipe {
- int opened;
- struct tspp2_device *device;
- struct tspp2_pipe_config_params cfg;
- struct sps_pipe *sps_pipe;
- struct sps_connect sps_connect_cfg;
- struct sps_register_event sps_event;
- struct ion_handle *desc_ion_handle;
- ion_phys_addr_t iova;
- u32 hw_index;
- u16 threshold;
- u32 ref_cnt;
-};
-
-/**
- * struct tspp2_output_pipe - Output pipe element to add to a source's list
- *
- * @pipe: A pointer to an output pipe object.
- * @link: A list element. When an output pipe is attached to a source,
- * it is added to the source's output pipe list. Note the same pipe
- * can be attached to multiple sources, so we allocate an output
- * pipe element to add to the list - we don't add the actual pipe.
- */
-struct tspp2_output_pipe {
- struct tspp2_pipe *pipe;
- struct list_head link;
-};
-
-/**
- * struct tspp2_filter_batch - Filter batch object
- *
- * @batch_id: Filter batch ID.
- * @hw_filters: An array of HW filters that belong to this batch. When set, this
- * indicates the filter is used. The actual HW index of a filter is
- * calculated according to the index in this array along with the
- * batch ID.
- * @src: Back-pointer to the source the batch is associated with. This is
- * also used to indicate this batch is "taken".
- * @link: A list element. When the batch is associated with a source, it
- * is added to the source's list of filter batches.
- */
-struct tspp2_filter_batch {
- u8 batch_id;
- int hw_filters[TSPP2_FILTERS_PER_BATCH];
- struct tspp2_src *src;
- struct list_head link;
-};
-
-/**
- * struct tspp2_src - Source object
- *
- * @opened: A flag to indicate whether the source is open.
- * @device: Back-pointer to the TSPP2 device the source
- * belongs to.
- * @hw_index: The source's HW index. This is used when writing
- * to HW registers relevant for this source.
- * There are registers specific to TSIF or memory
- * sources, and there are registers common to all
- * sources.
- * @input: Source input type (TSIF / memory).
- * @pkt_format: Input packet size and format for this source.
- * @scrambling_bits_monitoring: Scrambling bits monitoring mode.
- * @batches_list: A list of associated filter batches.
- * @filters_list: A list of associated filters.
- * @input_pipe: A pointer to the source's input pipe, if exists.
- * @output_pipe_list: A list of output pipes attached to the source.
- * For each pipe we also save whether it is
- * stalling for this source.
- * @num_associated_batches: Number of associated filter batches.
- * @num_associated_pipes: Number of associated pipes.
- * @num_associated_filters: Number of associated filters.
- * @reserved_filter_hw_index: A HW filter index reserved for updating an
- * active filter's operations.
- * @event_callback: A user callback to invoke when a source event
- * occurs.
- * @event_cookie: A user cookie to provide to the callback.
- * @event_bitmask: A bit mask of source events
- * TSPP2_SRC_EVENT_XXX.
- * @enabled: A flag to indicate whether the source
- * is enabled.
- */
-struct tspp2_src {
- int opened;
- struct tspp2_device *device;
- u8 hw_index;
- enum tspp2_src_input input;
- enum tspp2_packet_format pkt_format;
- enum tspp2_src_scrambling_monitoring scrambling_bits_monitoring;
- struct list_head batches_list;
- struct list_head filters_list;
- struct tspp2_pipe *input_pipe;
- struct list_head output_pipe_list;
- u8 num_associated_batches;
- u8 num_associated_pipes;
- u32 num_associated_filters;
- u16 reserved_filter_hw_index;
- void (*event_callback)(void *cookie, u32 event_bitmask);
- void *event_cookie;
- u32 event_bitmask;
- int enabled;
-};
-
-/**
- * struct tspp2_global_irq_stats - Global interrupt statistics counters
- *
- * @tsp_invalid_af_control: Invalid adaptation field control bit.
- * @tsp_invalid_length: Invalid adaptation field length.
- * @pes_no_sync: PES sync sequence not found.
- * @encrypt_level_err: Cipher operation configuration error.
- */
-struct tspp2_global_irq_stats {
- u32 tsp_invalid_af_control;
- u32 tsp_invalid_length;
- u32 pes_no_sync;
- u32 encrypt_level_err;
-};
-
-/**
- * struct tspp2_src_irq_stats - Memory source interrupt statistics counters
- *
- * @read_failure: Failure to read from memory input.
- * @flow_control_stall: Input is stalled due to flow control.
- */
-struct tspp2_src_irq_stats {
- u32 read_failure;
- u32 flow_control_stall;
-};
-
-/**
- * struct tspp2_keytable_irq_stats - Key table interrupt statistics counters
- *
- * @key_not_ready: Ciphering keys are not ready in the key table.
- */
-struct tspp2_keytable_irq_stats {
- u32 key_not_ready;
-};
-
-/**
- * struct tspp2_pipe_irq_stats - Pipe interrupt statistics counters
- *
- * @unexpected_reset: SW reset the pipe before all operations on this
- * pipe ended.
- * @qsb_response_error: TX operation ends with QSB error.
- * @wrong_pipe_direction: Trying to use a pipe in the wrong direction.
- */
-struct tspp2_pipe_irq_stats {
- u32 unexpected_reset;
- u32 qsb_response_error;
- u32 wrong_pipe_direction;
-};
-
-/**
- * struct tspp2_filter_context_irq_stats - Filter interrupt statistics counters
- *
- * @sc_go_high: Scrambling bits change from clear to encrypted.
- * @sc_go_low: Scrambling bits change from encrypted to clear.
- */
-struct tspp2_filter_context_irq_stats {
- u32 sc_go_high;
- u32 sc_go_low;
-};
-
-/**
- * struct tspp2_irq_stats - Interrupt statistics counters
- *
- * @global: Global interrupt statistics counters
- * @src: Memory source interrupt statistics counters
- * @kt: Key table interrupt statistics counters
- * @pipe: Pipe interrupt statistics counters
- * @ctx: Filter context interrupt statistics counters
- */
-struct tspp2_irq_stats {
- struct tspp2_global_irq_stats global;
- struct tspp2_src_irq_stats src[TSPP2_NUM_MEM_INPUTS];
- struct tspp2_keytable_irq_stats kt[TSPP2_NUM_KEYTABLES];
- struct tspp2_pipe_irq_stats pipe[TSPP2_NUM_PIPES];
- struct tspp2_filter_context_irq_stats ctx[TSPP2_NUM_CONTEXTS];
-};
-
-/**
- * struct tspp2_iommu_info - TSPP2 IOMMU information
- *
- * @hlos_group: TSPP2 IOMMU HLOS (Non-Secure) group.
- * @cpz_group: TSPP2 IOMMU HLOS (Secure) group.
- * @hlos_domain: TSPP2 IOMMU HLOS (Non-Secure) domain.
- * @cpz_domain: TSPP2 IOMMU CPZ (Secure) domain.
- * @hlos_domain_num: TSPP2 IOMMU HLOS (Non-Secure) domain number.
- * @cpz_domain_num: TSPP2 IOMMU CPZ (Secure) domain number.
- * @hlos_partition: TSPP2 IOMMU HLOS partition number.
- * @cpz_partition: TSPP2 IOMMU CPZ partition number.
- */
-struct tspp2_iommu_info {
- struct iommu_group *hlos_group;
- struct iommu_group *cpz_group;
- struct iommu_domain *hlos_domain;
- struct iommu_domain *cpz_domain;
- int hlos_domain_num;
- int cpz_domain_num;
- int hlos_partition;
- int cpz_partition;
-};
-
-/**
- * struct tspp2_device - TSPP2 device
- *
- * @dev_id: TSPP2 device ID.
- * @opened: A flag to indicate whether the device is open.
- * @pdev: Platform device.
- * @dev: Device structure, used for driver prints.
- * @base: TSPP2 Device memory base address.
- * @tspp2_irq: TSPP2 Device IRQ number.
- * @bam_handle: BAM handle.
- * @bam_irq: BAM IRQ number.
- * @bam_props: BAM properties.
- * @iommu_info: IOMMU information.
- * @wakeup_src: A wakeup source to keep CPU awake when needed.
- * @spinlock: A spinlock to protect accesses to
- * data structures that happen from APIs and ISRs.
- * @mutex: A mutex for mutual exclusion between API calls.
- * @tsif_devices: An array of TSIF devices.
- * @gdsc: GDSC power regulator.
- * @bus_client: Client for bus bandwidth voting.
- * @tspp2_ahb_clk: TSPP2 AHB clock.
- * @tspp2_core_clk: TSPP2 core clock.
- * @tspp2_vbif_clk: TSPP2 VBIF clock.
- * @vbif_ahb_clk: VBIF AHB clock.
- * @vbif_axi_clk: VBIF AXI clock.
- * @tspp2_klm_ahb_clk: TSPP2 KLM AHB clock.
- * @tsif_ref_clk: TSIF reference clock.
- * @batches: An array of filter batch objects.
- * @contexts: An array of context indexes. The index in this
- * array represents the context's HW index, while
- * the value represents whether it is used by a
- * filter or free.
- * @indexing_tables: An array of indexing tables.
- * @tsif_sources: An array of source objects for TSIF input.
- * @mem_sources: An array of source objects for memory input.
- * @filters: An array of filter objects.
- * @pipes: An array of pipe objects.
- * @num_secured_opened_pipes: Number of secured opened pipes.
- * @num_non_secured_opened_pipes: Number of non-secured opened pipes.
- * @num_enabled_sources: Number of enabled sources.
- * @work_queue: A work queue for invoking user callbacks.
- * @event_callback: A user callback to invoke when a global event
- * occurs.
- * @event_cookie: A user cookie to provide to the callback.
- * @event_bitmask: A bit mask of global events
- * TSPP2_GLOBAL_EVENT_XXX.
- * @debugfs_entry: TSPP2 device debugfs entry.
- * @irq_stats: TSPP2 IRQ statistics.
- * @free_work_list: A list of available work elements.
- * @work_pool: A pool of work elements.
- */
-struct tspp2_device {
- u32 dev_id;
- int opened;
- struct platform_device *pdev;
- struct device *dev;
- void __iomem *base;
- u32 tspp2_irq;
- unsigned long bam_handle;
- u32 bam_irq;
- struct sps_bam_props bam_props;
- struct tspp2_iommu_info iommu_info;
- struct wakeup_source wakeup_src;
- spinlock_t spinlock;
- struct mutex mutex;
- struct tspp2_tsif_device tsif_devices[TSPP2_NUM_TSIF_INPUTS];
- struct regulator *gdsc;
- uint32_t bus_client;
- struct clk *tspp2_ahb_clk;
- struct clk *tspp2_core_clk;
- struct clk *tspp2_vbif_clk;
- struct clk *vbif_ahb_clk;
- struct clk *vbif_axi_clk;
- struct clk *tspp2_klm_ahb_clk;
- struct clk *tsif_ref_clk;
- struct tspp2_filter_batch batches[TSPP2_NUM_BATCHES];
- int contexts[TSPP2_NUM_AVAIL_CONTEXTS];
- struct tspp2_indexing_table indexing_tables[TSPP2_NUM_INDEXING_TABLES];
- struct tspp2_src tsif_sources[TSPP2_NUM_TSIF_INPUTS];
- struct tspp2_src mem_sources[TSPP2_NUM_MEM_INPUTS];
- struct tspp2_filter filters[TSPP2_NUM_AVAIL_FILTERS];
- struct tspp2_pipe pipes[TSPP2_NUM_PIPES];
- u8 num_secured_opened_pipes;
- u8 num_non_secured_opened_pipes;
- u8 num_enabled_sources;
- struct workqueue_struct *work_queue;
- void (*event_callback)(void *cookie, u32 event_bitmask);
- void *event_cookie;
- u32 event_bitmask;
- struct dentry *debugfs_entry;
- struct tspp2_irq_stats irq_stats;
- struct list_head free_work_list;
- struct tspp2_event_work work_pool[TSPP2_NUM_EVENT_WORK_ELEMENTS];
-};
-
-/* Global TSPP2 devices database */
-static struct tspp2_device *tspp2_devices[TSPP2_NUM_DEVICES];
-
-/* debugfs support */
-
-static int debugfs_iomem_x32_set(void *data, u64 val)
-{
- int ret;
- struct tspp2_device *device = tspp2_devices[0]; /* Assuming device 0 */
-
- if (!device->opened)
- return -ENODEV;
-
- ret = pm_runtime_get_sync(device->dev);
- if (ret < 0)
- return ret;
-
- writel_relaxed(val, data);
- wmb();
-
- pm_runtime_mark_last_busy(device->dev);
- pm_runtime_put_autosuspend(device->dev);
-
- return 0;
-}
-
-static int debugfs_iomem_x32_get(void *data, u64 *val)
-{
- int ret;
- struct tspp2_device *device = tspp2_devices[0]; /* Assuming device 0 */
-
- if (!device->opened)
- return -ENODEV;
-
- ret = pm_runtime_get_sync(device->dev);
- if (ret < 0)
- return ret;
-
- *val = readl_relaxed(data);
-
- pm_runtime_mark_last_busy(device->dev);
- pm_runtime_put_autosuspend(device->dev);
-
- return 0;
-}
-
-DEFINE_SIMPLE_ATTRIBUTE(fops_iomem_x32, debugfs_iomem_x32_get,
- debugfs_iomem_x32_set, "0x%08llX");
-
-static int debugfs_dev_open_set(void *data, u64 val)
-{
- int ret = 0;
-
- /* Assuming device 0 */
- if (val == 1)
- ret = tspp2_device_open(0);
- else
- ret = tspp2_device_close(0);
-
- return ret;
-}
-
-static int debugfs_dev_open_get(void *data, u64 *val)
-{
- struct tspp2_device *device = tspp2_devices[0]; /* Assuming device 0 */
-
- *val = device->opened;
-
- return 0;
-}
-
-DEFINE_SIMPLE_ATTRIBUTE(fops_device_open, debugfs_dev_open_get,
- debugfs_dev_open_set, "0x%08llX");
-
-/**
- * tspp2_tsif_debugfs_init() - TSIF device debugfs initialization.
- *
- * @tsif_device: TSIF device.
- */
-static void tspp2_tsif_debugfs_init(struct tspp2_tsif_device *tsif_device)
-{
- int i;
- char name[10];
- struct dentry *dentry;
- void __iomem *base = tsif_device->base;
-
- snprintf(name, 10, "tsif%i", tsif_device->hw_index);
- tsif_device->debugfs_entry = debugfs_create_dir(name, NULL);
-
- if (!tsif_device->debugfs_entry)
- return;
-
- dentry = tsif_device->debugfs_entry;
- if (dentry) {
- for (i = 0; i < ARRAY_SIZE(tsif_regs); i++) {
- debugfs_create_file(
- tsif_regs[i].name,
- tsif_regs[i].mode,
- dentry,
- base + tsif_regs[i].offset,
- &fops_iomem_x32);
- }
- }
-
- dentry = debugfs_create_dir("statistics", tsif_device->debugfs_entry);
- if (dentry) {
- debugfs_create_u32(
- "stat_pkt_write_err",
- S_IRUGO | S_IWUSR | S_IWGRP,
- dentry,
- &tsif_device->stat_pkt_write_err);
-
- debugfs_create_u32(
- "stat_pkt_read_err",
- S_IRUGO | S_IWUSR | S_IWGRP,
- dentry,
- &tsif_device->stat_pkt_read_err);
-
- debugfs_create_u32(
- "stat_overflow",
- S_IRUGO | S_IWUSR | S_IWGRP,
- dentry,
- &tsif_device->stat_overflow);
-
- debugfs_create_u32(
- "stat_lost_sync",
- S_IRUGO | S_IWUSR | S_IWGRP,
- dentry,
- &tsif_device->stat_lost_sync);
-
- debugfs_create_u32(
- "stat_timeout",
- S_IRUGO | S_IWUSR | S_IWGRP,
- dentry,
- &tsif_device->stat_timeout);
- }
-}
-
-static char *op_to_string(enum tspp2_operation_type op)
-{
- switch (op) {
- case TSPP2_OP_PES_ANALYSIS:
- return "TSPP2_OP_PES_ANALYSIS";
- case TSPP2_OP_RAW_TRANSMIT:
- return "TSPP2_OP_RAW_TRANSMIT";
- case TSPP2_OP_PES_TRANSMIT:
- return "TSPP2_OP_PES_TRANSMIT";
- case TSPP2_OP_PCR_EXTRACTION:
- return "TSPP2_OP_PCR_EXTRACTION";
- case TSPP2_OP_CIPHER:
- return "TSPP2_OP_CIPHER";
- case TSPP2_OP_INDEXING:
- return "TSPP2_OP_INDEXING";
- case TSPP2_OP_COPY_PACKET:
- return "TSPP2_OP_COPY_PACKET";
- default:
- return "Invalid Operation";
- }
-}
-
-static char *src_input_to_string(enum tspp2_src_input src_input)
-{
- switch (src_input) {
- case TSPP2_INPUT_TSIF0:
- return "TSPP2_INPUT_TSIF0";
- case TSPP2_INPUT_TSIF1:
- return "TSPP2_INPUT_TSIF1";
- case TSPP2_INPUT_MEMORY:
- return "TSPP2_INPUT_MEMORY";
- default:
- return "Unknown source input type";
- }
-}
-
-static char *pkt_format_to_string(enum tspp2_packet_format pkt_format)
-{
- switch (pkt_format) {
- case TSPP2_PACKET_FORMAT_188_RAW:
- return "TSPP2_PACKET_FORMAT_188_RAW";
- case TSPP2_PACKET_FORMAT_192_HEAD:
- return "TSPP2_PACKET_FORMAT_192_HEAD";
- case TSPP2_PACKET_FORMAT_192_TAIL:
- return "TSPP2_PACKET_FORMAT_192_TAIL";
- default:
- return "Unknown packet format";
- }
-}
-
-/**
- * debugfs service to print device information.
- */
-static int tspp2_device_debugfs_print(struct seq_file *s, void *p)
-{
- int count;
- int exist_flag = 0;
- struct tspp2_device *device = (struct tspp2_device *)s->private;
-
- seq_printf(s, "dev_id: %d\n", device->dev_id);
- seq_puts(s, "Enabled filters:");
- for (count = 0; count < TSPP2_NUM_AVAIL_FILTERS; count++)
- if (device->filters[count].enabled) {
- seq_printf(s, "\n\tfilter%3d", count);
- exist_flag = 1;
- }
- if (!exist_flag)
- seq_puts(s, " none\n");
- else
- seq_puts(s, "\n");
-
- exist_flag = 0;
- seq_puts(s, "Opened filters:");
- for (count = 0; count < TSPP2_NUM_AVAIL_FILTERS; count++)
- if (device->filters[count].opened) {
- seq_printf(s, "\n\tfilter%3d", count);
- exist_flag = 1;
- }
- if (!exist_flag)
- seq_puts(s, " none\n");
- else
- seq_puts(s, "\n");
-
- exist_flag = 0;
- seq_puts(s, "Opened pipes:\n");
- for (count = 0; count < TSPP2_NUM_PIPES; count++)
- if (device->pipes[count].opened) {
- seq_printf(s, "\tpipe%2d\n", count);
- exist_flag = 1;
- }
- if (!exist_flag)
- seq_puts(s, " none\n");
- else
- seq_puts(s, "\n");
-
- return 0;
-}
-
-/**
- * debugfs service to print source information.
- */
-static int tspp2_src_debugfs_print(struct seq_file *s, void *p)
-{
- struct tspp2_filter_batch *batch;
- struct tspp2_filter *filter;
- struct tspp2_output_pipe *output_pipe;
- struct tspp2_src *src = (struct tspp2_src *)s->private;
-
- if (!src) {
- seq_puts(s, "error\n");
- return 1;
- }
- seq_printf(s, "Status: %s\n", src->enabled ? "enabled" : "disabled");
- seq_printf(s, "hw_index: %d\n", src->hw_index);
- seq_printf(s, "event_bitmask: 0x%08X\n", src->event_bitmask);
- if (src->input_pipe)
- seq_printf(s, "input_pipe hw_index: %d\n",
- src->input_pipe->hw_index);
- seq_printf(s, "tspp2_src_input: %s\n", src_input_to_string(src->input));
- seq_printf(s, "pkt_format: %s\n",
- pkt_format_to_string(src->pkt_format));
- seq_printf(s, "num_associated_batches: %d\n",
- src->num_associated_batches);
-
- if (src->num_associated_batches) {
- seq_puts(s, "batch_ids: ");
- list_for_each_entry(batch, &src->batches_list, link)
- seq_printf(s, "%d ", batch->batch_id);
- seq_puts(s, "\n");
- }
-
- seq_printf(s, "num_associated_pipes: %d\n", src->num_associated_pipes);
- if (src->num_associated_pipes) {
- seq_puts(s, "pipes_hw_idxs: ");
- list_for_each_entry(output_pipe, &src->output_pipe_list, link) {
- seq_printf(s, "%d ", output_pipe->pipe->hw_index);
- }
- seq_puts(s, "\n");
- }
-
- seq_printf(s, "reserved_filter_hw_index: %d\n",
- src->reserved_filter_hw_index);
-
- seq_printf(s, "num_associated_filters: %d\n",
- src->num_associated_filters);
- if (src->num_associated_filters) {
- int i;
- seq_puts(s, "Open filters:\n");
- list_for_each_entry(filter, &src->filters_list, link) {
- if (!filter->opened)
- continue;
- seq_printf(s, "\thw_index: %d\n",
- filter->hw_index);
- seq_printf(s, "\tStatus: %s\n",
- filter->enabled ? "enabled"
- : "disabled");
- seq_printf(s, "\tpid_value: 0x%08X\n",
- filter->pid_value);
- seq_printf(s, "\tmask: 0x%08X\n", filter->mask);
- seq_printf(s, "\tnum_user_operations: %d\n",
- filter->num_user_operations);
- if (filter->num_user_operations) {
- seq_puts(
- s, "\tTypes of operations:\n");
- for (i = 0;
- i < filter->num_user_operations; i++) {
- seq_printf(s, "\t\t%s\n", op_to_string(
- filter->operations[i].type));
- }
- }
- }
-
- } else {
- seq_puts(s, "no filters\n");
- }
-
- return 0;
-}
-
-/**
- * debugfs service to print filter information.
- */
-static int filter_debugfs_print(struct seq_file *s, void *p)
-{
- int i;
- struct tspp2_filter *filter = (struct tspp2_filter *)s->private;
-
- seq_printf(s, "Status: %s\n", filter->opened ? "opened" : "closed");
- if (filter->batch)
- seq_printf(s, "Located in batch %d\n", filter->batch->batch_id);
- if (filter->src)
- seq_printf(s, "Associated with src %d\n",
- filter->src->hw_index);
- seq_printf(s, "hw_index: %d\n", filter->hw_index);
- seq_printf(s, "pid_value: 0x%08X\n", filter->pid_value);
- seq_printf(s, "mask: 0x%08X\n", filter->mask);
- seq_printf(s, "context: %d\n", filter->context);
- seq_printf(s, "indexing_table_id: %d\n", filter->indexing_table_id);
- seq_printf(s, "num_user_operations: %d\n", filter->num_user_operations);
- seq_puts(s, "Types of operations:\n");
- for (i = 0; i < filter->num_user_operations; i++)
- seq_printf(s, "\t%s\n", op_to_string(
- filter->operations[i].type));
- seq_printf(s, "indexing_op_set: %d\n", filter->indexing_op_set);
- seq_printf(s, "raw_op_with_indexing: %d\n",
- filter->raw_op_with_indexing);
- seq_printf(s, "pes_analysis_op_set: %d\n", filter->pes_analysis_op_set);
- seq_printf(s, "raw_op_set: %d\n", filter->raw_op_set);
- seq_printf(s, "pes_tx_op_set: %d\n", filter->pes_tx_op_set);
- seq_printf(s, "Status: %s\n", filter->enabled ? "enabled" : "disabled");
-
- if (filter->enabled) {
- seq_printf(s, "Filter context-based counters, context %d\n",
- filter->context);
- seq_printf(s, "filter_tsp_sync_err = 0x%08X\n",
- readl_relaxed(filter->device->base +
- TSPP2_FILTER_TSP_SYNC_ERROR(filter->context)));
- seq_printf(s, "filter_erred_tsp = 0x%08X\n",
- readl_relaxed(filter->device->base +
- TSPP2_FILTER_ERRED_TSP(filter->context)));
- seq_printf(s, "filter_discontinuities = 0x%08X\n",
- readl_relaxed(filter->device->base +
- TSPP2_FILTER_DISCONTINUITIES(filter->context)));
- seq_printf(s, "filter_sc_bits_discard = 0x%08X\n",
- readl_relaxed(filter->device->base +
- TSPP2_FILTER_SCRAMBLING_BITS_DISCARD(filter->context)));
- seq_printf(s, "filter_tsp_total_num = 0x%08X\n",
- readl_relaxed(filter->device->base +
- TSPP2_FILTER_TSP_TOTAL_NUM(filter->context)));
- seq_printf(s, "filter_discont_indicator = 0x%08X\n",
- readl_relaxed(filter->device->base +
- TSPP2_FILTER_DISCONT_INDICATOR(filter->context)));
- seq_printf(s, "filter_tsp_no_payload = 0x%08X\n",
- readl_relaxed(filter->device->base +
- TSPP2_FILTER_TSP_NO_PAYLOAD(filter->context)));
- seq_printf(s, "filter_tsp_duplicate = 0x%08X\n",
- readl_relaxed(filter->device->base +
- TSPP2_FILTER_TSP_DUPLICATE(filter->context)));
- seq_printf(s, "filter_key_fetch_fail = 0x%08X\n",
- readl_relaxed(filter->device->base +
- TSPP2_FILTER_KEY_FETCH_FAILURE(filter->context)));
- seq_printf(s, "filter_dropped_pcr = 0x%08X\n",
- readl_relaxed(filter->device->base +
- TSPP2_FILTER_DROPPED_PCR(filter->context)));
- seq_printf(s, "filter_pes_errors = 0x%08X\n",
- readl_relaxed(filter->device->base +
- TSPP2_FILTER_PES_ERRORS(filter->context)));
- }
-
- return 0;
-}
-
-/**
- * debugfs service to print pipe information.
- */
-static int pipe_debugfs_print(struct seq_file *s, void *p)
-{
- struct tspp2_pipe *pipe = (struct tspp2_pipe *)s->private;
- seq_printf(s, "hw_index: %d\n", pipe->hw_index);
- seq_printf(s, "iova: 0x%08X\n", pipe->iova);
- seq_printf(s, "threshold: %d\n", pipe->threshold);
- seq_printf(s, "Status: %s\n", pipe->opened ? "opened" : "closed");
- seq_printf(s, "ref_cnt: %d\n", pipe->ref_cnt);
- return 0;
-}
-
-static int tspp2_dev_dbgfs_open(struct inode *inode, struct file *file)
-{
- return single_open(file, tspp2_device_debugfs_print,
- inode->i_private);
-}
-
-static int tspp2_filter_dbgfs_open(struct inode *inode, struct file *file)
-{
- return single_open(file, filter_debugfs_print, inode->i_private);
-}
-
-static int tspp2_pipe_dbgfs_open(struct inode *inode, struct file *file)
-{
- return single_open(file, pipe_debugfs_print, inode->i_private);
-}
-
-static int tspp2_src_dbgfs_open(struct inode *inode, struct file *file)
-{
- return single_open(file, tspp2_src_debugfs_print, inode->i_private);
-}
-
-static const struct file_operations dbgfs_tspp2_device_fops = {
- .open = tspp2_dev_dbgfs_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .owner = THIS_MODULE,
-};
-
-static const struct file_operations dbgfs_filter_fops = {
- .open = tspp2_filter_dbgfs_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .owner = THIS_MODULE,
-};
-
-static const struct file_operations dbgfs_pipe_fops = {
- .open = tspp2_pipe_dbgfs_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .owner = THIS_MODULE,
-};
-
-static const struct file_operations dbgfs_src_fops = {
- .open = tspp2_src_dbgfs_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .owner = THIS_MODULE,
-};
-
-/**
- * tspp2_tsif_debugfs_exit() - TSIF device debugfs teardown.
- *
- * @tsif_device: TSIF device.
- */
-static void tspp2_tsif_debugfs_exit(struct tspp2_tsif_device *tsif_device)
-{
- debugfs_remove_recursive(tsif_device->debugfs_entry);
- tsif_device->debugfs_entry = NULL;
-}
-
-/**
- * tspp2_debugfs_init() - TSPP2 device debugfs initialization.
- *
- * @device: TSPP2 device.
- */
-static void tspp2_debugfs_init(struct tspp2_device *device)
-{
- int i, j;
- char name[80];
- struct dentry *dentry;
- struct dentry *dir;
- void __iomem *base = device->base;
-
- snprintf(name, 80, "tspp2_%i", device->dev_id);
- device->debugfs_entry = debugfs_create_dir(name, NULL);
-
- if (!device->debugfs_entry)
- return;
-
- /* Support device open/close */
- debugfs_create_file("open", TSPP2_S_RW, device->debugfs_entry,
- NULL, &fops_device_open);
-
- dentry = debugfs_create_dir("regs", device->debugfs_entry);
- if (dentry) {
- for (i = 0; i < ARRAY_SIZE(tspp2_regs); i++) {
- debugfs_create_file(
- tspp2_regs[i].name,
- tspp2_regs[i].mode,
- dentry,
- base + tspp2_regs[i].offset,
- &fops_iomem_x32);
- }
- }
-
- dentry = debugfs_create_dir("statistics", device->debugfs_entry);
- if (dentry) {
- debugfs_create_u32(
- "stat_tsp_invalid_af_control",
- S_IRUGO | S_IWUSR | S_IWGRP,
- dentry,
- &device->irq_stats.global.tsp_invalid_af_control);
-
- debugfs_create_u32(
- "stat_tsp_invalid_length",
- S_IRUGO | S_IWUSR | S_IWGRP,
- dentry,
- &device->irq_stats.global.tsp_invalid_length);
-
- debugfs_create_u32(
- "stat_pes_no_sync",
- S_IRUGO | S_IWUSR | S_IWGRP,
- dentry,
- &device->irq_stats.global.pes_no_sync);
-
- debugfs_create_u32(
- "stat_encrypt_level_err",
- S_IRUGO | S_IWUSR | S_IWGRP,
- dentry,
- &device->irq_stats.global.encrypt_level_err);
- }
-
- dir = debugfs_create_dir("counters", device->debugfs_entry);
- for (i = 0; i < TSPP2_NUM_CONTEXTS; i++) {
- snprintf(name, 80, "context%03i", i);
- dentry = debugfs_create_dir(name, dir);
- if (dentry) {
- debugfs_create_file("filter_tsp_sync_err",
- TSPP2_S_RW,
- dentry,
- base + TSPP2_FILTER_TSP_SYNC_ERROR(i),
- &fops_iomem_x32);
-
- debugfs_create_file("filter_erred_tsp",
- TSPP2_S_RW,
- dentry,
- base + TSPP2_FILTER_ERRED_TSP(i),
- &fops_iomem_x32);
-
- debugfs_create_file("filter_discontinuities",
- TSPP2_S_RW,
- dentry,
- base + TSPP2_FILTER_DISCONTINUITIES(i),
- &fops_iomem_x32);
-
- debugfs_create_file("filter_sc_bits_discard",
- TSPP2_S_RW,
- dentry,
- base + TSPP2_FILTER_SCRAMBLING_BITS_DISCARD(i),
- &fops_iomem_x32);
-
- debugfs_create_file("filter_tsp_total_num",
- TSPP2_S_RW,
- dentry,
- base + TSPP2_FILTER_TSP_TOTAL_NUM(i),
- &fops_iomem_x32);
-
- debugfs_create_file("filter_discont_indicator",
- TSPP2_S_RW,
- dentry,
- base + TSPP2_FILTER_DISCONT_INDICATOR(i),
- &fops_iomem_x32);
-
- debugfs_create_file("filter_tsp_no_payload",
- TSPP2_S_RW,
- dentry,
- base + TSPP2_FILTER_TSP_NO_PAYLOAD(i),
- &fops_iomem_x32);
-
- debugfs_create_file("filter_tsp_duplicate",
- TSPP2_S_RW,
- dentry,
- base + TSPP2_FILTER_TSP_DUPLICATE(i),
- &fops_iomem_x32);
-
- debugfs_create_file("filter_key_fetch_fail",
- TSPP2_S_RW,
- dentry,
- base + TSPP2_FILTER_KEY_FETCH_FAILURE(i),
- &fops_iomem_x32);
-
- debugfs_create_file("filter_dropped_pcr",
- TSPP2_S_RW,
- dentry,
- base + TSPP2_FILTER_DROPPED_PCR(i),
- &fops_iomem_x32);
-
- debugfs_create_file("filter_pes_errors",
- TSPP2_S_RW,
- dentry,
- base + TSPP2_FILTER_PES_ERRORS(i),
- &fops_iomem_x32);
-
- debugfs_create_u32(
- "stat_sc_go_high",
- S_IRUGO | S_IWUSR | S_IWGRP,
- dentry,
- &device->irq_stats.ctx[i].sc_go_high);
-
- debugfs_create_u32(
- "stat_sc_go_low",
- S_IRUGO | S_IWUSR | S_IWGRP,
- dentry,
- &device->irq_stats.ctx[i].sc_go_low);
- }
- }
-
- dir = debugfs_create_dir("filters", device->debugfs_entry);
- for (i = 0; i < TSPP2_NUM_HW_FILTERS; i++) {
- snprintf(name, 80, "filter%03i", i);
- dentry = debugfs_create_dir(name, dir);
- if (dentry) {
- debugfs_create_file("filter_entry0",
- TSPP2_S_RW,
- dentry,
- base + TSPP2_FILTER_ENTRY0(i),
- &fops_iomem_x32);
-
- debugfs_create_file("filter_entry1",
- TSPP2_S_RW,
- dentry,
- base + TSPP2_FILTER_ENTRY1(i),
- &fops_iomem_x32);
-
- for (j = 0; j < TSPP2_MAX_OPS_PER_FILTER; j++) {
- snprintf(name, 80, "opcode%02i", j);
- debugfs_create_file(name,
- TSPP2_S_RW,
- dentry,
- base + TSPP2_OPCODE(i, j),
- &fops_iomem_x32);
- }
- }
- }
-
- dir = debugfs_create_dir("mem_sources", device->debugfs_entry);
- for (i = 0; i < TSPP2_NUM_MEM_INPUTS; i++) {
- snprintf(name, 80, "mem_src%i", i);
- dentry = debugfs_create_dir(name, dir);
- if (dentry) {
- debugfs_create_u32(
- "stat_read_failure",
- S_IRUGO | S_IWUSR | S_IWGRP,
- dentry,
- &device->irq_stats.src[i].read_failure);
-
- debugfs_create_u32(
- "stat_flow_control_stall",
- S_IRUGO | S_IWUSR | S_IWGRP,
- dentry,
- &device->irq_stats.src[i].flow_control_stall);
- }
- }
-
- dir = debugfs_create_dir("key_tables", device->debugfs_entry);
- for (i = 0; i < TSPP2_NUM_KEYTABLES; i++) {
- snprintf(name, 80, "key_table%02i", i);
- dentry = debugfs_create_dir(name, dir);
- if (dentry) {
- debugfs_create_u32(
- "stat_key_not_ready",
- S_IRUGO | S_IWUSR | S_IWGRP,
- dentry,
- &device->irq_stats.kt[i].key_not_ready);
- }
- }
-
- dir = debugfs_create_dir("pipes", device->debugfs_entry);
- for (i = 0; i < TSPP2_NUM_PIPES; i++) {
- snprintf(name, 80, "pipe%02i", i);
- dentry = debugfs_create_dir(name, dir);
- if (dentry) {
- debugfs_create_file("threshold",
- TSPP2_S_RW,
- dentry,
- base + TSPP2_PIPE_THRESH_CONFIG(i),
- &fops_iomem_x32);
-
- debugfs_create_file("last_address",
- S_IRUGO,
- dentry,
- base + TSPP2_PIPE_LAST_ADDRESS(i),
- &fops_iomem_x32);
-
- debugfs_create_file("data_not_sent",
- S_IRUGO,
- dentry,
- base + TSPP2_DATA_NOT_SENT_ON_PIPE(i),
- &fops_iomem_x32);
-
- debugfs_create_u32(
- "stat_unexpected_reset",
- S_IRUGO | S_IWUSR | S_IWGRP,
- dentry,
- &device->irq_stats.pipe[i].unexpected_reset);
-
- debugfs_create_u32(
- "stat_qsb_response_error",
- S_IRUGO | S_IWUSR | S_IWGRP,
- dentry,
- &device->irq_stats.pipe[i].qsb_response_error);
-
- debugfs_create_u32(
- "stat_wrong_pipe_direction",
- S_IRUGO | S_IWUSR | S_IWGRP,
- dentry,
- &device->irq_stats.pipe[i].
- wrong_pipe_direction);
- }
- }
-
- dir = debugfs_create_dir("indexing_tables", device->debugfs_entry);
- for (i = 0; i < TSPP2_NUM_INDEXING_TABLES; i++) {
- snprintf(name, 80, "indexing_table%i", i);
- dentry = debugfs_create_dir(name, dir);
- if (dentry) {
- debugfs_create_file("prefix",
- TSPP2_S_RW,
- dentry,
- base + TSPP2_INDEX_TABLE_PREFIX(i),
- &fops_iomem_x32);
-
- debugfs_create_file("mask",
- TSPP2_S_RW,
- dentry,
- base + TSPP2_INDEX_TABLE_PREFIX_MASK(i),
- &fops_iomem_x32);
-
- debugfs_create_file("parameters",
- TSPP2_S_RW,
- dentry,
- base + TSPP2_INDEX_TABLE_PARAMS(i),
- &fops_iomem_x32);
-
- for (j = 0; j < TSPP2_NUM_INDEXING_PATTERNS; j++) {
- snprintf(name, 80, "pattern_%02i", j);
- debugfs_create_file(name,
- TSPP2_S_RW,
- dentry,
- base + TSPP2_INDEX_TABLE_PATTEREN(i, j),
- &fops_iomem_x32);
-
- snprintf(name, 80, "mask_%02i", j);
- debugfs_create_file(name,
- TSPP2_S_RW,
- dentry,
- base + TSPP2_INDEX_TABLE_MASK(i, j),
- &fops_iomem_x32);
- }
- }
- }
- dir = debugfs_create_dir("software", device->debugfs_entry);
- debugfs_create_file("device", S_IRUGO, dir, device,
- &dbgfs_tspp2_device_fops);
-
- dentry = debugfs_create_dir("filters", dir);
- if (dentry) {
- for (i = 0; i < TSPP2_NUM_AVAIL_FILTERS; i++) {
- snprintf(name, 20, "filter%03i", i);
- debugfs_create_file(name, S_IRUGO, dentry,
- &(device->filters[i]), &dbgfs_filter_fops);
- }
- }
-
- dentry = debugfs_create_dir("pipes", dir);
- if (dentry) {
- for (i = 0; i < TSPP2_NUM_PIPES; i++) {
- snprintf(name, 20, "pipe%02i", i);
- debugfs_create_file(name, S_IRUGO, dentry,
- &(device->pipes[i]), &dbgfs_pipe_fops);
- }
- }
-
- dentry = debugfs_create_dir("sources", dir);
- if (dentry) {
- for (i = 0; i < TSPP2_NUM_TSIF_INPUTS; i++) {
- snprintf(name, 20, "tsif%d", i);
- debugfs_create_file(name, S_IRUGO, dentry,
- &(device->tsif_sources[i]), &dbgfs_src_fops);
- }
- for (i = 0; i < TSPP2_NUM_MEM_INPUTS; i++) {
- snprintf(name, 20, "mem%d", i);
- debugfs_create_file(name, S_IRUGO, dentry,
- &(device->mem_sources[i]), &dbgfs_src_fops);
- }
- }
-}
-
-/**
- * tspp2_debugfs_exit() - TSPP2 device debugfs teardown.
- *
- * @device: TSPP2 device.
- */
-static void tspp2_debugfs_exit(struct tspp2_device *device)
-{
- debugfs_remove_recursive(device->debugfs_entry);
- device->debugfs_entry = NULL;
-}
-
-/**
- * tspp2_tsif_start() - Start TSIF device HW.
- *
- * @tsif_device: TSIF device.
- *
- * Return 0 on success, error value otherwise.
- */
-static int tspp2_tsif_start(struct tspp2_tsif_device *tsif_device)
-{
- u32 ctl;
-
- if (tsif_device->ref_count > 0)
- return 0;
-
- ctl = (TSIF_STS_CTL_EN_IRQ | TSIF_STS_CTL_EN_DM |
- TSIF_STS_CTL_PACK_AVAIL | TSIF_STS_CTL_OVERFLOW |
- TSIF_STS_CTL_LOST_SYNC | TSIF_STS_CTL_TIMEOUT |
- TSIF_STS_CTL_PARALLEL);
-
- if (tsif_device->clock_inverse)
- ctl |= TSIF_STS_CTL_INV_CLOCK;
-
- if (tsif_device->data_inverse)
- ctl |= TSIF_STS_CTL_INV_DATA;
-
- if (tsif_device->sync_inverse)
- ctl |= TSIF_STS_CTL_INV_SYNC;
-
- if (tsif_device->enable_inverse)
- ctl |= TSIF_STS_CTL_INV_ENABLE;
-
- switch (tsif_device->mode) {
- case TSPP2_TSIF_MODE_LOOPBACK:
- ctl |= TSIF_STS_CTL_EN_NULL |
- TSIF_STS_CTL_EN_ERROR |
- TSIF_STS_CTL_TEST_MODE;
- break;
- case TSPP2_TSIF_MODE_1:
- ctl |= TSIF_STS_CTL_EN_TIME_LIM | TSIF_STS_CTL_EN_TCR;
- break;
- case TSPP2_TSIF_MODE_2:
- ctl |= TSIF_STS_CTL_EN_TIME_LIM |
- TSIF_STS_CTL_EN_TCR |
- TSIF_STS_CTL_MODE_2;
- break;
- default:
- pr_warn("%s: Unknown TSIF mode %d, setting to TSPP2_TSIF_MODE_2\n",
- __func__, tsif_device->mode);
- ctl |= TSIF_STS_CTL_EN_TIME_LIM |
- TSIF_STS_CTL_EN_TCR |
- TSIF_STS_CTL_MODE_2;
- break;
- }
-
- writel_relaxed(ctl, tsif_device->base + TSPP2_TSIF_STS_CTL);
- writel_relaxed(tsif_device->time_limit,
- tsif_device->base + TSPP2_TSIF_TIME_LIMIT);
- wmb();
- writel_relaxed(ctl | TSIF_STS_CTL_START,
- tsif_device->base + TSPP2_TSIF_STS_CTL);
- wmb();
-
- ctl = readl_relaxed(tsif_device->base + TSPP2_TSIF_STS_CTL);
- if (ctl & TSIF_STS_CTL_START)
- tsif_device->ref_count++;
-
- return (ctl & TSIF_STS_CTL_START) ? 0 : -EBUSY;
-}
-
-
-static int tspp2_vbif_clock_start(struct tspp2_device *device)
-{
- int ret;
-
- if (device->tspp2_vbif_clk) {
- ret = clk_prepare_enable(device->tspp2_vbif_clk);
- if (ret) {
- pr_err("%s: Can't start tspp2_vbif_clk\n", __func__);
- return ret;
- }
- }
-
- if (device->vbif_ahb_clk) {
- ret = clk_prepare_enable(device->vbif_ahb_clk);
- if (ret) {
- pr_err("%s: Can't start vbif_ahb_clk\n", __func__);
- goto disable_vbif_tspp2;
- }
- }
- if (device->vbif_axi_clk) {
- ret = clk_prepare_enable(device->vbif_axi_clk);
- if (ret) {
- pr_err("%s: Can't start vbif_ahb_clk\n", __func__);
- goto disable_vbif_ahb;
- }
- }
-
- return 0;
-
-disable_vbif_ahb:
- if (device->vbif_ahb_clk)
- clk_disable_unprepare(device->vbif_ahb_clk);
-disable_vbif_tspp2:
- if (device->tspp2_vbif_clk)
- clk_disable_unprepare(device->tspp2_vbif_clk);
-
- return ret;
-}
-
-static void tspp2_vbif_clock_stop(struct tspp2_device *device)
-{
- if (device->tspp2_vbif_clk)
- clk_disable_unprepare(device->tspp2_vbif_clk);
-
- if (device->vbif_ahb_clk)
- clk_disable_unprepare(device->vbif_ahb_clk);
-
- if (device->vbif_axi_clk)
- clk_disable_unprepare(device->vbif_axi_clk);
-}
-
-/**
- * tspp2_tsif_stop() - Stop TSIF device HW.
- *
- * @tsif_device: TSIF device.
- */
-static void tspp2_tsif_stop(struct tspp2_tsif_device *tsif_device)
-{
- if (tsif_device->ref_count == 0)
- return;
-
- tsif_device->ref_count--;
-
- if (tsif_device->ref_count == 0) {
- writel_relaxed(TSIF_STS_CTL_STOP,
- tsif_device->base + TSPP2_TSIF_STS_CTL);
- /*
- * The driver assumes that after this point the TSIF is stopped,
- * so a memory barrier is required to allow
- * further register writes.
- */
- wmb();
- }
-}
-
-/* Clock functions */
-
-static int tspp2_reg_clock_start(struct tspp2_device *device)
-{
- int rc;
-
- if (device->tspp2_ahb_clk &&
- clk_prepare_enable(device->tspp2_ahb_clk) != 0) {
- pr_err("%s: Can't start tspp2_ahb_clk\n", __func__);
- return -EBUSY;
- }
-
- if (device->tspp2_core_clk &&
- clk_prepare_enable(device->tspp2_core_clk) != 0) {
- pr_err("%s: Can't start tspp2_core_clk\n", __func__);
- if (device->tspp2_ahb_clk)
- clk_disable_unprepare(device->tspp2_ahb_clk);
- return -EBUSY;
- }
-
- /* Request minimal bandwidth on the bus, required for register access */
- if (device->bus_client) {
- rc = msm_bus_scale_client_update_request(device->bus_client, 1);
- if (rc) {
- pr_err("%s: Can't enable bus\n", __func__);
- if (device->tspp2_core_clk)
- clk_disable_unprepare(device->tspp2_core_clk);
- if (device->tspp2_ahb_clk)
- clk_disable_unprepare(device->tspp2_ahb_clk);
- return -EBUSY;
- }
- }
-
- return 0;
-}
-
-static int tspp2_reg_clock_stop(struct tspp2_device *device)
-{
- /* Minimize bandwidth bus voting */
- if (device->bus_client)
- msm_bus_scale_client_update_request(device->bus_client, 0);
-
- if (device->tspp2_core_clk)
- clk_disable_unprepare(device->tspp2_core_clk);
-
- if (device->tspp2_ahb_clk)
- clk_disable_unprepare(device->tspp2_ahb_clk);
-
- return 0;
-}
-
-/**
- * tspp2_clock_start() - Enable the required TSPP2 clocks
- *
- * @device: The TSPP2 device.
- *
- * Return 0 on success, error value otherwise.
- */
-static int tspp2_clock_start(struct tspp2_device *device)
-{
- int tspp2_ahb_clk = 0;
- int tspp2_core_clk = 0;
- int tspp2_vbif_clk = 0;
- int tspp2_klm_ahb_clk = 0;
- int tsif_ref_clk = 0;
-
- if (device == NULL) {
- pr_err("%s: Can't start clocks, invalid device\n", __func__);
- return -EINVAL;
- }
-
- if (device->tspp2_ahb_clk) {
- if (clk_prepare_enable(device->tspp2_ahb_clk) != 0) {
- pr_err("%s: Can't start tspp2_ahb_clk\n", __func__);
- goto err_clocks;
- }
- tspp2_ahb_clk = 1;
- }
-
- if (device->tspp2_core_clk) {
- if (clk_prepare_enable(device->tspp2_core_clk) != 0) {
- pr_err("%s: Can't start tspp2_core_clk\n", __func__);
- goto err_clocks;
- }
- tspp2_core_clk = 1;
- }
-
- if (device->tspp2_klm_ahb_clk) {
- if (clk_prepare_enable(device->tspp2_klm_ahb_clk) != 0) {
- pr_err("%s: Can't start tspp2_klm_ahb_clk\n", __func__);
- goto err_clocks;
- }
- tspp2_klm_ahb_clk = 1;
- }
-
- if (device->tsif_ref_clk) {
- if (clk_prepare_enable(device->tsif_ref_clk) != 0) {
- pr_err("%s: Can't start tsif_ref_clk\n", __func__);
- goto err_clocks;
- }
- tsif_ref_clk = 1;
- }
-
- /* Request Max bandwidth on the bus, required for full operation */
- if (device->bus_client &&
- msm_bus_scale_client_update_request(device->bus_client, 2)) {
- pr_err("%s: Can't enable bus\n", __func__);
- goto err_clocks;
- }
-
- return 0;
-
-err_clocks:
- if (tspp2_ahb_clk)
- clk_disable_unprepare(device->tspp2_ahb_clk);
-
- if (tspp2_core_clk)
- clk_disable_unprepare(device->tspp2_core_clk);
-
- if (tspp2_vbif_clk)
- clk_disable_unprepare(device->tspp2_vbif_clk);
-
- if (tspp2_klm_ahb_clk)
- clk_disable_unprepare(device->tspp2_klm_ahb_clk);
-
- if (tsif_ref_clk)
- clk_disable_unprepare(device->tsif_ref_clk);
-
- return -EBUSY;
-}
-
-/**
- * tspp2_clock_stop() - Disable TSPP2 clocks
- *
- * @device: The TSPP2 device.
- */
-static void tspp2_clock_stop(struct tspp2_device *device)
-{
- if (device == NULL) {
- pr_err("%s: Can't stop clocks, invalid device\n", __func__);
- return;
- }
-
- /* Minimize bandwidth bus voting */
- if (device->bus_client)
- msm_bus_scale_client_update_request(device->bus_client, 0);
-
- if (device->tsif_ref_clk)
- clk_disable_unprepare(device->tsif_ref_clk);
-
- if (device->tspp2_klm_ahb_clk)
- clk_disable_unprepare(device->tspp2_klm_ahb_clk);
-
- if (device->tspp2_core_clk)
- clk_disable_unprepare(device->tspp2_core_clk);
-
- if (device->tspp2_ahb_clk)
- clk_disable_unprepare(device->tspp2_ahb_clk);
-}
-
-/**
- * tspp2_filter_counters_reset() - Reset a filter's HW counters.
- *
- * @device: TSPP2 device.
- * @index: Filter context index. Note counters are based on the context
- * index and not on the filter HW index.
- */
-static void tspp2_filter_counters_reset(struct tspp2_device *device, u32 index)
-{
- /* Reset filter counters */
- writel_relaxed(0, device->base + TSPP2_FILTER_TSP_SYNC_ERROR(index));
- writel_relaxed(0, device->base + TSPP2_FILTER_ERRED_TSP(index));
- writel_relaxed(0, device->base + TSPP2_FILTER_DISCONTINUITIES(index));
- writel_relaxed(0,
- device->base + TSPP2_FILTER_SCRAMBLING_BITS_DISCARD(index));
- writel_relaxed(0, device->base + TSPP2_FILTER_TSP_TOTAL_NUM(index));
- writel_relaxed(0, device->base + TSPP2_FILTER_DISCONT_INDICATOR(index));
- writel_relaxed(0, device->base + TSPP2_FILTER_TSP_NO_PAYLOAD(index));
- writel_relaxed(0, device->base + TSPP2_FILTER_TSP_DUPLICATE(index));
- writel_relaxed(0, device->base + TSPP2_FILTER_KEY_FETCH_FAILURE(index));
- writel_relaxed(0, device->base + TSPP2_FILTER_DROPPED_PCR(index));
- writel_relaxed(0, device->base + TSPP2_FILTER_PES_ERRORS(index));
-}
-
-/**
- * tspp2_global_hw_reset() - Reset TSPP2 device registers to a default state.
- *
- * @device: TSPP2 device.
- * @enable_intr: Enable specific interrupts or disable them.
- *
- * A helper function called from probe() and remove(), this function resets both
- * TSIF devices' SW structures and verifies the TSIF HW is stopped. It resets
- * TSPP2 registers to appropriate default values and makes sure to disable
- * all sources, filters etc. Finally, it clears all interrupts and unmasks
- * the "important" interrupts.
- *
- * Return 0 on success, error value otherwise.
- */
-static int tspp2_global_hw_reset(struct tspp2_device *device,
- int enable_intr)
-{
- int i, n;
- unsigned long rate_in_hz = 0;
- u32 global_irq_en = 0;
-
- if (!device) {
- pr_err("%s: NULL device\n", __func__);
- return -ENODEV;
- }
-
- /* Stop TSIF devices */
- for (i = 0; i < TSPP2_NUM_TSIF_INPUTS; i++) {
- device->tsif_devices[i].hw_index = i;
- device->tsif_devices[i].dev = device;
- device->tsif_devices[i].mode = TSPP2_TSIF_MODE_2;
- device->tsif_devices[i].clock_inverse = 0;
- device->tsif_devices[i].data_inverse = 0;
- device->tsif_devices[i].sync_inverse = 0;
- device->tsif_devices[i].enable_inverse = 0;
- device->tsif_devices[i].stat_pkt_write_err = 0;
- device->tsif_devices[i].stat_pkt_read_err = 0;
- device->tsif_devices[i].stat_overflow = 0;
- device->tsif_devices[i].stat_lost_sync = 0;
- device->tsif_devices[i].stat_timeout = 0;
- device->tsif_devices[i].time_limit = TSPP2_TSIF_DEF_TIME_LIMIT;
- /* Set ref_count to 1 to allow stopping HW */
- device->tsif_devices[i].ref_count = 1;
- /* This will reset ref_count to 0 */
- tspp2_tsif_stop(&device->tsif_devices[i]);
- }
-
- /* Reset indexing table registers */
- for (i = 0; i < TSPP2_NUM_INDEXING_TABLES; i++) {
- writel_relaxed(0, device->base + TSPP2_INDEX_TABLE_PREFIX(i));
- writel_relaxed(0,
- device->base + TSPP2_INDEX_TABLE_PREFIX_MASK(i));
- for (n = 0; n < TSPP2_NUM_INDEXING_PATTERNS; n++) {
- writel_relaxed(0, device->base +
- TSPP2_INDEX_TABLE_PATTEREN(i, n));
- writel_relaxed(0,
- device->base + TSPP2_INDEX_TABLE_MASK(i, n));
- }
- /* Set number of patterns to 0, prefix size to 4 by default */
- writel_relaxed(0x00000400,
- device->base + TSPP2_INDEX_TABLE_PARAMS(i));
- }
-
- /* Disable TSIF inputs. Set mode of operation to 16 batches */
- for (i = 0; i < TSPP2_NUM_TSIF_INPUTS; i++)
- writel_relaxed((0x1 << TSIF_INPUT_SRC_CONFIG_16_BATCHES_OFFS),
- device->base + TSPP2_TSIF_INPUT_SRC_CONFIG(i));
-
- /* Reset source related registers and performance counters */
- for (i = 0; i < TSPP2_NUM_ALL_INPUTS; i++) {
- writel_relaxed(0, device->base + TSPP2_SRC_DEST_PIPES(i));
-
- /* Set source configuration to default values */
- writel_relaxed(TSPP2_DEFAULT_SRC_CONFIG,
- device->base + TSPP2_SRC_CONFIG(i));
- }
- writel_relaxed(0x000003FF, device->base + TSPP2_SRC_TOTAL_TSP_RESET);
- writel_relaxed(0x000003FF,
- device->base + TSPP2_SRC_FILTERED_OUT_TSP_RESET);
-
- /* Reset all contexts, each register handles 32 contexts */
- for (i = 0; i < 4; i++) {
- writel_relaxed(0xFFFFFFFF,
- device->base + TSPP2_TSP_CONTEXT_RESET(i));
- writel_relaxed(0xFFFFFFFF,
- device->base + TSPP2_PES_CONTEXT_RESET(i));
- writel_relaxed(0xFFFFFFFF,
- device->base + TSPP2_INDEXING_CONTEXT_RESET(i));
- }
-
- for (i = 0; i < TSPP2_NUM_HW_FILTERS; i++) {
- /*
- * Reset operations: put exit operation in all filter operations
- */
- for (n = 0; n < TSPP2_MAX_OPS_PER_FILTER; n++) {
- writel_relaxed(TSPP2_OPCODE_EXIT,
- device->base + TSPP2_OPCODE(i, n));
- }
- /* Disable all HW filters */
- writel_relaxed(0, device->base + TSPP2_FILTER_ENTRY0(i));
- writel_relaxed(0, device->base + TSPP2_FILTER_ENTRY1(i));
- }
-
- for (i = 0; i < TSPP2_NUM_CONTEXTS; i++) {
- /* Reset filter context-based counters */
- tspp2_filter_counters_reset(device, i);
- }
-
- /*
- * Disable memory inputs. Set mode of operation to 16 batches.
- * Configure last batch to be associated with all memory input sources,
- * and add a filter to match all PIDs and drop the TS packets in the
- * last HW filter entry. Use the last context for this filter.
- */
- for (i = 0; i < TSPP2_NUM_MEM_INPUTS; i++)
- writel_relaxed(TSPP2_DEFAULT_MEM_SRC_CONFIG,
- device->base + TSPP2_MEM_INPUT_SRC_CONFIG(i));
-
- writel_relaxed(((TSPP2_NUM_CONTEXTS - 1) << FILTER_ENTRY1_CONTEXT_OFFS),
- device->base + TSPP2_FILTER_ENTRY1((TSPP2_NUM_HW_FILTERS - 1)));
- writel_relaxed((0x1 << FILTER_ENTRY0_EN_OFFS),
- device->base + TSPP2_FILTER_ENTRY0((TSPP2_NUM_HW_FILTERS - 1)));
-
- /* Reset pipe registers */
- for (i = 0; i < TSPP2_NUM_PIPES; i++)
- writel_relaxed(0xFFFF,
- device->base + TSPP2_PIPE_THRESH_CONFIG(i));
-
- writel_relaxed(0, device->base + TSPP2_PIPE_SECURITY);
- writel_relaxed(0x7FFFFFFF,
- device->base + TSPP2_DATA_NOT_SENT_ON_PIPE_RESET);
-
- /* Set global configuration to default values */
-
- /*
- * Default: minimum time between PCRs = 50msec, STC offset is 0,
- * transmit PCR on discontinuity.
- */
- writel_relaxed(0x00000432, device->base + TSPP2_PCR_GLOBAL_CONFIG);
-
- /* Set correct value according to TSPP2 clock: */
- if (device->tspp2_core_clk) {
- rate_in_hz = clk_get_rate(device->tspp2_core_clk);
- writel_relaxed((rate_in_hz / MSEC_PER_SEC),
- device->base + TSPP2_CLK_TO_PCR_TIME_UNIT);
- } else {
- writel_relaxed(0x00000000,
- device->base + TSPP2_CLK_TO_PCR_TIME_UNIT);
- }
-
- writel_relaxed(0x00000000, device->base + TSPP2_DESC_WAIT_TIMEOUT);
-
- /* Clear all global interrupts */
- writel_relaxed(0xFFFF000F, device->base + TSPP2_GLOBAL_IRQ_CLEAR);
- writel_relaxed(0x7FFFFFFF,
- device->base + TSPP2_UNEXPECTED_RST_IRQ_CLEAR);
- writel_relaxed(0x7FFFFFFF,
- device->base + TSPP2_WRONG_PIPE_DIR_IRQ_CLEAR);
- writel_relaxed(0x7FFFFFFF,
- device->base + TSPP2_QSB_RESPONSE_ERROR_IRQ_CLEAR);
- writel_relaxed(0xFFFFFFFF,
- device->base + TSPP2_KEY_NOT_READY_IRQ_CLEAR);
-
- /*
- * Global interrupts configuration:
- * Flow Control (per memory source): Disabled
- * Read Failure (per memory source): Enabled
- * SC_GO_LOW (aggregate): Enabled
- * SC_GO_HIGH (aggregate): Enabled
- * Wrong Pipe Direction (aggregate): Enabled
- * QSB Response Error (aggregate): Enabled
- * Unexpected Reset (aggregate): Enabled
- * Key Not Ready (aggregate): Disabled
- * Op Encrypt Level Error: Enabled
- * PES No Sync: Disabled (module parameter)
- * TSP Invalid Length: Disabled (module parameter)
- * TSP Invalid AF Control: Disabled (module parameter)
- */
- global_irq_en = 0x00FF03E8;
- if (tspp2_en_invalid_af_ctrl)
- global_irq_en |=
- (0x1 << GLOBAL_IRQ_TSP_INVALID_AF_OFFS);
- if (tspp2_en_invalid_af_length)
- global_irq_en |= (0x1 << GLOBAL_IRQ_TSP_INVALID_LEN_OFFS);
- if (tspp2_en_pes_no_sync)
- global_irq_en |= (0x1 << GLOBAL_IRQ_PES_NO_SYNC_OFFS);
-
- if (enable_intr)
- writel_relaxed(global_irq_en,
- device->base + TSPP2_GLOBAL_IRQ_ENABLE);
- else
- writel_relaxed(0, device->base + TSPP2_GLOBAL_IRQ_ENABLE);
-
- if (enable_intr) {
- /* Enable all pipe related interrupts */
- writel_relaxed(0x7FFFFFFF,
- device->base + TSPP2_UNEXPECTED_RST_IRQ_ENABLE);
- writel_relaxed(0x7FFFFFFF,
- device->base + TSPP2_WRONG_PIPE_DIR_IRQ_ENABLE);
- writel_relaxed(0x7FFFFFFF,
- device->base + TSPP2_QSB_RESPONSE_ERROR_IRQ_ENABLE);
- } else {
- /* Disable all pipe related interrupts */
- writel_relaxed(0,
- device->base + TSPP2_UNEXPECTED_RST_IRQ_ENABLE);
- writel_relaxed(0,
- device->base + TSPP2_WRONG_PIPE_DIR_IRQ_ENABLE);
- writel_relaxed(0,
- device->base + TSPP2_QSB_RESPONSE_ERROR_IRQ_ENABLE);
- }
-
- /* Disable Key Ladder interrupts */
- writel_relaxed(0, device->base + TSPP2_KEY_NOT_READY_IRQ_ENABLE);
-
- /*
- * Clear and disable scrambling control interrupts.
- * Each register handles 32 filters.
- */
- for (i = 0; i < 4; i++) {
- writel_relaxed(0xFFFFFFFF,
- device->base + TSPP2_SC_GO_HIGH_CLEAR(i));
- writel_relaxed(0, device->base + TSPP2_SC_GO_HIGH_ENABLE(i));
- writel_relaxed(0xFFFFFFFF,
- device->base + TSPP2_SC_GO_LOW_CLEAR(i));
- writel_relaxed(0, device->base + TSPP2_SC_GO_LOW_ENABLE(i));
- }
-
- dev_dbg(device->dev, "%s: successful\n", __func__);
-
- return 0;
-}
-
-/**
- * tspp2_event_work_handler - Handle the work - invoke the user callback.
- *
- * @work: The work information.
- */
-static void tspp2_event_work_handler(struct work_struct *work)
-{
- struct tspp2_event_work *event_work =
- container_of(work, struct tspp2_event_work, work);
- struct tspp2_event_work cb_info = *event_work;
-
- if (mutex_lock_interruptible(&event_work->device->mutex))
- return;
-
- list_add_tail(&event_work->link, &event_work->device->free_work_list);
-
- mutex_unlock(&event_work->device->mutex);
-
- /*
- * Must run callback with tspp2 device mutex unlocked,
- * as callback might call tspp2 driver API and cause a deadlock.
- */
- if (cb_info.callback)
- cb_info.callback(cb_info.cookie, cb_info.event_bitmask);
-}
-
-/**
- * tspp2_device_initialize() - Initialize TSPP2 device SW structures.
- *
- * @device: TSPP2 device
- *
- * Initialize the required SW structures and fields in the TSPP2 device,
- * including ION client creation, BAM registration, debugfs initialization etc.
- *
- * Return 0 on success, error value otherwise.
- */
-static int tspp2_device_initialize(struct tspp2_device *device)
-{
- int i, ret;
-
- if (!device) {
- pr_err("%s: NULL device\n", __func__);
- return -ENODEV;
- }
-
- /* Register BAM */
- device->bam_props.summing_threshold = 0x10;
- device->bam_props.irq = device->bam_irq;
- device->bam_props.manage = SPS_BAM_MGR_LOCAL;
-
- ret = sps_register_bam_device(&device->bam_props, &device->bam_handle);
- if (ret) {
- pr_err("%s: failed to register BAM\n", __func__);
- return ret;
- }
- ret = sps_device_reset(device->bam_handle);
- if (ret) {
- sps_deregister_bam_device(device->bam_handle);
- pr_err("%s: error resetting BAM\n", __func__);
- return ret;
- }
-
- spin_lock_init(&device->spinlock);
- wakeup_source_init(&device->wakeup_src, dev_name(&device->pdev->dev));
-
- for (i = 0; i < TSPP2_NUM_TSIF_INPUTS; i++)
- tspp2_tsif_debugfs_init(&device->tsif_devices[i]);
-
- /*
- * The device structure was allocated using devm_kzalloc() so
- * the memory was initialized to zero. We don't need to specifically set
- * fields to zero, then. We only set the fields we need to, such as
- * batch_id.
- */
-
- for (i = 0; i < TSPP2_NUM_BATCHES; i++) {
- device->batches[i].batch_id = i;
- device->batches[i].src = NULL;
- INIT_LIST_HEAD(&device->batches[i].link);
- }
-
- /*
- * We set the device back-pointer in the sources, filters and pipes
- * databases here, so that back-pointer is always valid (instead of
- * setting it when opening a source, filter or pipe).
- */
- for (i = 0; i < TSPP2_NUM_TSIF_INPUTS; i++)
- device->tsif_sources[i].device = device;
-
- for (i = 0; i < TSPP2_NUM_MEM_INPUTS; i++)
- device->mem_sources[i].device = device;
-
- for (i = 0; i < TSPP2_NUM_AVAIL_FILTERS; i++)
- device->filters[i].device = device;
-
- for (i = 0; i < TSPP2_NUM_PIPES; i++)
- device->pipes[i].device = device;
-
- /*
- * Note: tsif_devices are initialized as part of tspp2_global_hw_reset()
- */
-
- device->work_queue =
- create_singlethread_workqueue(dev_name(device->dev));
- INIT_LIST_HEAD(&device->free_work_list);
- for (i = 0; i < TSPP2_NUM_EVENT_WORK_ELEMENTS; i++) {
- device->work_pool[i].device = device;
- device->work_pool[i].callback = 0;
- device->work_pool[i].cookie = 0;
- device->work_pool[i].event_bitmask = 0;
- INIT_LIST_HEAD(&device->work_pool[i].link);
- INIT_WORK(&device->work_pool[i].work,
- tspp2_event_work_handler);
-
- list_add_tail(&device->work_pool[i].link,
- &device->free_work_list);
- }
-
- device->event_callback = NULL;
- device->event_cookie = NULL;
-
- dev_dbg(device->dev, "%s: successful\n", __func__);
-
- return 0;
-}
-
-/**
- * tspp2_device_uninitialize() - TSPP2 device teardown and cleanup.
- *
- * @device: TSPP2 device
- *
- * TSPP2 device teardown: debugfs removal, BAM de-registration etc.
- * Return 0 on success, error value otherwise.
- */
-static int tspp2_device_uninitialize(struct tspp2_device *device)
-{
- int i;
-
- if (!device) {
- pr_err("%s: NULL device\n", __func__);
- return -ENODEV;
- }
-
- destroy_workqueue(device->work_queue);
-
- for (i = 0; i < TSPP2_NUM_TSIF_INPUTS; i++)
- tspp2_tsif_debugfs_exit(&device->tsif_devices[i]);
-
- /* Need to start clocks for BAM de-registration */
- if (pm_runtime_get_sync(device->dev) >= 0) {
- sps_deregister_bam_device(device->bam_handle);
- pm_runtime_mark_last_busy(device->dev);
- pm_runtime_put_autosuspend(device->dev);
- }
-
- wakeup_source_trash(&device->wakeup_src);
-
- dev_dbg(device->dev, "%s: successful\n", __func__);
-
- return 0;
-}
-
-/**
- * tspp2_src_disable_internal() - Helper function to disable a source.
- *
- * @src: Source to disable.
- *
- * Return 0 on success, error value otherwise.
- */
-static int tspp2_src_disable_internal(struct tspp2_src *src)
-{
- u32 reg;
-
- if (!src) {
- pr_err("%s: Invalid source handle\n", __func__);
- return -EINVAL;
- }
-
- if (!src->opened) {
- pr_err("%s: Source not opened\n", __func__);
- return -EINVAL;
- }
-
- if (!src->enabled) {
- pr_warn("%s: Source already disabled\n", __func__);
- return 0;
- }
-
- if ((src->input == TSPP2_INPUT_TSIF0) ||
- (src->input == TSPP2_INPUT_TSIF1)) {
- reg = readl_relaxed(src->device->base +
- TSPP2_TSIF_INPUT_SRC_CONFIG(src->input));
- reg &= ~(0x1 << TSIF_INPUT_SRC_CONFIG_INPUT_EN_OFFS);
- writel_relaxed(reg, src->device->base +
- TSPP2_TSIF_INPUT_SRC_CONFIG(src->input));
-
- tspp2_tsif_stop(&src->device->tsif_devices[src->input]);
- } else {
- reg = readl_relaxed(src->device->base +
- TSPP2_MEM_INPUT_SRC_CONFIG(src->hw_index));
- reg &= ~(0x1 << MEM_INPUT_SRC_CONFIG_INPUT_EN_OFFS);
- writel_relaxed(reg, src->device->base +
- TSPP2_MEM_INPUT_SRC_CONFIG(src->hw_index));
- }
-
- /*
- * HW requires we wait for up to 2ms here before closing the pipes
- * attached to (and used by) this source
- */
- udelay(TSPP2_HW_DELAY_USEC);
-
- src->enabled = 0;
- src->device->num_enabled_sources--;
-
- if (src->device->num_enabled_sources == 0) {
- __pm_relax(&src->device->wakeup_src);
- tspp2_clock_stop(src->device);
- }
-
- return 0;
-}
-
-/* TSPP2 device open / close API */
-
-/**
- * tspp2_device_open() - Open a TSPP2 device for use.
- *
- * @dev_id: TSPP2 device ID.
- *
- * Return 0 on success, error value otherwise.
- */
-int tspp2_device_open(u32 dev_id)
-{
- int rc;
- u32 reg = 0;
- struct tspp2_device *device;
-
- if (dev_id >= TSPP2_NUM_DEVICES) {
- pr_err("%s: Invalid device ID %d\n", __func__, dev_id);
- return -ENODEV;
- }
-
- device = tspp2_devices[dev_id];
- if (!device) {
- pr_err("%s: Invalid device\n", __func__);
- return -ENODEV;
- }
-
- if (mutex_lock_interruptible(&device->mutex))
- return -ERESTARTSYS;
-
- if (device->opened) {
- pr_err("%s: Device already opened\n", __func__);
- mutex_unlock(&device->mutex);
- return -EPERM;
- }
-
- /* Enable power regulator */
- rc = regulator_enable(device->gdsc);
- if (rc)
- goto err_mutex_unlock;
-
- /* Reset TSPP2 core */
- clk_reset(device->tspp2_core_clk, CLK_RESET_ASSERT);
- udelay(10);
- clk_reset(device->tspp2_core_clk, CLK_RESET_DEASSERT);
-
- /* Start HW clocks before accessing registers */
- rc = tspp2_reg_clock_start(device);
- if (rc)
- goto err_regulator_disable;
-
- rc = tspp2_global_hw_reset(device, 1);
- if (rc)
- goto err_stop_clocks;
-
- rc = tspp2_device_initialize(device);
- if (rc)
- goto err_stop_clocks;
-
- reg = readl_relaxed(device->base + TSPP2_VERSION);
- pr_info("TSPP2 HW Version: Major = %d, Minor = %d, Step = %d\n",
- ((reg & 0xF0000000) >> VERSION_MAJOR_OFFS),
- ((reg & 0x0FFF0000) >> VERSION_MINOR_OFFS),
- ((reg & 0x0000FFFF) >> VERSION_STEP_OFFS));
-
- /* Stop HW clocks to save power */
- tspp2_reg_clock_stop(device);
-
- /* Enable runtime power management */
- pm_runtime_set_autosuspend_delay(device->dev, MSEC_PER_SEC);
- pm_runtime_use_autosuspend(device->dev);
- pm_runtime_enable(device->dev);
-
- device->opened = 1;
-
- mutex_unlock(&device->mutex);
-
- dev_dbg(device->dev, "%s: successful\n", __func__);
-
- return 0;
-
-err_stop_clocks:
- tspp2_reg_clock_stop(device);
-err_regulator_disable:
- regulator_disable(device->gdsc);
-err_mutex_unlock:
- mutex_unlock(&device->mutex);
-
- return rc;
-}
-EXPORT_SYMBOL(tspp2_device_open);
-
-/**
- * tspp2_device_close() - Close a TSPP2 device.
- *
- * @dev_id: TSPP2 device ID.
- *
- * Return 0 on success, error value otherwise.
- */
-int tspp2_device_close(u32 dev_id)
-{
- int i;
- int ret = 0;
- struct tspp2_device *device;
-
- if (dev_id >= TSPP2_NUM_DEVICES) {
- pr_err("%s: Invalid device ID %d\n", __func__, dev_id);
- return -ENODEV;
- }
-
- device = tspp2_devices[dev_id];
- if (!device) {
- pr_err("%s: Invalid device\n", __func__);
- return -ENODEV;
- }
-
- ret = pm_runtime_get_sync(device->dev);
- if (ret < 0)
- return ret;
-
- mutex_lock(&device->mutex);
-
- if (!device->opened) {
- pr_err("%s: Device already closed\n", __func__);
- mutex_unlock(&device->mutex);
- pm_runtime_mark_last_busy(device->dev);
- pm_runtime_put_autosuspend(device->dev);
- return -EPERM;
- }
- device->opened = 0;
-
- /*
- * In case the user has not disabled all the enabled sources, we need
- * to disable them here, specifically in order to call tspp2_clock_stop,
- * because the calls to enable and disable the clocks should be
- * symmetrical (otherwise we cannot put the clocks).
- */
- for (i = 0; i < TSPP2_NUM_TSIF_INPUTS; i++) {
- if (device->tsif_sources[i].enabled)
- tspp2_src_disable_internal(&device->tsif_sources[i]);
- }
- for (i = 0; i < TSPP2_NUM_MEM_INPUTS; i++) {
- if (device->mem_sources[i].enabled)
- tspp2_src_disable_internal(&device->mem_sources[i]);
- }
-
- /* bring HW registers back to a known state */
- tspp2_global_hw_reset(device, 0);
-
- tspp2_device_uninitialize(device);
-
- pm_runtime_mark_last_busy(device->dev);
- pm_runtime_put_autosuspend(device->dev);
-
- /* Disable runtime power management */
- pm_runtime_disable(device->dev);
- pm_runtime_set_suspended(device->dev);
-
- if (regulator_disable(device->gdsc))
- pr_err("%s: Error disabling power regulator\n", __func__);
-
- mutex_unlock(&device->mutex);
-
- dev_dbg(device->dev, "%s: successful\n", __func__);
-
- return 0;
-}
-EXPORT_SYMBOL(tspp2_device_close);
-
-/* Global configuration API */
-
-/**
- * tspp2_config_set() - Set device global configuration.
- *
- * @dev_id: TSPP2 device ID.
- * @cfg: TSPP2 global configuration parameters to set.
- *
- * Return 0 on success, error value otherwise.
- */
-int tspp2_config_set(u32 dev_id, const struct tspp2_config *cfg)
-{
- int ret;
- u32 reg = 0;
- struct tspp2_device *device;
-
- if (dev_id >= TSPP2_NUM_DEVICES) {
- pr_err("%s: Invalid device ID %d\n", __func__, dev_id);
- return -ENODEV;
- }
- if (!cfg) {
- pr_err("%s: NULL configuration\n", __func__);
- return -EINVAL;
- }
- if (cfg->stc_byte_offset > 3) {
- pr_err("%s: Invalid stc_byte_offset %d, valid values are 0 - 3\n",
- __func__, cfg->stc_byte_offset);
- return -EINVAL;
- }
-
- device = tspp2_devices[dev_id];
- if (!device) {
- pr_err("%s: Invalid device\n", __func__);
- return -ENODEV;
- }
-
- ret = pm_runtime_get_sync(device->dev);
- if (ret < 0)
- return ret;
-
- if (mutex_lock_interruptible(&device->mutex)) {
- pm_runtime_mark_last_busy(device->dev);
- pm_runtime_put_autosuspend(device->dev);
- return -ERESTARTSYS;
- }
-
- if (!device->opened) {
- pr_err("%s: Device must be opened first\n", __func__);
- mutex_unlock(&device->mutex);
- pm_runtime_mark_last_busy(device->dev);
- pm_runtime_put_autosuspend(device->dev);
- return -EPERM;
- }
-
- if (cfg->pcr_on_discontinuity)
- reg |= (0x1 << PCR_GLOBAL_CONFIG_PCR_ON_DISCONT_OFFS);
-
- reg |= (cfg->stc_byte_offset << PCR_GLOBAL_CONFIG_STC_OFFSET_OFFS);
- reg |= (cfg->min_pcr_interval << PCR_GLOBAL_CONFIG_PCR_INTERVAL_OFFS);
-
- writel_relaxed(reg, device->base + TSPP2_PCR_GLOBAL_CONFIG);
-
- mutex_unlock(&device->mutex);
-
- pm_runtime_mark_last_busy(device->dev);
- pm_runtime_put_autosuspend(device->dev);
-
- dev_dbg(device->dev, "%s: successful\n", __func__);
-
- return 0;
-}
-EXPORT_SYMBOL(tspp2_config_set);
-
-/**
- * tspp2_config_get() - Get current global configuration.
- *
- * @dev_id: TSPP2 device ID.
- * @cfg: TSPP2 global configuration parameters.
- *
- * Return 0 on success, error value otherwise.
- */
-int tspp2_config_get(u32 dev_id, struct tspp2_config *cfg)
-{
- int ret;
- u32 reg = 0;
- struct tspp2_device *device;
-
- if (dev_id >= TSPP2_NUM_DEVICES) {
- pr_err("%s: Invalid device ID %d\n", __func__, dev_id);
- return -ENODEV;
- }
- if (!cfg) {
- pr_err("%s: NULL configuration\n", __func__);
- return -EINVAL;
- }
-
- device = tspp2_devices[dev_id];
- if (!device) {
- pr_err("%s: Invalid device\n", __func__);
- return -ENODEV;
- }
-
- ret = pm_runtime_get_sync(device->dev);
- if (ret < 0)
- return ret;
-
- if (mutex_lock_interruptible(&device->mutex)) {
- pm_runtime_mark_last_busy(device->dev);
- pm_runtime_put_autosuspend(device->dev);
- return -ERESTARTSYS;
- }
-
- if (!device->opened) {
- pr_err("%s: Device must be opened first\n", __func__);
- mutex_unlock(&device->mutex);
- pm_runtime_mark_last_busy(device->dev);
- pm_runtime_put_autosuspend(device->dev);
- return -EPERM;
- }
-
- reg = readl_relaxed(device->base + TSPP2_PCR_GLOBAL_CONFIG);
-
- cfg->pcr_on_discontinuity = ((reg & PCR_GLOBAL_CONFIG_PCR_ON_DISCONT) >>
- PCR_GLOBAL_CONFIG_PCR_ON_DISCONT_OFFS);
- cfg->stc_byte_offset = ((reg & PCR_GLOBAL_CONFIG_STC_OFFSET) >>
- PCR_GLOBAL_CONFIG_STC_OFFSET_OFFS);
- cfg->min_pcr_interval = ((reg & PCR_GLOBAL_CONFIG_PCR_INTERVAL) >>
- PCR_GLOBAL_CONFIG_PCR_INTERVAL_OFFS);
-
- mutex_unlock(&device->mutex);
-
- pm_runtime_mark_last_busy(device->dev);
- pm_runtime_put_autosuspend(device->dev);
-
- dev_dbg(device->dev, "%s: successful\n", __func__);
-
- return 0;
-}
-EXPORT_SYMBOL(tspp2_config_get);
-
-/* Indexing tables API functions */
-
-/**
- * tspp2_indexing_prefix_set() - Set prefix value and mask of an indexing table.
- *
- * @dev_id: TSPP2 device ID.
- * @table_id: Indexing table ID.
- * @value: Prefix 4-byte value.
- * @mask: Prefix 4-byte mask.
- *
- * Return 0 on success, error value otherwise.
- */
-int tspp2_indexing_prefix_set(u32 dev_id,
- u8 table_id,
- u32 value,
- u32 mask)
-{
- int ret;
- u32 reg;
- u8 size = 0;
- int i;
- struct tspp2_device *device;
- struct tspp2_indexing_table *table;
-
- if (dev_id >= TSPP2_NUM_DEVICES) {
- pr_err("%s: Invalid device ID %d\n", __func__, dev_id);
- return -ENODEV;
- }
- if (table_id >= TSPP2_NUM_INDEXING_TABLES) {
- pr_err("%s: Invalid table ID %d\n", __func__, table_id);
- return -EINVAL;
- }
-
- device = tspp2_devices[dev_id];
- if (!device) {
- pr_err("%s: Invalid device\n", __func__);
- return -ENODEV;
- }
-
- ret = pm_runtime_get_sync(device->dev);
- if (ret < 0)
- return ret;
-
- if (mutex_lock_interruptible(&device->mutex)) {
- pm_runtime_mark_last_busy(device->dev);
- pm_runtime_put_autosuspend(device->dev);
- return -ERESTARTSYS;
- }
-
- if (!device->opened) {
- pr_err("%s: Device must be opened first\n", __func__);
- mutex_unlock(&device->mutex);
- pm_runtime_mark_last_busy(device->dev);
- pm_runtime_put_autosuspend(device->dev);
- return -EPERM;
- }
-
- table = &device->indexing_tables[table_id];
- table->prefix_value = value;
- table->prefix_mask = mask;
-
- /* HW expects values/masks to be written in Big Endian format */
- writel_relaxed(cpu_to_be32(value),
- device->base + TSPP2_INDEX_TABLE_PREFIX(table_id));
- writel_relaxed(cpu_to_be32(mask),
- device->base + TSPP2_INDEX_TABLE_PREFIX_MASK(table_id));
-
- /* Find the actual size of the prefix and set to HW */
- reg = readl_relaxed(device->base + TSPP2_INDEX_TABLE_PARAMS(table_id));
- for (i = 0; i < 32; i += 8) {
- if (mask & (0x000000FF << i))
- size++;
- }
- reg &= ~(0x7 << INDEX_TABLE_PARAMS_PREFIX_SIZE_OFFS);
- reg |= (size << INDEX_TABLE_PARAMS_PREFIX_SIZE_OFFS);
- writel_relaxed(reg, device->base + TSPP2_INDEX_TABLE_PARAMS(table_id));
-
- mutex_unlock(&device->mutex);
-
- pm_runtime_mark_last_busy(device->dev);
- pm_runtime_put_autosuspend(device->dev);
-
- dev_dbg(device->dev, "%s: successful\n", __func__);
-
- return 0;
-}
-EXPORT_SYMBOL(tspp2_indexing_prefix_set);
-
-/**
- * tspp2_indexing_patterns_add() - Add patterns to an indexing table.
- *
- * @dev_id: TSPP2 device ID.
- * @table_id: Indexing table ID.
- * @values: An array of 4-byte pattern values.
- * @masks: An array of corresponding 4-byte masks.
- * @patterns_num: Number of patterns in the values / masks arrays.
- * Up to TSPP2_NUM_INDEXING_PATTERNS.
- *
- * Return 0 on success, error value otherwise.
- */
-int tspp2_indexing_patterns_add(u32 dev_id,
- u8 table_id,
- const u32 *values,
- const u32 *masks,
- u8 patterns_num)
-{
- int ret;
- int i;
- u16 offs = 0;
- u32 reg;
- struct tspp2_device *device;
- struct tspp2_indexing_table *table;
-
- if (dev_id >= TSPP2_NUM_DEVICES) {
- pr_err("%s: Invalid device ID %d\n", __func__, dev_id);
- return -ENODEV;
- }
- if (table_id >= TSPP2_NUM_INDEXING_TABLES) {
- pr_err("%s: Invalid table ID %d\n", __func__, table_id);
- return -EINVAL;
- }
- if (!values || !masks) {
- pr_err("%s: NULL values or masks array\n", __func__);
- return -EINVAL;
- }
-
- device = tspp2_devices[dev_id];
- if (!device) {
- pr_err("%s: Invalid device\n", __func__);
- return -ENODEV;
- }
-
- ret = pm_runtime_get_sync(device->dev);
- if (ret < 0)
- return ret;
-
- if (mutex_lock_interruptible(&device->mutex)) {
- pm_runtime_mark_last_busy(device->dev);
- pm_runtime_put_autosuspend(device->dev);
- return -ERESTARTSYS;
- }
-
- if (!device->opened) {
- pr_err("%s: Device must be opened first\n", __func__);
- mutex_unlock(&device->mutex);
- pm_runtime_mark_last_busy(device->dev);
- pm_runtime_put_autosuspend(device->dev);
- return -EPERM;
- }
-
- table = &device->indexing_tables[table_id];
-
- if ((table->num_valid_entries + patterns_num) >
- TSPP2_NUM_INDEXING_PATTERNS) {
- pr_err("%s: Trying to add too many patterns: current number %d, trying to add %d, maximum allowed %d\n",
- __func__, table->num_valid_entries, patterns_num,
- TSPP2_NUM_INDEXING_PATTERNS);
- mutex_unlock(&device->mutex);
- pm_runtime_mark_last_busy(device->dev);
- pm_runtime_put_autosuspend(device->dev);
- return -EINVAL;
- }
-
- /* There's enough room to add all the requested patterns */
- offs = table->num_valid_entries;
- for (i = 0; i < patterns_num; i++) {
- table->entry_value[offs + i] = values[i];
- table->entry_mask[offs + i] = masks[i];
- writel_relaxed(cpu_to_be32(values[i]),
- device->base +
- TSPP2_INDEX_TABLE_PATTEREN(table_id, offs + i));
- writel_relaxed(cpu_to_be32(masks[i]), device->base +
- TSPP2_INDEX_TABLE_MASK(table_id, offs + i));
- }
- table->num_valid_entries += patterns_num;
- reg = readl_relaxed(device->base + TSPP2_INDEX_TABLE_PARAMS(table_id));
- reg &= ~(0x1F << INDEX_TABLE_PARAMS_NUM_PATTERNS_OFFS);
- reg |= (table->num_valid_entries <<
- INDEX_TABLE_PARAMS_NUM_PATTERNS_OFFS);
- writel_relaxed(reg, device->base + TSPP2_INDEX_TABLE_PARAMS(table_id));
-
- mutex_unlock(&device->mutex);
-
- pm_runtime_mark_last_busy(device->dev);
- pm_runtime_put_autosuspend(device->dev);
-
- dev_dbg(device->dev, "%s: successful\n", __func__);
-
- return 0;
-}
-EXPORT_SYMBOL(tspp2_indexing_patterns_add);
-
-/**
- * tspp2_indexing_patterns_clear() - Clear all patterns of an indexing table.
- *
- * @dev_id: TSPP2 device ID.
- * @table_id: Indexing table ID.
- *
- * Return 0 on success, error value otherwise.
- */
-int tspp2_indexing_patterns_clear(u32 dev_id,
- u8 table_id)
-{
- int ret;
- int i;
- u32 reg;
- struct tspp2_device *device;
- struct tspp2_indexing_table *table;
-
- if (dev_id >= TSPP2_NUM_DEVICES) {
- pr_err("%s: Invalid device ID %d\n", __func__, dev_id);
- return -ENODEV;
- }
- if (table_id >= TSPP2_NUM_INDEXING_TABLES) {
- pr_err("%s: Invalid table ID %d\n", __func__, table_id);
- return -EINVAL;
- }
-
- device = tspp2_devices[dev_id];
- if (!device) {
- pr_err("%s: Invalid device\n", __func__);
- return -ENODEV;
- }
-
- ret = pm_runtime_get_sync(device->dev);
- if (ret < 0)
- return ret;
-
- if (mutex_lock_interruptible(&device->mutex)) {
- pm_runtime_mark_last_busy(device->dev);
- pm_runtime_put_autosuspend(device->dev);
- return -ERESTARTSYS;
- }
-
- if (!device->opened) {
- pr_err("%s: Device must be opened first\n", __func__);
- mutex_unlock(&device->mutex);
- pm_runtime_mark_last_busy(device->dev);
- pm_runtime_put_autosuspend(device->dev);
- return -EPERM;
- }
-
- table = &device->indexing_tables[table_id];
-
- for (i = 0; i < table->num_valid_entries; i++) {
- table->entry_value[i] = 0;
- table->entry_mask[i] = 0;
- writel_relaxed(0, device->base +
- TSPP2_INDEX_TABLE_PATTEREN(table_id, i));
- writel_relaxed(0, device->base +
- TSPP2_INDEX_TABLE_MASK(table_id, i));
-
- }
- table->num_valid_entries = 0;
- reg = readl_relaxed(device->base + TSPP2_INDEX_TABLE_PARAMS(table_id));
- reg &= ~(0x1F << INDEX_TABLE_PARAMS_NUM_PATTERNS_OFFS);
- writel_relaxed(reg, device->base + TSPP2_INDEX_TABLE_PARAMS(table_id));
-
- mutex_unlock(&device->mutex);
-
- pm_runtime_mark_last_busy(device->dev);
- pm_runtime_put_autosuspend(device->dev);
-
- dev_dbg(device->dev, "%s: successful\n", __func__);
-
- return 0;
-}
-EXPORT_SYMBOL(tspp2_indexing_patterns_clear);
-
-/* Pipe API functions */
-
-/**
- * tspp2_pipe_memory_init() - Initialize pipe memory helper function.
- *
- * @pipe: The pipe to work on.
- *
- * The user is responsible for allocating the pipe's memory buffer via ION.
- * This helper function maps the given buffer to TSPP2 IOMMU memory space,
- * and sets the pipe's secure bit.
- *
- * Return 0 on success, error value otherwise.
- */
-static int tspp2_pipe_memory_init(struct tspp2_pipe *pipe)
-{
- int ret = 0;
- u32 reg;
- size_t align;
- unsigned long dummy_size = 0;
- size_t len = 0;
- int domain = 0;
- int partition = 0;
- int hlos_group_attached = 0;
- int cpz_group_attached = 0;
- int vbif_clk_started = 0;
-
- if (pipe->cfg.is_secure) {
- domain = pipe->device->iommu_info.cpz_domain_num;
- partition = pipe->device->iommu_info.cpz_partition;
- align = SZ_1M;
- } else {
- domain = pipe->device->iommu_info.hlos_domain_num;
- partition = pipe->device->iommu_info.hlos_partition;
- align = SZ_4K;
- }
-
- if (tspp2_iommu_bypass) {
- ret = ion_phys(pipe->cfg.ion_client,
- pipe->cfg.buffer_handle, &pipe->iova, &len);
-
- dummy_size = 0;
-
- if (ret) {
- pr_err("%s: Failed to get buffer physical address, ret = %d\n",
- __func__, ret);
- return ret;
- }
-
- if ((pipe->device->num_secured_opened_pipes +
- pipe->device->num_non_secured_opened_pipes) == 0) {
- ret = tspp2_vbif_clock_start(pipe->device);
- if (ret) {
- pr_err(
- "%s: tspp2_vbif_clock_start failed, ret=%d\n",
- __func__, ret);
- return ret;
- }
- vbif_clk_started = 1;
- }
- } else {
- /*
- * We need to attach the group to enable the IOMMU and support
- * the required memory mapping. This needs to be done before
- * the first mapping is performed, so the number of opened pipes
- * (of each type: secure or non-secure) is used as a
- * reference count. Note that since the pipe descriptors are
- * always allocated from HLOS domain, the HLOS group must be
- * attached regardless of the pipe's security configuration.
- * The mutex is taken at this point so there is no problem with
- * synchronization.
- */
- if ((pipe->device->num_secured_opened_pipes +
- pipe->device->num_non_secured_opened_pipes) == 0) {
- ret = tspp2_vbif_clock_start(pipe->device);
- if (ret) {
- pr_err("%s: tspp2_vbif_clock_start failed, ret=%d\n",
- __func__, ret);
- goto err_out;
- }
- vbif_clk_started = 1;
-
- pr_debug("%s: attaching HLOS group\n", __func__);
- ret = iommu_attach_group(
- pipe->device->iommu_info.hlos_domain,
- pipe->device->iommu_info.hlos_group);
-
- if (ret) {
- pr_err("%s: Failed attaching IOMMU HLOS group, %d\n",
- __func__, ret);
- goto err_out;
- }
- hlos_group_attached = 1;
- }
-
- if (pipe->cfg.is_secure &&
- (pipe->device->num_secured_opened_pipes == 0)) {
- pr_debug("%s: attaching CPZ group\n", __func__);
- ret = iommu_attach_group(
- pipe->device->iommu_info.cpz_domain,
- pipe->device->iommu_info.cpz_group);
-
- if (ret) {
- pr_err("%s: Failed attaching IOMMU CPZ group, %d\n",
- __func__, ret);
- goto err_out;
- }
- cpz_group_attached = 1;
- }
-
- /* Map to TSPP2 IOMMU */
- ret = ion_map_iommu(pipe->cfg.ion_client,
- pipe->cfg.buffer_handle,
- domain,
- partition,
- align, 0, &pipe->iova,
- &dummy_size, 0, 0); /* Uncached mapping */
-
- if (ret) {
- pr_err("%s: Failed mapping buffer to TSPP2, %d\n",
- __func__, ret);
- goto err_out;
- }
- }
-
- if (pipe->cfg.is_secure) {
- reg = readl_relaxed(pipe->device->base + TSPP2_PIPE_SECURITY);
- reg |= (0x1 << pipe->hw_index);
- writel_relaxed(reg, pipe->device->base + TSPP2_PIPE_SECURITY);
- }
-
- dev_dbg(pipe->device->dev, "%s: successful\n", __func__);
-
- return 0;
-
-err_out:
- if (hlos_group_attached) {
- iommu_detach_group(pipe->device->iommu_info.hlos_domain,
- pipe->device->iommu_info.hlos_group);
- }
-
- if (cpz_group_attached) {
- iommu_detach_group(pipe->device->iommu_info.cpz_domain,
- pipe->device->iommu_info.cpz_group);
- }
-
- if (vbif_clk_started)
- tspp2_vbif_clock_stop(pipe->device);
-
- return ret;
-}
-
-/**
- * tspp2_pipe_memory_terminate() - Unmap pipe memory.
- *
- * @pipe: The pipe to work on.
- *
- * Unmap the pipe's memory and clear the pipe's secure bit.
- */
-static void tspp2_pipe_memory_terminate(struct tspp2_pipe *pipe)
-{
- u32 reg;
- int domain = 0;
- int partition = 0;
-
- if (pipe->cfg.is_secure) {
- domain = pipe->device->iommu_info.cpz_domain_num;
- partition = pipe->device->iommu_info.cpz_partition;
- } else {
- domain = pipe->device->iommu_info.hlos_domain_num;
- partition = pipe->device->iommu_info.hlos_partition;
- }
-
- if (!tspp2_iommu_bypass) {
- ion_unmap_iommu(pipe->cfg.ion_client,
- pipe->cfg.buffer_handle,
- domain,
- partition);
-
- /*
- * Opposite to what is done in tspp2_pipe_memory_init(),
- * here we detach the IOMMU group when it is no longer in use.
- */
- if (pipe->cfg.is_secure &&
- (pipe->device->num_secured_opened_pipes == 0)) {
- pr_debug("%s: detaching CPZ group\n", __func__);
- iommu_detach_group(
- pipe->device->iommu_info.cpz_domain,
- pipe->device->iommu_info.cpz_group);
- }
-
- if ((pipe->device->num_secured_opened_pipes +
- pipe->device->num_non_secured_opened_pipes) == 0) {
- pr_debug("%s: detaching HLOS group\n", __func__);
- iommu_detach_group(
- pipe->device->iommu_info.hlos_domain,
- pipe->device->iommu_info.hlos_group);
- tspp2_vbif_clock_stop(pipe->device);
- }
- } else if ((pipe->device->num_secured_opened_pipes +
- pipe->device->num_non_secured_opened_pipes) == 0) {
- tspp2_vbif_clock_stop(pipe->device);
- }
-
- pipe->iova = 0;
-
- if (pipe->cfg.is_secure) {
- reg = readl_relaxed(pipe->device->base + TSPP2_PIPE_SECURITY);
- reg &= ~(0x1 << pipe->hw_index);
- writel_relaxed(reg, pipe->device->base + TSPP2_PIPE_SECURITY);
- }
-
- dev_dbg(pipe->device->dev, "%s: successful\n", __func__);
-}
-
-/**
- * tspp2_sps_pipe_init() - BAM SPS pipe configuration and initialization
- *
- * @pipe: The pipe to work on.
- *
- * Return 0 on success, error value otherwise.
- */
-static int tspp2_sps_pipe_init(struct tspp2_pipe *pipe)
-{
- u32 descriptors_num;
- unsigned long dummy_size = 0;
- int ret = 0;
- int iommu_mapped = 0;
-
- if (pipe->cfg.buffer_size % pipe->cfg.sps_cfg.descriptor_size) {
- pr_err(
- "%s: Buffer size %d is not aligned to descriptor size %d\n",
- __func__, pipe->cfg.buffer_size,
- pipe->cfg.sps_cfg.descriptor_size);
- return -EINVAL;
- }
-
- pipe->sps_pipe = sps_alloc_endpoint();
- if (!pipe->sps_pipe) {
- pr_err("%s: Failed to allocate BAM pipe\n", __func__);
- return -ENOMEM;
- }
-
- /* get default configuration */
- sps_get_config(pipe->sps_pipe, &pipe->sps_connect_cfg);
- if (pipe->cfg.pipe_mode == TSPP2_SRC_PIPE_INPUT) {
- pipe->sps_connect_cfg.mode = SPS_MODE_DEST;
- pipe->sps_connect_cfg.source = SPS_DEV_HANDLE_MEM;
- pipe->sps_connect_cfg.destination = pipe->device->bam_handle;
- pipe->sps_connect_cfg.dest_pipe_index = pipe->hw_index;
- } else {
- pipe->sps_connect_cfg.mode = SPS_MODE_SRC;
- pipe->sps_connect_cfg.source = pipe->device->bam_handle;
- pipe->sps_connect_cfg.destination = SPS_DEV_HANDLE_MEM;
- pipe->sps_connect_cfg.src_pipe_index = pipe->hw_index;
- }
- pipe->sps_connect_cfg.desc.base = NULL;
- pipe->sps_connect_cfg.options = pipe->cfg.sps_cfg.setting;
- descriptors_num = (pipe->cfg.buffer_size /
- pipe->cfg.sps_cfg.descriptor_size);
-
- /*
- * If size of descriptors FIFO can hold N descriptors, we can submit
- * (N-1) descriptors only, therefore we allocate extra descriptor
- */
- descriptors_num++;
- pipe->sps_connect_cfg.desc.size = (descriptors_num *
- sizeof(struct sps_iovec));
-
- if (tspp2_iommu_bypass) {
- pipe->sps_connect_cfg.desc.base = dma_alloc_coherent(NULL,
- pipe->sps_connect_cfg.desc.size,
- &pipe->sps_connect_cfg.desc.phys_base,
- GFP_KERNEL);
-
- if (!pipe->sps_connect_cfg.desc.base) {
- pr_err("%s: Failed to allocate descriptor FIFO\n",
- __func__);
- ret = -ENOMEM;
- goto init_sps_failed_free_endpoint;
- }
- } else {
- pipe->desc_ion_handle = ion_alloc(pipe->cfg.ion_client,
- pipe->sps_connect_cfg.desc.size,
- SZ_4K, ION_HEAP(ION_IOMMU_HEAP_ID), 0);
-
- if (!pipe->desc_ion_handle) {
- pr_err("%s: Failed to allocate descriptors via ION\n",
- __func__);
- ret = -ENOMEM;
- goto init_sps_failed_free_endpoint;
- }
-
- ret = ion_map_iommu(pipe->cfg.ion_client,
- pipe->desc_ion_handle,
- pipe->device->iommu_info.hlos_domain_num,
- pipe->device->iommu_info.hlos_partition,
- SZ_4K, 0,
- &pipe->sps_connect_cfg.desc.phys_base,
- &dummy_size, 0, 0); /* Uncached mapping */
-
- if (ret) {
- pr_err("%s: Failed mapping descriptors to IOMMU\n",
- __func__);
- goto init_sps_failed_free_mem;
- }
-
- iommu_mapped = 1;
-
- pipe->sps_connect_cfg.desc.base =
- ion_map_kernel(pipe->cfg.ion_client,
- pipe->desc_ion_handle);
-
- if (!pipe->sps_connect_cfg.desc.base) {
- pr_err("%s: Failed mapping descriptors to kernel\n",
- __func__);
- ret = -ENOMEM;
- goto init_sps_failed_free_mem;
- }
- }
-
- ret = sps_connect(pipe->sps_pipe, &pipe->sps_connect_cfg);
- if (ret) {
- pr_err("%s: Failed to connect BAM, %d\n", __func__, ret);
- goto init_sps_failed_free_mem;
- }
-
- pipe->sps_event.options = pipe->cfg.sps_cfg.wakeup_events;
- if (pipe->sps_event.options) {
- pipe->sps_event.mode = SPS_TRIGGER_CALLBACK;
- pipe->sps_event.callback = pipe->cfg.sps_cfg.callback;
- pipe->sps_event.xfer_done = NULL;
- pipe->sps_event.user = pipe->cfg.sps_cfg.user_info;
-
- ret = sps_register_event(pipe->sps_pipe, &pipe->sps_event);
- if (ret) {
- pr_err("%s: Failed to register pipe event, %d\n",
- __func__, ret);
- goto init_sps_failed_free_connection;
- }
- }
-
- dev_dbg(pipe->device->dev, "%s: successful\n", __func__);
-
- return 0;
-
-init_sps_failed_free_connection:
- sps_disconnect(pipe->sps_pipe);
-init_sps_failed_free_mem:
- if (tspp2_iommu_bypass) {
- dma_free_coherent(NULL, pipe->sps_connect_cfg.desc.size,
- pipe->sps_connect_cfg.desc.base,
- pipe->sps_connect_cfg.desc.phys_base);
- } else {
- if (pipe->sps_connect_cfg.desc.base)
- ion_unmap_kernel(pipe->cfg.ion_client,
- pipe->desc_ion_handle);
-
- if (iommu_mapped) {
- ion_unmap_iommu(pipe->cfg.ion_client,
- pipe->desc_ion_handle,
- pipe->device->iommu_info.hlos_domain_num,
- pipe->device->iommu_info.hlos_partition);
- }
-
- ion_free(pipe->cfg.ion_client, pipe->desc_ion_handle);
- }
-init_sps_failed_free_endpoint:
- sps_free_endpoint(pipe->sps_pipe);
-
- return ret;
-}
-
-/**
- * tspp2_sps_queue_descriptors() - Queue BAM SPS descriptors
- *
- * @pipe: The pipe to work on.
- *
- * Return 0 on success, error value otherwise.
- */
-static int tspp2_sps_queue_descriptors(struct tspp2_pipe *pipe)
-{
- int ret = 0;
- u32 data_offset = 0;
- u32 desc_length = pipe->cfg.sps_cfg.descriptor_size;
- u32 desc_flags = pipe->cfg.sps_cfg.descriptor_flags;
- u32 data_length = pipe->cfg.buffer_size;
-
- while (data_length > 0) {
- ret = sps_transfer_one(pipe->sps_pipe,
- pipe->iova + data_offset,
- desc_length,
- pipe->cfg.sps_cfg.user_info,
- desc_flags);
-
- if (ret) {
- pr_err("%s: sps_transfer_one failed, %d\n",
- __func__, ret);
- return ret;
- }
-
- data_offset += desc_length;
- data_length -= desc_length;
- }
-
- return 0;
-}
-
-/**
- * tspp2_sps_pipe_terminate() - Disconnect and terminate SPS BAM pipe
- *
- * @pipe: The pipe to work on.
- *
- * Return 0 on success, error value otherwise.
- */
-static int tspp2_sps_pipe_terminate(struct tspp2_pipe *pipe)
-{
- int ret;
-
- ret = sps_disconnect(pipe->sps_pipe);
- if (ret) {
- pr_err("%s: failed to disconnect BAM pipe, %d\n",
- __func__, ret);
- return ret;
- }
- if (tspp2_iommu_bypass) {
- dma_free_coherent(NULL, pipe->sps_connect_cfg.desc.size,
- pipe->sps_connect_cfg.desc.base,
- pipe->sps_connect_cfg.desc.phys_base);
- } else {
- ion_unmap_kernel(pipe->cfg.ion_client,
- pipe->desc_ion_handle);
-
- ion_unmap_iommu(pipe->cfg.ion_client,
- pipe->desc_ion_handle,
- pipe->device->iommu_info.hlos_domain_num,
- pipe->device->iommu_info.hlos_partition);
-
- ion_free(pipe->cfg.ion_client, pipe->desc_ion_handle);
- }
- pipe->sps_connect_cfg.desc.base = NULL;
-
- ret = sps_free_endpoint(pipe->sps_pipe);
- if (ret) {
- pr_err("%s: failed to release BAM end-point, %d\n",
- __func__, ret);
- return ret;
- }
-
- return 0;
-}
-
-/**
- * tspp2_pipe_open() - Open a pipe for use.
- *
- * @dev_id: TSPP2 device ID.
- * @cfg: Pipe configuration parameters.
- * @iova: TSPP2 IOMMU virtual address of the pipe's buffer.
- * @pipe_handle: Opened pipe handle.
- *
- * Return 0 on success, error value otherwise.
- */
-int tspp2_pipe_open(u32 dev_id,
- const struct tspp2_pipe_config_params *cfg,
- ion_phys_addr_t *iova,
- u32 *pipe_handle)
-{
- struct tspp2_device *device;
- struct tspp2_pipe *pipe;
- int i;
- int ret = 0;
-
- if (dev_id >= TSPP2_NUM_DEVICES) {
- pr_err("%s: Invalid device ID %d\n", __func__, dev_id);
- return -ENODEV;
- }
-
- if (!cfg || !iova || !pipe_handle) {
- pr_err("%s: Invalid parameters\n", __func__);
- return -EINVAL;
- }
-
- /* Some minimal sanity tests on the pipe configuration: */
- if (!cfg->ion_client || !cfg->buffer_handle) {
- pr_err("%s: Invalid parameters\n", __func__);
- return -EINVAL;
- }
-
- device = tspp2_devices[dev_id];
- if (!device) {
- pr_err("%s: Invalid device\n", __func__);
- return -ENODEV;
- }
-
- ret = pm_runtime_get_sync(device->dev);
- if (ret < 0)
- return ret;
-
- if (mutex_lock_interruptible(&device->mutex)) {
- pm_runtime_mark_last_busy(device->dev);
- pm_runtime_put_autosuspend(device->dev);
- return -ERESTARTSYS;
- }
-
- if (!device->opened) {
- pr_err("%s: Device must be opened first\n", __func__);
- mutex_unlock(&device->mutex);
- pm_runtime_mark_last_busy(device->dev);
- pm_runtime_put_autosuspend(device->dev);
- return -EPERM;
- }
-
- /* Find a free pipe */
- for (i = 0; i < TSPP2_NUM_PIPES; i++) {
- pipe = &device->pipes[i];
- if (!pipe->opened)
- break;
- }
- if (i == TSPP2_NUM_PIPES) {
- pr_err("%s: No available pipes\n", __func__);
- mutex_unlock(&device->mutex);
- pm_runtime_mark_last_busy(device->dev);
- pm_runtime_put_autosuspend(device->dev);
- return -ENOMEM;
- }
-
- pipe->hw_index = i;
- /* Actual pipe threshold is set when the pipe is attached to a source */
- pipe->threshold = 0;
- pipe->cfg = *cfg;
- pipe->ref_cnt = 0;
- /* device back-pointer is already initialized, always remains valid */
-
- ret = tspp2_pipe_memory_init(pipe);
- if (ret) {
- pr_err("%s: Error initializing pipe memory\n", __func__);
- mutex_unlock(&device->mutex);
- pm_runtime_mark_last_busy(device->dev);
- pm_runtime_put_autosuspend(device->dev);
- return ret;
- }
- ret = tspp2_sps_pipe_init(pipe);
- if (ret) {
- pr_err("%s: Error initializing BAM pipe\n", __func__);
- tspp2_pipe_memory_terminate(pipe);
- mutex_unlock(&device->mutex);
- pm_runtime_mark_last_busy(device->dev);
- pm_runtime_put_autosuspend(device->dev);
- return ret;
- }
-
- /* For output pipes, we queue BAM descriptors here so they are ready */
- if (pipe->cfg.pipe_mode == TSPP2_SRC_PIPE_OUTPUT) {
- ret = tspp2_sps_queue_descriptors(pipe);
- if (ret) {
- pr_err("%s: Error queuing BAM pipe descriptors\n",
- __func__);
- tspp2_sps_pipe_terminate(pipe);
- tspp2_pipe_memory_terminate(pipe);
- mutex_unlock(&device->mutex);
- pm_runtime_mark_last_busy(device->dev);
- pm_runtime_put_autosuspend(device->dev);
- return ret;
- }
- }
-
- /* Reset counter */
- writel_relaxed((0x1 << pipe->hw_index),
- device->base + TSPP2_DATA_NOT_SENT_ON_PIPE_RESET);
-
- /* Return handle to the caller */
- *pipe_handle = (u32)pipe;
- *iova = pipe->iova;
-
- pipe->opened = 1;
- if (pipe->cfg.is_secure)
- device->num_secured_opened_pipes++;
- else
- device->num_non_secured_opened_pipes++;
-
- mutex_unlock(&device->mutex);
-
- pm_runtime_mark_last_busy(device->dev);
- pm_runtime_put_autosuspend(device->dev);
-
- dev_dbg(device->dev, "%s: successful\n", __func__);
-
- return 0;
-}
-EXPORT_SYMBOL(tspp2_pipe_open);
-
-/**
- * tspp2_pipe_close() - Close an opened pipe.
- *
- * @pipe_handle: Pipe to be closed.
- *
- * Return 0 on success, error value otherwise.
- */
-int tspp2_pipe_close(u32 pipe_handle)
-{
- int ret;
- struct tspp2_pipe *pipe = (struct tspp2_pipe *)pipe_handle;
-
- if (!pipe) {
- pr_err("%s: Invalid pipe handle\n", __func__);
- return -EINVAL;
- }
-
- ret = pm_runtime_get_sync(pipe->device->dev);
- if (ret < 0)
- return ret;
-
- mutex_lock(&pipe->device->mutex);
-
- if (!pipe->device->opened) {
- pr_err("%s: Device must be opened first\n", __func__);
- mutex_unlock(&pipe->device->mutex);
- pm_runtime_mark_last_busy(pipe->device->dev);
- pm_runtime_put_autosuspend(pipe->device->dev);
- return -EPERM;
- }
-
- if (!pipe->opened) {
- pr_err("%s: Pipe already closed\n", __func__);
- mutex_unlock(&pipe->device->mutex);
- pm_runtime_mark_last_busy(pipe->device->dev);
- pm_runtime_put_autosuspend(pipe->device->dev);
- return -EINVAL;
- }
-
- if (pipe->ref_cnt > 0) {
- pr_err("%s: Pipe %u is still attached to a source\n",
- __func__, pipe_handle);
- mutex_unlock(&pipe->device->mutex);
- pm_runtime_mark_last_busy(pipe->device->dev);
- pm_runtime_put_autosuspend(pipe->device->dev);
- return -EPERM;
- }
-
- /*
- * Note: need to decrement the pipe reference count here, before
- * calling tspp2_pipe_memory_terminate().
- */
- if (pipe->cfg.is_secure)
- pipe->device->num_secured_opened_pipes--;
- else
- pipe->device->num_non_secured_opened_pipes--;
-
- tspp2_sps_pipe_terminate(pipe);
- tspp2_pipe_memory_terminate(pipe);
-
- pipe->iova = 0;
- pipe->opened = 0;
-
- mutex_unlock(&pipe->device->mutex);
-
- pm_runtime_mark_last_busy(pipe->device->dev);
- pm_runtime_put_autosuspend(pipe->device->dev);
-
- dev_dbg(pipe->device->dev, "%s: successful\n", __func__);
-
- return 0;
-}
-EXPORT_SYMBOL(tspp2_pipe_close);
-
-/* Source API functions */
-
-/**
- * tspp2_src_open() - Open a new source for use.
- *
- * @dev_id: TSPP2 device ID.
- * @cfg: Source configuration parameters.
- * @src_handle: Opened source handle.
- *
- * Return 0 on success, error value otherwise.
- */
-int tspp2_src_open(u32 dev_id,
- struct tspp2_src_cfg *cfg,
- u32 *src_handle)
-{
- int ret;
- int i;
- struct tspp2_device *device;
- struct tspp2_src *src;
- enum tspp2_src_input input;
-
- if (dev_id >= TSPP2_NUM_DEVICES) {
- pr_err("%s: Invalid device ID %d\n", __func__, dev_id);
- return -ENODEV;
- }
- if (!src_handle) {
- pr_err("%s: Invalid source handle pointer\n", __func__);
- return -EINVAL;
- }
- if (!cfg) {
- pr_err("%s: Invalid configuration parameters\n", __func__);
- return -EINVAL;
- }
-
- device = tspp2_devices[dev_id];
- if (!device) {
- pr_err("%s: Invalid device\n", __func__);
- return -ENODEV;
- }
-
- ret = pm_runtime_get_sync(device->dev);
- if (ret < 0)
- return ret;
-
- if (mutex_lock_interruptible(&device->mutex)) {
- pm_runtime_mark_last_busy(device->dev);
- pm_runtime_put_autosuspend(device->dev);
- return -ERESTARTSYS;
- }
-
- if (!device->opened) {
- pr_err("%s: Device must be opened first\n", __func__);
- mutex_unlock(&device->mutex);
- pm_runtime_mark_last_busy(device->dev);
- pm_runtime_put_autosuspend(device->dev);
- return -EPERM;
- }
-
- input = cfg->input;
- if ((input == TSPP2_INPUT_TSIF0) || (input == TSPP2_INPUT_TSIF1)) {
- /* Input from TSIF */
- if (device->tsif_sources[input].opened) {
- pr_err("%s: TSIF input %d already opened\n",
- __func__, input);
- mutex_unlock(&device->mutex);
- pm_runtime_mark_last_busy(device->dev);
- pm_runtime_put_autosuspend(device->dev);
- return -EINVAL;
- }
- src = &device->tsif_sources[input];
-
- /*
- * When writing to HW registers that are relevant to sources
- * of both TSIF and memory input types, the register offsets
- * for the TSIF-related registers come after the memory-related
- * registers. For example: for TSPP2_SRC_CONFIG(n), n=[0..9],
- * indexes 0..7 are for memory inputs, and indexes 8, 9 are
- * for TSIF inputs.
- */
- src->hw_index = TSPP2_NUM_MEM_INPUTS + input;
-
- /* Save TSIF source parameters in TSIF device */
- device->tsif_devices[input].mode =
- cfg->params.tsif_params.tsif_mode;
- device->tsif_devices[input].clock_inverse =
- cfg->params.tsif_params.clock_inverse;
- device->tsif_devices[input].data_inverse =
- cfg->params.tsif_params.data_inverse;
- device->tsif_devices[input].sync_inverse =
- cfg->params.tsif_params.sync_inverse;
- device->tsif_devices[input].enable_inverse =
- cfg->params.tsif_params.enable_inverse;
- } else {
- /* Input from memory */
- for (i = 0; i < TSPP2_NUM_MEM_INPUTS; i++) {
- if (!device->mem_sources[i].opened)
- break;
- }
- if (i == TSPP2_NUM_MEM_INPUTS) {
- pr_err("%s: No memory inputs available\n", __func__);
- mutex_unlock(&device->mutex);
- pm_runtime_mark_last_busy(device->dev);
- pm_runtime_put_autosuspend(device->dev);
- return -ENOMEM;
- }
-
- src = &device->mem_sources[i];
- src->hw_index = i;
- }
-
- src->opened = 1;
- src->input = input;
- src->pkt_format = TSPP2_PACKET_FORMAT_188_RAW; /* default value */
- src->scrambling_bits_monitoring = TSPP2_SRC_SCRAMBLING_MONITOR_NONE;
- INIT_LIST_HEAD(&src->batches_list);
- INIT_LIST_HEAD(&src->filters_list);
- src->input_pipe = NULL;
- INIT_LIST_HEAD(&src->output_pipe_list);
- src->num_associated_batches = 0;
- src->num_associated_pipes = 0;
- src->num_associated_filters = 0;
- src->reserved_filter_hw_index = 0;
- src->event_callback = NULL;
- src->event_cookie = NULL;
- src->event_bitmask = 0;
- src->enabled = 0;
- /* device back-pointer is already initialized, always remains valid */
-
- /* Reset source-related registers */
- if ((input == TSPP2_INPUT_TSIF0) || (input == TSPP2_INPUT_TSIF1)) {
- writel_relaxed((0x1 << TSIF_INPUT_SRC_CONFIG_16_BATCHES_OFFS),
- device->base +
- TSPP2_TSIF_INPUT_SRC_CONFIG(src->input));
- } else {
- /*
- * Disable memory inputs. Set mode of operation to 16 batches.
- * Configure last batch to be associated with this source.
- */
- writel_relaxed(TSPP2_DEFAULT_MEM_SRC_CONFIG,
- device->base +
- TSPP2_MEM_INPUT_SRC_CONFIG(src->hw_index));
- }
- writel_relaxed(0, device->base +
- TSPP2_SRC_DEST_PIPES(src->hw_index));
- writel_relaxed(TSPP2_DEFAULT_SRC_CONFIG, device->base +
- TSPP2_SRC_CONFIG(src->hw_index));
- writel_relaxed((0x1 << src->hw_index),
- device->base + TSPP2_SRC_TOTAL_TSP_RESET);
- writel_relaxed((0x1 << src->hw_index),
- device->base + TSPP2_SRC_FILTERED_OUT_TSP_RESET);
-
- /* Return handle to the caller */
- *src_handle = (u32)src;
-
- mutex_unlock(&device->mutex);
-
- pm_runtime_mark_last_busy(device->dev);
- pm_runtime_put_autosuspend(device->dev);
-
- dev_dbg(device->dev, "%s: successful\n", __func__);
-
- return 0;
-}
-EXPORT_SYMBOL(tspp2_src_open);
-
-/**
- * tspp2_src_close() - Close an opened source.
- *
- * @src_handle: Source to be closed.
- *
- * Return 0 on success, error value otherwise.
- */
-int tspp2_src_close(u32 src_handle)
-{
- unsigned long flags;
- struct tspp2_src *src = (struct tspp2_src *)src_handle;
-
- if (!src) {
- pr_err("%s: Invalid source handle\n", __func__);
- return -EINVAL;
- }
-
- mutex_lock(&src->device->mutex);
-
- if (!src->device->opened) {
- pr_err("%s: Device must be opened first\n", __func__);
- mutex_unlock(&src->device->mutex);
- return -EPERM;
- }
-
- if (!src->opened) {
- pr_err("%s: Source already closed\n", __func__);
- mutex_unlock(&src->device->mutex);
- return -EINVAL;
- }
-
- if (src->enabled) {
- pr_err("%s: Source needs to be disabled before it can be closed\n",
- __func__);
- mutex_unlock(&src->device->mutex);
- return -EPERM;
- }
-
- /* Verify resources have been released by the caller */
- if ((src->num_associated_batches > 0) ||
- (src->num_associated_pipes > 0) ||
- (src->num_associated_filters > 0)) {
- pr_err("%s: Source's resources need to be removed before it can be closed\n",
- __func__);
- mutex_unlock(&src->device->mutex);
- return -EPERM;
- }
-
- /*
- * Most fields are reset to default values when opening a source, so
- * there is no need to reset them all here. We only need to mark the
- * source as closed.
- */
- src->opened = 0;
- spin_lock_irqsave(&src->device->spinlock, flags);
- src->event_callback = NULL;
- src->event_cookie = NULL;
- src->event_bitmask = 0;
- spin_unlock_irqrestore(&src->device->spinlock, flags);
- src->enabled = 0;
-
- /*
- * Source-related HW registers are reset when opening a source, so
- * we don't reser them here. Note that a source is disabled before
- * it is closed, so no need to disable it here either.
- */
-
- mutex_unlock(&src->device->mutex);
-
- dev_dbg(src->device->dev, "%s: successful\n", __func__);
-
- return 0;
-}
-EXPORT_SYMBOL(tspp2_src_close);
-
-/**
- * tspp2_src_parsing_option_set() - Set source parsing configuration option.
- *
- * @src_handle: Source to configure.
- * @option: Parsing configuration option to enable / disable.
- * @enable: Enable / disable option.
- *
- * Return 0 on success, error value otherwise.
- */
-int tspp2_src_parsing_option_set(u32 src_handle,
- enum tspp2_src_parsing_option option,
- int enable)
-{
- int ret;
- u32 reg = 0;
- struct tspp2_src *src = (struct tspp2_src *)src_handle;
-
- if (!src) {
- pr_err("%s: Invalid source handle\n", __func__);
- return -EINVAL;
- }
-
- ret = pm_runtime_get_sync(src->device->dev);
- if (ret < 0)
- return ret;
-
- if (mutex_lock_interruptible(&src->device->mutex)) {
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
- return -ERESTARTSYS;
- }
-
- if (!src->device->opened) {
- pr_err("%s: Device must be opened first\n", __func__);
- mutex_unlock(&src->device->mutex);
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
- return -EPERM;
- }
-
- if (!src->opened) {
- pr_err("%s: Source not opened\n", __func__);
- mutex_unlock(&src->device->mutex);
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
- return -EINVAL;
- }
-
- reg = readl_relaxed(src->device->base +
- TSPP2_SRC_CONFIG(src->hw_index));
-
- switch (option) {
- case TSPP2_SRC_PARSING_OPT_CHECK_CONTINUITY:
- if (enable)
- reg |= (0x1 << SRC_CONFIG_CHECK_CONT_OFFS);
- else
- reg &= ~(0x1 << SRC_CONFIG_CHECK_CONT_OFFS);
- break;
- case TSPP2_SRC_PARSING_OPT_IGNORE_DISCONTINUITY:
- if (enable)
- reg |= (0x1 << SRC_CONFIG_IGNORE_DISCONT_OFFS);
- else
- reg &= ~(0x1 << SRC_CONFIG_IGNORE_DISCONT_OFFS);
- break;
- case TSPP2_SRC_PARSING_OPT_ASSUME_DUPLICATE_PACKETS:
- if (enable)
- reg |= (0x1 << SRC_CONFIG_ASSUME_DUPLICATES_OFFS);
- else
- reg &= ~(0x1 << SRC_CONFIG_ASSUME_DUPLICATES_OFFS);
- break;
- case TSPP2_SRC_PARSING_OPT_DISCARD_INVALID_AF_PACKETS:
- if (enable)
- reg |= (0x1 << SRC_CONFIG_DISCARD_INVALID_AF_OFFS);
- else
- reg &= ~(0x1 << SRC_CONFIG_DISCARD_INVALID_AF_OFFS);
- break;
- case TSPP2_SRC_PARSING_OPT_VERIFY_PES_START:
- if (enable)
- reg |= (0x1 << SRC_CONFIG_VERIFY_PES_START_OFFS);
- else
- reg &= ~(0x1 << SRC_CONFIG_VERIFY_PES_START_OFFS);
- break;
- default:
- pr_err("%s: Invalid option %d\n", __func__, option);
- mutex_unlock(&src->device->mutex);
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
- return -EINVAL;
- }
-
- writel_relaxed(reg, src->device->base +
- TSPP2_SRC_CONFIG(src->hw_index));
-
- mutex_unlock(&src->device->mutex);
-
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
-
- dev_dbg(src->device->dev, "%s: successful\n", __func__);
-
- return 0;
-}
-EXPORT_SYMBOL(tspp2_src_parsing_option_set);
-
-/**
- * tspp2_src_parsing_option_get() - Get source parsing configuration option.
- *
- * @src_handle: Source handle.
- * @option: Parsing configuration option to get.
- * @enable: Option's enable / disable indication.
- *
- * Return 0 on success, error value otherwise.
- */
-int tspp2_src_parsing_option_get(u32 src_handle,
- enum tspp2_src_parsing_option option,
- int *enable)
-{
- int ret;
- u32 reg = 0;
- struct tspp2_src *src = (struct tspp2_src *)src_handle;
-
- if (!src) {
- pr_err("%s: Invalid source handle\n", __func__);
- return -EINVAL;
- }
- if (!enable) {
- pr_err("%s: NULL pointer\n", __func__);
- return -EINVAL;
- }
-
- ret = pm_runtime_get_sync(src->device->dev);
- if (ret < 0)
- return ret;
-
- if (mutex_lock_interruptible(&src->device->mutex)) {
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
- return -ERESTARTSYS;
- }
-
- if (!src->device->opened) {
- pr_err("%s: Device must be opened first\n", __func__);
- mutex_unlock(&src->device->mutex);
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
- return -EPERM;
- }
-
- if (!src->opened) {
- pr_err("%s: Source not opened\n", __func__);
- mutex_unlock(&src->device->mutex);
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
- return -EINVAL;
- }
-
- reg = readl_relaxed(src->device->base +
- TSPP2_SRC_CONFIG(src->hw_index));
-
- switch (option) {
- case TSPP2_SRC_PARSING_OPT_CHECK_CONTINUITY:
- *enable = ((reg >> SRC_CONFIG_CHECK_CONT_OFFS) & 0x1);
- break;
- case TSPP2_SRC_PARSING_OPT_IGNORE_DISCONTINUITY:
- *enable = ((reg >> SRC_CONFIG_IGNORE_DISCONT_OFFS) & 0x1);
- break;
- case TSPP2_SRC_PARSING_OPT_ASSUME_DUPLICATE_PACKETS:
- *enable = ((reg >> SRC_CONFIG_ASSUME_DUPLICATES_OFFS) & 0x1);
- break;
- case TSPP2_SRC_PARSING_OPT_DISCARD_INVALID_AF_PACKETS:
- *enable = ((reg >> SRC_CONFIG_DISCARD_INVALID_AF_OFFS) & 0x1);
- break;
- case TSPP2_SRC_PARSING_OPT_VERIFY_PES_START:
- *enable = ((reg >> SRC_CONFIG_VERIFY_PES_START_OFFS) & 0x1);
- break;
- default:
- pr_err("%s: Invalid option %d\n", __func__, option);
- mutex_unlock(&src->device->mutex);
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
- return -EINVAL;
- }
-
- mutex_unlock(&src->device->mutex);
-
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
-
- dev_dbg(src->device->dev, "%s: successful\n", __func__);
-
- return 0;
-}
-EXPORT_SYMBOL(tspp2_src_parsing_option_get);
-
-/**
- * tspp2_src_sync_byte_config_set() - Set source sync byte configuration.
- *
- * @src_handle: Source to configure.
- * @check_sync_byte: Check TS packet sync byte.
- * @sync_byte_value: Sync byte value to check (e.g., 0x47).
- *
- * Return 0 on success, error value otherwise.
- */
-int tspp2_src_sync_byte_config_set(u32 src_handle,
- int check_sync_byte,
- u8 sync_byte_value)
-{
- int ret;
- u32 reg = 0;
- struct tspp2_src *src = (struct tspp2_src *)src_handle;
-
- if (!src) {
- pr_err("%s: Invalid source handle\n", __func__);
- return -EINVAL;
- }
-
- ret = pm_runtime_get_sync(src->device->dev);
- if (ret < 0)
- return ret;
-
- if (mutex_lock_interruptible(&src->device->mutex)) {
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
- return -ERESTARTSYS;
- }
-
- if (!src->device->opened) {
- pr_err("%s: Device must be opened first\n", __func__);
- mutex_unlock(&src->device->mutex);
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
- return -EPERM;
- }
-
- if (!src->opened) {
- pr_err("%s: Source not opened\n", __func__);
- mutex_unlock(&src->device->mutex);
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
- return -EINVAL;
- }
-
- reg = readl_relaxed(src->device->base +
- TSPP2_SRC_CONFIG(src->hw_index));
-
- if (check_sync_byte)
- reg |= (0x1 << SRC_CONFIG_CHECK_SYNC_OFFS);
- else
- reg &= ~(0x1 << SRC_CONFIG_CHECK_SYNC_OFFS);
-
- reg &= ~(0xFF << SRC_CONFIG_SYNC_BYTE_OFFS);
- reg |= (sync_byte_value << SRC_CONFIG_SYNC_BYTE_OFFS);
-
- writel_relaxed(reg, src->device->base +
- TSPP2_SRC_CONFIG(src->hw_index));
-
- mutex_unlock(&src->device->mutex);
-
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
-
- dev_dbg(src->device->dev, "%s: successful\n", __func__);
-
- return 0;
-}
-EXPORT_SYMBOL(tspp2_src_sync_byte_config_set);
-
-/**
- * tspp2_src_sync_byte_config_get() - Get source sync byte configuration.
- *
- * @src_handle: Source handle.
- * @check_sync_byte: Check TS packet sync byte indication.
- * @sync_byte_value: Sync byte value.
- *
- * Return 0 on success, error value otherwise.
- */
-int tspp2_src_sync_byte_config_get(u32 src_handle,
- int *check_sync_byte,
- u8 *sync_byte_value)
-{
- int ret;
- u32 reg = 0;
- struct tspp2_src *src = (struct tspp2_src *)src_handle;
-
- if (!src) {
- pr_err("%s: Invalid source handle\n", __func__);
- return -EINVAL;
- }
- if (!check_sync_byte || !sync_byte_value) {
- pr_err("%s: NULL pointer\n", __func__);
- return -EINVAL;
- }
-
- ret = pm_runtime_get_sync(src->device->dev);
- if (ret < 0)
- return ret;
-
- if (mutex_lock_interruptible(&src->device->mutex)) {
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
- return -ERESTARTSYS;
- }
-
- if (!src->device->opened) {
- pr_err("%s: Device must be opened first\n", __func__);
- mutex_unlock(&src->device->mutex);
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
- return -EPERM;
- }
-
- if (!src->opened) {
- pr_err("%s: Source not opened\n", __func__);
- mutex_unlock(&src->device->mutex);
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
- return -EINVAL;
- }
-
- reg = readl_relaxed(src->device->base +
- TSPP2_SRC_CONFIG(src->hw_index));
-
- *check_sync_byte = (reg >> SRC_CONFIG_CHECK_SYNC_OFFS) & 0x1;
- *sync_byte_value = (reg >> SRC_CONFIG_SYNC_BYTE_OFFS) & 0xFF;
-
- mutex_unlock(&src->device->mutex);
-
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
-
- dev_dbg(src->device->dev, "%s: successful\n", __func__);
-
- return 0;
-}
-EXPORT_SYMBOL(tspp2_src_sync_byte_config_get);
-
-/**
- * tspp2_src_scrambling_config_set() - Set source scrambling configuration.
- *
- * @src_handle: Source to configure.
- * @cfg: Scrambling configuration to set.
- *
- * Return 0 on success, error value otherwise.
- */
-int tspp2_src_scrambling_config_set(u32 src_handle,
- const struct tspp2_src_scrambling_config *cfg)
-{
- int ret;
- u32 reg = 0;
- struct tspp2_src *src = (struct tspp2_src *)src_handle;
-
- if (!src) {
- pr_err("%s: Invalid source handle\n", __func__);
- return -EINVAL;
- }
- if (!cfg) {
- pr_err("%s: NULL pointer\n", __func__);
- return -EINVAL;
- }
-
- ret = pm_runtime_get_sync(src->device->dev);
- if (ret < 0)
- return ret;
-
- if (mutex_lock_interruptible(&src->device->mutex)) {
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
- return -ERESTARTSYS;
- }
-
- if (!src->device->opened) {
- pr_err("%s: Device must be opened first\n", __func__);
- mutex_unlock(&src->device->mutex);
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
- return -EPERM;
- }
-
- if (!src->opened) {
- pr_err("%s: Source not opened\n", __func__);
- mutex_unlock(&src->device->mutex);
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
- return -EINVAL;
- }
-
- reg = readl_relaxed(src->device->base +
- TSPP2_SRC_CONFIG(src->hw_index));
-
- /* Clear all scrambling configuration bits before setting them */
- reg &= ~(0x3 << SRC_CONFIG_SCRAMBLING0_OFFS);
- reg &= ~(0x3 << SRC_CONFIG_SCRAMBLING1_OFFS);
- reg &= ~(0x3 << SRC_CONFIG_SCRAMBLING2_OFFS);
- reg &= ~(0x3 << SRC_CONFIG_SCRAMBLING3_OFFS);
- reg &= ~(0x3 << SRC_CONFIG_SCRAMBLING_MONITOR_OFFS);
-
- reg |= (cfg->scrambling_0_ctrl << SRC_CONFIG_SCRAMBLING0_OFFS);
- reg |= (cfg->scrambling_1_ctrl << SRC_CONFIG_SCRAMBLING1_OFFS);
- reg |= (cfg->scrambling_2_ctrl << SRC_CONFIG_SCRAMBLING2_OFFS);
- reg |= (cfg->scrambling_3_ctrl << SRC_CONFIG_SCRAMBLING3_OFFS);
- reg |= (cfg->scrambling_bits_monitoring <<
- SRC_CONFIG_SCRAMBLING_MONITOR_OFFS);
-
- writel_relaxed(reg, src->device->base +
- TSPP2_SRC_CONFIG(src->hw_index));
-
- src->scrambling_bits_monitoring = cfg->scrambling_bits_monitoring;
-
- mutex_unlock(&src->device->mutex);
-
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
-
- dev_dbg(src->device->dev, "%s: successful\n", __func__);
-
- return 0;
-}
-EXPORT_SYMBOL(tspp2_src_scrambling_config_set);
-
-/**
- * tspp2_src_scrambling_config_get() - Get source scrambling configuration.
- *
- * @src_handle: Source handle.
- * @cfg: Scrambling configuration.
- *
- * Return 0 on success, error value otherwise.
- */
-int tspp2_src_scrambling_config_get(u32 src_handle,
- struct tspp2_src_scrambling_config *cfg)
-{
- int ret;
- u32 reg = 0;
- struct tspp2_src *src = (struct tspp2_src *)src_handle;
-
- if (!src) {
- pr_err("%s: Invalid source handle\n", __func__);
- return -EINVAL;
- }
- if (!cfg) {
- pr_err("%s: NULL pointer\n", __func__);
- return -EINVAL;
- }
-
- ret = pm_runtime_get_sync(src->device->dev);
- if (ret < 0)
- return ret;
-
- if (mutex_lock_interruptible(&src->device->mutex)) {
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
- return -ERESTARTSYS;
- }
-
- if (!src->device->opened) {
- pr_err("%s: Device must be opened first\n", __func__);
- mutex_unlock(&src->device->mutex);
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
- return -EPERM;
- }
-
- if (!src->opened) {
- pr_err("%s: Source not opened\n", __func__);
- mutex_unlock(&src->device->mutex);
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
- return -EINVAL;
- }
-
- reg = readl_relaxed(src->device->base +
- TSPP2_SRC_CONFIG(src->hw_index));
-
- cfg->scrambling_0_ctrl = ((reg >> SRC_CONFIG_SCRAMBLING0_OFFS) & 0x3);
- cfg->scrambling_1_ctrl = ((reg >> SRC_CONFIG_SCRAMBLING1_OFFS) & 0x3);
- cfg->scrambling_2_ctrl = ((reg >> SRC_CONFIG_SCRAMBLING2_OFFS) & 0x3);
- cfg->scrambling_3_ctrl = ((reg >> SRC_CONFIG_SCRAMBLING3_OFFS) & 0x3);
- cfg->scrambling_bits_monitoring =
- ((reg >> SRC_CONFIG_SCRAMBLING_MONITOR_OFFS) & 0x3);
-
- mutex_unlock(&src->device->mutex);
-
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
-
- dev_dbg(src->device->dev, "%s: successful\n", __func__);
-
- return 0;
-}
-EXPORT_SYMBOL(tspp2_src_scrambling_config_get);
-
-/**
- * tspp2_src_packet_format_set() - Set source packet size and format.
- *
- * @src_handle: Source to configure.
- * @format: Packet format.
- *
- * Return 0 on success, error value otherwise.
- */
-int tspp2_src_packet_format_set(u32 src_handle,
- enum tspp2_packet_format format)
-{
- int ret;
- u32 reg = 0;
- struct tspp2_src *src = (struct tspp2_src *)src_handle;
-
- if (!src) {
- pr_err("%s: Invalid source handle\n", __func__);
- return -EINVAL;
- }
-
- ret = pm_runtime_get_sync(src->device->dev);
- if (ret < 0)
- return ret;
-
- if (mutex_lock_interruptible(&src->device->mutex)) {
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
- return -ERESTARTSYS;
- }
-
- if (!src->device->opened) {
- pr_err("%s: Device must be opened first\n", __func__);
- mutex_unlock(&src->device->mutex);
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
- return -EPERM;
- }
-
- if (!src->opened) {
- pr_err("%s: Source not opened\n", __func__);
- mutex_unlock(&src->device->mutex);
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
- return -EINVAL;
- }
-
- if (src->input == TSPP2_INPUT_MEMORY) {
- reg = readl_relaxed(src->device->base +
- TSPP2_MEM_INPUT_SRC_CONFIG(src->hw_index));
-
- reg &= ~(0x1 << MEM_INPUT_SRC_CONFIG_STAMP_SUFFIX_OFFS);
- reg &= ~(0x1 << MEM_INPUT_SRC_CONFIG_STAMP_EN_OFFS);
-
- switch (format) {
- case TSPP2_PACKET_FORMAT_188_RAW:
- /* We do not need to set any bit */
- break;
- case TSPP2_PACKET_FORMAT_192_HEAD:
- reg |= (0x1 << MEM_INPUT_SRC_CONFIG_STAMP_EN_OFFS);
- break;
- case TSPP2_PACKET_FORMAT_192_TAIL:
- reg |= (0x1 << MEM_INPUT_SRC_CONFIG_STAMP_EN_OFFS);
- reg |= (0x1 << MEM_INPUT_SRC_CONFIG_STAMP_SUFFIX_OFFS);
- break;
- default:
- pr_err("%s: Unknown packet format\n", __func__);
- mutex_unlock(&src->device->mutex);
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
- return -EINVAL;
- }
- writel_relaxed(reg, src->device->base +
- TSPP2_MEM_INPUT_SRC_CONFIG(src->hw_index));
- }
- src->pkt_format = format;
-
- /* Update source's input pipe threshold if needed */
- if (src->input_pipe) {
- if (src->pkt_format == TSPP2_PACKET_FORMAT_188_RAW)
- src->input_pipe->threshold = 188;
- else
- src->input_pipe->threshold = 192;
-
- writel_relaxed(src->input_pipe->threshold,
- src->input_pipe->device->base +
- TSPP2_PIPE_THRESH_CONFIG(src->input_pipe->hw_index));
- }
-
- mutex_unlock(&src->device->mutex);
-
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
-
- dev_dbg(src->device->dev, "%s: successful\n", __func__);
-
- return 0;
-}
-EXPORT_SYMBOL(tspp2_src_packet_format_set);
-
-/**
- * tspp2_src_pipe_attach() - Attach a pipe to a source.
- *
- * @src_handle: Source to attach the pipe to.
- * @pipe_handle: Pipe to attach to the source.
- * @cfg: For output pipes - the pipe's pull mode parameters.
- * It is not allowed to pass NULL for output pipes.
- * For input pipes this is irrelevant and the caller can
- * pass NULL.
- *
- * This function attaches a given pipe to a given source.
- * The pipe's mode (input or output) was set when the pipe was opened.
- * An input pipe can be attached to a single source (with memory input).
- * A source can have multiple output pipes attached, and an output pipe can
- * be attached to multiple sources.
- *
- * Return 0 on success, error value otherwise.
- */
-int tspp2_src_pipe_attach(u32 src_handle,
- u32 pipe_handle,
- const struct tspp2_pipe_pull_mode_params *cfg)
-{
- int ret;
- struct tspp2_src *src = (struct tspp2_src *)src_handle;
- struct tspp2_pipe *pipe = (struct tspp2_pipe *)pipe_handle;
- struct tspp2_output_pipe *output_pipe = NULL;
- u32 reg;
-
- if (!src || !pipe) {
- pr_err("%s: Invalid source or pipe handle\n", __func__);
- return -EINVAL;
- }
-
- ret = pm_runtime_get_sync(src->device->dev);
- if (ret < 0)
- return ret;
-
- if (mutex_lock_interruptible(&src->device->mutex)) {
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
- return -ERESTARTSYS;
- }
-
- if (!src->device->opened) {
- pr_err("%s: Device must be opened first\n", __func__);
- mutex_unlock(&src->device->mutex);
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
- return -EPERM;
- }
-
- if (!src->opened) {
- pr_err("%s: Source not opened\n", __func__);
- goto err_inval;
- }
-
- if (!pipe->opened) {
- pr_err("%s: Pipe not opened\n", __func__);
- goto err_inval;
- }
- if ((pipe->cfg.pipe_mode == TSPP2_SRC_PIPE_OUTPUT) && (cfg == NULL)) {
- pr_err("%s: Invalid pull mode parameters\n", __func__);
- goto err_inval;
- }
-
- if (pipe->cfg.pipe_mode == TSPP2_SRC_PIPE_INPUT) {
- if (src->input_pipe != NULL) {
- pr_err("%s: Source already has an input pipe attached\n",
- __func__);
- goto err_inval;
- }
- if (pipe->ref_cnt > 0) {
- pr_err(
- "%s: Pipe %u is already attached to a source. An input pipe can only be attached once\n",
- __func__, pipe_handle);
- goto err_inval;
- }
- /*
- * Input pipe threshold is determined according to the
- * source's packet size.
- */
- if (src->pkt_format == TSPP2_PACKET_FORMAT_188_RAW)
- pipe->threshold = 188;
- else
- pipe->threshold = 192;
-
- src->input_pipe = pipe;
-
- reg = readl_relaxed(src->device->base +
- TSPP2_MEM_INPUT_SRC_CONFIG(src->hw_index));
- reg &= ~(0x1F << MEM_INPUT_SRC_CONFIG_INPUT_PIPE_OFFS);
- reg |= (pipe->hw_index << MEM_INPUT_SRC_CONFIG_INPUT_PIPE_OFFS);
- writel_relaxed(reg, src->device->base +
- TSPP2_MEM_INPUT_SRC_CONFIG(src->hw_index));
- } else {
- list_for_each_entry(output_pipe,
- &src->output_pipe_list, link) {
- if (output_pipe->pipe == pipe) {
- pr_err(
- "%s: Output pipe %u is already attached to source %u\n",
- __func__, pipe_handle, src_handle);
- goto err_inval;
- }
- }
- output_pipe = kmalloc(sizeof(struct tspp2_output_pipe),
- GFP_KERNEL);
- if (!output_pipe) {
- pr_err("%s: No memory to save output pipe\n", __func__);
- mutex_unlock(&src->device->mutex);
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
- return -ENOMEM;
- }
- output_pipe->pipe = pipe;
- pipe->threshold = (cfg->threshold & 0xFFFF);
- list_add_tail(&output_pipe->link, &src->output_pipe_list);
-
- reg = readl_relaxed(src->device->base +
- TSPP2_SRC_DEST_PIPES(src->hw_index));
- if (cfg->is_stalling)
- reg |= (0x1 << pipe->hw_index);
- else
- reg &= ~(0x1 << pipe->hw_index);
- writel_relaxed(reg, src->device->base +
- TSPP2_SRC_DEST_PIPES(src->hw_index));
- }
-
- reg = readl_relaxed(pipe->device->base +
- TSPP2_PIPE_THRESH_CONFIG(pipe->hw_index));
- if ((pipe->cfg.pipe_mode == TSPP2_SRC_PIPE_OUTPUT) &&
- (pipe->ref_cnt > 0) && (pipe->threshold != (reg & 0xFFFF))) {
- pr_warn("%s: overwriting output pipe threshold\n", __func__);
- }
-
- writel_relaxed(pipe->threshold, pipe->device->base +
- TSPP2_PIPE_THRESH_CONFIG(pipe->hw_index));
-
- pipe->ref_cnt++;
- src->num_associated_pipes++;
-
- mutex_unlock(&src->device->mutex);
-
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
-
- dev_dbg(src->device->dev, "%s: successful\n", __func__);
-
- return 0;
-
-err_inval:
- mutex_unlock(&src->device->mutex);
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
-
- return -EINVAL;
-}
-EXPORT_SYMBOL(tspp2_src_pipe_attach);
-
-/**
- * tspp2_src_pipe_detach() - Detach a pipe from a source.
- *
- * @src_handle: Source to detach the pipe from.
- * @pipe_handle: Pipe to detach from the source.
- *
- * Detaches a pipe from a source. The given pipe should have been previously
- * attached to this source as either an input pipe or an output pipe.
- * Note: there is no checking if this pipe is currently defined as the output
- * pipe of any operation!
- *
- * Return 0 on success, error value otherwise.
- */
-int tspp2_src_pipe_detach(u32 src_handle, u32 pipe_handle)
-{
- int ret;
- struct tspp2_src *src = (struct tspp2_src *)src_handle;
- struct tspp2_pipe *pipe = (struct tspp2_pipe *)pipe_handle;
- struct tspp2_output_pipe *output_pipe = NULL;
- int found = 0;
- u32 reg;
-
- if (!src || !pipe) {
- pr_err("%s: Invalid source or pipe handle\n", __func__);
- return -EINVAL;
- }
-
- ret = pm_runtime_get_sync(src->device->dev);
- if (ret < 0)
- return ret;
-
- mutex_lock(&src->device->mutex);
-
- if (!src->device->opened) {
- pr_err("%s: Device must be opened first\n", __func__);
- mutex_unlock(&src->device->mutex);
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
- return -EPERM;
- }
-
- if (!src->opened) {
- pr_err("%s: Source not opened\n", __func__);
- goto err_inval;
- }
-
- if (!pipe->opened) {
- pr_err("%s: Pipe not opened\n", __func__);
- goto err_inval;
- }
-
- if (pipe->cfg.pipe_mode == TSPP2_SRC_PIPE_INPUT) {
- if (src->input_pipe != pipe) {
- pr_err(
- "%s: Input pipe %u is not attached to source %u\n",
- __func__, pipe_handle, src_handle);
- goto err_inval;
- }
-
- writel_relaxed(0xFFFF, src->input_pipe->device->base +
- TSPP2_PIPE_THRESH_CONFIG(src->input_pipe->hw_index));
-
- if (src->enabled) {
- pr_warn("%s: Detaching input pipe from an active memory source\n",
- __func__);
- }
- /*
- * Note: not updating TSPP2_MEM_INPUT_SRC_CONFIG to reflect
- * this pipe is detached, since there is no invalid value we
- * can write instead. tspp2_src_pipe_attach() already takes
- * care of zeroing the relevant bit-field before writing the
- * new pipe nummber.
- */
-
- src->input_pipe = NULL;
- } else {
- list_for_each_entry(output_pipe,
- &src->output_pipe_list, link) {
- if (output_pipe->pipe == pipe) {
- found = 1;
- break;
- }
- }
- if (found) {
- list_del(&output_pipe->link);
- kfree(output_pipe);
- reg = readl_relaxed(src->device->base +
- TSPP2_SRC_DEST_PIPES(src->hw_index));
- reg &= ~(0x1 << pipe->hw_index);
- writel_relaxed(reg, src->device->base +
- TSPP2_SRC_DEST_PIPES(src->hw_index));
- if (pipe->ref_cnt == 1) {
- writel_relaxed(0xFFFF, pipe->device->base +
- TSPP2_PIPE_THRESH_CONFIG(
- pipe->hw_index));
- }
- } else {
- pr_err("%s: Output pipe %u is not attached to source %u\n",
- __func__, pipe_handle, src_handle);
- goto err_inval;
- }
- }
- pipe->ref_cnt--;
- src->num_associated_pipes--;
-
- mutex_unlock(&src->device->mutex);
-
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
-
- dev_dbg(src->device->dev, "%s: successful\n", __func__);
-
- return 0;
-
-err_inval:
- mutex_unlock(&src->device->mutex);
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
-
- return -EINVAL;
-}
-EXPORT_SYMBOL(tspp2_src_pipe_detach);
-
-/**
- * tspp2_src_enable() - Enable source.
- *
- * @src_handle: Source to enable.
- *
- * Return 0 on success, error value otherwise.
- */
-int tspp2_src_enable(u32 src_handle)
-{
- struct tspp2_src *src = (struct tspp2_src *)src_handle;
- u32 reg;
- int ret;
-
- if (!src) {
- pr_err("%s: Invalid source handle\n", __func__);
- return -EINVAL;
- }
-
- ret = pm_runtime_get_sync(src->device->dev);
- if (ret < 0)
- return ret;
-
- if (mutex_lock_interruptible(&src->device->mutex)) {
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
- return -ERESTARTSYS;
- }
-
- if (!src->device->opened) {
- pr_err("%s: Device must be opened first\n", __func__);
- mutex_unlock(&src->device->mutex);
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
- return -EPERM;
- }
-
- if (!src->opened) {
- pr_err("%s: Source not opened\n", __func__);
- mutex_unlock(&src->device->mutex);
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
- return -EINVAL;
- }
-
- if (src->enabled) {
- pr_warn("%s: Source already enabled\n", __func__);
- mutex_unlock(&src->device->mutex);
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
- return 0;
- }
-
- /*
- * Memory sources require their input pipe to be configured
- * before enabling the source.
- */
- if ((src->input == TSPP2_INPUT_MEMORY) && (src->input_pipe == NULL)) {
- pr_err("%s: A memory source must have an input pipe attached before enabling the source",
- __func__);
- mutex_unlock(&src->device->mutex);
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
- return -EINVAL;
- }
-
- if (src->device->num_enabled_sources == 0) {
- ret = tspp2_clock_start(src->device);
- if (ret) {
- mutex_unlock(&src->device->mutex);
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
- return ret;
- }
- __pm_stay_awake(&src->device->wakeup_src);
- }
-
- if ((src->input == TSPP2_INPUT_TSIF0) ||
- (src->input == TSPP2_INPUT_TSIF1)) {
- tspp2_tsif_start(&src->device->tsif_devices[src->input]);
-
- reg = readl_relaxed(src->device->base +
- TSPP2_TSIF_INPUT_SRC_CONFIG(src->input));
- reg |= (0x1 << TSIF_INPUT_SRC_CONFIG_INPUT_EN_OFFS);
- writel_relaxed(reg, src->device->base +
- TSPP2_TSIF_INPUT_SRC_CONFIG(src->input));
- } else {
- reg = readl_relaxed(src->device->base +
- TSPP2_MEM_INPUT_SRC_CONFIG(src->hw_index));
- reg |= (0x1 << MEM_INPUT_SRC_CONFIG_INPUT_EN_OFFS);
- writel_relaxed(reg, src->device->base +
- TSPP2_MEM_INPUT_SRC_CONFIG(src->hw_index));
- }
-
- src->enabled = 1;
- src->device->num_enabled_sources++;
-
- mutex_unlock(&src->device->mutex);
-
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
-
- dev_dbg(src->device->dev, "%s: successful\n", __func__);
-
- return 0;
-}
-EXPORT_SYMBOL(tspp2_src_enable);
-
-/**
- * tspp2_src_disable() - Disable source.
- *
- * @src_handle: Source to disable.
- *
- * Return 0 on success, error value otherwise.
- */
-int tspp2_src_disable(u32 src_handle)
-{
- struct tspp2_src *src = (struct tspp2_src *)src_handle;
- int ret;
-
- if (!src) {
- pr_err("%s: Invalid source handle\n", __func__);
- return -EINVAL;
- }
-
- ret = pm_runtime_get_sync(src->device->dev);
- if (ret < 0)
- return ret;
-
- mutex_lock(&src->device->mutex);
-
- if (!src->device->opened) {
- pr_err("%s: Device must be opened first\n", __func__);
- mutex_unlock(&src->device->mutex);
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
- return -EPERM;
- }
-
- ret = tspp2_src_disable_internal(src);
-
- mutex_unlock(&src->device->mutex);
-
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
-
- if (!ret)
- dev_dbg(src->device->dev, "%s: successful\n", __func__);
-
- return ret;
-}
-EXPORT_SYMBOL(tspp2_src_disable);
-
-/**
- * tspp2_filter_ops_clear() - Clear filter operations database and HW
- *
- * @filter: The filter to work on.
- */
-static void tspp2_filter_ops_clear(struct tspp2_filter *filter)
-{
- int i;
-
- /* Set all filter operations in HW to Exit operation */
- for (i = 0; i < TSPP2_MAX_OPS_PER_FILTER; i++) {
- writel_relaxed(TSPP2_OPCODE_EXIT, filter->device->base +
- TSPP2_OPCODE(filter->hw_index, i));
- }
- memset(filter->operations, 0,
- (sizeof(struct tspp2_operation) * TSPP2_MAX_OPS_PER_FILTER));
- filter->num_user_operations = 0;
- filter->indexing_op_set = 0;
- filter->raw_op_with_indexing = 0;
- filter->pes_analysis_op_set = 0;
- filter->raw_op_set = 0;
- filter->pes_tx_op_set = 0;
-}
-
-/**
- * tspp2_filter_context_reset() - Reset filter context and release it.
- *
- * @filter: The filter to work on.
- */
-static void tspp2_filter_context_reset(struct tspp2_filter *filter)
-{
- /* Reset this filter's context. Each register handles 32 contexts */
- writel_relaxed((0x1 << TSPP2_MODULUS_OP(filter->context, 32)),
- filter->device->base +
- TSPP2_TSP_CONTEXT_RESET(filter->context >> 5));
- writel_relaxed((0x1 << TSPP2_MODULUS_OP(filter->context, 32)),
- filter->device->base +
- TSPP2_PES_CONTEXT_RESET(filter->context >> 5));
- writel_relaxed((0x1 << TSPP2_MODULUS_OP(filter->context, 32)),
- filter->device->base +
- TSPP2_INDEXING_CONTEXT_RESET(filter->context >> 5));
-
- writel_relaxed(0, filter->device->base +
- TSPP2_FILTER_ENTRY1(filter->hw_index));
-
- /* Release context */
- filter->device->contexts[filter->context] = 0;
-}
-
-/**
- * tspp2_filter_sw_reset() - Reset filter SW fields helper function.
- *
- * @filter: The filter to work on.
- */
-static void tspp2_filter_sw_reset(struct tspp2_filter *filter)
-{
- unsigned long flags;
- /*
- * All fields are cleared when opening a filter. Still it is important
- * to reset some of the fields here, specifically to set opened to 0 and
- * also to set the callback to NULL.
- */
- filter->opened = 0;
- filter->src = NULL;
- filter->batch = NULL;
- filter->context = 0;
- filter->hw_index = 0;
- filter->pid_value = 0;
- filter->mask = 0;
- spin_lock_irqsave(&filter->device->spinlock, flags);
- filter->event_callback = NULL;
- filter->event_cookie = NULL;
- filter->event_bitmask = 0;
- spin_unlock_irqrestore(&filter->device->spinlock, flags);
- filter->enabled = 0;
-}
-
-/**
- * tspp2_src_batch_set() - Set/clear a filter batch to/from a source.
- *
- * @src: The source to work on.
- * @batch_id: The batch to set/clear.
- * @set: Set/clear flag.
- */
-static void tspp2_src_batch_set(struct tspp2_src *src, u8 batch_id, int set)
-{
- u32 reg = 0;
-
- if (src->input == TSPP2_INPUT_MEMORY) {
- reg = readl_relaxed(src->device->base +
- TSPP2_MEM_INPUT_SRC_CONFIG(src->hw_index));
- if (set)
- reg |= ((1 << batch_id) <<
- MEM_INPUT_SRC_CONFIG_BATCHES_OFFS);
- else
- reg &= ~((1 << batch_id) <<
- MEM_INPUT_SRC_CONFIG_BATCHES_OFFS);
- writel_relaxed(reg, src->device->base +
- TSPP2_MEM_INPUT_SRC_CONFIG(src->hw_index));
- } else {
- reg = readl_relaxed(src->device->base +
- TSPP2_TSIF_INPUT_SRC_CONFIG(src->input));
- if (set)
- reg |= ((1 << batch_id) <<
- TSIF_INPUT_SRC_CONFIG_BATCHES_OFFS);
- else
- reg &= ~((1 << batch_id) <<
- TSIF_INPUT_SRC_CONFIG_BATCHES_OFFS);
- writel_relaxed(reg, src->device->base +
- TSPP2_TSIF_INPUT_SRC_CONFIG(src->input));
- }
-}
-
-/**
- * tspp2_src_filters_clear() - Clear all filters from a source.
- *
- * @src_handle: Source to clear all filters from.
- *
- * Return 0 on success, error value otherwise.
- */
-int tspp2_src_filters_clear(u32 src_handle)
-{
- int ret;
- int i;
- struct tspp2_filter *filter = NULL;
- struct tspp2_filter *tmp_filter;
- struct tspp2_filter_batch *batch = NULL;
- struct tspp2_filter_batch *tmp_batch;
- struct tspp2_src *src = (struct tspp2_src *)src_handle;
-
- if (!src) {
- pr_err("%s: Invalid source handle\n", __func__);
- return -EINVAL;
- }
-
- ret = pm_runtime_get_sync(src->device->dev);
- if (ret < 0)
- return ret;
-
- mutex_lock(&src->device->mutex);
-
- if (!src->device->opened) {
- pr_err("%s: Device must be opened first\n", __func__);
- mutex_unlock(&src->device->mutex);
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
- return -EPERM;
- }
-
- if (!src->opened) {
- pr_err("%s: Source not opened\n", __func__);
- mutex_unlock(&src->device->mutex);
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
- return -EINVAL;
- }
-
- /* Go over filters in source, disable them, clear their operations,
- * "close" them (similar to tspp2_filter_close function but simpler).
- * No need to worry about cases of reserved filter, so just clear
- * filters HW- and SW-wise. Then update source's filters and batches
- * lists and numbers. Simple :)
- */
- list_for_each_entry_safe(filter, tmp_filter, &src->filters_list, link) {
- /* Disable filter */
- writel_relaxed(0, filter->device->base +
- TSPP2_FILTER_ENTRY0(filter->hw_index));
- /* Clear filter operations in HW as well as related SW fields */
- tspp2_filter_ops_clear(filter);
- /* Reset filter context-based counters */
- tspp2_filter_counters_reset(filter->device, filter->context);
- /* Reset filter context and release it back to the device */
- tspp2_filter_context_reset(filter);
- /* Reset filter SW fields */
- tspp2_filter_sw_reset(filter);
-
- list_del(&filter->link);
- }
-
- list_for_each_entry_safe(batch, tmp_batch, &src->batches_list, link) {
- tspp2_src_batch_set(src, batch->batch_id, 0);
- for (i = 0; i < TSPP2_FILTERS_PER_BATCH; i++)
- batch->hw_filters[i] = 0;
- batch->src = NULL;
- list_del(&batch->link);
- }
-
- src->num_associated_batches = 0;
- src->num_associated_filters = 0;
- src->reserved_filter_hw_index = 0;
-
- mutex_unlock(&src->device->mutex);
-
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
-
- dev_dbg(src->device->dev, "%s: successful\n", __func__);
-
- return 0;
-}
-EXPORT_SYMBOL(tspp2_src_filters_clear);
-
-/* Filters and Operations API functions */
-
-/**
- * tspp2_filter_open() - Open a new filter and add it to a source.
- *
- * @src_handle: Source to add the new filter to.
- * @pid: Filter's 13-bit PID value.
- * @mask: Filter's 13-bit mask. Note it is highly recommended
- * to use a full bit mask of 0x1FFF, so the filter
- * operates on a unique PID.
- * @filter_handle: Opened filter handle.
- *
- * Return 0 on success, error value otherwise.
- */
-int tspp2_filter_open(u32 src_handle, u16 pid, u16 mask, u32 *filter_handle)
-{
- struct tspp2_src *src = (struct tspp2_src *)src_handle;
- struct tspp2_filter_batch *batch;
- struct tspp2_filter *filter = NULL;
- u16 hw_idx;
- int i;
- u32 reg = 0;
- int found = 0;
- int ret;
-
- if (!src) {
- pr_err("%s: Invalid source handle\n", __func__);
- return -EINVAL;
- }
- if (!filter_handle) {
- pr_err("%s: Invalid filter handle pointer\n", __func__);
- return -EINVAL;
- }
-
- if ((pid & ~0x1FFF) || (mask & ~0x1FFF)) {
- pr_err("%s: Invalid PID or mask values (13 bits available)\n",
- __func__);
- return -EINVAL;
- }
-
- ret = pm_runtime_get_sync(src->device->dev);
- if (ret < 0)
- return ret;
-
- if (mutex_lock_interruptible(&src->device->mutex)) {
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
- return -ERESTARTSYS;
- }
-
- if (!src->device->opened) {
- pr_err("%s: Device must be opened first\n", __func__);
- mutex_unlock(&src->device->mutex);
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
- return -EPERM;
- }
-
- if (!src->opened) {
- pr_err("%s: Source not opened\n", __func__);
- mutex_unlock(&src->device->mutex);
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
- return -EINVAL;
- }
-
- /* Find an available filter object in the device's filters database */
- for (i = 0; i < TSPP2_NUM_AVAIL_FILTERS; i++)
- if (!src->device->filters[i].opened)
- break;
- if (i == TSPP2_NUM_AVAIL_FILTERS) {
- pr_err("%s: No available filters\n", __func__);
- mutex_unlock(&src->device->mutex);
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
- return -ENOMEM;
- }
- filter = &src->device->filters[i];
-
- /* Find an available context. Each new filter needs a unique context */
- for (i = 0; i < TSPP2_NUM_AVAIL_CONTEXTS; i++)
- if (!src->device->contexts[i])
- break;
- if (i == TSPP2_NUM_AVAIL_CONTEXTS) {
- pr_err("%s: No available filters\n", __func__);
- mutex_unlock(&src->device->mutex);
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
- return -ENOMEM;
- }
- src->device->contexts[i] = 1;
- filter->context = i;
-
- if (src->num_associated_batches) {
- /*
- * Look for an available HW filter among the batches
- * already associated with this source.
- */
- list_for_each_entry(batch, &src->batches_list, link) {
- for (i = 0; i < TSPP2_FILTERS_PER_BATCH; i++) {
- hw_idx = (batch->batch_id *
- TSPP2_FILTERS_PER_BATCH) + i;
- if ((hw_idx != src->reserved_filter_hw_index) &&
- (batch->hw_filters[i] == 0))
- break;
- }
- if (i < TSPP2_FILTERS_PER_BATCH) {
- /* Found an available HW filter */
- batch->hw_filters[i] = 1;
- found = 1;
- break;
- }
- }
- }
-
- if (!found) {
- /* Either the source did not have any associated batches,
- * or we could not find an available HW filter in any of
- * the source's batches. In any case, we need to find a new
- * batch. Then we use the first filter in this batch.
- */
- for (i = 0; i < TSPP2_NUM_BATCHES; i++) {
- if (!src->device->batches[i].src) {
- src->device->batches[i].src = src;
- batch = &src->device->batches[i];
- batch->hw_filters[0] = 1;
- hw_idx = (batch->batch_id *
- TSPP2_FILTERS_PER_BATCH);
- break;
- }
- }
- if (i == TSPP2_NUM_BATCHES) {
- pr_err("%s: No available filters\n", __func__);
- src->device->contexts[filter->context] = 0;
- filter->context = 0;
- mutex_unlock(&src->device->mutex);
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
- return -ENOMEM;
- }
-
- tspp2_src_batch_set(src, batch->batch_id, 1);
-
- list_add_tail(&batch->link, &src->batches_list);
-
- /* Update reserved filter index only when needed */
- if (src->num_associated_batches == 0) {
- src->reserved_filter_hw_index =
- (batch->batch_id * TSPP2_FILTERS_PER_BATCH) +
- TSPP2_FILTERS_PER_BATCH - 1;
- }
- src->num_associated_batches++;
- }
-
- filter->opened = 1;
- filter->src = src;
- filter->batch = batch;
- filter->hw_index = hw_idx;
- filter->pid_value = pid;
- filter->mask = mask;
- filter->indexing_table_id = 0;
- tspp2_filter_ops_clear(filter);
- filter->event_callback = NULL;
- filter->event_cookie = NULL;
- filter->event_bitmask = 0;
- filter->enabled = 0;
- /* device back-pointer is already initialized, always remains valid */
-
- list_add_tail(&filter->link, &src->filters_list);
- src->num_associated_filters++;
-
- /* Reset filter context-based counters */
- tspp2_filter_counters_reset(filter->device, filter->context);
-
- /* Reset this filter's context */
- writel_relaxed((0x1 << TSPP2_MODULUS_OP(filter->context, 32)),
- filter->device->base +
- TSPP2_TSP_CONTEXT_RESET(filter->context >> 5));
- writel_relaxed((0x1 << TSPP2_MODULUS_OP(filter->context, 32)),
- filter->device->base +
- TSPP2_PES_CONTEXT_RESET(filter->context >> 5));
- writel_relaxed((0x1 << TSPP2_MODULUS_OP(filter->context, 32)),
- filter->device->base +
- TSPP2_INDEXING_CONTEXT_RESET(filter->context >> 5));
-
- /* Write PID and mask */
- reg = ((pid << FILTER_ENTRY0_PID_OFFS) |
- (mask << FILTER_ENTRY0_MASK_OFFS));
- writel_relaxed(reg, filter->device->base +
- TSPP2_FILTER_ENTRY0(filter->hw_index));
-
- writel_relaxed((filter->context << FILTER_ENTRY1_CONTEXT_OFFS),
- filter->device->base + TSPP2_FILTER_ENTRY1(filter->hw_index));
-
- *filter_handle = (u32)filter;
-
- mutex_unlock(&src->device->mutex);
-
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
-
- dev_dbg(src->device->dev, "%s: successful\n", __func__);
-
- return 0;
-}
-EXPORT_SYMBOL(tspp2_filter_open);
-
-/**
- * tspp2_hw_filters_in_batch() - Check for used HW filters in a batch.
- *
- * @batch: The filter batch to check.
- *
- * Helper function to check if there are any HW filters used on this batch.
- *
- * Return 1 if found a used filter in this batch, 0 otherwise.
- */
-static inline int tspp2_hw_filters_in_batch(struct tspp2_filter_batch *batch)
-{
- int i;
-
- for (i = 0; i < TSPP2_FILTERS_PER_BATCH; i++)
- if (batch->hw_filters[i] == 1)
- return 1;
-
- return 0;
-}
-
-/**
- * tspp2_filter_close() - Close a filter.
- *
- * @filter_handle: Filter to close.
- *
- * Return 0 on success, error value otherwise.
- */
-int tspp2_filter_close(u32 filter_handle)
-{
- int i;
- int ret;
- struct tspp2_device *device;
- struct tspp2_src *src = NULL;
- struct tspp2_filter_batch *batch = NULL;
- struct tspp2_filter_batch *tmp_batch;
- struct tspp2_filter *filter = (struct tspp2_filter *)filter_handle;
-
- if (!filter) {
- pr_err("%s: Invalid filter handle\n", __func__);
- return -EINVAL;
- }
-
- device = filter->device;
-
- ret = pm_runtime_get_sync(device->dev);
- if (ret < 0)
- return ret;
-
- mutex_lock(&device->mutex);
-
- if (!device->opened) {
- pr_err("%s: Device must be opened first\n", __func__);
- mutex_unlock(&device->mutex);
- pm_runtime_mark_last_busy(device->dev);
- pm_runtime_put_autosuspend(device->dev);
- return -EPERM;
- }
-
- if (!filter->opened) {
- pr_err("%s: Filter already closed\n", __func__);
- mutex_unlock(&device->mutex);
- pm_runtime_mark_last_busy(device->dev);
- pm_runtime_put_autosuspend(device->dev);
- return -EINVAL;
- }
-
- if (filter->num_user_operations)
- pr_warn("%s: Closing filters that has %d operations\n",
- __func__, filter->num_user_operations);
-
- /* Disable filter */
- writel_relaxed(0, device->base +
- TSPP2_FILTER_ENTRY0(filter->hw_index));
-
- /* Clear filter operations in HW as well as related SW fields */
- tspp2_filter_ops_clear(filter);
-
- /* Reset filter context-based counters */
- tspp2_filter_counters_reset(device, filter->context);
-
- /* Reset filter context and release it back to the device */
- tspp2_filter_context_reset(filter);
-
- /* Mark filter as unused in batch */
- filter->batch->hw_filters[(filter->hw_index -
- (filter->batch->batch_id * TSPP2_FILTERS_PER_BATCH))] = 0;
-
- /* Remove filter from source */
- list_del(&filter->link);
- filter->src->num_associated_filters--;
-
- /* We may need to update the reserved filter for this source.
- * Cases to handle:
- * 1. This is the last filter on this source.
- * 2. This is the last filter on this batch + reserved filter is not on
- * this batch.
- * 3. This is the last filter on this batch + reserved filter is on this
- * batch. Can possibly move reserved filter to another batch if space is
- * available.
- * 4. This is not the last filter on this batch. The reserved filter may
- * be the only one taking another batch and may be moved to this batch
- * to save space.
- */
-
- src = filter->src;
- /*
- * Case #1: this could be the last filter associated with this source.
- * If this is the case, we can release the batch too. We don't care
- * about the reserved HW filter index, since there are no more filters.
- */
- if (src->num_associated_filters == 0) {
- filter->batch->src = NULL;
- list_del(&filter->batch->link);
- src->num_associated_batches--;
- tspp2_src_batch_set(src, filter->batch->batch_id, 0);
- src->reserved_filter_hw_index = 0;
- goto filter_clear;
- }
-
- /*
- * If this is the last filter that was used in this batch, we may be
- * able to release this entire batch. However, we have to make sure the
- * reserved filter is not in this batch. If it is, we may find a place
- * for it in another batch in this source.
- */
- if (!tspp2_hw_filters_in_batch(filter->batch)) {
- /* There are no more used filters on this batch */
- if ((src->reserved_filter_hw_index <
- (filter->batch->batch_id * TSPP2_FILTERS_PER_BATCH)) ||
- (src->reserved_filter_hw_index >=
- ((filter->batch->batch_id * TSPP2_FILTERS_PER_BATCH) +
- TSPP2_FILTERS_PER_BATCH))) {
- /* Case #2: the reserved filter is not on this batch */
- filter->batch->src = NULL;
- list_del(&filter->batch->link);
- src->num_associated_batches--;
- tspp2_src_batch_set(src, filter->batch->batch_id, 0);
- } else {
- /*
- * Case #3: see if we can "move" the reserved filter to
- * a different batch.
- */
- list_for_each_entry_safe(batch, tmp_batch,
- &src->batches_list, link) {
- if (batch == filter->batch)
- continue;
-
- for (i = 0; i < TSPP2_FILTERS_PER_BATCH; i++) {
- if (batch->hw_filters[i] == 0) {
- src->reserved_filter_hw_index =
- (batch->batch_id *
- TSPP2_FILTERS_PER_BATCH)
- + i;
-
- filter->batch->src = NULL;
- list_del(&filter->batch->link);
- src->num_associated_batches--;
- tspp2_src_batch_set(src,
- filter->batch->batch_id,
- 0);
- goto filter_clear;
- }
- }
- }
- }
- } else {
- /* Case #4: whenever we remove a filter, there is always a
- * chance that the reserved filter was the only filter used on a
- * different batch. So now this is a good opportunity to check
- * if we can release that batch and use the index of the filter
- * we're freeing instead.
- */
- list_for_each_entry_safe(batch, tmp_batch,
- &src->batches_list, link) {
- if (((src->reserved_filter_hw_index >=
- (batch->batch_id * TSPP2_FILTERS_PER_BATCH)) &&
- (src->reserved_filter_hw_index <
- (batch->batch_id * TSPP2_FILTERS_PER_BATCH +
- TSPP2_FILTERS_PER_BATCH))) &&
- !tspp2_hw_filters_in_batch(batch)) {
- src->reserved_filter_hw_index =
- filter->hw_index;
- batch->src = NULL;
- list_del(&batch->link);
- src->num_associated_batches--;
- tspp2_src_batch_set(src, batch->batch_id, 0);
- break;
- }
- }
- }
-
-filter_clear:
- tspp2_filter_sw_reset(filter);
-
- mutex_unlock(&device->mutex);
-
- pm_runtime_mark_last_busy(device->dev);
- pm_runtime_put_autosuspend(device->dev);
-
- dev_dbg(device->dev, "%s: successful\n", __func__);
-
- return 0;
-}
-EXPORT_SYMBOL(tspp2_filter_close);
-
-/**
- * tspp2_filter_enable() - Enable a filter.
- *
- * @filter_handle: Filter to enable.
- *
- * Return 0 on success, error value otherwise.
- */
-int tspp2_filter_enable(u32 filter_handle)
-{
- struct tspp2_filter *filter = (struct tspp2_filter *)filter_handle;
- u32 reg;
- int ret;
-
- if (!filter) {
- pr_err("%s: Invalid filter handle\n", __func__);
- return -EINVAL;
- }
-
- ret = pm_runtime_get_sync(filter->device->dev);
- if (ret < 0)
- return ret;
-
- if (mutex_lock_interruptible(&filter->device->mutex)) {
- pm_runtime_mark_last_busy(filter->device->dev);
- pm_runtime_put_autosuspend(filter->device->dev);
- return -ERESTARTSYS;
- }
-
- if (!filter->device->opened) {
- pr_err("%s: Device must be opened first\n", __func__);
- mutex_unlock(&filter->device->mutex);
- pm_runtime_mark_last_busy(filter->device->dev);
- pm_runtime_put_autosuspend(filter->device->dev);
- return -EPERM;
- }
-
- if (!filter->opened) {
- pr_err("%s: Filter not opened\n", __func__);
- mutex_unlock(&filter->device->mutex);
- pm_runtime_mark_last_busy(filter->device->dev);
- pm_runtime_put_autosuspend(filter->device->dev);
- return -EINVAL;
- }
-
- if (filter->enabled) {
- pr_warn("%s: Filter already enabled\n", __func__);
- mutex_unlock(&filter->device->mutex);
- pm_runtime_mark_last_busy(filter->device->dev);
- pm_runtime_put_autosuspend(filter->device->dev);
- return 0;
- }
-
- reg = readl_relaxed(filter->device->base +
- TSPP2_FILTER_ENTRY0(filter->hw_index));
- reg |= (0x1 << FILTER_ENTRY0_EN_OFFS);
- writel_relaxed(reg, filter->device->base +
- TSPP2_FILTER_ENTRY0(filter->hw_index));
-
- filter->enabled = 1;
-
- mutex_unlock(&filter->device->mutex);
-
- pm_runtime_mark_last_busy(filter->device->dev);
- pm_runtime_put_autosuspend(filter->device->dev);
-
- dev_dbg(filter->device->dev, "%s: successful\n", __func__);
-
- return 0;
-}
-EXPORT_SYMBOL(tspp2_filter_enable);
-
-/**
- * tspp2_filter_disable() - Disable a filter.
- *
- * @filter_handle: Filter to disable.
- *
- * Return 0 on success, error value otherwise.
- */
-int tspp2_filter_disable(u32 filter_handle)
-{
- struct tspp2_filter *filter = (struct tspp2_filter *)filter_handle;
- u32 reg;
- int ret;
-
- if (!filter) {
- pr_err("%s: Invalid filter handle\n", __func__);
- return -EINVAL;
- }
-
- ret = pm_runtime_get_sync(filter->device->dev);
- if (ret < 0)
- return ret;
-
- mutex_lock(&filter->device->mutex);
-
- if (!filter->device->opened) {
- pr_err("%s: Device must be opened first\n", __func__);
- mutex_unlock(&filter->device->mutex);
- pm_runtime_mark_last_busy(filter->device->dev);
- pm_runtime_put_autosuspend(filter->device->dev);
- return -EPERM;
- }
-
- if (!filter->opened) {
- pr_err("%s: Filter not opened\n", __func__);
- mutex_unlock(&filter->device->mutex);
- pm_runtime_mark_last_busy(filter->device->dev);
- pm_runtime_put_autosuspend(filter->device->dev);
- return -EINVAL;
- }
-
- if (!filter->enabled) {
- pr_warn("%s: Filter already disabled\n", __func__);
- mutex_unlock(&filter->device->mutex);
- pm_runtime_mark_last_busy(filter->device->dev);
- pm_runtime_put_autosuspend(filter->device->dev);
- return 0;
- }
-
- reg = readl_relaxed(filter->device->base +
- TSPP2_FILTER_ENTRY0(filter->hw_index));
- reg &= ~(0x1 << FILTER_ENTRY0_EN_OFFS);
- writel_relaxed(reg, filter->device->base +
- TSPP2_FILTER_ENTRY0(filter->hw_index));
-
- /*
- * HW requires we wait for up to 2ms here before closing the pipes
- * used by this filter
- */
- udelay(TSPP2_HW_DELAY_USEC);
-
- filter->enabled = 0;
-
- mutex_unlock(&filter->device->mutex);
-
- pm_runtime_mark_last_busy(filter->device->dev);
- pm_runtime_put_autosuspend(filter->device->dev);
-
- dev_dbg(filter->device->dev, "%s: successful\n", __func__);
-
- return 0;
-}
-EXPORT_SYMBOL(tspp2_filter_disable);
-
-/**
- * tspp2_pes_analysis_op_write() - Write a PES Analysis operation.
- *
- * @filter: The filter to set the operation to.
- * @op: The operation.
- * @op_index: The operation's index in this filter.
- *
- * Return 0 on success, error value otherwise.
- */
-static int tspp2_pes_analysis_op_write(struct tspp2_filter *filter,
- const struct tspp2_operation *op,
- u8 op_index)
-{
- u32 reg = 0;
-
- if (filter->mask != TSPP2_UNIQUE_PID_MASK) {
- pr_err(
- "%s: A filter with a PES Analysis operation must handle a unique PID\n",
- __func__);
- return -EINVAL;
- }
-
- /*
- * Bits[19:6] = 0, Bit[5] = Source,
- * Bit[4] = Skip, Bits[3:0] = Opcode
- */
- reg |= TSPP2_OPCODE_PES_ANALYSIS;
- if (op->params.pes_analysis.skip_ts_errs)
- reg |= (0x1 << 4);
-
- if (op->params.pes_analysis.input == TSPP2_OP_BUFFER_B)
- reg |= (0x1 << 5);
-
- filter->pes_analysis_op_set = 1;
-
- writel_relaxed(reg, filter->device->base +
- TSPP2_OPCODE(filter->hw_index, op_index));
-
- dev_dbg(filter->device->dev, "%s: successful\n", __func__);
-
- return 0;
-}
-
-/**
- * tspp2_raw_tx_op_write() - Write a RAW Transmit operation.
- *
- * @filter: The filter to set the operation to.
- * @op: The operation.
- * @op_index: The operation's index in this filter.
- *
- * Return 0 on success, error value otherwise.
- */
-static int tspp2_raw_tx_op_write(struct tspp2_filter *filter,
- const struct tspp2_operation *op,
- u8 op_index)
-{
- u32 reg = 0;
- int timestamp = 0;
- struct tspp2_pipe *pipe = (struct tspp2_pipe *)
- op->params.raw_transmit.output_pipe_handle;
-
- if (!pipe || !pipe->opened) {
- pr_err("%s: Invalid pipe handle\n", __func__);
- return -EINVAL;
- }
-
- /*
- * Bits[19:16] = 0, Bit[15] = Support Indexing,
- * Bit[14] = Timestamp position,
- * Bits[13:12] = Timestamp mode,
- * Bits[11:6] = Output pipe, Bit[5] = Source,
- * Bit[4] = Skip, Bits[3:0] = Opcode
- */
- reg |= TSPP2_OPCODE_RAW_TRANSMIT;
- if (op->params.raw_transmit.skip_ts_errs)
- reg |= (0x1 << 4);
-
- if (op->params.raw_transmit.input == TSPP2_OP_BUFFER_B)
- reg |= (0x1 << 5);
-
- reg |= ((pipe->hw_index & 0x3F) << 6);
-
- switch (op->params.raw_transmit.timestamp_mode) {
- case TSPP2_OP_TIMESTAMP_NONE:
- /* nothing to do, keep bits value as 0 */
- break;
- case TSPP2_OP_TIMESTAMP_ZERO:
- reg |= (0x1 << 12);
- timestamp = 1;
- break;
- case TSPP2_OP_TIMESTAMP_STC:
- reg |= (0x2 << 12);
- timestamp = 1;
- break;
- default:
- pr_err("%s: Invalid timestamp mode\n", __func__);
- return -EINVAL;
- }
-
- if (timestamp && op->params.raw_transmit.timestamp_position ==
- TSPP2_PACKET_FORMAT_188_RAW) {
- pr_err("%s: Invalid timestamp position\n", __func__);
- return -EINVAL;
- }
-
- if (op->params.raw_transmit.timestamp_position ==
- TSPP2_PACKET_FORMAT_192_TAIL)
- reg |= (0x1 << 14);
-
- if (op->params.raw_transmit.support_indexing) {
- if (filter->raw_op_with_indexing) {
- pr_err(
- "%s: Only one Raw Transmit operation per filter can support HW indexing\n",
- __func__);
- return -EINVAL;
- }
- filter->raw_op_with_indexing = 1;
- reg |= (0x1 << 15);
- }
-
- filter->raw_op_set = 1;
-
- writel_relaxed(reg, filter->device->base +
- TSPP2_OPCODE(filter->hw_index, op_index));
-
- dev_dbg(filter->device->dev, "%s: successful\n", __func__);
-
- return 0;
-}
-
-/**
- * tspp2_pes_tx_op_write() - Write a PES Transmit operation.
- *
- * @filter: The filter to set the operation to.
- * @op: The operation.
- * @op_index: The operation's index in this filter.
- *
- * Return 0 on success, error value otherwise.
- */
-static int tspp2_pes_tx_op_write(struct tspp2_filter *filter,
- const struct tspp2_operation *op,
- u8 op_index)
-{
- u32 reg = 0;
- struct tspp2_pipe *payload_pipe = (struct tspp2_pipe *)
- op->params.pes_transmit.output_pipe_handle;
- struct tspp2_pipe *header_pipe;
-
- if (!payload_pipe || !payload_pipe->opened) {
- pr_err("%s: Invalid payload pipe handle\n", __func__);
- return -EINVAL;
- }
-
- if (!filter->pes_analysis_op_set) {
- pr_err(
- "%s: PES Analysys operation must precede any PES Transmit operation\n",
- __func__);
- return -EINVAL;
- }
-
- /*
- * Bits[19:18] = 0, Bits[17:12] = PES Header output pipe,
- * Bits[11:6] = Output pipe, Bit[5] = Source,
- * Bit[4] = Attach STC and flags,
- * Bit[3] = Disable TX on PES discontinuity,
- * Bit[2] = Enable SW indexing, Bit[1] = Mode, Bit[0] = 0
- */
-
- if (op->params.pes_transmit.mode == TSPP2_OP_PES_TRANSMIT_FULL) {
- reg |= (0x1 << 1);
- } else {
- /* Separated PES mode requires another pipe */
- header_pipe = (struct tspp2_pipe *)
- op->params.pes_transmit.header_output_pipe_handle;
-
- if (!header_pipe || !header_pipe->opened) {
- pr_err("%s: Invalid header pipe handle\n", __func__);
- return -EINVAL;
- }
-
- reg |= ((header_pipe->hw_index & 0x3F) << 12);
- }
-
- if (op->params.pes_transmit.enable_sw_indexing) {
- if (!filter->raw_op_set) {
- pr_err(
- "%s: PES Transmit operation with SW indexing must be preceded by a Raw Transmit operation\n",
- __func__);
- return -EINVAL;
- }
- reg |= (0x1 << 2);
- }
-
- if (op->params.pes_transmit.disable_tx_on_pes_discontinuity)
- reg |= (0x1 << 3);
-
- if (op->params.pes_transmit.attach_stc_flags)
- reg |= (0x1 << 4);
-
- if (op->params.pes_transmit.input == TSPP2_OP_BUFFER_B)
- reg |= (0x1 << 5);
-
- reg |= ((payload_pipe->hw_index & 0x3F) << 6);
-
- filter->pes_tx_op_set = 1;
-
- writel_relaxed(reg, filter->device->base +
- TSPP2_OPCODE(filter->hw_index, op_index));
-
- dev_dbg(filter->device->dev, "%s: successful\n", __func__);
-
- return 0;
-}
-
-/**
- * tspp2_pcr_op_write() - Write a PCR Extraction operation.
- *
- * @filter: The filter to set the operation to.
- * @op: The operation.
- * @op_index: The operation's index in this filter.
- *
- * Return 0 on success, error value otherwise.
- */
-static int tspp2_pcr_op_write(struct tspp2_filter *filter,
- const struct tspp2_operation *op,
- u8 op_index)
-{
- u32 reg = 0;
- struct tspp2_pipe *pipe = (struct tspp2_pipe *)
- op->params.pcr_extraction.output_pipe_handle;
-
- if (!pipe || !pipe->opened) {
- pr_err("%s: Invalid pipe handle\n", __func__);
- return -EINVAL;
- }
-
- if (!op->params.pcr_extraction.extract_pcr &&
- !op->params.pcr_extraction.extract_opcr &&
- !op->params.pcr_extraction.extract_splicing_point &&
- !op->params.pcr_extraction.extract_transport_private_data &&
- !op->params.pcr_extraction.extract_af_extension &&
- !op->params.pcr_extraction.extract_all_af) {
- pr_err("%s: Invalid extraction parameters\n", __func__);
- return -EINVAL;
- }
-
- /*
- * Bits[19:18] = 0, Bit[17] = All AF, Bit[16] = AF Extension,
- * Bit[15] = Transport Priave Data, Bit[14] = Splicing Point,
- * Bit[13] = OPCR, Bit[12] = PCR, Bits[11:6] = Output pipe,
- * Bit[5] = Source, Bit[4] = Skip, Bits[3:0] = Opcode
- */
- reg |= TSPP2_OPCODE_PCR_EXTRACTION;
- if (op->params.pcr_extraction.skip_ts_errs)
- reg |= (0x1 << 4);
-
- if (op->params.pcr_extraction.input == TSPP2_OP_BUFFER_B)
- reg |= (0x1 << 5);
-
- reg |= ((pipe->hw_index & 0x3F) << 6);
-
- if (op->params.pcr_extraction.extract_pcr)
- reg |= (0x1 << 12);
-
- if (op->params.pcr_extraction.extract_opcr)
- reg |= (0x1 << 13);
-
- if (op->params.pcr_extraction.extract_splicing_point)
- reg |= (0x1 << 14);
-
- if (op->params.pcr_extraction.extract_transport_private_data)
- reg |= (0x1 << 15);
-
- if (op->params.pcr_extraction.extract_af_extension)
- reg |= (0x1 << 16);
-
- if (op->params.pcr_extraction.extract_all_af)
- reg |= (0x1 << 17);
-
- writel_relaxed(reg, filter->device->base +
- TSPP2_OPCODE(filter->hw_index, op_index));
-
- dev_dbg(filter->device->dev, "%s: successful\n", __func__);
-
- return 0;
-}
-
-/**
- * tspp2_cipher_op_write() - Write a Cipher operation.
- *
- * @filter: The filter to set the operation to.
- * @op: The operation.
- * @op_index: The operation's index in this filter.
- *
- * Return 0 on success, error value otherwise.
- */
-static int tspp2_cipher_op_write(struct tspp2_filter *filter,
- const struct tspp2_operation *op,
- u8 op_index)
-{
- u32 reg = 0;
-
- /*
- * Bits[19:18] = 0, Bits[17:15] = Scrambling related,
- * Bit[14] = Mode, Bit[13] = Decrypt PES header,
- * Bits[12:7] = Key ladder index, Bit[6] = Destination,
- * Bit[5] = Source, Bit[4] = Skip, Bits[3:0] = Opcode
- */
-
- reg |= TSPP2_OPCODE_CIPHER;
- if (op->params.cipher.skip_ts_errs)
- reg |= (0x1 << 4);
-
- if (op->params.cipher.input == TSPP2_OP_BUFFER_B)
- reg |= (0x1 << 5);
-
- if (op->params.cipher.output == TSPP2_OP_BUFFER_B)
- reg |= (0x1 << 6);
-
- reg |= ((op->params.cipher.key_ladder_index & 0x3F) << 7);
-
- if (op->params.cipher.mode == TSPP2_OP_CIPHER_ENCRYPT &&
- op->params.cipher.decrypt_pes_header) {
- pr_err("%s: Invalid parameters\n", __func__);
- return -EINVAL;
- }
-
- if (op->params.cipher.decrypt_pes_header)
- reg |= (0x1 << 13);
-
- if (op->params.cipher.mode == TSPP2_OP_CIPHER_ENCRYPT)
- reg |= (0x1 << 14);
-
- switch (op->params.cipher.scrambling_mode) {
- case TSPP2_OP_CIPHER_AS_IS:
- reg |= (0x1 << 15);
- break;
- case TSPP2_OP_CIPHER_SET_SCRAMBLING_0:
- /* nothing to do, keep bits[17:16] as 0 */
- break;
- case TSPP2_OP_CIPHER_SET_SCRAMBLING_1:
- reg |= (0x1 << 16);
- break;
- case TSPP2_OP_CIPHER_SET_SCRAMBLING_2:
- reg |= (0x2 << 16);
- break;
- case TSPP2_OP_CIPHER_SET_SCRAMBLING_3:
- reg |= (0x3 << 16);
- break;
- default:
- pr_err("%s: Invalid scrambling mode\n", __func__);
- return -EINVAL;
- }
-
- writel_relaxed(reg, filter->device->base +
- TSPP2_OPCODE(filter->hw_index, op_index));
-
- dev_dbg(filter->device->dev, "%s: successful\n", __func__);
-
- return 0;
-}
-
-/**
- * tspp2_index_op_write() - Write an Indexing operation.
- *
- * @filter: The filter to set the operation to.
- * @op: The operation.
- * @op_index: The operation's index in this filter.
- *
- * Return 0 on success, error value otherwise.
- */
-static int tspp2_index_op_write(struct tspp2_filter *filter,
- const struct tspp2_operation *op,
- u8 op_index)
-{
- u32 reg = 0;
- u32 filter_reg = 0;
- struct tspp2_pipe *pipe = (struct tspp2_pipe *)
- op->params.indexing.output_pipe_handle;
-
- if (!pipe || !pipe->opened) {
- pr_err("%s: Invalid pipe handle\n", __func__);
- return -EINVAL;
- }
-
- /* Enforce Indexing related HW restrictions */
- if (filter->indexing_op_set) {
- pr_err(
- "%s: Only one indexing operation supported per filter\n",
- __func__);
- return -EINVAL;
- }
- if (!filter->raw_op_with_indexing) {
- pr_err(
- "%s: Raw Transmit operation with indexing support must be configured before the Indexing operation\n",
- __func__);
- return -EINVAL;
- }
-
- if (!filter->pes_analysis_op_set) {
- pr_err(
- "%s: PES Analysis operation must precede Indexing operation\n",
- __func__);
- return -EINVAL;
- }
-
- /*
- * Bits [19:15] = 0, Bit[14] = Index by RAI,
- * Bits[13:12] = 0,
- * Bits[11:6] = Output pipe, Bit[5] = Source,
- * Bit[4] = Skip, Bits[3:0] = Opcode
- */
-
- reg |= TSPP2_OPCODE_INDEXING;
- if (op->params.indexing.skip_ts_errs)
- reg |= (0x1 << 4);
-
- if (op->params.indexing.input == TSPP2_OP_BUFFER_B)
- reg |= (0x1 << 5);
-
- reg |= ((pipe->hw_index & 0x3F) << 6);
-
- if (op->params.indexing.random_access_indicator_indexing)
- reg |= (0x1 << 14);
-
- /* Indexing table ID is set in the filter and not in the operation */
- filter->indexing_table_id = op->params.indexing.indexing_table_id;
- filter_reg = readl_relaxed(filter->device->base +
- TSPP2_FILTER_ENTRY0(filter->hw_index));
- filter_reg &= ~(0x3 << FILTER_ENTRY0_CODEC_OFFS);
- filter_reg |= (filter->indexing_table_id << FILTER_ENTRY0_CODEC_OFFS);
- writel_relaxed(filter_reg, filter->device->base +
- TSPP2_FILTER_ENTRY0(filter->hw_index));
-
- filter->indexing_op_set = 1;
-
- writel_relaxed(reg, filter->device->base +
- TSPP2_OPCODE(filter->hw_index, op_index));
-
- dev_dbg(filter->device->dev, "%s: successful\n", __func__);
-
- return 0;
-}
-
-/**
- * tspp2_copy_op_write() - Write an Copy operation.
- *
- * @filter: The filter to set the operation to.
- * @op: The operation.
- * @op_index: The operation's index in this filter.
- *
- * Return 0 on success, error value otherwise.
- */
-static int tspp2_copy_op_write(struct tspp2_filter *filter,
- const struct tspp2_operation *op,
- u8 op_index)
-{
- u32 reg = 0;
-
- /* Bits[19:6] = 0, Bit[5] = Source, Bit[4] = 0, Bits[3:0] = Opcode */
- reg |= TSPP2_OPCODE_COPY_PACKET;
- if (op->params.copy_packet.input == TSPP2_OP_BUFFER_B)
- reg |= (0x1 << 5);
-
- writel_relaxed(reg, filter->device->base +
- TSPP2_OPCODE(filter->hw_index, op_index));
-
- dev_dbg(filter->device->dev, "%s: successful\n", __func__);
-
- return 0;
-}
-
-/**
- * tspp2_op_write() - Write an operation of any type.
- *
- * @filter: The filter to set the operation to.
- * @op: The operation.
- * @op_index: The operation's index in this filter.
- *
- * Return 0 on success, error value otherwise.
- */
-static int tspp2_op_write(struct tspp2_filter *filter,
- const struct tspp2_operation *op,
- u8 op_index)
-{
- switch (op->type) {
- case TSPP2_OP_PES_ANALYSIS:
- return tspp2_pes_analysis_op_write(filter, op, op_index);
- case TSPP2_OP_RAW_TRANSMIT:
- return tspp2_raw_tx_op_write(filter, op, op_index);
- case TSPP2_OP_PES_TRANSMIT:
- return tspp2_pes_tx_op_write(filter, op, op_index);
- case TSPP2_OP_PCR_EXTRACTION:
- return tspp2_pcr_op_write(filter, op, op_index);
- case TSPP2_OP_CIPHER:
- return tspp2_cipher_op_write(filter, op, op_index);
- case TSPP2_OP_INDEXING:
- return tspp2_index_op_write(filter, op, op_index);
- case TSPP2_OP_COPY_PACKET:
- return tspp2_copy_op_write(filter, op, op_index);
- default:
- pr_warn("%s: Unknown operation type\n", __func__);
- return -EINVAL;
- }
-}
-
-/**
- * tspp2_filter_ops_add() - Set the operations of a disabled filter.
- *
- * @filter: The filter to work on.
- * @op: The new operations array.
- * @op_index: The number of operations in the array.
- *
- * Return 0 on success, error value otherwise.
- */
-static int tspp2_filter_ops_add(struct tspp2_filter *filter,
- const struct tspp2_operation *ops,
- u8 operations_num)
-{
- int i;
- int ret = 0;
-
- /* User parameter validity checks were already performed */
-
- /*
- * We want to start with a clean slate here. The user may call us to
- * set operations several times, so need to make sure only the last call
- * counts.
- */
- tspp2_filter_ops_clear(filter);
-
- /* Save user operations in filter's database */
- for (i = 0; i < operations_num; i++)
- filter->operations[i] = ops[i];
-
- /* Write user operations to HW */
- for (i = 0; i < operations_num; i++) {
- ret = tspp2_op_write(filter, &ops[i], i);
- if (ret)
- goto ops_cleanup;
- }
-
- /*
- * Here we want to add the Exit operation implicitly if required, that
- * is, if the user provided less than TSPP2_MAX_OPS_PER_FILTER
- * operations. However, we already called tspp2_filter_ops_clear()
- * which set all the operations in HW to Exit, before writing the
- * actual user operations. So, no need to do it again here.
- * Also, if someone calls this function with operations_num == 0,
- * it is similar to calling tspp2_filter_operations_clear().
- */
-
- filter->num_user_operations = operations_num;
-
- dev_dbg(filter->device->dev, "%s: successful\n", __func__);
-
- return 0;
-
-ops_cleanup:
- pr_err("%s: Failed to set operations to filter, clearing all\n",
- __func__);
-
- tspp2_filter_ops_clear(filter);
-
- return ret;
-}
-
-/**
- * tspp2_filter_ops_update() - Update the operations of an enabled filter.
- *
- * This function updates the operations of an enabled filter. In fact, it is
- * not possible to update an existing filter without disabling it, clearing
- * the existing operations and setting new ones. However, if we do that,
- * we'll miss TS packets and not handle the stream properly, so a smooth
- * transition is required.
- * The algorithm is as follows:
- * 1. Find a free temporary filter object.
- * 2. Set the new filter's HW index to the reserved HW index.
- * 3. Set the operations to the new filter. This sets the operations to
- * the correct HW registers, based on the new HW index, and also updates
- * the relevant information in the temporary filter object. Later we copy this
- * to the actual filter object.
- * 4. Use the same context as the old filter (to maintain HW state).
- * 5. Reset parts of the context if needed.
- * 6. Enable the new HW filter, then disable the old filter.
- * 7. Update the source's reserved filter HW index.
- * 8. Update the filter's batch, HW index and operations-related information.
- *
- * @filter: The filter to work on.
- * @op: The new operations array.
- * @op_index: The number of operations in the array.
- *
- * Return 0 on success, error value otherwise.
- */
-static int tspp2_filter_ops_update(struct tspp2_filter *filter,
- const struct tspp2_operation *ops,
- u8 operations_num)
-{
- int i;
- int ret = 0;
- int found = 0;
- u32 reg = 0;
- u16 hw_idx;
- struct tspp2_filter_batch *batch;
- struct tspp2_filter *tmp_filter = NULL;
- struct tspp2_src *src = filter->src;
-
- /*
- * Find an available temporary filter object in the device's
- * filters database.
- */
- for (i = 0; i < TSPP2_NUM_AVAIL_FILTERS; i++)
- if (!src->device->filters[i].opened)
- break;
- if (i == TSPP2_NUM_AVAIL_FILTERS) {
- /* Should never happen */
- pr_err("%s: No available filters\n", __func__);
- return -ENOMEM;
- }
- tmp_filter = &src->device->filters[i];
-
- /*
- * Set new filter operations. We do this relatively early
- * in the function to avoid cleanup operations if this fails.
- * Since this also writes to HW, we have to set the correct HW index.
- */
- tmp_filter->hw_index = src->reserved_filter_hw_index;
- /*
- * Need to set the mask properly to indicate if the filter handles
- * a unique PID.
- */
- tmp_filter->mask = filter->mask;
- ret = tspp2_filter_ops_add(tmp_filter, ops, operations_num);
- if (ret) {
- tmp_filter->hw_index = 0;
- tmp_filter->mask = 0;
- return ret;
- }
-
- /*
- * Mark new filter (in fact, the new filter HW index) as used in the
- * appropriate batch. The batch has to be one of the batches already
- * associated with the source.
- */
- list_for_each_entry(batch, &src->batches_list, link) {
- for (i = 0; i < TSPP2_FILTERS_PER_BATCH; i++) {
- hw_idx = (batch->batch_id *
- TSPP2_FILTERS_PER_BATCH) + i;
- if (hw_idx == tmp_filter->hw_index) {
- batch->hw_filters[i] = 1;
- found = 1;
- break;
- }
- }
- if (found)
- break;
- }
-
- if (!found) {
- pr_err("%s: Could not find matching batch\n", __func__);
- tspp2_filter_ops_clear(tmp_filter);
- tmp_filter->hw_index = 0;
- return -EINVAL;
- }
-
- /* Set the same context of the old filter to the new HW filter */
- writel_relaxed((filter->context << FILTER_ENTRY1_CONTEXT_OFFS),
- filter->device->base +
- TSPP2_FILTER_ENTRY1(tmp_filter->hw_index));
-
- /*
- * Reset partial context, if necessary. We want to reset a partial
- * context before we start using it, so if there's a new operation
- * that uses a context where before there was no operation that used it,
- * we reset that context. We need to do this before we start using the
- * new operation, so before we enable the new filter.
- * Note: there is no need to reset most of the filter's context-based
- * counters, because the filter keeps using the same context. The
- * exception is the PES error counters that we may want to reset when
- * resetting the entire PES context.
- */
- if (!filter->pes_tx_op_set && tmp_filter->pes_tx_op_set) {
- /* PES Tx operation added */
- writel_relaxed(
- (0x1 << TSPP2_MODULUS_OP(filter->context, 32)),
- filter->device->base +
- TSPP2_PES_CONTEXT_RESET(filter->context >> 5));
- writel_relaxed(0, filter->device->base +
- TSPP2_FILTER_PES_ERRORS(filter->context));
- }
-
- if (!filter->indexing_op_set && tmp_filter->indexing_op_set) {
- /* Indexing operation added */
- writel_relaxed(
- (0x1 << TSPP2_MODULUS_OP(filter->context, 32)),
- filter->device->base +
- TSPP2_INDEXING_CONTEXT_RESET(filter->context >> 5));
- }
-
- /*
- * Write PID and mask to new filter HW registers and enable it.
- * Preserve filter indexing table ID.
- */
- reg |= (0x1 << FILTER_ENTRY0_EN_OFFS);
- reg |= ((filter->pid_value << FILTER_ENTRY0_PID_OFFS) |
- (filter->mask << FILTER_ENTRY0_MASK_OFFS));
- reg |= (tmp_filter->indexing_table_id << FILTER_ENTRY0_CODEC_OFFS);
- writel_relaxed(reg, filter->device->base +
- TSPP2_FILTER_ENTRY0(tmp_filter->hw_index));
-
- /* Disable old HW filter */
- writel_relaxed(0, filter->device->base +
- TSPP2_FILTER_ENTRY0(filter->hw_index));
-
- /*
- * HW requires we wait for up to 2ms here before removing the
- * operations used by this filter.
- */
- udelay(TSPP2_HW_DELAY_USEC);
-
- tspp2_filter_ops_clear(filter);
-
- writel_relaxed(0, filter->device->base +
- TSPP2_FILTER_ENTRY1(filter->hw_index));
-
- /* Mark HW filter as unused in old batch */
- filter->batch->hw_filters[(filter->hw_index -
- (filter->batch->batch_id * TSPP2_FILTERS_PER_BATCH))] = 0;
-
- /* The new HW filter may be in a new batch, so we need to update */
- filter->batch = batch;
-
- /*
- * Update source's reserved filter HW index, and also update the
- * new HW index in the filter object.
- */
- src->reserved_filter_hw_index = filter->hw_index;
- filter->hw_index = tmp_filter->hw_index;
-
- /*
- * We've already set the new operations to HW, but we want to
- * update the filter object, too. tmp_filter contains all the
- * operations' related information we need (operations and flags).
- * Also, we make sure to update indexing_table_id based on the new
- * indexing operations.
- */
- memcpy(filter->operations, tmp_filter->operations,
- (sizeof(struct tspp2_operation) * TSPP2_MAX_OPS_PER_FILTER));
- filter->num_user_operations = tmp_filter->num_user_operations;
- filter->indexing_op_set = tmp_filter->indexing_op_set;
- filter->raw_op_with_indexing = tmp_filter->raw_op_with_indexing;
- filter->pes_analysis_op_set = tmp_filter->pes_analysis_op_set;
- filter->raw_op_set = tmp_filter->raw_op_set;
- filter->pes_tx_op_set = tmp_filter->pes_tx_op_set;
- filter->indexing_table_id = tmp_filter->indexing_table_id;
-
- /*
- * Now we can clean tmp_filter. This is really just to keep the filter
- * object clean. However, we don't want to use tspp2_filter_ops_clear()
- * because it clears the operations from HW too.
- */
- memset(tmp_filter->operations, 0,
- (sizeof(struct tspp2_operation) * TSPP2_MAX_OPS_PER_FILTER));
- tmp_filter->num_user_operations = 0;
- tmp_filter->indexing_op_set = 0;
- tmp_filter->raw_op_with_indexing = 0;
- tmp_filter->pes_analysis_op_set = 0;
- tmp_filter->raw_op_set = 0;
- tmp_filter->pes_tx_op_set = 0;
- tmp_filter->indexing_table_id = 0;
- tmp_filter->hw_index = 0;
-
- dev_dbg(filter->device->dev, "%s: successful\n", __func__);
-
- return 0;
-}
-
-/**
- * tspp2_filter_operations_set() - Set operations to a filter.
- *
- * @filter_handle: Filter to set operations to.
- * @ops: An array of up to TSPP2_MAX_OPS_PER_FILTER
- * operations.
- * @operations_num: Number of operations in the ops array.
- *
- * This function sets the required operations to a given filter. The filter
- * can either be disabled (in which case it may or may not already have some
- * operations set), or enabled (in which case it certainly has some oprations
- * set). In any case, the filter's previous operations are cleared, and the new
- * operations provided are set.
- *
- * In addition to some trivial parameter validity checks, the following
- * restrictions are enforced:
- * 1. A filter with a PES Analysis operation must handle a unique PID (i.e.,
- * should have a mask that equals TSPP2_UNIQUE_PID_MASK).
- * 2. Only a single Raw Transmit operation per filter can support HW indexing
- * (i.e., can have its support_indexing configuration parameter set).
- * 3. A PES Analysys operation must precede any PES Transmit operation.
- * 4. A PES Transmit operation with SW indexing (i.e., with its
- * enable_sw_indexing parameter set) must be preceded by a Raw Transmit
- * operation.
- * 5. Only a single indexing operation is supported per filter.
- * 6. A Raw Transmit operation with indexing support must be configured before
- * the Indexing operation.
- * 7. A PES Analysis operation must precede the Indexing operation.
- *
- * Return 0 on success, error value otherwise.
- */
-int tspp2_filter_operations_set(u32 filter_handle,
- const struct tspp2_operation *ops,
- u8 operations_num)
-{
- struct tspp2_filter *filter = (struct tspp2_filter *)filter_handle;
- int ret = 0;
-
- if (!filter) {
- pr_err("%s: Invalid filter handle\n", __func__);
- return -EINVAL;
- }
- if (!ops || operations_num > TSPP2_MAX_OPS_PER_FILTER ||
- operations_num == 0) {
- pr_err("%s: Invalid ops parameter\n", __func__);
- return -EINVAL;
- }
-
- ret = pm_runtime_get_sync(filter->device->dev);
- if (ret < 0)
- return ret;
-
- if (mutex_lock_interruptible(&filter->device->mutex)) {
- pm_runtime_mark_last_busy(filter->device->dev);
- pm_runtime_put_autosuspend(filter->device->dev);
- return -ERESTARTSYS;
- }
-
- if (!filter->device->opened) {
- pr_err("%s: Device must be opened first\n", __func__);
- mutex_unlock(&filter->device->mutex);
- pm_runtime_mark_last_busy(filter->device->dev);
- pm_runtime_put_autosuspend(filter->device->dev);
- return -EPERM;
- }
-
- if (!filter->opened) {
- pr_err("%s: Filter not opened\n", __func__);
- mutex_unlock(&filter->device->mutex);
- pm_runtime_mark_last_busy(filter->device->dev);
- pm_runtime_put_autosuspend(filter->device->dev);
- return -EINVAL;
- }
-
- if (filter->enabled)
- ret = tspp2_filter_ops_update(filter, ops, operations_num);
- else
- ret = tspp2_filter_ops_add(filter, ops, operations_num);
-
- mutex_unlock(&filter->device->mutex);
-
- pm_runtime_mark_last_busy(filter->device->dev);
- pm_runtime_put_autosuspend(filter->device->dev);
-
- return ret;
-}
-EXPORT_SYMBOL(tspp2_filter_operations_set);
-
-/**
- * tspp2_filter_operations_clear() - Clear all operations from a filter.
- *
- * @filter_handle: Filter to clear all operations from.
- *
- * Return 0 on success, error value otherwise.
- */
-int tspp2_filter_operations_clear(u32 filter_handle)
-{
- int ret;
- struct tspp2_filter *filter = (struct tspp2_filter *)filter_handle;
-
- if (!filter) {
- pr_err("%s: Invalid filter handle\n", __func__);
- return -EINVAL;
- }
-
- ret = pm_runtime_get_sync(filter->device->dev);
- if (ret < 0)
- return ret;
-
- mutex_lock(&filter->device->mutex);
-
- if (!filter->device->opened) {
- pr_err("%s: Device must be opened first\n", __func__);
- mutex_unlock(&filter->device->mutex);
- pm_runtime_mark_last_busy(filter->device->dev);
- pm_runtime_put_autosuspend(filter->device->dev);
- return -EPERM;
- }
-
- if (!filter->opened) {
- pr_err("%s: Filter not opened\n", __func__);
- mutex_unlock(&filter->device->mutex);
- pm_runtime_mark_last_busy(filter->device->dev);
- pm_runtime_put_autosuspend(filter->device->dev);
- return -EINVAL;
- }
-
- if (filter->num_user_operations == 0) {
- pr_warn("%s: No operations to clear from filter\n", __func__);
- mutex_unlock(&filter->device->mutex);
- pm_runtime_mark_last_busy(filter->device->dev);
- pm_runtime_put_autosuspend(filter->device->dev);
- return 0;
- }
-
- tspp2_filter_ops_clear(filter);
-
- mutex_unlock(&filter->device->mutex);
-
- pm_runtime_mark_last_busy(filter->device->dev);
- pm_runtime_put_autosuspend(filter->device->dev);
-
- dev_dbg(filter->device->dev, "%s: successful\n", __func__);
-
- return 0;
-}
-EXPORT_SYMBOL(tspp2_filter_operations_clear);
-
-/**
- * tspp2_filter_current_scrambling_bits_get() - Get the current scrambling bits.
- *
- * @filter_handle: Filter to get the scrambling bits from.
- * @scrambling_bits_value: The current value of the scrambling bits.
- * This could be the value from the TS packet
- * header, the value from the PES header, or a
- * logical OR operation of both values, depending
- * on the scrambling_bits_monitoring configuration
- * of the source this filter belongs to.
- *
- * Return 0 on success, error value otherwise.
- */
-int tspp2_filter_current_scrambling_bits_get(u32 filter_handle,
- u8 *scrambling_bits_value)
-{
- struct tspp2_filter *filter = (struct tspp2_filter *)filter_handle;
- u32 reg;
- u32 ts_bits;
- u32 pes_bits;
- int ret;
-
- if (!filter) {
- pr_err("%s: Invalid filter handle\n", __func__);
- return -EINVAL;
- }
- if (scrambling_bits_value == NULL) {
- pr_err("%s: Invalid parameter\n", __func__);
- return -EINVAL;
- }
-
- ret = pm_runtime_get_sync(filter->device->dev);
- if (ret < 0)
- return ret;
-
- if (mutex_lock_interruptible(&filter->device->mutex)) {
- pm_runtime_mark_last_busy(filter->device->dev);
- pm_runtime_put_autosuspend(filter->device->dev);
- return -ERESTARTSYS;
- }
-
- if (!filter->device->opened) {
- pr_err("%s: Device must be opened first\n", __func__);
- mutex_unlock(&filter->device->mutex);
- pm_runtime_mark_last_busy(filter->device->dev);
- pm_runtime_put_autosuspend(filter->device->dev);
- return -EPERM;
- }
-
- if (!filter->opened) {
- pr_err("%s: Filter not opened\n", __func__);
- mutex_unlock(&filter->device->mutex);
- pm_runtime_mark_last_busy(filter->device->dev);
- pm_runtime_put_autosuspend(filter->device->dev);
- return -EINVAL;
- }
-
- reg = readl_relaxed(filter->device->base +
- TSPP2_TSP_CONTEXT(filter->context));
-
- ts_bits = ((reg >> TSP_CONTEXT_TS_HEADER_SC_OFFS) & 0x3);
- pes_bits = ((reg >> TSP_CONTEXT_PES_HEADER_SC_OFFS) & 0x3);
-
- switch (filter->src->scrambling_bits_monitoring) {
- case TSPP2_SRC_SCRAMBLING_MONITOR_PES_ONLY:
- *scrambling_bits_value = pes_bits;
- break;
- case TSPP2_SRC_SCRAMBLING_MONITOR_TS_ONLY:
- *scrambling_bits_value = ts_bits;
- break;
- case TSPP2_SRC_SCRAMBLING_MONITOR_PES_AND_TS:
- *scrambling_bits_value = (pes_bits | ts_bits);
- break;
- case TSPP2_SRC_SCRAMBLING_MONITOR_NONE:
- /* fall through to default case */
- default:
- pr_err("%s: Invalid scrambling bits mode\n", __func__);
- mutex_unlock(&filter->device->mutex);
- pm_runtime_mark_last_busy(filter->device->dev);
- pm_runtime_put_autosuspend(filter->device->dev);
- return -EINVAL;
- }
-
- mutex_unlock(&filter->device->mutex);
-
- pm_runtime_mark_last_busy(filter->device->dev);
- pm_runtime_put_autosuspend(filter->device->dev);
-
- dev_dbg(filter->device->dev, "%s: successful\n", __func__);
-
- return 0;
-}
-EXPORT_SYMBOL(tspp2_filter_current_scrambling_bits_get);
-
-/* Data-path API functions */
-
-/**
- * tspp2_pipe_descriptor_get() - Get a data descriptor from a pipe.
- *
- * @pipe_handle: Pipe to get the descriptor from.
- * @desc: Received pipe data descriptor.
- *
- * Return 0 on success, error value otherwise.
- */
-int tspp2_pipe_descriptor_get(u32 pipe_handle, struct sps_iovec *desc)
-{
- int ret;
- struct tspp2_pipe *pipe = (struct tspp2_pipe *)pipe_handle;
-
- if (!pipe) {
- pr_err("%s: Invalid pipe handle\n", __func__);
- return -EINVAL;
- }
- if (!desc) {
- pr_err("%s: Invalid descriptor pointer\n", __func__);
- return -EINVAL;
- }
-
- /* Descriptor pointer validity is checked inside the SPS driver. */
-
- ret = pm_runtime_get_sync(pipe->device->dev);
- if (ret < 0)
- return ret;
-
- if (mutex_lock_interruptible(&pipe->device->mutex)) {
- pm_runtime_mark_last_busy(pipe->device->dev);
- pm_runtime_put_autosuspend(pipe->device->dev);
- return -ERESTARTSYS;
- }
-
- if (!pipe->device->opened) {
- pr_err("%s: Device must be opened first\n", __func__);
- mutex_unlock(&pipe->device->mutex);
- pm_runtime_mark_last_busy(pipe->device->dev);
- pm_runtime_put_autosuspend(pipe->device->dev);
- return -EPERM;
- }
-
- if (!pipe->opened) {
- pr_err("%s: Pipe not opened\n", __func__);
- mutex_unlock(&pipe->device->mutex);
- pm_runtime_mark_last_busy(pipe->device->dev);
- pm_runtime_put_autosuspend(pipe->device->dev);
- return -EINVAL;
- }
-
- ret = sps_get_iovec(pipe->sps_pipe, desc);
-
- mutex_unlock(&pipe->device->mutex);
-
- pm_runtime_mark_last_busy(pipe->device->dev);
- pm_runtime_put_autosuspend(pipe->device->dev);
-
- dev_dbg(pipe->device->dev, "%s: successful\n", __func__);
-
- return ret;
-
-}
-EXPORT_SYMBOL(tspp2_pipe_descriptor_get);
-
-/**
- * tspp2_pipe_descriptor_put() - Release a descriptor for reuse by the pipe.
- *
- * @pipe_handle: Pipe to release the descriptor to.
- * @addr: Address to release for reuse.
- * @size: Size to release.
- * @flags: Descriptor flags.
- *
- * Return 0 on success, error value otherwise.
- */
-int tspp2_pipe_descriptor_put(u32 pipe_handle, u32 addr, u32 size, u32 flags)
-{
- int ret;
- struct tspp2_pipe *pipe = (struct tspp2_pipe *)pipe_handle;
-
- if (!pipe) {
- pr_err("%s: Invalid pipe handle\n", __func__);
- return -EINVAL;
- }
-
- ret = pm_runtime_get_sync(pipe->device->dev);
- if (ret < 0)
- return ret;
-
- if (mutex_lock_interruptible(&pipe->device->mutex)) {
- pm_runtime_mark_last_busy(pipe->device->dev);
- pm_runtime_put_autosuspend(pipe->device->dev);
- return -ERESTARTSYS;
- }
-
- if (!pipe->device->opened) {
- pr_err("%s: Device must be opened first\n", __func__);
- mutex_unlock(&pipe->device->mutex);
- pm_runtime_mark_last_busy(pipe->device->dev);
- pm_runtime_put_autosuspend(pipe->device->dev);
- return -EPERM;
- }
-
- if (!pipe->opened) {
- pr_err("%s: Pipe not opened\n", __func__);
- mutex_unlock(&pipe->device->mutex);
- pm_runtime_mark_last_busy(pipe->device->dev);
- pm_runtime_put_autosuspend(pipe->device->dev);
- return -EINVAL;
- }
-
- ret = sps_transfer_one(pipe->sps_pipe, addr, size, NULL, flags);
-
- mutex_unlock(&pipe->device->mutex);
-
- pm_runtime_mark_last_busy(pipe->device->dev);
- pm_runtime_put_autosuspend(pipe->device->dev);
-
- dev_dbg(pipe->device->dev, "%s: successful\n", __func__);
-
- return ret;
-}
-EXPORT_SYMBOL(tspp2_pipe_descriptor_put);
-
-/**
- * tspp2_pipe_last_address_used_get() - Get the last address the TSPP2 used.
- *
- * @pipe_handle: Pipe to get the address from.
- * @address: The last (virtual) address TSPP2 wrote data to.
- *
- * Return 0 on success, error value otherwise.
- */
-int tspp2_pipe_last_address_used_get(u32 pipe_handle, u32 *address)
-{
- int ret;
- struct tspp2_pipe *pipe = (struct tspp2_pipe *)pipe_handle;
-
- if (!pipe) {
- pr_err("%s: Invalid pipe handle\n", __func__);
- return -EINVAL;
- }
- if (!address) {
- pr_err("%s: Invalid address pointer\n", __func__);
- return -EINVAL;
- }
-
- ret = pm_runtime_get_sync(pipe->device->dev);
- if (ret < 0)
- return ret;
-
- if (mutex_lock_interruptible(&pipe->device->mutex)) {
- pm_runtime_mark_last_busy(pipe->device->dev);
- pm_runtime_put_autosuspend(pipe->device->dev);
- return -ERESTARTSYS;
- }
-
- if (!pipe->device->opened) {
- pr_err("%s: Device must be opened first\n", __func__);
- mutex_unlock(&pipe->device->mutex);
- pm_runtime_mark_last_busy(pipe->device->dev);
- pm_runtime_put_autosuspend(pipe->device->dev);
- return -EPERM;
- }
-
- if (!pipe->opened) {
- pr_err("%s: Pipe not opened\n", __func__);
- mutex_unlock(&pipe->device->mutex);
- pm_runtime_mark_last_busy(pipe->device->dev);
- pm_runtime_put_autosuspend(pipe->device->dev);
- return -EINVAL;
- }
-
- *address = readl_relaxed(pipe->device->base +
- TSPP2_PIPE_LAST_ADDRESS(pipe->hw_index));
-
- mutex_unlock(&pipe->device->mutex);
-
- pm_runtime_mark_last_busy(pipe->device->dev);
- pm_runtime_put_autosuspend(pipe->device->dev);
-
- *address = be32_to_cpu(*address);
-
- dev_dbg(pipe->device->dev, "%s: successful\n", __func__);
-
- return 0;
-}
-EXPORT_SYMBOL(tspp2_pipe_last_address_used_get);
-
-/**
- * tspp2_data_write() - Write (feed) data to a source.
- *
- * @src_handle: Source to feed data to.
- * @offset: Offset in the source's input pipe buffer.
- * @size: Size of data to write, in bytes.
- *
- * Schedule BAM transfers to feed data from the source's input pipe
- * to TSPP2 for processing. Note that the user is responsible for opening
- * an input pipe with the appropriate configuration parameters, and attaching
- * this pipe as an input pipe to the source. Pipe configuration validity is not
- * verified by this function.
- *
- * Return 0 on success, error value otherwise.
- */
-int tspp2_data_write(u32 src_handle, u32 offset, u32 size)
-{
- int ret;
- u32 desc_length;
- u32 desc_flags;
- u32 data_length = size;
- u32 data_offset = offset;
- struct tspp2_pipe *pipe;
- struct tspp2_src *src = (struct tspp2_src *)src_handle;
-
- if (!src) {
- pr_err("%s: Invalid source handle\n", __func__);
- return -EINVAL;
- }
-
- ret = pm_runtime_get_sync(src->device->dev);
- if (ret < 0)
- return ret;
-
- if (mutex_lock_interruptible(&src->device->mutex)) {
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
- return -ERESTARTSYS;
- }
-
- if (!src->device->opened) {
- pr_err("%s: Device must be opened first\n", __func__);
- mutex_unlock(&src->device->mutex);
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
- return -EPERM;
- }
-
- if (!src->opened) {
- pr_err("%s: Source not opened\n", __func__);
- goto err_inval;
- }
-
- if (!src->enabled) {
- pr_err("%s: Source not enabled\n", __func__);
- goto err_inval;
- }
-
- if ((src->input != TSPP2_INPUT_MEMORY) || !src->input_pipe) {
- pr_err("%s: Invalid source input or no input pipe\n", __func__);
- goto err_inval;
- }
-
- pipe = src->input_pipe;
-
- if (offset + size > pipe->cfg.buffer_size) {
- pr_err("%s: offset + size > buffer size\n", __func__);
- goto err_inval;
- }
-
- while (data_length) {
- if (data_length > pipe->cfg.sps_cfg.descriptor_size) {
- desc_length = pipe->cfg.sps_cfg.descriptor_size;
- desc_flags = 0;
- } else {
- /* last descriptor */
- desc_length = data_length;
- desc_flags = SPS_IOVEC_FLAG_EOT;
- }
-
- ret = sps_transfer_one(pipe->sps_pipe,
- pipe->iova + data_offset,
- desc_length,
- pipe->cfg.sps_cfg.user_info,
- desc_flags);
-
- if (ret) {
- pr_err("%s: sps_transfer_one failed, %d\n",
- __func__, ret);
- mutex_unlock(&src->device->mutex);
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
- return ret;
- }
-
- data_offset += desc_length;
- data_length -= desc_length;
- }
-
- mutex_unlock(&src->device->mutex);
-
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
-
- dev_dbg(src->device->dev, "%s: successful\n", __func__);
-
- return 0;
-
-err_inval:
- mutex_unlock(&src->device->mutex);
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
-
- return -EINVAL;
-}
-EXPORT_SYMBOL(tspp2_data_write);
-
-/**
- * tspp2_tsif_data_write() - Write (feed) data to a TSIF source via Loopback.
- *
- * @src_handle: Source to feed data to.
- * @data: data buffer containing one TS packet of size 188 Bytes.
- *
- * Write one TS packet of size 188 bytes to the TSIF loopback interface.
- *
- * Return 0 on success, error value otherwise.
- */
-int tspp2_tsif_data_write(u32 src_handle, u32 *data)
-{
- int i;
- int ret;
- struct tspp2_src *src = (struct tspp2_src *)src_handle;
- struct tspp2_tsif_device *tsif_device;
- const unsigned int loopback_flags[3] = {0x01000000, 0, 0x02000000};
-
- if (data == NULL) {
- pr_err("%s: NULL data\n", __func__);
- return -EINVAL;
- }
-
- if (!src) {
- pr_err("%s: Invalid source handle\n", __func__);
- return -EINVAL;
- }
-
- ret = pm_runtime_get_sync(src->device->dev);
- if (ret < 0)
- return ret;
-
- if (mutex_lock_interruptible(&src->device->mutex)) {
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
- return -ERESTARTSYS;
- }
-
- if (!src->device->opened) {
- pr_err("%s: Device must be opened first\n", __func__);
- mutex_unlock(&src->device->mutex);
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
- return -EPERM;
- }
-
- if (!src->opened) {
- pr_err("%s: Source not opened\n", __func__);
- goto err_inval;
- }
-
- if (!src->enabled) {
- pr_err("%s: Source not enabled\n", __func__);
- goto err_inval;
- }
-
- if ((src->input != TSPP2_INPUT_TSIF0)
- && (src->input != TSPP2_INPUT_TSIF1)) {
- pr_err("%s: Invalid source input\n", __func__);
- goto err_inval;
- }
-
- tsif_device = &src->device->tsif_devices[src->input];
-
- /* lpbk_flags : start && !last */
- writel_relaxed(loopback_flags[0],
- tsif_device->base + TSPP2_TSIF_LPBK_FLAGS);
-
- /* 1-st dword of data */
- writel_relaxed(data[0],
- tsif_device->base + TSPP2_TSIF_LPBK_DATA);
-
- /* Clear start bit */
- writel_relaxed(loopback_flags[1],
- tsif_device->base + TSPP2_TSIF_LPBK_FLAGS);
-
- /* 45 more dwords */
- for (i = 1; i < 46; i++)
- writel_relaxed(data[i],
- tsif_device->base + TSPP2_TSIF_LPBK_DATA);
-
- /* Set last bit */
- writel_relaxed(loopback_flags[2],
- tsif_device->base + TSPP2_TSIF_LPBK_FLAGS);
-
- /* Last data dword */
- writel_relaxed(data[46], tsif_device->base + TSPP2_TSIF_LPBK_DATA);
-
- mutex_unlock(&src->device->mutex);
-
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
-
- dev_dbg(src->device->dev, "%s: successful\n", __func__);
-
- return 0;
-
-err_inval:
- mutex_unlock(&src->device->mutex);
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
-
- return -EINVAL;
-}
-EXPORT_SYMBOL(tspp2_tsif_data_write);
-
-/* Event notification API functions */
-
-/**
- * tspp2_global_event_notification_register() - Get notified on a global event.
- *
- * @dev_id: TSPP2 device ID.
- * @global_event_bitmask: A bitmask of global events,
- * TSPP2_GLOBAL_EVENT_XXX.
- * @callback: User callback function.
- * @cookie: User information passed to the callback.
- *
- * Register a user callback which will be invoked when certain global
- * events occur. Note the values (mask, callback and cookie) are overwritten
- * when calling this function multiple times. Therefore it is possible to
- * "unregister" a callback by calling this function with the bitmask set to 0
- * and with NULL callback and cookie.
- *
- * Return 0 on success, error value otherwise.
- */
-int tspp2_global_event_notification_register(u32 dev_id,
- u32 global_event_bitmask,
- void (*callback)(void *cookie, u32 event_bitmask),
- void *cookie)
-{
- struct tspp2_device *device;
- unsigned long flags;
- u32 reg = 0;
-
- if (dev_id >= TSPP2_NUM_DEVICES) {
- pr_err("%s: Invalid device ID %d\n", __func__, dev_id);
- return -ENODEV;
- }
-
- device = tspp2_devices[dev_id];
- if (!device) {
- pr_err("%s: Invalid device\n", __func__);
- return -ENODEV;
- }
-
- if (mutex_lock_interruptible(&device->mutex))
- return -ERESTARTSYS;
-
- if (!device->opened) {
- pr_err("%s: Device must be opened first\n", __func__);
- mutex_unlock(&device->mutex);
- return -EPERM;
- }
-
- /*
- * Some of the interrupts that are generated when these events occur
- * may be disabled due to module parameters. So we make sure to enable
- * them here, depending on which event was requested. If some events
- * were requested before and now this function is called again with
- * other events, though, we want to restore the interrupt configuration
- * to the default state according to the module parameters.
- */
- reg = readl_relaxed(device->base + TSPP2_GLOBAL_IRQ_ENABLE);
- if (global_event_bitmask & TSPP2_GLOBAL_EVENT_INVALID_AF_CTRL) {
- reg |= (0x1 << GLOBAL_IRQ_TSP_INVALID_AF_OFFS);
- } else {
- if (tspp2_en_invalid_af_ctrl)
- reg |= (0x1 << GLOBAL_IRQ_TSP_INVALID_AF_OFFS);
- else
- reg &= ~(0x1 << GLOBAL_IRQ_TSP_INVALID_AF_OFFS);
- }
-
- if (global_event_bitmask & TSPP2_GLOBAL_EVENT_INVALID_AF_LENGTH) {
- reg |= (0x1 << GLOBAL_IRQ_TSP_INVALID_LEN_OFFS);
- } else {
- if (tspp2_en_invalid_af_length)
- reg |= (0x1 << GLOBAL_IRQ_TSP_INVALID_LEN_OFFS);
- else
- reg &= ~(0x1 << GLOBAL_IRQ_TSP_INVALID_LEN_OFFS);
- }
-
- if (global_event_bitmask & TSPP2_GLOBAL_EVENT_PES_NO_SYNC) {
- reg |= (0x1 << GLOBAL_IRQ_PES_NO_SYNC_OFFS);
- } else {
- if (tspp2_en_pes_no_sync)
- reg |= (0x1 << GLOBAL_IRQ_PES_NO_SYNC_OFFS);
- else
- reg &= ~(0x1 << GLOBAL_IRQ_PES_NO_SYNC_OFFS);
- }
-
- writel_relaxed(reg, device->base + TSPP2_GLOBAL_IRQ_ENABLE);
-
- spin_lock_irqsave(&device->spinlock, flags);
- device->event_callback = callback;
- device->event_cookie = cookie;
- device->event_bitmask = global_event_bitmask;
- spin_unlock_irqrestore(&device->spinlock, flags);
-
- mutex_unlock(&device->mutex);
-
- dev_dbg(device->dev, "%s: successful\n", __func__);
-
- return 0;
-}
-EXPORT_SYMBOL(tspp2_global_event_notification_register);
-
-/**
- * tspp2_src_event_notification_register() - Get notified on a source event.
- *
- * @src_handle: Source handle.
- * @src_event_bitmask: A bitmask of source events,
- * TSPP2_SRC_EVENT_XXX.
- * @callback: User callback function.
- * @cookie: User information passed to the callback.
- *
- * Register a user callback which will be invoked when certain source
- * events occur. Note the values (mask, callback and cookie) are overwritten
- * when calling this function multiple times. Therefore it is possible to
- * "unregister" a callback by calling this function with the bitmask set to 0
- * and with NULL callback and cookie.
- *
- * Return 0 on success, error value otherwise.
- */
-int tspp2_src_event_notification_register(u32 src_handle,
- u32 src_event_bitmask,
- void (*callback)(void *cookie, u32 event_bitmask),
- void *cookie)
-{
- int ret;
- u32 reg;
- unsigned long flags;
- struct tspp2_src *src = (struct tspp2_src *)src_handle;
-
- if (!src) {
- pr_err("%s: Invalid source handle\n", __func__);
- return -EINVAL;
- }
-
- ret = pm_runtime_get_sync(src->device->dev);
- if (ret < 0)
- return ret;
-
- if (mutex_lock_interruptible(&src->device->mutex)) {
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
- return -ERESTARTSYS;
- }
-
- if (!src->device->opened) {
- pr_err("%s: Device must be opened first\n", __func__);
- mutex_unlock(&src->device->mutex);
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
- return -EPERM;
- }
-
- if (!src->opened) {
- pr_err("%s: Source not opened\n", __func__);
- goto err_inval;
- }
-
- if (((src->input == TSPP2_INPUT_TSIF0) ||
- (src->input == TSPP2_INPUT_TSIF1)) &&
- ((src_event_bitmask & TSPP2_SRC_EVENT_MEMORY_READ_ERROR) ||
- (src_event_bitmask & TSPP2_SRC_EVENT_FLOW_CTRL_STALL))) {
- pr_err("%s: Invalid event bitmask for a source with TSIF input\n",
- __func__);
- goto err_inval;
- }
-
- if ((src->input == TSPP2_INPUT_MEMORY) &&
- ((src_event_bitmask & TSPP2_SRC_EVENT_TSIF_LOST_SYNC) ||
- (src_event_bitmask & TSPP2_SRC_EVENT_TSIF_TIMEOUT) ||
- (src_event_bitmask & TSPP2_SRC_EVENT_TSIF_OVERFLOW) ||
- (src_event_bitmask & TSPP2_SRC_EVENT_TSIF_PKT_READ_ERROR) ||
- (src_event_bitmask & TSPP2_SRC_EVENT_TSIF_PKT_WRITE_ERROR))) {
- pr_err("%s: Invalid event bitmask for a source with memory input\n",
- __func__);
- goto err_inval;
- }
-
- spin_lock_irqsave(&src->device->spinlock, flags);
- src->event_callback = callback;
- src->event_cookie = cookie;
- src->event_bitmask = src_event_bitmask;
- spin_unlock_irqrestore(&src->device->spinlock, flags);
-
- /* Enable/disable flow control stall interrupt on the source */
- reg = readl_relaxed(src->device->base + TSPP2_GLOBAL_IRQ_ENABLE);
- if (callback && (src_event_bitmask & TSPP2_SRC_EVENT_FLOW_CTRL_STALL)) {
- reg |= ((0x1 << src->hw_index) <<
- GLOBAL_IRQ_FC_STALL_OFFS);
- } else {
- reg &= ~((0x1 << src->hw_index) <<
- GLOBAL_IRQ_FC_STALL_OFFS);
- }
- writel_relaxed(reg, src->device->base + TSPP2_GLOBAL_IRQ_ENABLE);
-
- mutex_unlock(&src->device->mutex);
-
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
-
- dev_dbg(src->device->dev, "%s: successful\n", __func__);
-
- return 0;
-
-err_inval:
- mutex_unlock(&src->device->mutex);
- pm_runtime_mark_last_busy(src->device->dev);
- pm_runtime_put_autosuspend(src->device->dev);
-
- return -EINVAL;
-}
-EXPORT_SYMBOL(tspp2_src_event_notification_register);
-
-/**
- * tspp2_filter_event_notification_register() - Get notified on a filter event.
- *
- * @filter_handle: Filter handle.
- * @filter_event_bitmask: A bitmask of filter events,
- * TSPP2_FILTER_EVENT_XXX.
- * @callback: User callback function.
- * @cookie: User information passed to the callback.
- *
- * Register a user callback which will be invoked when certain filter
- * events occur. Note the values (mask, callback and cookie) are overwritten
- * when calling this function multiple times. Therefore it is possible to
- * "unregister" a callback by calling this function with the bitmask set to 0
- * and with NULL callback and cookie.
- *
- * Return 0 on success, error value otherwise.
- */
-int tspp2_filter_event_notification_register(u32 filter_handle,
- u32 filter_event_bitmask,
- void (*callback)(void *cookie, u32 event_bitmask),
- void *cookie)
-{
- int ret;
- int idx;
- u32 reg;
- unsigned long flags;
- struct tspp2_filter *filter = (struct tspp2_filter *)filter_handle;
-
- if (!filter) {
- pr_err("%s: Invalid filter handle\n", __func__);
- return -EINVAL;
- }
-
- ret = pm_runtime_get_sync(filter->device->dev);
- if (ret < 0)
- return ret;
-
- if (mutex_lock_interruptible(&filter->device->mutex)) {
- pm_runtime_mark_last_busy(filter->device->dev);
- pm_runtime_put_autosuspend(filter->device->dev);
- return -ERESTARTSYS;
- }
-
- if (!filter->device->opened) {
- pr_err("%s: Device must be opened first\n", __func__);
- mutex_unlock(&filter->device->mutex);
- pm_runtime_mark_last_busy(filter->device->dev);
- pm_runtime_put_autosuspend(filter->device->dev);
- return -EPERM;
- }
-
- if (!filter->opened) {
- pr_err("%s: Filter not opened\n", __func__);
- mutex_unlock(&filter->device->mutex);
- pm_runtime_mark_last_busy(filter->device->dev);
- pm_runtime_put_autosuspend(filter->device->dev);
- return -EINVAL;
- }
-
- spin_lock_irqsave(&filter->device->spinlock, flags);
- filter->event_callback = callback;
- filter->event_cookie = cookie;
- filter->event_bitmask = filter_event_bitmask;
- spin_unlock_irqrestore(&filter->device->spinlock, flags);
-
- /* Enable/disable SC high/low interrupts per filter as requested */
- idx = (filter->context >> 5);
- reg = readl_relaxed(filter->device->base +
- TSPP2_SC_GO_HIGH_ENABLE(idx));
- if (callback &&
- (filter_event_bitmask & TSPP2_FILTER_EVENT_SCRAMBLING_HIGH)) {
- reg |= (0x1 << TSPP2_MODULUS_OP(filter->context, 32));
- } else {
- reg &= ~(0x1 << TSPP2_MODULUS_OP(filter->context, 32));
- }
- writel_relaxed(reg, filter->device->base +
- TSPP2_SC_GO_HIGH_ENABLE(idx));
-
- reg = readl_relaxed(filter->device->base +
- TSPP2_SC_GO_LOW_ENABLE(idx));
- if (callback &&
- (filter_event_bitmask & TSPP2_FILTER_EVENT_SCRAMBLING_LOW)) {
- reg |= (0x1 << TSPP2_MODULUS_OP(filter->context, 32));
- } else {
- reg &= ~(0x1 << TSPP2_MODULUS_OP(filter->context, 32));
- }
- writel_relaxed(reg, filter->device->base +
- TSPP2_SC_GO_LOW_ENABLE(idx));
-
- mutex_unlock(&filter->device->mutex);
-
- pm_runtime_mark_last_busy(filter->device->dev);
- pm_runtime_put_autosuspend(filter->device->dev);
-
- dev_dbg(filter->device->dev, "%s: successful\n", __func__);
-
- return 0;
-}
-EXPORT_SYMBOL(tspp2_filter_event_notification_register);
-
-/**
- * tspp2_get_filter_hw_index() - Get a filter's hardware index.
- *
- * @filter_handle: Filter handle.
- *
- * This is an helper function to support tspp2 auto-testing.
- *
- * Return the filter's hardware index on success, error value otherwise.
- */
-int tspp2_get_filter_hw_index(u32 filter_handle)
-{
- struct tspp2_filter *filter = (struct tspp2_filter *)filter_handle;
- if (!filter_handle)
- return -EINVAL;
- return filter->hw_index;
-}
-EXPORT_SYMBOL(tspp2_get_filter_hw_index);
-
-/**
- * tspp2_get_reserved_hw_index() - Get a source's reserved hardware index.
- *
- * @src_handle: Source handle.
- *
- * This is an helper function to support tspp2 auto-testing.
- *
- * Return the source's reserved hardware index on success,
- * error value otherwise.
- */
-int tspp2_get_reserved_hw_index(u32 src_handle)
-{
- struct tspp2_src *src = (struct tspp2_src *)src_handle;
- if (!src_handle)
- return -EINVAL;
- return src->reserved_filter_hw_index;
-}
-EXPORT_SYMBOL(tspp2_get_reserved_hw_index);
-
-/**
- * tspp2_get_ops_array() - Get filter's operations.
- *
- * @filter_handle: Filter handle.
- * @ops_array: The filter's operations.
- * @num_of_ops: The filter's number of operations.
- *
- * This is an helper function to support tspp2 auto-testing.
- *
- * Return 0 on success, error value otherwise.
- */
-int tspp2_get_ops_array(u32 filter_handle,
- struct tspp2_operation ops_array[TSPP2_MAX_OPS_PER_FILTER],
- u8 *num_of_ops)
-{
- int i;
- struct tspp2_filter *filter = (struct tspp2_filter *)filter_handle;
- if (!filter_handle || !num_of_ops)
- return -EINVAL;
- *num_of_ops = filter->num_user_operations;
- for (i = 0; i < *num_of_ops; i++)
- ops_array[i] = filter->operations[i];
- return 0;
-}
-EXPORT_SYMBOL(tspp2_get_ops_array);
-
-/* Platform driver related functions: */
-
-/**
- * msm_tspp2_dt_to_pdata() - Copy device-tree data to platfrom data structure.
- *
- * @pdev: Platform device.
- *
- * Return pointer to allocated platform data on success, NULL on failure.
- */
-static struct msm_tspp2_platform_data *
-msm_tspp2_dt_to_pdata(struct platform_device *pdev)
-{
- struct device_node *node = pdev->dev.of_node;
- struct msm_tspp2_platform_data *data;
- int rc;
-
- /* Note: memory allocated by devm_kzalloc is freed automatically */
- data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
- if (!data) {
- pr_err("%s: Unable to allocate platform data\n", __func__);
- return NULL;
- }
-
- /* Get power regulator */
- if (!of_get_property(node, "vdd-supply", NULL)) {
- pr_err("%s: Could not find vdd-supply property\n", __func__);
- return NULL;
- }
-
- /* Get IOMMU information */
- rc = of_property_read_string(node, "qcom,iommu-hlos-group",
- &data->hlos_group);
- if (rc) {
- pr_err("%s: Could not find iommu-hlos-group property, err = %d\n",
- __func__, rc);
- return NULL;
- }
- rc = of_property_read_string(node, "qcom,iommu-cpz-group",
- &data->cpz_group);
- if (rc) {
- pr_err("%s: Could not find iommu-cpz-group property, err = %d\n",
- __func__, rc);
- return NULL;
- }
- rc = of_property_read_u32(node, "qcom,iommu-hlos-partition",
- &data->hlos_partition);
- if (rc) {
- pr_err("%s: Could not find iommu-hlos-partition property, err = %d\n",
- __func__, rc);
- return NULL;
- }
- rc = of_property_read_u32(node, "qcom,iommu-cpz-partition",
- &data->cpz_partition);
- if (rc) {
- pr_err("%s: Could not find iommu-cpz-partition property, err = %d\n",
- __func__, rc);
- return NULL;
- }
-
- return data;
-}
-
-static void msm_tspp2_iommu_info_free(struct tspp2_device *device)
-{
- if (device->iommu_info.hlos_group) {
- iommu_group_put(device->iommu_info.hlos_group);
- device->iommu_info.hlos_group = NULL;
- }
-
- if (device->iommu_info.cpz_group) {
- iommu_group_put(device->iommu_info.cpz_group);
- device->iommu_info.cpz_group = NULL;
- }
-
- device->iommu_info.hlos_domain = NULL;
- device->iommu_info.cpz_domain = NULL;
- device->iommu_info.hlos_domain_num = -1;
- device->iommu_info.cpz_domain_num = -1;
- device->iommu_info.hlos_partition = -1;
- device->iommu_info.cpz_partition = -1;
-}
-
-/**
- * msm_tspp2_iommu_info_get() - Get IOMMU information.
- *
- * @pdev: Platform device, containing platform information.
- * @device: TSPP2 device.
- *
- * Return 0 on success, error value otherwise.
- */
-static int msm_tspp2_iommu_info_get(struct platform_device *pdev,
- struct tspp2_device *device)
-{
- int ret = 0;
- struct msm_tspp2_platform_data *data = pdev->dev.platform_data;
-
- device->iommu_info.hlos_group = NULL;
- device->iommu_info.cpz_group = NULL;
- device->iommu_info.hlos_domain = NULL;
- device->iommu_info.cpz_domain = NULL;
- device->iommu_info.hlos_domain_num = -1;
- device->iommu_info.cpz_domain_num = -1;
- device->iommu_info.hlos_partition = -1;
- device->iommu_info.cpz_partition = -1;
-
- device->iommu_info.hlos_group = iommu_group_find(data->hlos_group);
- if (!device->iommu_info.hlos_group) {
- dev_err(&pdev->dev, "%s: Cannot find IOMMU HLOS group",
- __func__);
- ret = -EINVAL;
- goto err_out;
- }
- device->iommu_info.cpz_group = iommu_group_find(data->cpz_group);
- if (!device->iommu_info.cpz_group) {
- dev_err(&pdev->dev, "%s: Cannot find IOMMU CPZ group",
- __func__);
- ret = -EINVAL;
- goto err_out;
- }
-
- device->iommu_info.hlos_domain =
- iommu_group_get_iommudata(device->iommu_info.hlos_group);
- if (IS_ERR_OR_NULL(device->iommu_info.hlos_domain)) {
- dev_err(&pdev->dev, "%s: iommu_group_get_iommudata failed",
- __func__);
- ret = -EINVAL;
- goto err_out;
- }
-
- device->iommu_info.cpz_domain =
- iommu_group_get_iommudata(device->iommu_info.cpz_group);
- if (IS_ERR_OR_NULL(device->iommu_info.cpz_domain)) {
- device->iommu_info.hlos_domain = NULL;
- dev_err(&pdev->dev, "%s: iommu_group_get_iommudata failed",
- __func__);
- ret = -EINVAL;
- goto err_out;
- }
-
- device->iommu_info.hlos_domain_num =
- msm_find_domain_no(device->iommu_info.hlos_domain);
- device->iommu_info.cpz_domain_num =
- msm_find_domain_no(device->iommu_info.cpz_domain);
- device->iommu_info.hlos_partition = data->hlos_partition;
- device->iommu_info.cpz_partition = data->cpz_partition;
-
- return 0;
-
-err_out:
- msm_tspp2_iommu_info_free(device);
-
- return ret;
-}
-
-/**
- * tspp2_clocks_put() - Put clocks and disable regulator.
- *
- * @device: TSPP2 device.
- */
-static void tspp2_clocks_put(struct tspp2_device *device)
-{
- if (device->tsif_ref_clk)
- clk_put(device->tsif_ref_clk);
-
- if (device->tspp2_klm_ahb_clk)
- clk_put(device->tspp2_klm_ahb_clk);
-
- if (device->tspp2_vbif_clk)
- clk_put(device->tspp2_vbif_clk);
-
- if (device->vbif_ahb_clk)
- clk_put(device->vbif_ahb_clk);
-
- if (device->vbif_axi_clk)
- clk_put(device->vbif_axi_clk);
-
- if (device->tspp2_core_clk)
- clk_put(device->tspp2_core_clk);
-
- if (device->tspp2_ahb_clk)
- clk_put(device->tspp2_ahb_clk);
-
- device->tspp2_ahb_clk = NULL;
- device->tspp2_core_clk = NULL;
- device->tspp2_vbif_clk = NULL;
- device->vbif_ahb_clk = NULL;
- device->vbif_axi_clk = NULL;
- device->tspp2_klm_ahb_clk = NULL;
- device->tsif_ref_clk = NULL;
-}
-
-/**
- * msm_tspp2_clocks_setup() - Get clocks and set their rate, enable regulator.
- *
- * @pdev: Platform device, containing platform information.
- * @device: TSPP2 device.
- *
- * Return 0 on success, error value otherwise.
- */
-static int msm_tspp2_clocks_setup(struct platform_device *pdev,
- struct tspp2_device *device)
-{
- int ret = 0;
- unsigned long rate_in_hz = 0;
- struct clk *tspp2_core_clk_src = NULL;
-
- /* Get power regulator (GDSC) */
- device->gdsc = devm_regulator_get(&pdev->dev, "vdd");
- if (IS_ERR(device->gdsc)) {
- pr_err("%s: Failed to get vdd power regulator\n", __func__);
- ret = PTR_ERR(device->gdsc);
- device->gdsc = NULL;
- return ret;
- }
-
- device->tspp2_ahb_clk = NULL;
- device->tspp2_core_clk = NULL;
- device->tspp2_vbif_clk = NULL;
- device->vbif_ahb_clk = NULL;
- device->vbif_axi_clk = NULL;
- device->tspp2_klm_ahb_clk = NULL;
- device->tsif_ref_clk = NULL;
-
- device->tspp2_ahb_clk = clk_get(&pdev->dev, "bcc_tspp2_ahb_clk");
- if (IS_ERR(device->tspp2_ahb_clk)) {
- pr_err("%s: Failed to get %s", __func__, "bcc_tspp2_ahb_clk");
- ret = PTR_ERR(device->tspp2_ahb_clk);
- device->tspp2_ahb_clk = NULL;
- goto err_clocks;
- }
-
- device->tspp2_core_clk = clk_get(&pdev->dev, "bcc_tspp2_core_clk");
- if (IS_ERR(device->tspp2_core_clk)) {
- pr_err("%s: Failed to get %s", __func__, "bcc_tspp2_core_clk");
- ret = PTR_ERR(device->tspp2_core_clk);
- device->tspp2_core_clk = NULL;
- goto err_clocks;
- }
-
- device->tspp2_vbif_clk = clk_get(&pdev->dev, "bcc_vbif_tspp2_clk");
- if (IS_ERR(device->tspp2_vbif_clk)) {
- pr_err("%s: Failed to get %s", __func__, "bcc_vbif_tspp2_clk");
- ret = PTR_ERR(device->tspp2_vbif_clk);
- device->tspp2_vbif_clk = NULL;
- goto err_clocks;
- }
-
- device->vbif_ahb_clk = clk_get(&pdev->dev, "iface_vbif_clk");
- if (IS_ERR(device->vbif_ahb_clk)) {
- pr_err("%s: Failed to get %s", __func__, "iface_vbif_clk");
- ret = PTR_ERR(device->vbif_ahb_clk);
- device->vbif_ahb_clk = NULL;
- goto err_clocks;
- }
-
- device->vbif_axi_clk = clk_get(&pdev->dev, "vbif_core_clk");
- if (IS_ERR(device->vbif_axi_clk)) {
- pr_err("%s: Failed to get %s", __func__, "vbif_core_clk");
- ret = PTR_ERR(device->vbif_axi_clk);
- device->vbif_axi_clk = NULL;
- goto err_clocks;
- }
-
- device->tspp2_klm_ahb_clk = clk_get(&pdev->dev, "bcc_klm_ahb_clk");
- if (IS_ERR(device->tspp2_klm_ahb_clk)) {
- pr_err("%s: Failed to get %s", __func__, "bcc_klm_ahb_clk");
- ret = PTR_ERR(device->tspp2_klm_ahb_clk);
- device->tspp2_klm_ahb_clk = NULL;
- goto err_clocks;
- }
-
- device->tsif_ref_clk = clk_get(&pdev->dev, "gcc_tsif_ref_clk");
- if (IS_ERR(device->tsif_ref_clk)) {
- pr_err("%s: Failed to get %s", __func__, "gcc_tsif_ref_clk");
- ret = PTR_ERR(device->tsif_ref_clk);
- device->tsif_ref_clk = NULL;
- goto err_clocks;
- }
-
- /* Set relevant clock rates */
- rate_in_hz = clk_round_rate(device->tsif_ref_clk, 1);
- if (clk_set_rate(device->tsif_ref_clk, rate_in_hz)) {
- pr_err("%s: Failed to set rate %lu to %s\n", __func__,
- rate_in_hz, "gcc_tsif_ref_clk");
- goto err_clocks;
- }
-
- /* We need to set the rate of tspp2_core_clk_src */
- tspp2_core_clk_src = clk_get_parent(device->tspp2_core_clk);
- if (tspp2_core_clk_src) {
- rate_in_hz = clk_round_rate(tspp2_core_clk_src, 1);
- if (clk_set_rate(tspp2_core_clk_src, rate_in_hz)) {
- pr_err("%s: Failed to set rate %lu to tspp2_core_clk_src\n",
- __func__, rate_in_hz);
- goto err_clocks;
- }
- } else {
- pr_err("%s: Failed to get tspp2_core_clk parent\n", __func__);
- goto err_clocks;
- }
-
- return 0;
-
-err_clocks:
- tspp2_clocks_put(device);
-
- return ret;
-}
-
-/**
- * msm_tspp2_map_io_memory() - Map memory resources to kernel space.
- *
- * @pdev: Platform device, containing platform information.
- * @device: TSPP2 device.
- *
- * Return 0 on success, error value otherwise.
- */
-static int msm_tspp2_map_io_memory(struct platform_device *pdev,
- struct tspp2_device *device)
-{
- struct resource *mem_tsif0;
- struct resource *mem_tsif1;
- struct resource *mem_tspp2;
- struct resource *mem_bam;
-
- /* Get memory resources */
- mem_tsif0 = platform_get_resource_byname(pdev,
- IORESOURCE_MEM, "MSM_TSIF0");
- if (!mem_tsif0) {
- dev_err(&pdev->dev, "%s: Missing TSIF0 MEM resource", __func__);
- return -ENXIO;
- }
-
- mem_tsif1 = platform_get_resource_byname(pdev,
- IORESOURCE_MEM, "MSM_TSIF1");
- if (!mem_tsif1) {
- dev_err(&pdev->dev, "%s: Missing TSIF1 MEM resource", __func__);
- return -ENXIO;
- }
-
- mem_tspp2 = platform_get_resource_byname(pdev,
- IORESOURCE_MEM, "MSM_TSPP2");
- if (!mem_tspp2) {
- dev_err(&pdev->dev, "%s: Missing TSPP2 MEM resource", __func__);
- return -ENXIO;
- }
-
- mem_bam = platform_get_resource_byname(pdev,
- IORESOURCE_MEM, "MSM_TSPP2_BAM");
- if (!mem_bam) {
- dev_err(&pdev->dev, "%s: Missing BAM MEM resource", __func__);
- return -ENXIO;
- }
-
- /* Map memory physical addresses to kernel space */
- device->tsif_devices[0].base = ioremap(mem_tsif0->start,
- resource_size(mem_tsif0));
- if (!device->tsif_devices[0].base) {
- dev_err(&pdev->dev, "%s: ioremap failed", __func__);
- goto err_map_tsif0;
- }
-
- device->tsif_devices[1].base = ioremap(mem_tsif1->start,
- resource_size(mem_tsif1));
- if (!device->tsif_devices[1].base) {
- dev_err(&pdev->dev, "%s: ioremap failed", __func__);
- goto err_map_tsif1;
- }
-
- device->base = ioremap(mem_tspp2->start, resource_size(mem_tspp2));
- if (!device->base) {
- dev_err(&pdev->dev, "%s: ioremap failed", __func__);
- goto err_map_dev;
- }
-
- memset(&device->bam_props, 0, sizeof(device->bam_props));
- device->bam_props.phys_addr = mem_bam->start;
- device->bam_props.virt_addr = ioremap(mem_bam->start,
- resource_size(mem_bam));
- if (!device->bam_props.virt_addr) {
- dev_err(&pdev->dev, "%s: ioremap failed", __func__);
- goto err_map_bam;
- }
-
- return 0;
-
-err_map_bam:
- iounmap(device->base);
-
-err_map_dev:
- iounmap(device->tsif_devices[1].base);
-
-err_map_tsif1:
- iounmap(device->tsif_devices[0].base);
-
-err_map_tsif0:
- return -ENXIO;
-}
-
-/**
- * tspp2_event_work_prepare() - Prepare and queue a work element.
- *
- * @device: TSPP2 device.
- * @callback: User callback to invoke.
- * @cookie: User cookie.
- * @event_bitmask: Event bitmask
- *
- * Get a free work element from the pool, prepare it and queue it
- * to the work queue. When scheduled, the work will invoke the user callback
- * for the event that the HW reported.
- */
-static void tspp2_event_work_prepare(struct tspp2_device *device,
- void (*callback)(void *cookie, u32 event_bitmask),
- void *cookie,
- u32 event_bitmask)
-{
- struct tspp2_event_work *work = NULL;
-
- if (!list_empty(&device->free_work_list)) {
- work = list_first_entry(&device->free_work_list,
- struct tspp2_event_work, link);
- list_del(&work->link);
- work->callback = callback;
- work->cookie = cookie;
- work->event_bitmask = event_bitmask;
- queue_work(device->work_queue, &work->work);
- } else {
- pr_warn("%s: No available work element\n", __func__);
- }
-}
-
-/**
- * tspp2_isr() - TSPP2 interrupt handler.
- *
- * @irq: Interrupt number.
- * @dev: TSPP2 device.
- *
- * Handle TSPP2 HW interrupt. Collect relevant statistics and invoke
- * user registered callbacks for global, source or filter events.
- *
- * Return IRQ_HANDLED.
- */
-static irqreturn_t tspp2_isr(int irq, void *dev)
-{
- struct tspp2_device *device = dev;
- struct tspp2_src *src = NULL;
- struct tspp2_filter *f = NULL;
- unsigned long ext_reg = 0;
- unsigned long val = 0;
- unsigned long flags;
- u32 i = 0, j = 0;
- u32 global_bitmask = 0;
- u32 src_bitmask[TSPP2_NUM_MEM_INPUTS] = {0};
- u32 filter_bitmask[TSPP2_NUM_CONTEXTS] = {0};
- u32 reg = 0;
-
- reg = readl_relaxed(device->base + TSPP2_GLOBAL_IRQ_STATUS);
-
- if (reg & (0x1 << GLOBAL_IRQ_TSP_INVALID_AF_OFFS)) {
- device->irq_stats.global.tsp_invalid_af_control++;
- global_bitmask |= TSPP2_GLOBAL_EVENT_INVALID_AF_CTRL;
- }
-
- if (reg & (0x1 << GLOBAL_IRQ_TSP_INVALID_LEN_OFFS)) {
- device->irq_stats.global.tsp_invalid_length++;
- global_bitmask |= TSPP2_GLOBAL_EVENT_INVALID_AF_LENGTH;
- }
-
- if (reg & (0x1 << GLOBAL_IRQ_PES_NO_SYNC_OFFS)) {
- device->irq_stats.global.pes_no_sync++;
- global_bitmask |= TSPP2_GLOBAL_EVENT_PES_NO_SYNC;
- }
-
- if (reg & (0x1 << GLOBAL_IRQ_ENCRYPT_LEVEL_ERR_OFFS))
- device->irq_stats.global.encrypt_level_err++;
-
- if (reg & (0x1 << GLOBAL_IRQ_KEY_NOT_READY_OFFS)) {
- ext_reg = readl_relaxed(device->base +
- TSPP2_KEY_NOT_READY_IRQ_STATUS);
- for_each_set_bit(i, &ext_reg, TSPP2_NUM_KEYTABLES)
- device->irq_stats.kt[i].key_not_ready++;
- writel_relaxed(ext_reg, device->base +
- TSPP2_KEY_NOT_READY_IRQ_CLEAR);
- }
-
- if (reg & (0x1 << GLOBAL_IRQ_UNEXPECTED_RESET_OFFS)) {
- ext_reg = readl_relaxed(device->base +
- TSPP2_UNEXPECTED_RST_IRQ_STATUS);
- for_each_set_bit(i, &ext_reg, TSPP2_NUM_PIPES)
- device->irq_stats.pipe[i].unexpected_reset++;
- writel_relaxed(ext_reg, device->base +
- TSPP2_UNEXPECTED_RST_IRQ_CLEAR);
- }
-
- if (reg & (0x1 << GLOBAL_IRQ_WRONG_PIPE_DIR_OFFS)) {
- ext_reg = readl_relaxed(device->base +
- TSPP2_WRONG_PIPE_DIR_IRQ_STATUS);
- for_each_set_bit(i, &ext_reg, TSPP2_NUM_PIPES)
- device->irq_stats.pipe[i].wrong_pipe_direction++;
- writel_relaxed(ext_reg, device->base +
- TSPP2_WRONG_PIPE_DIR_IRQ_CLEAR);
- }
-
- if (reg & (0x1 << GLOBAL_IRQ_QSB_RESP_ERR_OFFS)) {
- global_bitmask |= TSPP2_GLOBAL_EVENT_TX_FAIL;
- ext_reg = readl_relaxed(device->base +
- TSPP2_QSB_RESPONSE_ERROR_IRQ_STATUS);
- for_each_set_bit(i, &ext_reg, TSPP2_NUM_PIPES)
- device->irq_stats.pipe[i].qsb_response_error++;
- writel_relaxed(ext_reg, device->base +
- TSPP2_QSB_RESPONSE_ERROR_IRQ_CLEAR);
- }
-
- if (reg & (0x1 << GLOBAL_IRQ_SC_GO_HIGH_OFFS)) {
- for (j = 0; j < 3; j++) {
- ext_reg = readl_relaxed(device->base +
- TSPP2_SC_GO_HIGH_STATUS(j));
- for_each_set_bit(i, &ext_reg, 32) {
- filter_bitmask[j*32 + i] |=
- TSPP2_FILTER_EVENT_SCRAMBLING_HIGH;
- device->irq_stats.ctx[j*32 + i].sc_go_high++;
- }
- writel_relaxed(ext_reg, device->base +
- TSPP2_SC_GO_HIGH_CLEAR(j));
- }
- }
-
- if (reg & (0x1 << GLOBAL_IRQ_SC_GO_LOW_OFFS)) {
- for (j = 0; j < 3; j++) {
- ext_reg = readl_relaxed(device->base +
- TSPP2_SC_GO_LOW_STATUS(j));
- for_each_set_bit(i, &ext_reg, 32) {
- filter_bitmask[j*32 + i] |=
- TSPP2_FILTER_EVENT_SCRAMBLING_LOW;
- device->irq_stats.ctx[j*32 + i].sc_go_low++;
- }
- writel_relaxed(ext_reg, device->base +
- TSPP2_SC_GO_LOW_CLEAR(j));
- }
- }
-
- if (reg & (0xFF << GLOBAL_IRQ_READ_FAIL_OFFS)) {
- val = ((reg & (0xFF << GLOBAL_IRQ_READ_FAIL_OFFS)) >>
- GLOBAL_IRQ_READ_FAIL_OFFS);
- for_each_set_bit(i, &val, TSPP2_NUM_MEM_INPUTS) {
- src_bitmask[i] |= TSPP2_SRC_EVENT_MEMORY_READ_ERROR;
- device->irq_stats.src[i].read_failure++;
- }
- }
-
- if (reg & (0xFF << GLOBAL_IRQ_FC_STALL_OFFS)) {
- val = ((reg & (0xFF << GLOBAL_IRQ_FC_STALL_OFFS)) >>
- GLOBAL_IRQ_FC_STALL_OFFS);
- for_each_set_bit(i, &val, TSPP2_NUM_MEM_INPUTS) {
- src_bitmask[i] |= TSPP2_SRC_EVENT_FLOW_CTRL_STALL;
- device->irq_stats.src[i].flow_control_stall++;
- }
- }
-
- spin_lock_irqsave(&device->spinlock, flags);
-
- /* Invoke user callback for global events */
- if (device->event_callback && (global_bitmask & device->event_bitmask))
- tspp2_event_work_prepare(device, device->event_callback,
- device->event_cookie,
- (global_bitmask & device->event_bitmask));
-
- /* Invoke user callbacks on memory source events */
- for (i = 0; i < TSPP2_NUM_MEM_INPUTS; i++) {
- src = &device->mem_sources[i];
- if (src->event_callback &&
- (src_bitmask[src->hw_index] & src->event_bitmask))
- tspp2_event_work_prepare(device,
- src->event_callback,
- src->event_cookie,
- (src_bitmask[src->hw_index] &
- src->event_bitmask));
- }
-
- /* Invoke user callbacks on filter events */
- for (i = 0; i < TSPP2_NUM_AVAIL_FILTERS; i++) {
- f = &device->filters[i];
- if (f->event_callback &&
- (f->event_bitmask & filter_bitmask[f->context]))
- tspp2_event_work_prepare(device,
- f->event_callback,
- f->event_cookie,
- (f->event_bitmask &
- filter_bitmask[f->context]));
- }
-
- spin_unlock_irqrestore(&device->spinlock, flags);
-
- /*
- * Clear global interrupts. Note bits [9:4] are an aggregation of
- * other IRQs, and are reserved in the TSPP2_GLOBAL_IRQ_CLEAR register.
- */
- reg &= ~(0x0FFF << GLOBAL_IRQ_CLEAR_RESERVED_OFFS);
- writel_relaxed(reg, device->base + TSPP2_GLOBAL_IRQ_CLEAR);
- /*
- * Before returning IRQ_HANDLED to the generic interrupt handling
- * framework, we need to make sure all operations, including clearing of
- * interrupt status registers in the hardware, are performed.
- * Thus a barrier after clearing the interrupt status register
- * is required to guarantee that the interrupt status register has
- * really been cleared by the time we return from this handler.
- */
- wmb();
-
- return IRQ_HANDLED;
-}
-
-/**
- * tsif_isr() - TSIF interrupt handler.
- *
- * @irq: Interrupt number.
- * @dev: TSIF device that generated the interrupt.
- *
- * Handle TSIF HW interrupt. Collect HW statistics and, if the user registered
- * a relevant source callback, invoke it.
- *
- * Return IRQ_HANDLED on success, IRQ_NONE on irrelevant interrupts.
- */
-static irqreturn_t tsif_isr(int irq, void *dev)
-{
- u32 src_bitmask = 0;
- unsigned long flags;
- struct tspp2_src *src = NULL;
- struct tspp2_tsif_device *tsif_device = dev;
- u32 sts_ctl = 0;
-
- sts_ctl = readl_relaxed(tsif_device->base + TSPP2_TSIF_STS_CTL);
-
- if (!(sts_ctl & (TSIF_STS_CTL_PACK_AVAIL |
- TSIF_STS_CTL_PKT_WRITE_ERR |
- TSIF_STS_CTL_PKT_READ_ERR |
- TSIF_STS_CTL_OVERFLOW |
- TSIF_STS_CTL_LOST_SYNC |
- TSIF_STS_CTL_TIMEOUT))) {
- return IRQ_NONE;
- }
-
- if (sts_ctl & TSIF_STS_CTL_PKT_WRITE_ERR) {
- src_bitmask |= TSPP2_SRC_EVENT_TSIF_PKT_WRITE_ERROR;
- tsif_device->stat_pkt_write_err++;
- }
-
- if (sts_ctl & TSIF_STS_CTL_PKT_READ_ERR) {
- src_bitmask |= TSPP2_SRC_EVENT_TSIF_PKT_READ_ERROR;
- tsif_device->stat_pkt_read_err++;
- }
-
- if (sts_ctl & TSIF_STS_CTL_OVERFLOW) {
- src_bitmask |= TSPP2_SRC_EVENT_TSIF_OVERFLOW;
- tsif_device->stat_overflow++;
- }
-
- if (sts_ctl & TSIF_STS_CTL_LOST_SYNC) {
- src_bitmask |= TSPP2_SRC_EVENT_TSIF_LOST_SYNC;
- tsif_device->stat_lost_sync++;
- }
-
- if (sts_ctl & TSIF_STS_CTL_TIMEOUT) {
- src_bitmask |= TSPP2_SRC_EVENT_TSIF_TIMEOUT;
- tsif_device->stat_timeout++;
- }
-
- /* Invoke user TSIF source callbacks if registered for these events */
- src = &tsif_device->dev->tsif_sources[tsif_device->hw_index];
-
- spin_lock_irqsave(&src->device->spinlock, flags);
-
- if (src->event_callback && (src->event_bitmask & src_bitmask))
- tspp2_event_work_prepare(tsif_device->dev, src->event_callback,
- src->event_cookie, (src->event_bitmask & src_bitmask));
-
- spin_unlock_irqrestore(&src->device->spinlock, flags);
-
- writel_relaxed(sts_ctl, tsif_device->base + TSPP2_TSIF_STS_CTL);
- /*
- * Before returning IRQ_HANDLED to the generic interrupt handling
- * framework, we need to make sure all operations, including clearing of
- * interrupt status registers in the hardware, are performed.
- * Thus a barrier after clearing the interrupt status register
- * is required to guarantee that the interrupt status register has
- * really been cleared by the time we return from this handler.
- */
- wmb();
-
- return IRQ_HANDLED;
-}
-
-/**
- * msm_tspp2_map_irqs() - Get and request IRQs.
- *
- * @pdev: Platform device, containing platform information.
- * @device: TSPP2 device.
- *
- * Helper function to get IRQ numbers from the platform device and request
- * the IRQs (i.e., set interrupt handlers) for the TSPP2 and TSIF interrupts.
- *
- * Return 0 on success, error value otherwise.
- */
-static int msm_tspp2_map_irqs(struct platform_device *pdev,
- struct tspp2_device *device)
-{
- int rc;
- int i;
-
- /* get IRQ numbers from platform information */
-
- rc = platform_get_irq_byname(pdev, "TSPP2");
- if (rc > 0) {
- device->tspp2_irq = rc;
- } else {
- dev_err(&pdev->dev, "%s: Failed to get TSPP2 IRQ", __func__);
- return -EINVAL;
- }
-
- rc = platform_get_irq_byname(pdev, "TSIF0");
- if (rc > 0) {
- device->tsif_devices[0].tsif_irq = rc;
- } else {
- dev_err(&pdev->dev, "%s: Failed to get TSIF0 IRQ", __func__);
- return -EINVAL;
- }
-
- rc = platform_get_irq_byname(pdev, "TSIF1");
- if (rc > 0) {
- device->tsif_devices[1].tsif_irq = rc;
- } else {
- dev_err(&pdev->dev, "%s: Failed to get TSIF1 IRQ", __func__);
- return -EINVAL;
- }
-
- rc = platform_get_irq_byname(pdev, "TSPP2_BAM");
- if (rc > 0) {
- device->bam_irq = rc;
- } else {
- dev_err(&pdev->dev,
- "%s: Failed to get TSPP2 BAM IRQ", __func__);
- return -EINVAL;
- }
-
- rc = request_irq(device->tspp2_irq, tspp2_isr, IRQF_SHARED,
- dev_name(&pdev->dev), device);
- if (rc) {
- dev_err(&pdev->dev,
- "%s: Failed to request TSPP2 IRQ %d : %d",
- __func__, device->tspp2_irq, rc);
- goto request_irq_err;
- }
-
- for (i = 0; i < TSPP2_NUM_TSIF_INPUTS; i++) {
- rc = request_irq(device->tsif_devices[i].tsif_irq,
- tsif_isr, IRQF_SHARED,
- dev_name(&pdev->dev), &device->tsif_devices[i]);
- if (rc) {
- dev_warn(&pdev->dev,
- "%s: Failed to request TSIF%d IRQ: %d",
- __func__, i, rc);
- device->tsif_devices[i].tsif_irq = 0;
- }
- }
-
- return 0;
-
-request_irq_err:
- device->tspp2_irq = 0;
- device->tsif_devices[0].tsif_irq = 0;
- device->tsif_devices[1].tsif_irq = 0;
- device->bam_irq = 0;
-
- return -EINVAL;
-}
-
-/* Device driver probe function */
-static int msm_tspp2_probe(struct platform_device *pdev)
-{
- int rc = 0;
- struct msm_tspp2_platform_data *data;
- struct tspp2_device *device;
- struct msm_bus_scale_pdata *tspp2_bus_pdata = NULL;
-
- if (pdev->dev.of_node) {
- /* Get information from device tree */
- data = msm_tspp2_dt_to_pdata(pdev);
- /* get device ID */
- rc = of_property_read_u32(pdev->dev.of_node,
- "cell-index", &pdev->id);
- if (rc)
- pdev->id = -1;
-
- tspp2_bus_pdata = msm_bus_cl_get_pdata(pdev);
- pdev->dev.platform_data = data;
- } else {
- /* Get information from platform data */
- data = pdev->dev.platform_data;
- }
- if (!data) {
- pr_err("%s: Platform data not available\n", __func__);
- return -EINVAL;
- }
-
- /* Verify device id is valid */
- if ((pdev->id < 0) || (pdev->id >= TSPP2_NUM_DEVICES)) {
- pr_err("%s: Invalid device ID %d\n", __func__, pdev->id);
- return -EINVAL;
- }
-
- device = devm_kzalloc(&pdev->dev,
- sizeof(struct tspp2_device),
- GFP_KERNEL);
- if (!device) {
- pr_err("%s: Failed to allocate memory for device\n", __func__);
- return -ENOMEM;
- }
- platform_set_drvdata(pdev, device);
- device->pdev = pdev;
- device->dev = &pdev->dev;
- device->dev_id = pdev->id;
- device->opened = 0;
-
- /* Register bus client */
- if (tspp2_bus_pdata) {
- device->bus_client =
- msm_bus_scale_register_client(tspp2_bus_pdata);
- if (!device->bus_client)
- pr_err("%s: Unable to register bus client\n", __func__);
- } else {
- pr_err("%s: Platform bus client data not available. Continue anyway...\n",
- __func__);
- }
-
- rc = msm_tspp2_iommu_info_get(pdev, device);
- if (rc) {
- pr_err("%s: Failed to get IOMMU information\n", __func__);
- goto err_bus_client;
- }
-
- rc = msm_tspp2_clocks_setup(pdev, device);
- if (rc)
- goto err_clocks_setup;
-
- rc = msm_tspp2_map_io_memory(pdev, device);
- if (rc)
- goto err_map_io_memory;
-
- rc = msm_tspp2_map_irqs(pdev, device);
- if (rc)
- goto err_map_irq;
-
- mutex_init(&device->mutex);
-
- tspp2_devices[pdev->id] = device;
-
- tspp2_debugfs_init(device);
-
- return rc;
-
-err_map_irq:
- iounmap(device->base);
- iounmap(device->tsif_devices[0].base);
- iounmap(device->tsif_devices[1].base);
- iounmap(device->bam_props.virt_addr);
-
-err_map_io_memory:
- tspp2_clocks_put(device);
-
-err_clocks_setup:
- msm_tspp2_iommu_info_free(device);
-
-err_bus_client:
- if (device->bus_client)
- msm_bus_scale_unregister_client(device->bus_client);
-
- return rc;
-}
-
-/* Device driver remove function */
-static int msm_tspp2_remove(struct platform_device *pdev)
-{
- int i;
- int rc = 0;
- struct tspp2_device *device = platform_get_drvdata(pdev);
-
- tspp2_debugfs_exit(device);
-
- if (device->tspp2_irq)
- free_irq(device->tspp2_irq, device);
-
- for (i = 0; i < TSPP2_NUM_TSIF_INPUTS; i++)
- if (device->tsif_devices[i].tsif_irq)
- free_irq(device->tsif_devices[i].tsif_irq,
- &device->tsif_devices[i]);
-
- /* Unmap memory */
- iounmap(device->base);
- iounmap(device->tsif_devices[0].base);
- iounmap(device->tsif_devices[1].base);
- iounmap(device->bam_props.virt_addr);
-
- msm_tspp2_iommu_info_free(device);
-
- if (device->bus_client)
- msm_bus_scale_unregister_client(device->bus_client);
-
- mutex_destroy(&device->mutex);
-
- tspp2_clocks_put(device);
-
- return rc;
-}
-
-/* Power Management */
-
-static int tspp2_runtime_suspend(struct device *dev)
-{
- int ret = 0;
- struct tspp2_device *device;
- struct platform_device *pdev;
-
- /*
- * HW manages power collapse automatically.
- * Disabling AHB and Core clocsk and "cancelling" bus bandwidth voting.
- */
-
- pdev = container_of(dev, struct platform_device, dev);
- device = platform_get_drvdata(pdev);
-
- mutex_lock(&device->mutex);
-
- if (!device->opened)
- ret = -EPERM;
- else
- ret = tspp2_reg_clock_stop(device);
-
- mutex_unlock(&device->mutex);
-
- dev_dbg(dev, "%s\n", __func__);
-
- return ret;
-}
-
-static int tspp2_runtime_resume(struct device *dev)
-{
- int ret = 0;
- struct tspp2_device *device;
- struct platform_device *pdev;
-
- /*
- * HW manages power collapse automatically.
- * Enabling AHB and Core clocks to allow access to unit registers,
- * and voting for the required bus bandwidth for register access.
- */
-
- pdev = container_of(dev, struct platform_device, dev);
- device = platform_get_drvdata(pdev);
-
- mutex_lock(&device->mutex);
-
- if (!device->opened)
- ret = -EPERM;
- else
- ret = tspp2_reg_clock_start(device);
-
- mutex_unlock(&device->mutex);
-
- dev_dbg(dev, "%s\n", __func__);
-
- return ret;
-}
-
-static const struct dev_pm_ops tspp2_dev_pm_ops = {
- .runtime_suspend = tspp2_runtime_suspend,
- .runtime_resume = tspp2_runtime_resume,
-};
-
-/* Platform driver information */
-
-static struct of_device_id msm_tspp2_match_table[] = {
- {.compatible = "qcom,msm_tspp2"},
- {}
-};
-
-static struct platform_driver msm_tspp2_driver = {
- .probe = msm_tspp2_probe,
- .remove = msm_tspp2_remove,
- .driver = {
- .name = "msm_tspp2",
- .pm = &tspp2_dev_pm_ops,
- .of_match_table = msm_tspp2_match_table,
- },
-};
-
-/**
- * tspp2_module_init() - TSPP2 driver module init function.
- *
- * Return 0 on success, error value otherwise.
- */
-static int __init tspp2_module_init(void)
-{
- int rc;
-
- rc = platform_driver_register(&msm_tspp2_driver);
- if (rc)
- pr_err("%s: platform_driver_register failed: %d\n",
- __func__, rc);
-
- return rc;
-}
-
-/**
- * tspp2_module_exit() - TSPP2 driver module exit function.
- */
-static void __exit tspp2_module_exit(void)
-{
- platform_driver_unregister(&msm_tspp2_driver);
-}
-
-module_init(tspp2_module_init);
-module_exit(tspp2_module_exit);
-
-MODULE_DESCRIPTION("TSPP2 (Transport Stream Packet Processor v2) platform device driver");
-MODULE_LICENSE("GPL v2");
--
cgit v1.1