DivestOS/Patches/Linux_CVEs/CVE-2015-0573/ANY/0001.patch

12988 lines
385 KiB
Diff
Raw Normal View History

2017-11-07 17:32:46 -05:00
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