Merge "IKXCLOCK-11260 smelt: bcmdhd: security patches for Broadcom" into msm-moto-3.10
diff --git a/CVE_2016_2465.patch.txt b/CVE_2016_2465.patch.txt
new file mode 100644
index 0000000..1664e8f
--- /dev/null
+++ b/CVE_2016_2465.patch.txt
@@ -0,0 +1,173 @@
+From c0cef7a615b4b22c834f83dfe5e99b93737bf0ef Mon Sep 17 00:00:00 2001
+From: Veera Sundaram Sankaran <veeras@codeaurora.org>
+Date: Tue, 15 Mar 2016 18:42:27 -0700
+Subject: [PATCH] msm: mdss: fix possible out-of-bounds and overflow issue in
+ mdp debugfs
+
+There are few cases where the count argument passed by the user
+space is not validated, which can potentially lead to out of bounds
+or overflow issues. In some cases, kernel might copy more data than
+what is requested. Add necessary checks to avoid such cases.
+
+Change-Id: Ifa42fbd475665a0ca581c907ce5432584ea0e7ed
+Signed-off-by: Veera Sundaram Sankaran <veeras@codeaurora.org>
+---
+ drivers/video/msm/mdss/mdss_debug.c | 44 +++++++++++++++++++++----------------
+ 1 file changed, 25 insertions(+), 19 deletions(-)
+
+diff --git a/drivers/video/msm/mdss/mdss_debug.c b/drivers/video/msm/mdss/mdss_debug.c
+index 3b01bfc..e07aeeb 100644
+--- a/drivers/video/msm/mdss/mdss_debug.c
++++ b/drivers/video/msm/mdss/mdss_debug.c
+@@ -1,4 +1,4 @@
+-/* Copyright (c) 2009-2015, The Linux Foundation. All rights reserved.
++/* Copyright (c) 2009-2016, 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
+@@ -109,10 +109,10 @@ static ssize_t panel_debug_base_offset_read(struct file *file,
+ return 0; /* the end */
+
+ len = snprintf(buf, sizeof(buf), "0x%02zx %zx\n", dbg->off, dbg->cnt);
+- if (len < 0)
++ if (len < 0 || len >= sizeof(buf))
+ return 0;
+
+- if (copy_to_user(buff, buf, len))
++ if ((count < sizeof(buf)) || copy_to_user(buff, buf, len))
+ return -EFAULT;
+
+ *ppos += len; /* increase offset */
+@@ -231,10 +231,11 @@ static ssize_t panel_debug_base_reg_read(struct file *file,
+ if (mdata->debug_inf.debug_enable_clock)
+ mdata->debug_inf.debug_enable_clock(0);
+
+- if (len < 0)
++ if (len < 0 || len >= sizeof(to_user_buf))
+ return 0;
+
+- if (copy_to_user(user_buf, to_user_buf, len))
++ if ((count < sizeof(to_user_buf))
++ || copy_to_user(user_buf, to_user_buf, len))
+ return -EFAULT;
+
+ *ppos += len; /* increase offset */
+@@ -368,7 +369,7 @@ static ssize_t mdss_debug_base_offset_read(struct file *file,
+ {
+ struct mdss_debug_base *dbg = file->private_data;
+ int len = 0;
+- char buf[24];
++ char buf[24] = {'\0'};
+
+ if (!dbg)
+ return -ENODEV;
+@@ -377,10 +378,10 @@ static ssize_t mdss_debug_base_offset_read(struct file *file,
+ return 0; /* the end */
+
+ len = snprintf(buf, sizeof(buf), "0x%08zx %zx\n", dbg->off, dbg->cnt);
+- if (len < 0)
++ if (len < 0 || len >= sizeof(buf))
+ return 0;
+
+- if (copy_to_user(buff, buf, len))
++ if ((count < sizeof(buf)) || copy_to_user(buff, buf, len))
+ return -EFAULT;
+
+ *ppos += len; /* increase offset */
+@@ -702,7 +703,7 @@ static ssize_t mdss_debug_factor_read(struct file *file,
+ {
+ struct mdss_fudge_factor *factor = file->private_data;
+ int len = 0;
+- char buf[32];
++ char buf[32] = {'\0'};
+
+ if (!factor)
+ return -ENODEV;
+@@ -712,10 +713,10 @@ static ssize_t mdss_debug_factor_read(struct file *file,
+
+ len = snprintf(buf, sizeof(buf), "%d/%d\n",
+ factor->numer, factor->denom);
+- if (len < 0)
++ if (len < 0 || len >= sizeof(buf))
+ return 0;
+
+- if (copy_to_user(buff, buf, len))
++ if ((count < sizeof(buf)) || copy_to_user(buff, buf, len))
+ return -EFAULT;
+
+ *ppos += len; /* increase offset */
+@@ -746,6 +747,8 @@ static ssize_t mdss_debug_perf_mode_write(struct file *file,
+ if (copy_from_user(buf, user_buf, count))
+ return -EFAULT;
+
++ buf[count] = 0; /* end of string */
++
+ if (sscanf(buf, "%d", &perf_mode) != 1)
+ return -EFAULT;
+
+@@ -766,7 +769,7 @@ static ssize_t mdss_debug_perf_mode_read(struct file *file,
+ {
+ struct mdss_perf_tune *perf_tune = file->private_data;
+ int len = 0;
+- char buf[40];
++ char buf[40] = {'\0'};
+
+ if (!perf_tune)
+ return -ENODEV;
+@@ -774,14 +777,12 @@ static ssize_t mdss_debug_perf_mode_read(struct file *file,
+ if (*ppos)
+ return 0; /* the end */
+
+- buf[count] = 0;
+-
+ len = snprintf(buf, sizeof(buf), "min_mdp_clk %lu min_bus_vote %llu\n",
+ perf_tune->min_mdp_clk, perf_tune->min_bus_vote);
+- if (len < 0)
++ if (len < 0 || len >= sizeof(buf))
+ return 0;
+
+- if (copy_to_user(buff, buf, len))
++ if ((count < sizeof(buf)) || copy_to_user(buff, buf, len))
+ return -EFAULT;
+
+ *ppos += len; /* increase offset */
+@@ -801,7 +802,7 @@ static ssize_t mdss_debug_perf_panic_read(struct file *file,
+ {
+ struct mdss_data_type *mdata = file->private_data;
+ int len = 0;
+- char buf[40];
++ char buf[40] = {'\0'};
+
+ if (!mdata)
+ return -ENODEV;
+@@ -811,10 +812,10 @@ static ssize_t mdss_debug_perf_panic_read(struct file *file,
+
+ len = snprintf(buf, sizeof(buf), "%d\n",
+ !mdata->has_panic_ctrl);
+- if (len < 0)
++ if (len < 0 || len >= sizeof(buf))
+ return 0;
+
+- if (copy_to_user(buff, buf, len))
++ if ((count < sizeof(buf)) || copy_to_user(buff, buf, len))
+ return -EFAULT;
+
+ *ppos += len; /* increase offset */
+@@ -877,9 +878,14 @@ static ssize_t mdss_debug_perf_panic_write(struct file *file,
+ if (!mdata)
+ return -EFAULT;
+
++ if (count >= sizeof(buf))
++ return -EFAULT;
++
+ if (copy_from_user(buf, user_buf, count))
+ return -EFAULT;
+
++ buf[count] = 0; /* end of string */
++
+ if (sscanf(buf, "%d", &disable_panic) != 1)
+ return -EFAULT;
+
+--
+1.8.2.1
+
diff --git a/CVE_2016_2468.patch.txt b/CVE_2016_2468.patch.txt
new file mode 100644
index 0000000..7a59844
--- /dev/null
+++ b/CVE_2016_2468.patch.txt
@@ -0,0 +1,50 @@
+From 616b5bfab8f8c7c25a113bd1c5fe48215cddab1d Mon Sep 17 00:00:00 2001
+From: Rajesh Kemisetti <rajeshk@codeaurora.org>
+Date: Mon, 9 May 2016 22:12:20 +0530
+Subject: [PATCH] msm: kgsl: Add missing checks for alloc size and sglen
+
+In _kgsl_sharedmem_page_alloc(), check for boundary limits
+of requested alloc size before honoring and make sure sglen
+is greater than zero before marking it as end of sg list.
+
+Change-Id: I8b9e225e515a0f31593df6f4cad253236475d0ae
+Signed-off-by: Rajesh Kemisetti <rajeshk@codeaurora.org>
+---
+ drivers/gpu/msm/kgsl_sharedmem.c | 10 ++++++++--
+ 1 file changed, 8 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c
+index 24a1680..98f634d 100644
+--- a/drivers/gpu/msm/kgsl_sharedmem.c
++++ b/drivers/gpu/msm/kgsl_sharedmem.c
+@@ -1,4 +1,4 @@
+-/* Copyright (c) 2002,2007-2015, The Linux Foundation. All rights reserved.
++/* Copyright (c) 2002,2007-2016, 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
+@@ -609,6 +609,10 @@ _kgsl_sharedmem_page_alloc(struct kgsl_memdesc *memdesc,
+ unsigned int align;
+ int step = ((VMALLOC_END - VMALLOC_START)/8) >> PAGE_SHIFT;
+
++ size = PAGE_ALIGN(size);
++ if (size == 0 || size > UINT_MAX)
++ return -EINVAL;
++
+ align = (memdesc->flags & KGSL_MEMALIGN_MASK) >> KGSL_MEMALIGN_SHIFT;
+
+ page_size = get_page_size(size, align);
+@@ -712,7 +716,9 @@ _kgsl_sharedmem_page_alloc(struct kgsl_memdesc *memdesc,
+
+ memdesc->sglen = sglen;
+ memdesc->size = size;
+- sg_mark_end(&memdesc->sg[sglen - 1]);
++
++ if (sglen > 0)
++ sg_mark_end(&memdesc->sg[sglen - 1]);
+
+ /*
+ * All memory that goes to the user has to be zeroed out before it gets
+--
+1.8.2.1
+
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/Documentation/devicetree/bindings/fb/mdss-dsi-ctrl.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-ctrl.txt
index be70c75..d163edb 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi-ctrl.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi-ctrl.txt
@@ -43,6 +43,7 @@
-- qcom,supply-max-voltage: maximum voltage level (uV)
-- qcom,supply-enable-load: load drawn (uA) from enabled supply
-- qcom,supply-disable-load: load drawn (uA) from disabled supply
+ -- qcom,supply-ulp-load: load drawn (uA) from supply in ultra-low power mode
-- qcom,supply-pre-on-sleep: time to sleep (ms) before turning on
-- qcom,supply-post-on-sleep: time to sleep (ms) after turning on
-- qcom,supply-pre-off-sleep: time to sleep (ms) before turning off
@@ -159,6 +160,7 @@
qcom,supply-max-voltage = <2800000>;
qcom,supply-enable-load = <100000>;
qcom,supply-disable-load = <100>;
+ qcom,supply-ulp-load = <100>;
qcom,supply-pre-on-sleep = <0>;
qcom,supply-post-on-sleep = <0>;
qcom,supply-pre-off-sleep = <0>;
@@ -172,6 +174,7 @@
qcom,supply-max-voltage = <1800000>;
qcom,supply-enable-load = <100000>;
qcom,supply-disable-load = <100>;
+ qcom,supply-ulp-load = <100>;
qcom,supply-pre-on-sleep = <0>;
qcom,supply-post-on-sleep = <0>;
qcom,supply-pre-off-sleep = <0>;
diff --git a/Documentation/devicetree/bindings/qseecom/qseecom.txt b/Documentation/devicetree/bindings/qseecom/qseecom.txt
index 83a77e3..2c584e8 100644
--- a/Documentation/devicetree/bindings/qseecom/qseecom.txt
+++ b/Documentation/devicetree/bindings/qseecom/qseecom.txt
@@ -16,7 +16,8 @@
- qcom,support-bus-scaling : indicates if driver support scaling the bus for crypto operation.
- qcom,support-fde : indicates if driver support key managing for full disk encryption feature.
- qcom,support-pfe : indicates if driver support key managing for per file encryption feature.
- - qcom,no-clock-support; indicates clocks are not handled by qseecom (could be handled by RPM)
+ - qcom,no-clock-support : indicates clocks are not handled by qseecom (could be handled by RPM)
+ - qcom,appsbl-qseecom-support : indicates if there is qseecom support in appsbootloader
Example:
qcom,qseecom@fe806000 {
@@ -34,6 +35,7 @@
qcom,msm_bus,active_only = <0>;
qcom,msm_bus,num_paths = <1>;
qcom,no-clock-support;
+ qcom,appsbl-qseecom-support;
qcom,msm_bus,vectors =
<55 512 0 0>,
<55 512 3936000000 393600000>,
diff --git a/Documentation/devicetree/bindings/regulator/rpm-smd-regulator.txt b/Documentation/devicetree/bindings/regulator/rpm-smd-regulator.txt
index e9ddf67..c2c246d 100644
--- a/Documentation/devicetree/bindings/regulator/rpm-smd-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/rpm-smd-regulator.txt
@@ -88,6 +88,12 @@
current updates are only sent if the given
regulator has also been enabled by a Linux
consumer.
+- qcom,send-defaults: Boolean flag which indicates that the initial
+ parameter values should be sent to the RPM
+ before consumers make their own requests. If
+ this flag is not specified, then initial
+ parameters values will only be sent after some
+ consumer makes a request.
The following properties specify initial values for parameters to be sent to the
RPM in regulator requests.
diff --git a/arch/arm/boot/dts/qcom/Makefile b/arch/arm/boot/dts/qcom/Makefile
index 14417b2..deaf141 100644
--- a/arch/arm/boot/dts/qcom/Makefile
+++ b/arch/arm/boot/dts/qcom/Makefile
@@ -94,6 +94,7 @@
msm8926-v2-qrd-skug-pvt.dtb \
msm8926-v1-320p-w-mtp.dtb \
msm8926-v1-320p-w-g.dtb \
+ msm8926-v1-1080p-w-mtp.dtb \
msm8226-v1-qrd-skuf.dtb \
msm8226-v2-qrd-skuf.dtb \
apq8026-v1-xpm.dtb \
diff --git a/arch/arm/boot/dts/qcom/apq8026-v1-w-cdp.dts b/arch/arm/boot/dts/qcom/apq8026-v1-w-cdp.dts
index 8c0bf8e..6a79376 100644
--- a/arch/arm/boot/dts/qcom/apq8026-v1-w-cdp.dts
+++ b/arch/arm/boot/dts/qcom/apq8026-v1-w-cdp.dts
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2015, 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
@@ -55,3 +55,17 @@
status = "disabled";
};
};
+
+&sdhc_2 {
+ status = "disabled";
+};
+
+&pm8226_l18 {
+ qcom,init-enable = <0>;
+ qcom,send-defaults;
+};
+
+&pm8226_l21 {
+ qcom,init-enable = <0>;
+ qcom,send-defaults;
+};
diff --git a/arch/arm/boot/dts/qcom/apq8026-v1-w-mtp.dts b/arch/arm/boot/dts/qcom/apq8026-v1-w-mtp.dts
index 97cbd22..a9ec2f4 100644
--- a/arch/arm/boot/dts/qcom/apq8026-v1-w-mtp.dts
+++ b/arch/arm/boot/dts/qcom/apq8026-v1-w-mtp.dts
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2015, 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
@@ -48,3 +48,17 @@
&pm8x26_rtc {
qcom,qpnp-rtc-write = <1>;
};
+
+&sdhc_2 {
+ status = "disabled";
+};
+
+&pm8226_l18 {
+ qcom,init-enable = <0>;
+ qcom,send-defaults;
+};
+
+&pm8226_l21 {
+ qcom,init-enable = <0>;
+ qcom,send-defaults;
+};
diff --git a/arch/arm/boot/dts/qcom/apq8026-v2-320p-w-cdp.dts b/arch/arm/boot/dts/qcom/apq8026-v2-320p-w-cdp.dts
index 8bf08e3..a063751 100644
--- a/arch/arm/boot/dts/qcom/apq8026-v2-320p-w-cdp.dts
+++ b/arch/arm/boot/dts/qcom/apq8026-v2-320p-w-cdp.dts
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2015, 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
@@ -73,3 +73,17 @@
status = "disabled";
};
};
+
+&sdhc_2 {
+ status = "disabled";
+};
+
+&pm8226_l18 {
+ qcom,init-enable = <0>;
+ qcom,send-defaults;
+};
+
+&pm8226_l21 {
+ qcom,init-enable = <0>;
+ qcom,send-defaults;
+};
diff --git a/arch/arm/boot/dts/qcom/apq8026-v2-320p-w-g-mtp.dts b/arch/arm/boot/dts/qcom/apq8026-v2-320p-w-g-mtp.dts
index 86de278..87fdf1b 100644
--- a/arch/arm/boot/dts/qcom/apq8026-v2-320p-w-g-mtp.dts
+++ b/arch/arm/boot/dts/qcom/apq8026-v2-320p-w-g-mtp.dts
@@ -198,3 +198,17 @@
qcom,use-dynamic-ocv-setting;
qcom,ocv-rbatt-compensation;
};
+
+&sdhc_2 {
+ status = "disabled";
+};
+
+&pm8226_l18 {
+ qcom,init-enable = <0>;
+ qcom,send-defaults;
+};
+
+&pm8226_l21 {
+ qcom,init-enable = <0>;
+ qcom,send-defaults;
+};
diff --git a/arch/arm/boot/dts/qcom/apq8026-v2-320p-w-mtp.dts b/arch/arm/boot/dts/qcom/apq8026-v2-320p-w-mtp.dts
index 58ea077..a08854e 100644
--- a/arch/arm/boot/dts/qcom/apq8026-v2-320p-w-mtp.dts
+++ b/arch/arm/boot/dts/qcom/apq8026-v2-320p-w-mtp.dts
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2015, 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
@@ -59,3 +59,17 @@
&pm8x26_rtc {
qcom,qpnp-rtc-write = <1>;
};
+
+&sdhc_2 {
+ status = "disabled";
+};
+
+&pm8226_l18 {
+ qcom,init-enable = <0>;
+ qcom,send-defaults;
+};
+
+&pm8226_l21 {
+ qcom,init-enable = <0>;
+ qcom,send-defaults;
+};
diff --git a/arch/arm/boot/dts/qcom/dsi-panel-auo-qvga-cmd.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-auo-qvga-cmd.dtsi
index ada02b1..5e616c6 100644
--- a/arch/arm/boot/dts/qcom/dsi-panel-auo-qvga-cmd.dtsi
+++ b/arch/arm/boot/dts/qcom/dsi-panel-auo-qvga-cmd.dtsi
@@ -14,6 +14,7 @@
dsi_auo_qvga_cmd: qcom,mdss_dsi_auo_qvga_cmd {
qcom,mdss-dsi-panel-name = "AUO qvga command mode dsi panel";
qcom,mdss-dsi-panel-controller = <&mdss_dsi0>;
+ qcom,ulps-enabled;
qcom,mdss-dsi-panel-type = "dsi_cmd_mode";
qcom,mdss-dsi-panel-destination = "display_1";
qcom,mdss-dsi-panel-framerate = <60>;
diff --git a/arch/arm/boot/dts/qcom/dsi-panel-jdi-qvga-video.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-jdi-qvga-video.dtsi
new file mode 100644
index 0000000..82146a7
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/dsi-panel-jdi-qvga-video.dtsi
@@ -0,0 +1,72 @@
+/* Copyright (c) 2013-2015, 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.
+ */
+
+/*---------------------------------------------------------------------------
+ * This file is autogenerated file using gcdb parser. Please do not edit it.
+ * Update input XML file to add a new entry or update variable in this file
+ * VERSION = "1.0"
+ *---------------------------------------------------------------------------*/
+&mdss_mdp {
+ dsi_jdi_qvga_vid: qcom,mdss_dsi_jdi_qvga_video {
+ qcom,mdss-dsi-panel-name = "jdi 1080p video mode dsi panel";
+ qcom,mdss-dsi-panel-controller = <&mdss_dsi0>;
+ qcom,mdss-dsi-panel-type = "dsi_video_mode";
+ qcom,mdss-dsi-panel-destination = "display_1";
+ qcom,mdss-dsi-panel-framerate = <60>;
+ qcom,mdss-dsi-virtual-channel-id = <0>;
+ qcom,mdss-dsi-stream = <0>;
+ qcom,mdss-dsi-panel-width = <320>;
+ qcom,mdss-dsi-panel-height = <240>;
+ qcom,mdss-dsi-h-front-porch = <96>;
+ qcom,mdss-dsi-h-back-porch = <64>;
+ qcom,mdss-dsi-h-pulse-width = <16>;
+ qcom,mdss-dsi-h-sync-skew = <0>;
+ qcom,mdss-dsi-v-back-porch = <16>;
+ qcom,mdss-dsi-v-front-porch = <4>;
+ qcom,mdss-dsi-v-pulse-width = <1>;
+ qcom,mdss-dsi-h-left-border = <0>;
+ qcom,mdss-dsi-h-right-border = <0>;
+ qcom,mdss-dsi-v-top-border = <0>;
+ qcom,mdss-dsi-v-bottom-border = <0>;
+ qcom,mdss-dsi-bpp = <24>;
+ qcom,mdss-dsi-underflow-color = <0xff>;
+ qcom,mdss-dsi-border-color = <0>;
+ qcom,mdss-dsi-on-command = [15 01 00 00 00 00 02 55 00
+ 15 01 00 00 00 00 02 53 2C
+ 15 01 00 00 00 00 02 35 00
+ 05 01 00 00 78 00 02 29 00
+ 05 01 00 00 78 00 02 11 00];
+ qcom,mdss-dsi-off-command = [05 01 00 00 02 00 02 28 00
+ 05 01 00 00 79 00 02 10 00];
+ qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+ qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+ qcom,mdss-dsi-h-sync-pulse = <0>;
+ qcom,mdss-dsi-traffic-mode = "burst_mode";
+ qcom,mdss-dsi-bllp-eof-power-mode;
+ qcom,mdss-dsi-bllp-power-mode;
+ qcom,mdss-dsi-lane-0-state;
+ qcom,mdss-dsi-lane-1-state;
+ qcom,mdss-dsi-lane-2-state;
+ qcom,mdss-dsi-lane-3-state;
+ qcom,mdss-dsi-panel-timings = [e7 36 24 00 66 6a 2a 3a 2d 03 04 00];
+ qcom,mdss-dsi-t-clk-post = <0x04>;
+ qcom,mdss-dsi-t-clk-pre = <0x1b>;
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,mdss-dsi-dma-trigger = "trigger_sw";
+ qcom,mdss-dsi-mdp-trigger = "none";
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>;
+ qcom,mdss-pan-physical-width-dimension = <61>;
+ qcom,mdss-pan-physical-height-dimension = <110>;
+ };
+};
diff --git a/arch/arm/boot/dts/qcom/msm8226-mdss-panels.dtsi b/arch/arm/boot/dts/qcom/msm8226-mdss-panels.dtsi
index d8ca6dc..0bd5a68 100644
--- a/arch/arm/boot/dts/qcom/msm8226-mdss-panels.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8226-mdss-panels.dtsi
@@ -19,3 +19,4 @@
#include "dsi-panel-jdi-1080p-video.dtsi"
#include "dsi-panel-nt35590-qvga-cmd.dtsi"
#include "dsi-panel-auo-qvga-cmd.dtsi"
+#include "dsi-panel-jdi-qvga-video.dtsi"
diff --git a/arch/arm/boot/dts/qcom/msm8226-mdss.dtsi b/arch/arm/boot/dts/qcom/msm8226-mdss.dtsi
index dd298e3..5c1636f 100644
--- a/arch/arm/boot/dts/qcom/msm8226-mdss.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8226-mdss.dtsi
@@ -167,6 +167,7 @@
qcom,supply-max-voltage = <1200000>;
qcom,supply-enable-load = <100000>;
qcom,supply-disable-load = <100>;
+ qcom,supply-ulp-load = <1000>;
qcom,supply-post-on-sleep = <20>;
};
@@ -177,6 +178,7 @@
qcom,supply-max-voltage = <1800000>;
qcom,supply-enable-load = <100000>;
qcom,supply-disable-load = <100>;
+ qcom,supply-ulp-load = <100>;
};
};
@@ -191,6 +193,7 @@
qcom,supply-max-voltage = <2800000>;
qcom,supply-enable-load = <100000>;
qcom,supply-disable-load = <100>;
+ qcom,supply-ulp-load = <100>;
};
qcom,panel-supply-entry@1 {
@@ -200,6 +203,7 @@
qcom,supply-max-voltage = <1800000>;
qcom,supply-enable-load = <100000>;
qcom,supply-disable-load = <100>;
+ qcom,supply-ulp-load = <100>;
};
};
};
diff --git a/arch/arm/boot/dts/qcom/msm8226-qseecom.dtsi b/arch/arm/boot/dts/qcom/msm8226-qseecom.dtsi
index 54990c6..84f87d8 100644
--- a/arch/arm/boot/dts/qcom/msm8226-qseecom.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8226-qseecom.dtsi
@@ -24,6 +24,7 @@
qcom,msm-bus,num-paths = <1>;
qcom,support-bus-scaling;
qcom,support-fde;
+ qcom,appsbl-qseecom-support;
qcom,msm-bus,vectors-KBps =
<55 512 0 0>,
<55 512 0 0>,
diff --git a/arch/arm/boot/dts/qcom/msm8226-v1-w-cdp.dts b/arch/arm/boot/dts/qcom/msm8226-v1-w-cdp.dts
index 0dc53ee..2797c95 100644
--- a/arch/arm/boot/dts/qcom/msm8226-v1-w-cdp.dts
+++ b/arch/arm/boot/dts/qcom/msm8226-v1-w-cdp.dts
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2015, 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
@@ -54,3 +54,17 @@
status = "disabled";
};
};
+
+&sdhc_2 {
+ status = "disabled";
+};
+
+&pm8226_l18 {
+ qcom,init-enable = <0>;
+ qcom,send-defaults;
+};
+
+&pm8226_l21 {
+ qcom,init-enable = <0>;
+ qcom,send-defaults;
+};
diff --git a/arch/arm/boot/dts/qcom/msm8226-v1-w-mtp.dts b/arch/arm/boot/dts/qcom/msm8226-v1-w-mtp.dts
index 01a0e92..323f9aa 100644
--- a/arch/arm/boot/dts/qcom/msm8226-v1-w-mtp.dts
+++ b/arch/arm/boot/dts/qcom/msm8226-v1-w-mtp.dts
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2015, 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
@@ -47,3 +47,17 @@
&pm8x26_rtc {
qcom,qpnp-rtc-write = <1>;
};
+
+&sdhc_2 {
+ status = "disabled";
+};
+
+&pm8226_l18 {
+ qcom,init-enable = <0>;
+ qcom,send-defaults;
+};
+
+&pm8226_l21 {
+ qcom,init-enable = <0>;
+ qcom,send-defaults;
+};
diff --git a/arch/arm/boot/dts/qcom/msm8226-v2-320p-w-cdp.dts b/arch/arm/boot/dts/qcom/msm8226-v2-320p-w-cdp.dts
index 67039de..f905f8e 100644
--- a/arch/arm/boot/dts/qcom/msm8226-v2-320p-w-cdp.dts
+++ b/arch/arm/boot/dts/qcom/msm8226-v2-320p-w-cdp.dts
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2015, 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
@@ -63,3 +63,17 @@
status = "disabled";
};
};
+
+&sdhc_2 {
+ status = "disabled";
+};
+
+&pm8226_l18 {
+ qcom,init-enable = <0>;
+ qcom,send-defaults;
+};
+
+&pm8226_l21 {
+ qcom,init-enable = <0>;
+ qcom,send-defaults;
+};
diff --git a/arch/arm/boot/dts/qcom/msm8226-v2-320p-w-mtp.dts b/arch/arm/boot/dts/qcom/msm8226-v2-320p-w-mtp.dts
index 0182cae..a1086dd 100644
--- a/arch/arm/boot/dts/qcom/msm8226-v2-320p-w-mtp.dts
+++ b/arch/arm/boot/dts/qcom/msm8226-v2-320p-w-mtp.dts
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2015, 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
@@ -49,3 +49,17 @@
&pm8x26_rtc {
qcom,qpnp-rtc-write = <1>;
};
+
+&sdhc_2 {
+ status = "disabled";
+};
+
+&pm8226_l18 {
+ qcom,init-enable = <0>;
+ qcom,send-defaults;
+};
+
+&pm8226_l21 {
+ qcom,init-enable = <0>;
+ qcom,send-defaults;
+};
diff --git a/arch/arm/boot/dts/qcom/msm8226-w-qseecom.dtsi b/arch/arm/boot/dts/qcom/msm8226-w-qseecom.dtsi
index 39f755c..4ecd120 100644
--- a/arch/arm/boot/dts/qcom/msm8226-w-qseecom.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8226-w-qseecom.dtsi
@@ -25,6 +25,7 @@
qcom,msm-bus,num-paths = <1>;
qcom,support-bus-scaling;
qcom,support-fde;
+ qcom,appsbl-qseecom-support;
qcom,msm-bus,vectors-KBps =
<55 512 0 0>,
<55 512 0 0>,
diff --git a/arch/arm/boot/dts/qcom/msm8926-v1-1080p-w-mtp.dts b/arch/arm/boot/dts/qcom/msm8926-v1-1080p-w-mtp.dts
new file mode 100644
index 0000000..d912604
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/msm8926-v1-1080p-w-mtp.dts
@@ -0,0 +1,59 @@
+/* Copyright (c) 2015, 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.
+ */
+
+
+/dts-v1/;
+#include "msm8926-v1.dtsi"
+#include "msm8926-w-memory.dtsi"
+#include "msm8226-w-qseecom.dtsi"
+#include "msm8926-w-sharedmem.dtsi"
+#include "msm8226-720p-mtp.dtsi"
+#include "msm8x26w-gpu.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. MSM 8926W MTP";
+ compatible = "qcom,msm8926-mtp", "qcom,msm8926", "qcom,mtp";
+ qcom,board-id = <8 6>;
+};
+
+&mdss_fb0 {
+ /* cont_splash memory*/
+ qcom,memblock-reserve = <0x0149c000 0x64000>;
+};
+
+
+&mdss_mdp {
+ qcom,mdss-pref-prim-intf = "dsi";
+};
+
+&mdss_dsi0 {
+ qcom,dsi-pref-prim-pan = <&dsi_jdi_qvga_vid>;
+ qcom,platform-enable-gpio = <&msmgpio 109 0>;
+};
+
+&pm8x26_rtc {
+ qcom,qpnp-rtc-write = <1>;
+};
+
+&sdhc_2 {
+ status = "disabled";
+};
+
+&pm8226_l18 {
+ qcom,init-enable = <0>;
+ qcom,send-defaults;
+};
+
+&pm8226_l21 {
+ qcom,init-enable = <0>;
+ qcom,send-defaults;
+};
diff --git a/arch/arm/boot/dts/qcom/msm8926-v1-320p-w-cdp.dts b/arch/arm/boot/dts/qcom/msm8926-v1-320p-w-cdp.dts
index eb06964..8e6972f 100755
--- a/arch/arm/boot/dts/qcom/msm8926-v1-320p-w-cdp.dts
+++ b/arch/arm/boot/dts/qcom/msm8926-v1-320p-w-cdp.dts
@@ -48,3 +48,17 @@
&pm8x26_rtc {
qcom,qpnp-rtc-write = <1>;
};
+
+&sdhc_2 {
+ status = "disabled";
+};
+
+&pm8226_l18 {
+ qcom,init-enable = <0>;
+ qcom,send-defaults;
+};
+
+&pm8226_l21 {
+ qcom,init-enable = <0>;
+ qcom,send-defaults;
+};
diff --git a/arch/arm/boot/dts/qcom/msm8926-v1-320p-w-g.dts b/arch/arm/boot/dts/qcom/msm8926-v1-320p-w-g.dts
index fc10d4a..6801ca7 100755
--- a/arch/arm/boot/dts/qcom/msm8926-v1-320p-w-g.dts
+++ b/arch/arm/boot/dts/qcom/msm8926-v1-320p-w-g.dts
@@ -126,14 +126,17 @@
cdc-vdd-a-1p2v-supply = <&pm8226_l4>;
qcom,cdc-vdd-a-1p2v-voltage = <1200000 1200000>;
qcom,cdc-vdd-a-1p2v-current = <2000>;
+ qcom,cdc-vdd-a-1p2v-active-current = <2000>;
cdc-vddcx-1-supply = <&pm8226_l4>;
qcom,cdc-vddcx-1-voltage = <1200000 1200000>;
- qcom,cdc-vddcx-1-current = <33000>;
+ qcom,cdc-vddcx-1-current = <2000>;
+ qcom,cdc-vddcx-1-active-current = <33000>;
cdc-vddcx-2-supply = <&pm8226_l4>;
qcom,cdc-vddcx-2-voltage = <1200000 1200000>;
- qcom,cdc-vddcx-2-current = <33000>;
+ qcom,cdc-vddcx-2-current = <2000>;
+ qcom,cdc-vddcx-2-active-current = <33000>;
qcom,cdc-static-supplies = "cdc-vdd-buck",
"cdc-vdd-tx-h",
@@ -162,6 +165,7 @@
&spmi_bus {
qcom,pm8226@1{
qcom,leds@d800 {
+ status = "disabled";
};
};
@@ -192,3 +196,17 @@
qcom,use-dynamic-ocv-setting;
qcom,ocv-rbatt-compensation;
};
+
+&sdhc_2 {
+ status = "disabled";
+};
+
+&pm8226_l18 {
+ qcom,init-enable = <0>;
+ qcom,send-defaults;
+};
+
+&pm8226_l21 {
+ qcom,init-enable = <0>;
+ qcom,send-defaults;
+};
diff --git a/arch/arm/boot/dts/qcom/msm8926-v1-320p-w-mtp.dts b/arch/arm/boot/dts/qcom/msm8926-v1-320p-w-mtp.dts
index 9cee43c..3070f93 100644
--- a/arch/arm/boot/dts/qcom/msm8926-v1-320p-w-mtp.dts
+++ b/arch/arm/boot/dts/qcom/msm8926-v1-320p-w-mtp.dts
@@ -29,6 +29,7 @@
i2c@f9927000 { /* BLSP1 QUP5 */
synaptics@20 {
synaptics,display-coords = <0 0 319 239>;
+ synaptics,is_wake;
};
};
};
@@ -49,3 +50,17 @@
&pm8x26_rtc {
qcom,qpnp-rtc-write = <1>;
};
+
+&sdhc_2 {
+ status = "disabled";
+};
+
+&pm8226_l18 {
+ qcom,init-enable = <0>;
+ qcom,send-defaults;
+};
+
+&pm8226_l21 {
+ qcom,init-enable = <0>;
+ qcom,send-defaults;
+};
diff --git a/arch/arm/boot/dts/qcom/msm8926-w-memory.dtsi b/arch/arm/boot/dts/qcom/msm8926-w-memory.dtsi
index 09b802c..77fac7b 100644
--- a/arch/arm/boot/dts/qcom/msm8926-w-memory.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8926-w-memory.dtsi
@@ -43,19 +43,19 @@
label = "external_image_mem";
};
- adsp_pil_mem: adsp_region@1e00000 {
+ adsp_pil_mem: adsp_region@1d00000 {
linux,reserve-contiguous-region;
linux,reserve-region;
linux,remove-completely;
- reg = <0x01e00000 0x1100000>;
+ reg = <0x01d00000 0x1200000>;
label = "adsp_pil_mem";
};
- peripheral_mem: peripheral_region@1900000 {
+ peripheral_mem: peripheral_region@1800000 {
linux,reserve-contiguous-region;
linux,reserve-region;
linux,remove-completely;
- reg = <0x01900000 0x500000>;
+ reg = <0x01800000 0x500000>;
label = "peripheral_mem";
};
@@ -67,11 +67,11 @@
label = "modem_mem";
};
- modem_efs: modem_efs_region@1700000 {
+ modem_efs: modem_efs_region@1600000 {
linux,reserve-contiguous-region;
linux,reserve-region;
linux,remove-completely;
- reg = <0x01700000 0x200000>;
+ reg = <0x01600000 0x200000>;
label = "modem_efs";
};
diff --git a/arch/arm/boot/dts/qcom/msm8926-w-sharedmem.dtsi b/arch/arm/boot/dts/qcom/msm8926-w-sharedmem.dtsi
index a8e8c37..681c9b6 100644
--- a/arch/arm/boot/dts/qcom/msm8926-w-sharedmem.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8926-w-sharedmem.dtsi
@@ -12,9 +12,9 @@
/ {
- qcom,rmtfs_sharedmem@01700000 {
+ qcom,rmtfs_sharedmem@01600000 {
compatible = "qcom,sharedmem-uio";
- reg = <0x01700000 0x200000>;
+ reg = <0x01600000 0x200000>;
reg-names = "rmtfs";
qcom,client-id = <0x00000001>;
};
diff --git a/arch/arm/boot/dts/qcom/msm8926.dtsi b/arch/arm/boot/dts/qcom/msm8926.dtsi
index e6fc5cf..2cb6e1f 100644
--- a/arch/arm/boot/dts/qcom/msm8926.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8926.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2015, 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
@@ -201,7 +201,3 @@
hsic,data-gpio = <&msmgpio 120 0x00>;
};
-&usb_otg {
- /delete-property/ qcom,hsusb-otg-disable-reset;
- qcom,ahb-async-bridge-bypass;
-};
diff --git a/arch/arm/configs/apq8026-lw-perf_defconfig b/arch/arm/configs/apq8026-lw-perf_defconfig
index a1257bb..13ca8c3 100644
--- a/arch/arm/configs/apq8026-lw-perf_defconfig
+++ b/arch/arm/configs/apq8026-lw-perf_defconfig
@@ -17,6 +17,8 @@
# CONFIG_UTS_NS is not set
# CONFIG_IPC_NS is not set
# CONFIG_PID_NS is not set
+# CONFIG_DEVMEM is not set
+# CONFIG_DEVKMEM is not set
CONFIG_RELAY=y
CONFIG_BLK_DEV_INITRD=y
CONFIG_RD_BZIP2=y
@@ -112,6 +114,7 @@
CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y
CONFIG_NETFILTER_XT_TARGET_LOG=y
+CONFIG_NETFILTER_XT_TARGET_NFLOG=y
CONFIG_NETFILTER_XT_TARGET_MARK=y
CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
CONFIG_NETFILTER_XT_TARGET_NOTRACK=y
@@ -458,5 +461,6 @@
CONFIG_CRYPTO_DEV_QCRYPTO=m
CONFIG_CRYPTO_DEV_QCE=y
CONFIG_CRYPTO_DEV_QCEDEV=m
+CONFIG_SECCOMP=y
CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y
CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y
diff --git a/arch/arm/configs/apq8026-lw_defconfig b/arch/arm/configs/apq8026-lw_defconfig
index 86271c2..d300f7f 100644
--- a/arch/arm/configs/apq8026-lw_defconfig
+++ b/arch/arm/configs/apq8026-lw_defconfig
@@ -17,6 +17,8 @@
# CONFIG_UTS_NS is not set
# CONFIG_IPC_NS is not set
# CONFIG_PID_NS is not set
+# CONFIG_DEVMEM is not set
+# CONFIG_DEVKMEM is not set
CONFIG_RELAY=y
CONFIG_BLK_DEV_INITRD=y
CONFIG_RD_BZIP2=y
@@ -111,6 +113,7 @@
CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y
CONFIG_NETFILTER_XT_TARGET_LOG=y
+CONFIG_NETFILTER_XT_TARGET_NFLOG=y
CONFIG_NETFILTER_XT_TARGET_MARK=y
CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
CONFIG_NETFILTER_XT_TARGET_NOTRACK=y
@@ -498,5 +501,6 @@
CONFIG_CRYPTO_DEV_QCRYPTO=m
CONFIG_CRYPTO_DEV_QCE=y
CONFIG_CRYPTO_DEV_QCEDEV=m
+CONFIG_SECCOMP=y
CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y
CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y
diff --git a/arch/arm/include/uapi/asm/unistd.h b/arch/arm/include/uapi/asm/unistd.h
index fad66d8..eafa35e 100644
--- a/arch/arm/include/uapi/asm/unistd.h
+++ b/arch/arm/include/uapi/asm/unistd.h
@@ -408,7 +408,10 @@
#define __NR_finit_module (__NR_SYSCALL_BASE+379)
#define __NR_sched_setattr (__NR_SYSCALL_BASE+380)
#define __NR_sched_getattr (__NR_SYSCALL_BASE+381)
-#define __NR_seccomp (__NR_SYSCALL_BASE+383)
+/* Backporting seccomp, skip a few ...
+ #define __NR_renameat2 (__NR_SYSCALL_BASE+382)
+ */
+#define __NR_seccomp (__NR_SYSCALL_BASE+383)
/*
* This may need to be greater than __NR_last_syscall+1 in order to
diff --git a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S
index e4df5b6..6f675b8 100644
--- a/arch/arm/kernel/calls.S
+++ b/arch/arm/kernel/calls.S
@@ -391,8 +391,8 @@
CALL(sys_finit_module)
/* 380 */ CALL(sys_sched_setattr)
CALL(sys_sched_getattr)
- CALL(sys_ni_syscall)
- CALL(sys_seccomp)
+ CALL(sys_ni_syscall) /* reserved sys_renameat2 */
+ CALL(sys_seccomp)
#ifndef syscalls_counted
.equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls
#define syscalls_counted
diff --git a/arch/arm/kernel/perf_event_msm_krait.c b/arch/arm/kernel/perf_event_msm_krait.c
index 49aae5a..34f9b4e 100644
--- a/arch/arm/kernel/perf_event_msm_krait.c
+++ b/arch/arm/kernel/perf_event_msm_krait.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011-2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2014, 2016 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
@@ -208,9 +208,6 @@
code = (krait_evt_type & 0x00FF0) >> 4;
group = krait_evt_type & 0x0000F;
- if ((group > 3) || (reg > KRAIT_MAX_L1_REG))
- return -EINVAL;
-
if (prefix != KRAIT_EVT_PREFIX && prefix != KRAIT_VENUMEVT_PREFIX)
return -EINVAL;
@@ -221,6 +218,9 @@
reg += VENUM_BASE_OFFSET;
}
+ if ((group > 3) || (reg > KRAIT_MAX_L1_REG))
+ return -EINVAL;
+
evtinfo->group_setval = 0x80000000 | (code << (group * 8));
evtinfo->groupcode = reg;
evtinfo->armv7_evt_type = evt_type_base[reg] | group;
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 60bfd03..1f6c68b 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -767,16 +767,6 @@
to secure execution in the fsm9xxx and msm8x26 targets. This module
utilizes Ion for buffer management.
-config MSM_BUSPM_DEV
- tristate "MSM Bus Performance Monitor Kernel Module"
- depends on MSM_BUS_SCALING
- default n
- help
- This kernel module is used to mmap() hardware registers for the
- performance monitors, counters, etc. The module can also be used to
- allocate physical memory which is used by bus performance hardware to
- dump performance data.
-
config MSM_DIRECT_SCLK_ACCESS
bool "Direct access to the SCLK timer"
default n
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index feca7b7..edb053b 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -46,8 +46,6 @@
CFLAGS_msm_vibrator.o += -Idrivers/staging/android
obj-$(CONFIG_MSM_LPM_TEST) += test-lpm.o
-obj-$(CONFIG_MSM_BUSPM_DEV) += msm-buspm-dev.o
-
obj-$(CONFIG_ARCH_MSM8974) += gpiomux-v2.o gpiomux.o
obj-$(CONFIG_ARCH_MDM9630) += gpiomux-v2.o gpiomux.o
diff --git a/arch/arm/mach-msm/msm-buspm-dev.c b/arch/arm/mach-msm/msm-buspm-dev.c
deleted file mode 100644
index 5862e05..0000000
--- a/arch/arm/mach-msm/msm-buspm-dev.c
+++ /dev/null
@@ -1,335 +0,0 @@
-/* Copyright (c) 2011-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.
- */
-
-/* #define DEBUG */
-
-#include <linux/module.h>
-#include <linux/fs.h>
-#include <linux/mm.h>
-#include <linux/err.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/device.h>
-#include <linux/uaccess.h>
-#include <linux/miscdevice.h>
-#include <linux/dma-mapping.h>
-#include <soc/qcom/rpm-smd.h>
-#include "msm-buspm-dev.h"
-
-#define MSM_BUSPM_DRV_NAME "msm-buspm-dev"
-
-enum msm_buspm_spdm_res {
- SPDM_RES_ID = 0,
- SPDM_RES_TYPE = 0x63707362,
- SPDM_KEY = 0x00006e65,
- SPDM_SIZE = 4,
-};
-/*
- * Allocate kernel buffer.
- * Currently limited to one buffer per file descriptor. If alloc() is
- * called twice for the same descriptor, the original buffer is freed.
- * There is also no locking protection so the same descriptor can not be shared.
- */
-
-static inline void *msm_buspm_dev_get_vaddr(struct file *filp)
-{
- struct msm_buspm_map_dev *dev = filp->private_data;
-
- return (dev) ? dev->vaddr : NULL;
-}
-
-static inline unsigned int msm_buspm_dev_get_buflen(struct file *filp)
-{
- struct msm_buspm_map_dev *dev = filp->private_data;
-
- return dev ? dev->buflen : 0;
-}
-
-static inline unsigned long msm_buspm_dev_get_paddr(struct file *filp)
-{
- struct msm_buspm_map_dev *dev = filp->private_data;
-
- return (dev) ? dev->paddr : 0L;
-}
-
-static void msm_buspm_dev_free(struct file *filp)
-{
- struct msm_buspm_map_dev *dev = filp->private_data;
-
- if (dev && dev->vaddr) {
- pr_debug("freeing memory at 0x%p\n", dev->vaddr);
- dma_free_coherent(NULL, dev->buflen, dev->vaddr, dev->paddr);
- dev->paddr = 0L;
- dev->vaddr = NULL;
- }
-}
-
-static int msm_buspm_dev_open(struct inode *inode, struct file *filp)
-{
- struct msm_buspm_map_dev *dev;
-
- if (capable(CAP_SYS_ADMIN)) {
- dev = kzalloc(sizeof(*dev), GFP_KERNEL);
- if (dev)
- filp->private_data = dev;
- else
- return -ENOMEM;
- } else {
- return -EPERM;
- }
-
- return 0;
-}
-
-static int
-msm_buspm_dev_alloc(struct file *filp, struct buspm_alloc_params data)
-{
- dma_addr_t paddr;
- void *vaddr;
- struct msm_buspm_map_dev *dev = filp->private_data;
-
- /* If buffer already allocated, then free it */
- if (dev->vaddr)
- msm_buspm_dev_free(filp);
-
- /* Allocate uncached memory */
- vaddr = dma_alloc_coherent(NULL, data.size, &paddr, GFP_KERNEL);
-
- if (vaddr == NULL) {
- pr_err("allocation of 0x%x bytes failed", data.size);
- return -ENOMEM;
- }
-
- dev->vaddr = vaddr;
- dev->paddr = paddr;
- dev->buflen = data.size;
- filp->f_pos = 0;
- pr_debug("virt addr = 0x%p\n", dev->vaddr);
- pr_debug("phys addr = 0x%lx\n", dev->paddr);
-
- return 0;
-}
-
-static int msm_bus_rpm_req(u32 rsc_type, u32 key, u32 hwid,
- int ctx, u32 val)
-{
- struct msm_rpm_request *rpm_req;
- int ret, msg_id;
-
- rpm_req = msm_rpm_create_request(ctx, rsc_type, SPDM_RES_ID, 1);
- if (rpm_req == NULL) {
- pr_err("RPM: Couldn't create RPM Request\n");
- return -ENXIO;
- }
-
- ret = msm_rpm_add_kvp_data(rpm_req, key, (const uint8_t *)&val,
- (int)(sizeof(uint32_t)));
- if (ret) {
- pr_err("RPM: Add KVP failed for RPM Req:%u\n",
- rsc_type);
- goto err;
- }
-
- pr_debug("Added Key: %d, Val: %u, size: %d\n", key,
- (uint32_t)val, sizeof(uint32_t));
- msg_id = msm_rpm_send_request(rpm_req);
- if (!msg_id) {
- pr_err("RPM: No message ID for req\n");
- ret = -ENXIO;
- goto err;
- }
-
- ret = msm_rpm_wait_for_ack(msg_id);
- if (ret) {
- pr_err("RPM: Ack failed\n");
- goto err;
- }
-
-err:
- msm_rpm_free_request(rpm_req);
- return ret;
-}
-
-static int msm_buspm_ioc_cmds(uint32_t arg)
-{
- switch (arg) {
- case MSM_BUSPM_SPDM_CLK_DIS:
- case MSM_BUSPM_SPDM_CLK_EN:
- return msm_bus_rpm_req(SPDM_RES_TYPE, SPDM_KEY, 0,
- MSM_RPM_CTX_ACTIVE_SET, arg);
- default:
- pr_warn("Unsupported ioctl command: %d\n", arg);
- return -EINVAL;
- }
-}
-
-
-
-static long
-msm_buspm_dev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
-{
- struct buspm_xfer_req xfer;
- struct buspm_alloc_params alloc_data;
- unsigned long paddr;
- int retval = 0;
- void *buf = msm_buspm_dev_get_vaddr(filp);
- unsigned int buflen = msm_buspm_dev_get_buflen(filp);
- unsigned char *dbgbuf = buf;
-
- if (_IOC_TYPE(cmd) != MSM_BUSPM_IOC_MAGIC) {
- pr_err("Wrong IOC_MAGIC.Exiting\n");
- return -ENOTTY;
- }
-
- switch (cmd) {
- case MSM_BUSPM_IOC_FREE:
- pr_debug("cmd = 0x%x (FREE)\n", cmd);
- msm_buspm_dev_free(filp);
- break;
-
- case MSM_BUSPM_IOC_ALLOC:
- pr_debug("cmd = 0x%x (ALLOC)\n", cmd);
- retval = __get_user(alloc_data.size, (size_t __user *)arg);
-
- if (retval == 0)
- retval = msm_buspm_dev_alloc(filp, alloc_data);
- break;
-
- case MSM_BUSPM_IOC_RD_PHYS_ADDR:
- pr_debug("Read Physical Address\n");
- paddr = msm_buspm_dev_get_paddr(filp);
- if (paddr == 0L) {
- retval = -EINVAL;
- } else {
- pr_debug("phys addr = 0x%lx\n", paddr);
- retval = __put_user(paddr,
- (unsigned long __user *)arg);
- }
- break;
-
- case MSM_BUSPM_IOC_RDBUF:
- pr_debug("Read Buffer: 0x%x%x%x%x\n",
- dbgbuf[0], dbgbuf[1], dbgbuf[2], dbgbuf[3]);
-
- if (!buf) {
- retval = -EINVAL;
- break;
- }
-
- if (copy_from_user(&xfer, (void __user *)arg, sizeof(xfer))) {
- retval = -EFAULT;
- break;
- }
-
- if ((xfer.size <= buflen) &&
- (copy_to_user((void __user *)xfer.data, buf,
- xfer.size))) {
- retval = -EFAULT;
- break;
- }
- break;
-
- case MSM_BUSPM_IOC_WRBUF:
- pr_debug("Write Buffer\n");
-
- if (!buf) {
- retval = -EINVAL;
- break;
- }
-
- if (copy_from_user(&xfer, (void __user *)arg, sizeof(xfer))) {
- retval = -EFAULT;
- break;
- }
-
- if ((buflen <= xfer.size) &&
- (copy_from_user(buf, (void __user *)xfer.data,
- xfer.size))) {
- retval = -EFAULT;
- break;
- }
- break;
-
- case MSM_BUSPM_IOC_CMD:
- pr_debug("IOCTL command: cmd: %d arg: %lu\n", cmd, arg);
- retval = msm_buspm_ioc_cmds(arg);
- break;
-
- default:
- pr_debug("Unknown command 0x%x\n", cmd);
- retval = -EINVAL;
- break;
- }
-
- return retval;
-}
-
-static int msm_buspm_dev_release(struct inode *inode, struct file *filp)
-{
- struct msm_buspm_map_dev *dev = filp->private_data;
-
- msm_buspm_dev_free(filp);
- kfree(dev);
- filp->private_data = NULL;
-
- return 0;
-}
-
-static int msm_buspm_dev_mmap(struct file *filp, struct vm_area_struct *vma)
-{
- pr_debug("vma = 0x%p\n", vma);
-
- /* Mappings are uncached */
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
- if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
- vma->vm_end - vma->vm_start, vma->vm_page_prot))
- return -EFAULT;
-
- return 0;
-}
-
-static const struct file_operations msm_buspm_dev_fops = {
- .owner = THIS_MODULE,
- .mmap = msm_buspm_dev_mmap,
- .open = msm_buspm_dev_open,
- .unlocked_ioctl = msm_buspm_dev_ioctl,
- .llseek = noop_llseek,
- .release = msm_buspm_dev_release,
-};
-
-struct miscdevice msm_buspm_misc = {
- .minor = MISC_DYNAMIC_MINOR,
- .name = MSM_BUSPM_DRV_NAME,
- .fops = &msm_buspm_dev_fops,
-};
-
-static int __init msm_buspm_dev_init(void)
-{
- int ret = 0;
-
- ret = misc_register(&msm_buspm_misc);
- if (ret < 0)
- pr_err("%s: Cannot register misc device\n", __func__);
-
- return ret;
-}
-
-static void __exit msm_buspm_dev_exit(void)
-{
- misc_deregister(&msm_buspm_misc);
-}
-module_init(msm_buspm_dev_init);
-module_exit(msm_buspm_dev_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_VERSION("1.0");
-MODULE_ALIAS("platform:"MSM_BUSPM_DRV_NAME);
diff --git a/arch/arm/mach-msm/msm-buspm-dev.h b/arch/arm/mach-msm/msm-buspm-dev.h
deleted file mode 100644
index 9c428fb..0000000
--- a/arch/arm/mach-msm/msm-buspm-dev.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/* Copyright (c) 2011,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.
- */
-
-#ifndef __MSM_BUSPM_DEV_H__
-#define __MSM_BUSPM_DEV_H__
-
-#include <linux/ioctl.h>
-
-struct msm_buspm_map_dev {
- void *vaddr;
- unsigned long paddr;
- size_t buflen;
-};
-
-/* Read/write data into kernel buffer */
-struct buspm_xfer_req {
- unsigned int size; /* Size of this request, in bytes */
- void *data; /* Data buffer to transfer data to/from */
-};
-
-struct buspm_alloc_params {
- size_t size;
-};
-
-enum msm_buspm_ioc_cmds {
- MSM_BUSPM_SPDM_CLK_DIS = 0,
- MSM_BUSPM_SPDM_CLK_EN,
-};
-
-#define MSM_BUSPM_IOC_MAGIC 'p'
-
-#define MSM_BUSPM_IOC_FREE \
- _IOW(MSM_BUSPM_IOC_MAGIC, 0, void *)
-
-#define MSM_BUSPM_IOC_ALLOC \
- _IOW(MSM_BUSPM_IOC_MAGIC, 1, size_t)
-
-#define MSM_BUSPM_IOC_RDBUF \
- _IOW(MSM_BUSPM_IOC_MAGIC, 2, struct buspm_xfer_req)
-
-#define MSM_BUSPM_IOC_WRBUF \
- _IOW(MSM_BUSPM_IOC_MAGIC, 3, struct buspm_xfer_req)
-
-#define MSM_BUSPM_IOC_RD_PHYS_ADDR \
- _IOR(MSM_BUSPM_IOC_MAGIC, 4, unsigned long)
-
-#define MSM_BUSPM_IOC_CMD \
- _IOR(MSM_BUSPM_IOC_MAGIC, 5, uint32_t)
-#endif
diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c
index 2a82b88..fa1b3f8 100644
--- a/drivers/char/diag/diag_masks.c
+++ b/drivers/char/diag/diag_masks.c
@@ -277,13 +277,15 @@
}
for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) {
- if (((first < mask->ssid_first) || (last > mask->ssid_last)) &&
- first != ALL_SSID) {
+ if (((first < mask->ssid_first) ||
+ (last > mask->ssid_last_tools)) && first != ALL_SSID) {
continue;
}
+ mutex_lock(&mask->lock);
if (msg_mask.status == DIAG_CTRL_MASK_VALID) {
- mask_size = mask->ssid_last - mask->ssid_first + 1;
+ mask_size =
+ mask->ssid_last_tools - mask->ssid_first + 1;
temp_len = mask_size * sizeof(uint32_t);
if (temp_len + header_len <= msg_mask.update_buf_len)
goto proceed;
@@ -307,13 +309,14 @@
header.stream_id = 1;
header.msg_mode = 0;
header.ssid_first = mask->ssid_first;
- header.ssid_last = mask->ssid_last;
+ header.ssid_last = mask->ssid_last_tools;
header.msg_mask_size = mask_size;
mask_size *= sizeof(uint32_t);
header.data_len = MSG_MASK_CTRL_HEADER_LEN + mask_size;
memcpy(buf, &header, header_len);
if (mask_size > 0)
memcpy(buf + header_len, mask->ptr, mask_size);
+ mutex_unlock(&mask->lock);
err = diag_smd_write(smd_info, buf, header_len + mask_size);
if (err) {
@@ -409,7 +412,7 @@
break;
}
ssid_range.ssid_first = mask_ptr->ssid_first;
- ssid_range.ssid_last = mask_ptr->ssid_last;
+ ssid_range.ssid_last = mask_ptr->ssid_last_tools;
memcpy(dest_buf + write_len, &ssid_range, sizeof(ssid_range));
write_len += sizeof(ssid_range);
}
@@ -501,7 +504,7 @@
mask = (struct diag_msg_mask_t *)msg_mask.ptr;
for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) {
if ((req->ssid_first < mask->ssid_first) ||
- (req->ssid_first > mask->ssid_last)) {
+ (req->ssid_first > mask->ssid_last_tools)) {
continue;
}
mask_size = mask->range * sizeof(uint32_t);
@@ -531,6 +534,7 @@
struct diag_msg_mask_t *mask = NULL;
struct diag_msg_build_mask_t *req = NULL;
struct diag_msg_build_mask_t rsp;
+ uint32_t *temp = NULL;
if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0) {
pr_err("diag: Invalid input in %s, src_buf: %p, src_len: %d, dest_buf: %p, dest_len: %d",
@@ -544,30 +548,51 @@
mask = (struct diag_msg_mask_t *)msg_mask.ptr;
for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) {
if ((req->ssid_first < mask->ssid_first) ||
- (req->ssid_first > mask->ssid_last)) {
+ (req->ssid_first > (mask->ssid_first +
+ MAX_SSID_PER_RANGE))) {
continue;
}
found = 1;
- if (req->ssid_last > mask->ssid_last) {
- pr_debug("diag: Msg SSID range mismatch\n");
- mask->ssid_last = req->ssid_last;
- }
+ mutex_lock(&mask->lock);
mask_size = req->ssid_last - req->ssid_first + 1;
- if (mask_size > mask->range) {
+ if (mask_size > MAX_SSID_PER_RANGE) {
pr_warn("diag: In %s, truncating ssid range, %d-%d to max allowed: %d\n",
__func__, mask->ssid_first, mask->ssid_last,
- mask->range);
- mask_size = mask->range;
- mask->ssid_last = mask->ssid_first + mask->range;
+ MAX_SSID_PER_RANGE);
+ mask_size = MAX_SSID_PER_RANGE;
+ mask->range_tools = MAX_SSID_PER_RANGE;
+ mask->ssid_last_tools =
+ mask->ssid_first + mask->range_tools;
}
+ if (req->ssid_last > mask->ssid_last_tools) {
+ pr_debug("diag: Msg SSID range mismatch\n");
+ if (mask_size != MAX_SSID_PER_RANGE)
+ mask->ssid_last_tools = req->ssid_last;
+ mask->range_tools =
+ mask->ssid_last_tools - mask->ssid_first + 1;
+ temp = krealloc(mask->ptr,
+ mask->range_tools * sizeof(uint32_t),
+ GFP_KERNEL);
+ if (!temp) {
+ pr_err_ratelimited("diag: In %s, unable to allocate memory for msg mask ptr, mask_size: %d\n",
+ __func__, mask_size);
+ mutex_unlock(&mask->lock);
+ mutex_unlock(&msg_mask.lock);
+ return -ENOMEM;
+ }
+ mask->ptr = temp;
+ }
+
offset = req->ssid_first - mask->ssid_first;
- if (offset + mask_size > mask->range) {
- pr_err("diag: In %s, Not enough space for msg mask, mask_size: %d\n",
- __func__, mask_size);
+ if (offset + mask_size > mask->range_tools) {
+ pr_err("diag: In %s, Not in msg mask range, mask_size: %d, offset: %d\n",
+ __func__, mask_size, offset);
+ mutex_unlock(&mask->lock);
break;
}
mask_size = mask_size * sizeof(uint32_t);
memcpy(mask->ptr + offset, src_buf + header_len, mask_size);
+ mutex_unlock(&mask->lock);
msg_mask.status = DIAG_CTRL_MASK_VALID;
break;
}
@@ -1039,9 +1064,12 @@
return -EINVAL;
msg_mask->ssid_first = range->ssid_first;
msg_mask->ssid_last = range->ssid_last;
+ msg_mask->ssid_last_tools = range->ssid_last;
msg_mask->range = msg_mask->ssid_last - msg_mask->ssid_first + 1;
if (msg_mask->range < MAX_SSID_PER_RANGE)
msg_mask->range = MAX_SSID_PER_RANGE;
+ msg_mask->range_tools = msg_mask->range;
+ mutex_init(&msg_mask->lock);
if (msg_mask->range > 0) {
msg_mask->ptr = kzalloc(msg_mask->range * sizeof(uint32_t),
GFP_KERNEL);
@@ -1393,19 +1421,23 @@
for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) {
ptr = msg_mask.update_buf;
len = 0;
+ mutex_lock(&mask->lock);
header.ssid_first = mask->ssid_first;
- header.ssid_last = mask->ssid_last;
- header.range = mask->range;
+ header.ssid_last = mask->ssid_last_tools;
+ header.range = mask->range_tools;
memcpy(ptr, &header, sizeof(header));
len += sizeof(header);
- copy_len = (sizeof(uint32_t) * mask->range);
+ copy_len = (sizeof(uint32_t) * mask->range_tools);
if ((len + copy_len) > msg_mask.update_buf_len) {
pr_err("diag: In %s, no space to update msg mask, first: %d, last: %d\n",
- __func__, mask->ssid_first, mask->ssid_last);
+ __func__, mask->ssid_first,
+ mask->ssid_last_tools);
+ mutex_unlock(&mask->lock);
continue;
}
memcpy(ptr + len, mask->ptr, copy_len);
len += copy_len;
+ mutex_unlock(&mask->lock);
/* + sizeof(int) to account for data_type already in buf */
if (total_len + sizeof(int) + len > count) {
pr_err("diag: In %s, unable to send msg masks to user space, total_len: %d, count: %zu\n",
diff --git a/drivers/char/diag/diag_masks.h b/drivers/char/diag/diag_masks.h
index 08023c4..877875d 100644
--- a/drivers/char/diag/diag_masks.h
+++ b/drivers/char/diag/diag_masks.h
@@ -30,7 +30,10 @@
struct diag_msg_mask_t {
uint32_t ssid_first;
uint32_t ssid_last;
+ uint32_t ssid_last_tools;
uint32_t range;
+ uint32_t range_tools;
+ struct mutex lock;
uint32_t *ptr;
} __packed;
diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c
index 84b324e..5df3aa1 100644
--- a/drivers/char/diag/diagfwd_cntl.c
+++ b/drivers/char/diag/diagfwd_cntl.c
@@ -337,7 +337,6 @@
struct diag_ssid_range_t *range)
{
uint32_t temp_range;
- uint32_t *temp = NULL;
if (!mask || !range)
return -EIO;
@@ -348,11 +347,6 @@
}
if (range->ssid_last >= mask->ssid_last) {
temp_range = range->ssid_last - mask->ssid_first + 1;
- temp = krealloc(mask->ptr, temp_range * sizeof(uint32_t),
- GFP_KERNEL);
- if (!temp)
- return -ENOMEM;
- mask->ptr = temp;
mask->ssid_last = range->ssid_last;
mask->range = temp_range;
}
diff --git a/drivers/devfreq/Makefile b/drivers/devfreq/Makefile
index 445fc6d..8ff3477 100644
--- a/drivers/devfreq/Makefile
+++ b/drivers/devfreq/Makefile
@@ -1,3 +1,5 @@
+CFLAGS_devfreq_trace.o := -I$(src)
+
obj-$(CONFIG_PM_DEVFREQ) += devfreq.o
obj-$(CONFIG_PM_DEVFREQ) += devfreq_trace.o
obj-$(CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND) += governor_simpleondemand.o
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index e91377e..f87a014 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -517,7 +517,7 @@
return 0;
}
- t = min_t(int, group->reg_count, count);
+ t = min_t(unsigned int, group->reg_count, count);
buf = kmalloc(t * sizeof(unsigned int), GFP_KERNEL);
if (buf == NULL) {
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 370b2f2..8cfc20b 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -2624,6 +2624,20 @@
}
#endif
+static int check_vma_flags(struct vm_area_struct *vma,
+ unsigned int flags)
+{
+ unsigned long flags_requested = (VM_READ | VM_WRITE);
+
+ if (flags & KGSL_MEMFLAGS_GPUREADONLY)
+ flags_requested &= ~VM_WRITE;
+
+ if ((vma->vm_flags & flags_requested) == flags_requested)
+ return 0;
+
+ return -EFAULT;
+}
+
static int check_vma(struct vm_area_struct *vma, struct file *vmfile,
struct kgsl_memdesc *memdesc)
{
@@ -2637,7 +2651,7 @@
if (vma->vm_start != memdesc->useraddr ||
(memdesc->useraddr + memdesc->size) != vma->vm_end)
return -EINVAL;
- return 0;
+ return check_vma_flags(vma, memdesc->flags);
}
static int memdesc_sg_virt(struct kgsl_memdesc *memdesc, struct file *vmfile)
@@ -2646,7 +2660,7 @@
long npages = 0, i;
unsigned long sglen = memdesc->size / PAGE_SIZE;
struct page **pages = NULL;
- int write = (memdesc->flags & KGSL_MEMFLAGS_GPUREADONLY) != 0;
+ int write = ((memdesc->flags & KGSL_MEMFLAGS_GPUREADONLY) ? 0 : 1);
if (sglen == 0 || sglen >= LONG_MAX)
return -EINVAL;
@@ -2716,6 +2730,7 @@
struct kgsl_map_user_mem *param = data;
struct dma_buf *dmabuf = NULL;
struct vm_area_struct *vma = NULL;
+ int ret;
if (param->offset != 0 || param->hostptr == 0
|| !KGSL_IS_PAGE_ALIGNED(param->hostptr)
@@ -2732,6 +2747,12 @@
if (vma && vma->vm_file) {
int fd;
+ ret = check_vma_flags(vma, entry->memdesc.flags);
+ if (ret) {
+ up_read(¤t->mm->mmap_sem);
+ return ret;
+ }
+
/*
* Check to see that this isn't our own memory that we have
* already mapped
@@ -2750,7 +2771,7 @@
up_read(¤t->mm->mmap_sem);
if (!IS_ERR_OR_NULL(dmabuf)) {
- int ret = kgsl_setup_dma_buf(entry, pagetable, device, dmabuf);
+ ret = kgsl_setup_dma_buf(entry, pagetable, device, dmabuf);
if (ret)
dma_buf_put(dmabuf);
return ret;
diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c
index b62c3a3..13006f9 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.c
+++ b/drivers/gpu/msm/kgsl_sharedmem.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2007-2014,2016, 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
@@ -576,6 +576,10 @@
unsigned int align;
int step = ((VMALLOC_END - VMALLOC_START)/8) >> PAGE_SHIFT;
+ size = PAGE_ALIGN(size);
+ if (size == 0 || size > UINT_MAX)
+ return -EINVAL;
+
align = (memdesc->flags & KGSL_MEMALIGN_MASK) >> KGSL_MEMALIGN_SHIFT;
page_size = get_page_size(size, align);
diff --git a/drivers/input/touchscreen/it7258_ts_i2c.c b/drivers/input/touchscreen/it7258_ts_i2c.c
index c1415f2..87db92e 100644
--- a/drivers/input/touchscreen/it7258_ts_i2c.c
+++ b/drivers/input/touchscreen/it7258_ts_i2c.c
@@ -1585,11 +1585,11 @@
return -EBUSY;
}
- /* put the device in low power idle mode */
- IT7260_ts_chipLowPowerMode(PWR_CTL_LOW_POWER_MODE);
-
if (device_may_wakeup(dev)) {
if (!gl_ts->device_needs_wakeup) {
+ /* put the device in low power idle mode */
+ IT7260_ts_chipLowPowerMode(PWR_CTL_LOW_POWER_MODE);
+
gl_ts->device_needs_wakeup = true;
enable_irq_wake(gl_ts->client->irq);
}
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");
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
index 48e5027..a36856b 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
@@ -43,8 +43,12 @@
{
struct msm_isp_bufq *bufq = NULL;
uint32_t bufq_index = bufq_handle & 0xFF;
- if (bufq_index > buf_mgr->num_buf_q)
- return bufq;
+
+ /* bufq_handle cannot be 0 */
+ if ((bufq_handle == 0) ||
+ bufq_index >= BUF_MGR_NUM_BUF_Q ||
+ (bufq_index > buf_mgr->num_buf_q))
+ return NULL;
bufq = &buf_mgr->bufq[bufq_index];
if (bufq->bufq_handle == bufq_handle)
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
index a8d8eb5..9a0e911 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
@@ -24,15 +24,12 @@
struct msm_vfe_axi_shared_data *axi_data,
struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd)
{
- int i, rc = -1;
- for (i = 0; i < MAX_NUM_STREAM; i++) {
- if (axi_data->stream_info[i].state == AVALIABLE)
- break;
- }
+ uint32_t i = stream_cfg_cmd->stream_src;
- if (i == MAX_NUM_STREAM) {
- pr_err("%s: No free stream\n", __func__);
- return rc;
+ if (i >= VFE_AXI_SRC_MAX) {
+ pr_err("%s:%d invalid stream_src %d\n", __func__, __LINE__,
+ stream_cfg_cmd->stream_src);
+ return -EINVAL;
}
if ((axi_data->stream_handle_cnt << 8) == 0)
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
index a9a9c72..680a8a6 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
@@ -639,12 +639,12 @@
break;
case VIDIOC_MSM_ISP_AXI_RESET:
mutex_lock(&vfe_dev->core_mutex);
- rc = msm_isp_axi_reset(vfe_dev, arg);
+ rc = msm_isp_axi_reset(vfe_dev, arg);
mutex_unlock(&vfe_dev->core_mutex);
break;
case VIDIOC_MSM_ISP_AXI_RESTART:
mutex_lock(&vfe_dev->core_mutex);
- rc = msm_isp_axi_restart(vfe_dev, arg);
+ rc = msm_isp_axi_restart(vfe_dev, arg);
mutex_unlock(&vfe_dev->core_mutex);
break;
case VIDIOC_MSM_ISP_INPUT_CFG:
@@ -1293,8 +1293,6 @@
{
struct msm_vfe_error_info *error_info = &vfe_dev->error_info;
error_info->info_dump_frame_count++;
- if (error_info->info_dump_frame_count == 0)
- error_info->info_dump_frame_count++;
}
void msm_isp_process_error_info(struct vfe_device *vfe_dev)
@@ -1390,6 +1388,7 @@
*irq_status0 = 0;
*irq_status1 = 0;
+ memset(&error_event, 0, sizeof(error_event));
error_event.frame_id =
vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id;
error_event.u.error_info.error_mask = 1 << ISP_WM_BUS_OVERFLOW;
@@ -1406,8 +1405,7 @@
stream_info->stream_type != BURST_STREAM) {
return;
}
- if (stream_info->stream_type == BURST_STREAM &&
- stream_info->num_burst_capture != 0) {
+ if (stream_info->num_burst_capture != 0) {
stream_cfg_cmd.burst_count =
stream_info->num_burst_capture;
stream_cfg_cmd.frame_skip_pattern =
@@ -1419,7 +1417,6 @@
msm_isp_reset_framedrop(vfe_dev, stream_info);
}
}
-
irqreturn_t msm_isp_process_irq(int irq_num, void *data)
{
unsigned long flags;
diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
index 9e35513..0eac216 100644
--- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2016, 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
@@ -363,23 +363,23 @@
switch (intftype) {
case PIX0:
data &= ~(BIT(1) | BIT(0));
- data |= csid;
+ data |= (uint32_t) csid;
break;
case RDI0:
data &= ~(BIT(5) | BIT(4));
- data |= (csid << 4);
+ data |= ((uint32_t) csid) << 4;
break;
case PIX1:
data &= ~(BIT(9) | BIT(8));
- data |= (csid << 8);
+ data |= ((uint32_t) csid) << 8;
break;
case RDI1:
data &= ~(BIT(13) | BIT(12));
- data |= (csid << 12);
+ data |= ((uint32_t) csid) << 12;
break;
case RDI2:
data &= ~(BIT(21) | BIT(20));
- data |= (csid << 20);
+ data |= ((uint32_t) csid) << 20;
break;
}
@@ -455,9 +455,9 @@
data = msm_camera_io_r(ispif->base + intf_addr);
if (enable)
- data |= cid_mask;
+ data |= (uint32_t) cid_mask;
else
- data &= ~cid_mask;
+ data &= ~((uint32_t) cid_mask);
msm_camera_io_w_mb(data, ispif->base + intf_addr);
}
@@ -1136,9 +1136,15 @@
static int msm_ispif_set_vfe_info(struct ispif_device *ispif,
struct msm_ispif_vfe_info *vfe_info)
{
- memcpy(&ispif->vfe_info, vfe_info, sizeof(struct msm_ispif_vfe_info));
- if (ispif->vfe_info.num_vfe > ispif->hw_num_isps)
+ if (!vfe_info || (vfe_info->num_vfe <= 0) ||
+ ((uint32_t)(vfe_info->num_vfe) > ispif->hw_num_isps)) {
+ pr_err("Invalid VFE info: %p %d\n", vfe_info,
+ (vfe_info ? vfe_info->num_vfe:0));
return -EINVAL;
+ }
+
+ memcpy(&ispif->vfe_info, vfe_info, sizeof(struct msm_ispif_vfe_info));
+
return 0;
}
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
index 1ff4941..2214a8d 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, 2016 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
@@ -1695,6 +1695,11 @@
struct msm_camera_v4l2_ioctl_t *ioctl_ptr)
{
int ret;
+ if ((ioctl_ptr->ioctl_ptr == NULL) || (ioctl_ptr->len == 0)) {
+ pr_err("%s: Wrong ioctl_ptr %p / len %zu\n", __func__,
+ ioctl_ptr, ioctl_ptr->len);
+ return -EINVAL;
+ }
/* For compat task, source ptr is in kernel space */
if (is_compat_task()) {
@@ -1714,6 +1719,12 @@
{
int ret;
+ if ((ioctl_ptr->ioctl_ptr == NULL) || (ioctl_ptr->len == 0)) {
+ pr_err("%s: Wrong ioctl_ptr %p / len %zu\n", __func__,
+ ioctl_ptr, ioctl_ptr->len);
+ return -EINVAL;
+ }
+
ret = copy_from_user(dst_ptr,
(void __user *)ioctl_ptr->ioctl_ptr, ioctl_ptr->len);
if (ret)
@@ -2046,6 +2057,10 @@
struct msm_pproc_queue_buf_info queue_buf_info;
CPP_DBG("VIDIOC_MSM_CPP_QUEUE_BUF\n");
+ if (ioctl_ptr->len != sizeof(struct msm_pproc_queue_buf_info)) {
+ pr_err("%s: Not valid ioctl_ptr->len\n", __func__);
+ return -EINVAL;
+ }
rc = msm_cpp_copy_from_ioctl_ptr(&queue_buf_info, ioctl_ptr);
if (rc) {
ERR_COPY_FROM_USER();
diff --git a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
index 007411b..1092b45 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
@@ -421,12 +421,18 @@
{
int16_t code_per_step = 0;
int16_t cur_code = 0;
- int16_t step_index = 0, region_index = 0;
+ uint16_t step_index = 0, region_index = 0;
uint16_t step_boundary = 0;
uint32_t max_code_size = 1;
uint16_t data_size = set_info->actuator_params.data_size;
CDBG("Enter\n");
+ /* validate the actuator state */
+ if (a_ctrl->actuator_state != ACTUATOR_POWER_UP) {
+ pr_err("%s:%d invalid actuator_state %d\n"
+ , __func__, __LINE__, a_ctrl->actuator_state);
+ return -EINVAL;
+ }
for (; data_size > 0; data_size--)
max_code_size *= 2;
@@ -458,6 +464,15 @@
step_boundary =
a_ctrl->region_params[region_index].
step_bound[MOVE_NEAR];
+ if (step_boundary >
+ set_info->af_tuning_params.total_steps) {
+ pr_err("invalid step_boundary = %d, max_val = %d",
+ step_boundary,
+ set_info->af_tuning_params.total_steps);
+ kfree(a_ctrl->step_position_table);
+ a_ctrl->step_position_table = NULL;
+ return -EINVAL;
+ }
for (; step_index <= step_boundary;
step_index++) {
cur_code += code_per_step;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index 7470b77..0666523 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -714,11 +714,23 @@
return 0;
}
+static bool valid_v4l2_buffer(struct v4l2_buffer *b,
+ struct msm_vidc_inst *inst) {
+ enum vidc_ports port =
+ !V4L2_TYPE_IS_MULTIPLANAR(b->type) ? MAX_PORT_NUM :
+ b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ? CAPTURE_PORT :
+ b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ? OUTPUT_PORT :
+ MAX_PORT_NUM;
+
+ return port != MAX_PORT_NUM &&
+ inst->fmts[port]->num_planes == b->length;
+}
+
int msm_vidc_prepare_buf(void *instance, struct v4l2_buffer *b)
{
struct msm_vidc_inst *inst = instance;
- if (!inst || !b)
+ if (!inst || !b || !valid_v4l2_buffer(b, inst))
return -EINVAL;
if (!V4L2_TYPE_IS_MULTIPLANAR(b->type) || !b->length ||
@@ -879,7 +891,7 @@
int rc = 0;
int i;
- if (!inst || !b)
+ if (!inst || !b || !valid_v4l2_buffer(b, inst))
return -EINVAL;
if (!V4L2_TYPE_IS_MULTIPLANAR(b->type) || !b->length ||
@@ -963,7 +975,7 @@
struct buffer_info *buffer_info = NULL;
int i = 0, rc = 0;
- if (!inst || !b)
+ if (!inst || !b || !valid_v4l2_buffer(b, inst))
return -EINVAL;
if (!V4L2_TYPE_IS_MULTIPLANAR(b->type) || !b->length ||
@@ -971,7 +983,6 @@
dprintk(VIDC_ERR, "%s: wrong input params\n",
__func__);
return -EINVAL;
- }
if (inst->session_type == MSM_VIDC_DECODER)
rc = msm_vdec_dqbuf(instance, b);
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 13930a1..9e1f222 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -121,6 +121,7 @@
struct list_head list;
u32 app_id;
u32 ref_cnt;
+ char app_name[MAX_APP_NAME_SIZE];
};
struct qseecom_registered_kclient_list {
@@ -182,6 +183,7 @@
struct cdev cdev;
bool timer_running;
bool no_clock_support;
+ bool appsbl_qseecom_support;
};
struct qseecom_client_handle {
@@ -191,6 +193,7 @@
unsigned long user_virt_sb_base;
size_t sb_length;
struct ion_handle *ihandle; /* Retrieve phy addr */
+ char app_name[MAX_APP_NAME_SIZE];
};
struct qseecom_listener_handle {
@@ -215,7 +218,7 @@
};
struct qseecom_sg_entry {
- phys_addr_t phys_addr;
+ uint32_t phys_addr;
uint32_t len;
};
@@ -353,7 +356,6 @@
return -EFAULT;
data->listener.id = 0;
- data->type = QSEECOM_LISTENER_SERVICE;
if (!__qseecom_is_svc_unique(data, &rcvd_lstnr)) {
pr_err("Service is not unique and is already registered\n");
data->released = true;
@@ -1049,7 +1051,8 @@
}
entry->app_id = app_id;
entry->ref_cnt = 1;
-
+ strlcpy(entry->app_name, load_img_req.img_name,
+ MAX_APP_NAME_SIZE);
/* Deallocate the handle */
if (!IS_ERR_OR_NULL(ihandle))
ion_free(qseecom.ion_clnt, ihandle);
@@ -1063,6 +1066,8 @@
(char *)(load_img_req.img_name));
}
data->client.app_id = app_id;
+ strlcpy(data->client.app_name, load_img_req.img_name,
+ MAX_APP_NAME_SIZE);
load_img_req.app_id = app_id;
if (copy_to_user(argp, &load_img_req, sizeof(load_img_req))) {
pr_err("copy_to_user failed\n");
@@ -1107,50 +1112,60 @@
return ret;
}
-static int qseecom_unload_app(struct qseecom_dev_handle *data)
+static int qseecom_unload_app(struct qseecom_dev_handle *data,
+ bool app_crash)
{
unsigned long flags;
+ unsigned long flags1;
int ret = 0;
struct qseecom_command_scm_resp resp;
- struct qseecom_registered_app_list *ptr_app;
+ struct qseecom_registered_app_list *ptr_app = NULL;
bool unload = false;
bool found_app = false;
+ bool found_dead_app = false;
+
+ if (!memcmp(data->client.app_name, "keymaste", strlen("keymaste"))) {
+ pr_debug("Do not unload keymaster app from tz\n");
+ goto unload_exit;
+ }
if (data->client.app_id > 0) {
spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
list_for_each_entry(ptr_app, &qseecom.registered_app_list_head,
- list) {
+ list) {
if (ptr_app->app_id == data->client.app_id) {
- found_app = true;
- if (ptr_app->ref_cnt == 1) {
- unload = true;
+ if (!memcmp((void *)ptr_app->app_name,
+ (void *)data->client.app_name,
+ strlen(data->client.app_name))) {
+ found_app = true;
+ if (app_crash || ptr_app->ref_cnt == 1)
+ unload = true;
break;
} else {
- ptr_app->ref_cnt--;
- pr_debug("Can't unload app(%d) inuse\n",
- ptr_app->app_id);
+ found_dead_app = true;
break;
}
}
}
spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
flags);
- if (found_app == false) {
- pr_err("Cannot find app with id = %d\n",
- data->client.app_id);
+ if (found_app == false && found_dead_app == false) {
+ pr_err("Cannot find app with id = %d (%s)\n",
+ data->client.app_id,
+ (char *)data->client.app_name);
return -EINVAL;
}
}
+ if (found_dead_app) {
+ pr_warn("cleanup app_id %d(%s)\n", data->client.app_id,
+ (char *)data->client.app_name);
+ __qseecom_cleanup_app(data);
+ }
+
if (unload) {
struct qseecom_unload_app_ireq req;
- __qseecom_cleanup_app(data);
- spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
- list_del(&ptr_app->list);
- kzfree(ptr_app);
- spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
- flags);
/* Populate the structure for sending scm call to load image */
req.qsee_cmd_id = QSEOS_APP_SHUTDOWN_COMMAND;
req.app_id = data->client.app_id;
@@ -1161,20 +1176,54 @@
&resp, sizeof(resp));
if (ret) {
pr_err("scm_call to unload app (id = %d) failed\n",
- req.app_id);
+ req.app_id);
return -EFAULT;
} else {
pr_warn("App id %d now unloaded\n", req.app_id);
}
+
+ if (resp.result == QSEOS_RESULT_FAILURE) {
+ pr_err("app (%d) unload_failed!!\n",
+ data->client.app_id);
+ return -EFAULT;
+ }
+ if (resp.result == QSEOS_RESULT_SUCCESS)
+ pr_debug("App (%d) is unloaded!!\n",
+ data->client.app_id);
+ __qseecom_cleanup_app(data);
if (resp.result == QSEOS_RESULT_INCOMPLETE) {
ret = __qseecom_process_incomplete_cmd(data, &resp);
if (ret) {
pr_err("process_incomplete_cmd fail err: %d\n",
- ret);
+ ret);
return ret;
}
}
}
+
+ if (found_app) {
+ spin_lock_irqsave(&qseecom.registered_app_list_lock, flags1);
+ if (app_crash) {
+ ptr_app->ref_cnt = 0;
+ pr_debug("app_crash: ref_count = 0\n");
+ } else {
+ if (ptr_app->ref_cnt == 1) {
+ ptr_app->ref_cnt = 0;
+ pr_debug("ref_count set to 0\n");
+ } else {
+ ptr_app->ref_cnt--;
+ pr_debug("Can't unload app(%d) inuse\n",
+ ptr_app->app_id);
+ }
+ }
+ if (unload) {
+ list_del(&ptr_app->list);
+ kzfree(ptr_app);
+ }
+ spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
+ flags1);
+ }
+unload_exit:
qseecom_unmap_ion_allocated_memory(data);
data->released = true;
return ret;
@@ -1525,6 +1574,32 @@
u32 reqd_len_sb_in = 0;
struct qseecom_client_send_data_ireq send_data_req;
struct qseecom_command_scm_resp resp;
+ unsigned long flags;
+ struct qseecom_registered_app_list *ptr_app;
+ bool found_app = false;
+ int name_len = 0;
+
+ reqd_len_sb_in = req->cmd_req_len + req->resp_len;
+ /* find app_id & img_name from list */
+ spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
+ list_for_each_entry(ptr_app, &qseecom.registered_app_list_head,
+ list) {
+ name_len = min(strlen(data->client.app_name),
+ strlen(ptr_app->app_name));
+ if ((ptr_app->app_id == data->client.app_id) &&
+ (!memcmp(ptr_app->app_name,
+ data->client.app_name, name_len))) {
+ found_app = true;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&qseecom.registered_app_list_lock, flags);
+
+ if (!found_app) {
+ pr_err("app_id %d (%s) is not found\n", data->client.app_id,
+ (char *)data->client.app_name);
+ return -EINVAL;
+ }
send_data_req.qsee_cmd_id = QSEOS_CLIENT_SEND_DATA_COMMAND;
send_data_req.app_id = data->client.app_id;
@@ -2283,6 +2358,16 @@
size_t len;
ion_phys_addr_t pa;
+ if (!app_name) {
+ pr_err("failed to get the app name\n");
+ return -EINVAL;
+ }
+ if (strlen(app_name) >= MAX_APP_NAME_SIZE) {
+ pr_err("The app_name (%s) with length %zu is not valid\n",
+ app_name, strlen(app_name));
+ return -EINVAL;
+ }
+
*handle = kzalloc(sizeof(struct qseecom_handle), GFP_KERNEL);
if (!(*handle)) {
pr_err("failed to allocate memory for kernel client handle\n");
@@ -2363,6 +2448,7 @@
if (ret < 0)
goto err;
data->client.app_id = ret;
+ strlcpy(data->client.app_name, app_name, MAX_APP_NAME_SIZE);
}
if (!found_app) {
entry = kmalloc(sizeof(*entry), GFP_KERNEL);
@@ -2373,6 +2459,7 @@
}
entry->app_id = ret;
entry->ref_cnt = 1;
+ strlcpy(entry->app_name, app_name, MAX_APP_NAME_SIZE);
spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
list_add_tail(&entry->list, &qseecom.registered_app_list_head);
@@ -2436,6 +2523,9 @@
return -EINVAL;
}
data = (struct qseecom_dev_handle *) ((*handle)->dev);
+ mutex_lock(&app_access_lock);
+ atomic_inc(&data->ioctl_count);
+
spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
list_for_each_entry(kclient, &qseecom.registered_kclient_list_head,
list) {
@@ -2449,7 +2539,7 @@
if (!found_handle)
pr_err("Unable to find the handle, exiting\n");
else
- ret = qseecom_unload_app(data);
+ ret = qseecom_unload_app(data, false);
if (qseecom.support_bus_scaling) {
mutex_lock(&qsee_bw_mutex);
@@ -2468,12 +2558,16 @@
if (data->perf_enabled == true)
qsee_disable_clock_vote(data, CLK_DFAB);
}
+
+ atomic_dec(&data->ioctl_count);
+ mutex_unlock(&app_access_lock);
if (ret == 0) {
kzfree(data);
kzfree(*handle);
kzfree(kclient);
*handle = NULL;
}
+
return ret;
}
EXPORT_SYMBOL(qseecom_shutdown_app);
@@ -2632,7 +2726,7 @@
}
resp.resp_buf_ptr = this_lstnr->sb_virt +
(uintptr_t)(resp.resp_buf_ptr - this_lstnr->user_virt_sb_base);
- __qseecom_update_cmd_buf(&resp, false, data, true);
+ __qseecom_update_cmd_buf(&resp, false, data, false);
qseecom.send_resp_flag = 1;
wake_up_interruptible(&qseecom.send_resp_wq);
return 0;
@@ -2659,16 +2753,19 @@
static int __qseecom_enable_clk(enum qseecom_ce_hw_instance ce)
{
int rc = 0;
- struct qseecom_clk *qclk;
+ struct qseecom_clk *qclk = NULL;
if (qseecom.no_clock_support)
return 0;
if (ce == CLK_QSEE)
qclk = &qseecom.qsee;
- else
+ if (ce == CLK_CE_DRV)
qclk = &qseecom.ce_drv;
-
+ if (qclk == NULL) {
+ pr_err("CLK type not supported\n");
+ return -EINVAL;
+ }
mutex_lock(&clk_access_lock);
if (qclk->clk_access_cnt == ULONG_MAX)
@@ -2681,31 +2778,39 @@
}
/* Enable CE core clk */
- rc = clk_prepare_enable(qclk->ce_core_clk);
- if (rc) {
- pr_err("Unable to enable/prepare CE core clk\n");
- goto err;
+ if (qclk->ce_core_clk != NULL) {
+ rc = clk_prepare_enable(qclk->ce_core_clk);
+ if (rc) {
+ pr_err("Unable to enable/prepare CE core clk\n");
+ goto err;
+ }
}
/* Enable CE clk */
- rc = clk_prepare_enable(qclk->ce_clk);
- if (rc) {
- pr_err("Unable to enable/prepare CE iface clk\n");
- goto ce_clk_err;
+ if (qclk->ce_clk != NULL) {
+ rc = clk_prepare_enable(qclk->ce_clk);
+ if (rc) {
+ pr_err("Unable to enable/prepare CE iface clk\n");
+ goto ce_clk_err;
+ }
}
/* Enable AXI clk */
- rc = clk_prepare_enable(qclk->ce_bus_clk);
- if (rc) {
- pr_err("Unable to enable/prepare CE bus clk\n");
- goto ce_bus_clk_err;
+ if (qclk->ce_bus_clk != NULL) {
+ rc = clk_prepare_enable(qclk->ce_bus_clk);
+ if (rc) {
+ pr_err("Unable to enable/prepare CE bus clk\n");
+ goto ce_bus_clk_err;
+ }
}
qclk->clk_access_cnt++;
mutex_unlock(&clk_access_lock);
return 0;
ce_bus_clk_err:
- clk_disable_unprepare(qclk->ce_clk);
+ if (qclk->ce_clk != NULL)
+ clk_disable_unprepare(qclk->ce_clk);
ce_clk_err:
- clk_disable_unprepare(qclk->ce_core_clk);
+ if (qclk->ce_core_clk != NULL)
+ clk_disable_unprepare(qclk->ce_core_clk);
err:
mutex_unlock(&clk_access_lock);
return -EIO;
@@ -3103,6 +3208,7 @@
struct qseecom_check_app_ireq req;
struct qseecom_registered_app_list *entry = NULL;
unsigned long flags = 0;
+ bool found_app = false;
/* Copy the relevant information needed for loading the image */
if (copy_from_user(&query_req,
@@ -3129,6 +3235,7 @@
&qseecom.registered_app_list_head, list){
if (entry->app_id == ret) {
entry->ref_cnt++;
+ found_app = true;
break;
}
}
@@ -3136,7 +3243,31 @@
&qseecom.registered_app_list_lock, flags);
data->client.app_id = ret;
query_req.app_id = ret;
-
+ strlcpy(data->client.app_name, query_req.app_name,
+ MAX_APP_NAME_SIZE);
+ /*
+ * If app was loaded by appsbl or kernel client before
+ * and was not registered, regiser this app now.
+ */
+ if (!found_app) {
+ pr_debug("Register app %d [%s] which was loaded before\n",
+ ret, (char *)query_req.app_name);
+ entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+ if (!entry) {
+ pr_err("kmalloc for app entry failed\n");
+ return -ENOMEM;
+ }
+ entry->app_id = ret;
+ entry->ref_cnt = 1;
+ strlcpy(entry->app_name, data->client.app_name,
+ MAX_APP_NAME_SIZE);
+ spin_lock_irqsave(&qseecom.registered_app_list_lock,
+ flags);
+ list_add_tail(&entry->list,
+ &qseecom.registered_app_list_head);
+ spin_unlock_irqrestore(
+ &qseecom.registered_app_list_lock, flags);
+ }
if (copy_to_user(argp, &query_req, sizeof(query_req))) {
pr_err("copy_to_user failed\n");
return -EFAULT;
@@ -4141,7 +4272,7 @@
pr_debug("UNLOAD_APP: qseecom_addr = 0x%p\n", data);
mutex_lock(&app_access_lock);
atomic_inc(&data->ioctl_count);
- ret = qseecom_unload_app(data);
+ ret = qseecom_unload_app(data, false);
atomic_dec(&data->ioctl_count);
mutex_unlock(&app_access_lock);
if (ret)
@@ -4497,6 +4628,7 @@
data->abort = 0;
data->type = QSEECOM_GENERIC;
data->released = false;
+ memset((void *)data->client.app_name, 0, MAX_APP_NAME_SIZE);
data->mode = INACTIVE;
init_waitqueue_head(&data->abort_wq);
atomic_set(&data->ioctl_count, 0);
@@ -4517,13 +4649,13 @@
ret = qseecom_unregister_listener(data);
break;
case QSEECOM_CLIENT_APP:
- ret = qseecom_unload_app(data);
+ ret = qseecom_unload_app(data, true);
break;
case QSEECOM_SECURE_SERVICE:
case QSEECOM_GENERIC:
ret = qseecom_unmap_ion_allocated_memory(data);
if (ret)
- pr_err("Close failed\n");
+ pr_err("Ion Unmap failed\n");
break;
case QSEECOM_UNAVAILABLE_CLIENT_APP:
break;
@@ -4599,6 +4731,15 @@
pr_err("Invalid ce hw instance: %d!\n", ce);
return -EIO;
}
+
+ if (qseecom.no_clock_support) {
+ qclk->ce_core_clk = NULL;
+ qclk->ce_clk = NULL;
+ qclk->ce_bus_clk = NULL;
+ qclk->ce_core_src_clk = NULL;
+ return 0;
+ }
+
pdev = qseecom.pdev;
/* Get CE3 src core clk. */
@@ -4608,6 +4749,7 @@
rc = clk_set_rate(qclk->ce_core_src_clk, QSEE_CE_CLK_100MHZ);
if (rc) {
clk_put(qclk->ce_core_src_clk);
+ qclk->ce_core_src_clk = NULL;
pr_err("Unable to set the core src clk @100Mhz.\n");
return -EIO;
}
@@ -4615,8 +4757,6 @@
pr_warn("Unable to get CE core src clk, set to NULL\n");
qclk->ce_core_src_clk = NULL;
}
- if (qseecom.no_clock_support)
- return 0;
/* Get CE core clk */
qclk->ce_core_clk = clk_get(pdev, core_clk);
if (IS_ERR(qclk->ce_core_clk)) {
@@ -4649,6 +4789,7 @@
clk_put(qclk->ce_clk);
return -EIO;
}
+
return rc;
}
@@ -4849,6 +4990,12 @@
qseecom.ce_info.qsee_ce_hw_instance);
}
+ qseecom.appsbl_qseecom_support =
+ of_property_read_bool((&pdev->dev)->of_node,
+ "qcom,appsbl-qseecom-support");
+ pr_info("qseecom.appsbl_qseecom_support = 0x%x",
+ qseecom.appsbl_qseecom_support);
+
qseecom.no_clock_support =
of_property_read_bool((&pdev->dev)->of_node,
"qcom,no-clock-support");
@@ -4885,7 +5032,8 @@
qseecom_platform_support = (struct msm_bus_scale_pdata *)
msm_bus_cl_get_pdata(pdev);
- if (qseecom.qsee_version >= (QSEE_VERSION_02)) {
+ if (qseecom.qsee_version >= (QSEE_VERSION_02) &&
+ !qseecom.appsbl_qseecom_support) {
struct resource *resource = NULL;
struct qsee_apps_region_info_ireq req;
struct qseecom_command_scm_resp resp;
@@ -4912,6 +5060,8 @@
goto exit_destroy_ion_client;
}
}
+ if(qseecom.appsbl_qseecom_support)
+ qseecom.commonlib_loaded = true;
} else {
qseecom_platform_support = (struct msm_bus_scale_pdata *)
pdev->dev.platform_data;
@@ -4965,7 +5115,7 @@
goto exit_free_kc_handle;
list_del(&kclient->list);
- ret = qseecom_unload_app(kclient->handle->dev);
+ ret = qseecom_unload_app(kclient->handle->dev, false);
if (!ret) {
kzfree(kclient->handle->dev);
kzfree(kclient->handle);
@@ -5080,26 +5230,29 @@
}
if (qclk->clk_access_cnt) {
-
- ret = clk_prepare_enable(qclk->ce_core_clk);
- if (ret) {
- pr_err("Unable to enable/prepare CE core clk\n");
- qclk->clk_access_cnt = 0;
- goto err;
+ if (qclk->ce_core_clk != NULL) {
+ ret = clk_prepare_enable(qclk->ce_core_clk);
+ if (ret) {
+ pr_err("Unable to enable/prep CE core clk\n");
+ qclk->clk_access_cnt = 0;
+ goto err;
+ }
}
-
- ret = clk_prepare_enable(qclk->ce_clk);
- if (ret) {
- pr_err("Unable to enable/prepare CE iface clk\n");
- qclk->clk_access_cnt = 0;
- goto ce_clk_err;
+ if (qclk->ce_clk != NULL) {
+ ret = clk_prepare_enable(qclk->ce_clk);
+ if (ret) {
+ pr_err("Unable to enable/prep CE iface clk\n");
+ qclk->clk_access_cnt = 0;
+ goto ce_clk_err;
+ }
}
-
- ret = clk_prepare_enable(qclk->ce_bus_clk);
- if (ret) {
- pr_err("Unable to enable/prepare CE bus clk\n");
- qclk->clk_access_cnt = 0;
- goto ce_bus_clk_err;
+ if (qclk->ce_bus_clk != NULL) {
+ ret = clk_prepare_enable(qclk->ce_bus_clk);
+ if (ret) {
+ pr_err("Unable to enable/prep CE bus clk\n");
+ qclk->clk_access_cnt = 0;
+ goto ce_bus_clk_err;
+ }
}
}
diff --git a/drivers/platform/msm/ipa/rmnet_ipa.c b/drivers/platform/msm/ipa/rmnet_ipa.c
index 5d02833..ba48b94 100644
--- a/drivers/platform/msm/ipa/rmnet_ipa.c
+++ b/drivers/platform/msm/ipa/rmnet_ipa.c
@@ -1175,6 +1175,11 @@
rmnet_mux_val.mux_id);
return rc;
}
+ if (rmnet_index >= MAX_NUM_OF_MUX_CHANNEL) {
+ IPAWANERR("Exceed mux_channel limit(%d)\n",
+ rmnet_index);
+ return -EFAULT;
+ }
IPAWANDBG("ADD_MUX_CHANNEL(%d, name: %s)\n",
extend_ioctl_data.u.rmnet_mux_val.mux_id,
extend_ioctl_data.u.rmnet_mux_val.vchannel_name);
diff --git a/drivers/platform/msm/msm_bus/msm_buspm_coresight_adhoc.c b/drivers/platform/msm/msm_bus/msm_buspm_coresight_adhoc.c
index c154878..61a4e27 100644
--- a/drivers/platform/msm/msm_bus/msm_buspm_coresight_adhoc.c
+++ b/drivers/platform/msm/msm_bus/msm_buspm_coresight_adhoc.c
@@ -135,6 +135,7 @@
return PTR_ERR(pdata);
drvdata = platform_get_drvdata(pdev);
+ dev_dbg(dev, "info: removed buspm module from kernel space\n");
if (IS_ERR_OR_NULL(drvdata)) {
drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
if (!drvdata) {
diff --git a/drivers/regulator/rpm-smd-regulator.c b/drivers/regulator/rpm-smd-regulator.c
index 3067a0b..f4d9cf2 100644
--- a/drivers/regulator/rpm-smd-regulator.c
+++ b/drivers/regulator/rpm-smd-regulator.c
@@ -893,6 +893,19 @@
return reg->rpm_vreg->enable_time;
}
+static int rpm_vreg_send_defaults(struct rpm_regulator *reg)
+{
+ int rc;
+
+ rpm_vreg_lock(reg->rpm_vreg);
+ rc = rpm_vreg_aggregate_requests(reg);
+ if (rc)
+ vreg_err(reg, "RPM request failed, rc=%d", rc);
+ rpm_vreg_unlock(reg->rpm_vreg);
+
+ return rc;
+}
+
/**
* rpm_regulator_get() - lookup and obtain a handle to an RPM regulator
* @dev: device for regulator consumer
@@ -1500,6 +1513,14 @@
list_add(®->list, &rpm_vreg->reg_list);
rpm_vreg_unlock(rpm_vreg);
+ if (of_property_read_bool(node, "qcom,send-defaults")) {
+ rc = rpm_vreg_send_defaults(reg);
+ if (rc) {
+ vreg_err(reg, "could not send defaults, rc=%d\n", rc);
+ goto fail_remove_from_list;
+ }
+ }
+
reg_config.dev = dev;
reg_config.init_data = init_data;
reg_config.of_node = node;
diff --git a/drivers/soc/qcom/bam_dmux.c b/drivers/soc/qcom/bam_dmux.c
index b183334..1654bdb 100644
--- a/drivers/soc/qcom/bam_dmux.c
+++ b/drivers/soc/qcom/bam_dmux.c
@@ -271,7 +271,6 @@
static DEFINE_MUTEX(smsm_cb_lock);
static DEFINE_MUTEX(delayed_ul_vote_lock);
static int need_delayed_ul_vote;
-static int in_ssr;
static int ssr_skipped_disconnect;
static struct completion shutdown_completion;
@@ -1952,8 +1951,11 @@
{
int i;
- in_global_reset = 0;
- in_ssr = 0;
+ if (in_global_reset) {
+ BAM_DMUX_LOG("%s: skipping due to SSR\n", __func__);
+ return;
+ }
+
vote_dfab();
if (ssr_skipped_disconnect) {
@@ -2029,8 +2031,8 @@
/* tear down BAM connection */
INIT_COMPLETION(bam_connection_completion);
- /* in_ssr documentation/assumptions found in restart_notifier_cb */
- if (likely(!in_ssr)) {
+ /* documentation/assumptions found in restart_notifier_cb */
+ if (likely(!in_global_reset)) {
BAM_DMUX_LOG("%s: disconnect tx\n", __func__);
bam_ops->sps_disconnect_ptr(bam_tx_pipe);
BAM_DMUX_LOG("%s: disconnect rx\n", __func__);
@@ -2164,12 +2166,13 @@
if (code == SUBSYS_BEFORE_SHUTDOWN) {
BAM_DMUX_LOG("%s: begin\n", __func__);
in_global_reset = 1;
- in_ssr = 1;
- /* wait till all bam_dmux writes completes */
+ /* sync to ensure the driver sees SSR */
synchronize_srcu(&bam_dmux_srcu);
BAM_DMUX_LOG("%s: ssr signaling complete\n", __func__);
flush_workqueue(bam_mux_rx_workqueue);
}
+ if (code == SUBSYS_BEFORE_POWERUP)
+ in_global_reset = 0;
if (code != SUBSYS_AFTER_SHUTDOWN)
return NOTIFY_DONE;
@@ -2242,6 +2245,7 @@
void *a2_virt_addr;
int skip_iounmap = 0;
+ in_global_reset = 0;
vote_dfab();
/* init BAM */
a2_virt_addr = ioremap_nocache(a2_phys_base, a2_phys_size);
@@ -2431,7 +2435,9 @@
static void bam_dmux_smsm_cb(void *priv, uint32_t old_state, uint32_t new_state)
{
static int last_processed_state;
+ int rcu_id;
+ rcu_id = srcu_read_lock(&bam_dmux_srcu);
mutex_lock(&smsm_cb_lock);
bam_dmux_power_state = new_state & SMSM_A2_POWER_CONTROL ? 1 : 0;
DBG_INC_A2_POWER_CONTROL_IN_CNT();
@@ -2440,6 +2446,7 @@
if (last_processed_state == (new_state & SMSM_A2_POWER_CONTROL)) {
BAM_DMUX_LOG("%s: already processed this state\n", __func__);
mutex_unlock(&smsm_cb_lock);
+ srcu_read_unlock(&bam_dmux_srcu, rcu_id);
return;
}
@@ -2463,16 +2470,20 @@
pr_err("%s: unsupported state change\n", __func__);
}
mutex_unlock(&smsm_cb_lock);
-
+ srcu_read_unlock(&bam_dmux_srcu, rcu_id);
}
static void bam_dmux_smsm_ack_cb(void *priv, uint32_t old_state,
uint32_t new_state)
{
+ int rcu_id;
+
+ rcu_id = srcu_read_lock(&bam_dmux_srcu);
DBG_INC_ACK_IN_CNT();
BAM_DMUX_LOG("%s: 0x%08x -> 0x%08x\n", __func__, old_state,
new_state);
complete_all(&ul_wakeup_ack_completion);
+ srcu_read_unlock(&bam_dmux_srcu, rcu_id);
}
/**
@@ -2501,8 +2512,9 @@
{
restart_notifier_cb(NULL, SUBSYS_BEFORE_SHUTDOWN, NULL);
restart_notifier_cb(NULL, SUBSYS_AFTER_SHUTDOWN, NULL);
+ restart_notifier_cb(NULL, SUBSYS_BEFORE_POWERUP, NULL);
+ restart_notifier_cb(NULL, SUBSYS_AFTER_POWERUP, NULL);
in_global_reset = 0;
- in_ssr = 0;
}
EXPORT_SYMBOL(msm_bam_dmux_deinit);
diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c
index a7fa903..68f692f 100644
--- a/drivers/soc/qcom/socinfo.c
+++ b/drivers/soc/qcom/socinfo.c
@@ -111,6 +111,7 @@
PLATFORM_SUBTYPE_STRANGE_2A = 0x3,
PLATFORM_SUBTYPE_QVGA = 0x4,
PLATFORM_SUBTYPE_G_QVGA = 0x5,
+ PLATFORM_SUBTYPE_JDI_QVGA = 0x6,
PLATFORM_SUBTYPE_INVALID,
};
@@ -121,6 +122,7 @@
[PLATFORM_SUBTYPE_STRANGE_2A] = "strange_2a,",
[PLATFORM_SUBTYPE_QVGA] = "qvga",
[PLATFORM_SUBTYPE_G_QVGA] = "qvga_g",
+ [PLATFORM_SUBTYPE_JDI_QVGA] = "jdi_qvga",
};
/* Used to parse shared memory. Must match the modem. */
diff --git a/drivers/thermal/msm_thermal-dev.c b/drivers/thermal/msm_thermal-dev.c
index 0acde30..6328cd7 100644
--- a/drivers/thermal/msm_thermal-dev.c
+++ b/drivers/thermal/msm_thermal-dev.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, 2016 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
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index eaa87cf..e2f63a2 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -430,7 +430,7 @@
func->name ? func->name : "");
func->func_wakeup_pending = true;
ret = 0;
- } else if (ret < 0) {
+ } else if (ret < 0 && ret != -ENOTSUPP) {
ERROR(func->config->cdev,
"Failed to wake function %s from suspend state. ret=%d. Canceling USB request.\n",
func->name ? func->name : "", ret);
@@ -1915,7 +1915,7 @@
"Function wakeup for %s could not complete due to suspend state.\n",
f->name ? f->name : "");
break;
- } else {
+ } else if (ret != -ENOTSUPP) {
ERROR(f->config->cdev,
"Failed to wake function %s from suspend state. ret=%d. Canceling USB request.\n",
f->name ? f->name : "",
diff --git a/drivers/usb/gadget/f_serial.c b/drivers/usb/gadget/f_serial.c
index 7190194..c51c5b8 100644
--- a/drivers/usb/gadget/f_serial.c
+++ b/drivers/usb/gadget/f_serial.c
@@ -1358,6 +1358,13 @@
smd_port_num =
gserial_ports[gser->port_num].client_port_num;
+ if (smd_write_arg.size > GSERIAL_BUF_LEN) {
+ pr_err("%s: Invalid size:%u, max: %u", __func__,
+ smd_write_arg.size, GSERIAL_BUF_LEN);
+ ret = -EINVAL;
+ break;
+ }
+
pr_debug("%s: Copying %d bytes from user buffer to local\n",
__func__, smd_write_arg.size);
diff --git a/drivers/video/msm/mdss/Makefile b/drivers/video/msm/mdss/Makefile
index 0c14e8b..de19866 100644
--- a/drivers/video/msm/mdss/Makefile
+++ b/drivers/video/msm/mdss/Makefile
@@ -1,3 +1,5 @@
+ccflags-y += -I$(src)
+
mdss-mdp3-objs = mdp3.o mdp3_dma.o mdp3_ctrl.o dsi_status_v2.o
mdss-mdp3-objs += mdp3_ppp.o mdp3_ppp_hwio.o mdp3_ppp_data.o
obj-$(CONFIG_FB_MSM_MDSS_MDP3) += mdss-mdp3.o
diff --git a/drivers/video/msm/mdss/dsi_status_6g.c b/drivers/video/msm/mdss/dsi_status_6g.c
index bb16d8f..6d9986c 100644
--- a/drivers/video/msm/mdss/dsi_status_6g.c
+++ b/drivers/video/msm/mdss/dsi_status_6g.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2015, 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
diff --git a/drivers/video/msm/mdss/dsi_v2.c b/drivers/video/msm/mdss/dsi_v2.c
index e364859..ea20432 100644
--- a/drivers/video/msm/mdss/dsi_v2.c
+++ b/drivers/video/msm/mdss/dsi_v2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2015, 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
@@ -333,7 +333,7 @@
__func__, rc);
goto error;
}
- mp->vreg_config[i].enable_load = tmp;
+ mp->vreg_config[i].load[DSS_REG_MODE_ENABLE] = tmp;
/* disable-load */
rc = of_property_read_u32(supply_node,
@@ -343,7 +343,7 @@
__func__, rc);
goto error;
}
- mp->vreg_config[i].disable_load = tmp;
+ mp->vreg_config[i].load[DSS_REG_MODE_DISABLE] = tmp;
/* pre-sleep */
rc = of_property_read_u32(supply_node,
@@ -392,8 +392,8 @@
mp->vreg_config[i].vreg_name,
mp->vreg_config[i].min_voltage,
mp->vreg_config[i].max_voltage,
- mp->vreg_config[i].enable_load,
- mp->vreg_config[i].disable_load,
+ mp->vreg_config[i].load[DSS_REG_MODE_ENABLE],
+ mp->vreg_config[i].load[DSS_REG_MODE_DISABLE],
mp->vreg_config[i].pre_on_sleep,
mp->vreg_config[i].post_on_sleep,
mp->vreg_config[i].pre_off_sleep,
diff --git a/drivers/video/msm/mdss/mdss_debug.c b/drivers/video/msm/mdss/mdss_debug.c
index 8778aff..dabc726 100644
--- a/drivers/video/msm/mdss/mdss_debug.c
+++ b/drivers/video/msm/mdss/mdss_debug.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2009-2016, 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
@@ -90,7 +90,7 @@
{
struct mdss_debug_base *dbg = file->private_data;
int len = 0;
- char buf[24];
+ char buf[24] = {'\0'};
if (!dbg)
return -ENODEV;
@@ -99,10 +99,10 @@
return 0; /* the end */
len = snprintf(buf, sizeof(buf), "0x%08zx %zx\n", dbg->off, dbg->cnt);
- if (len < 0)
+ if (len < 0 || len >= sizeof(buf))
return 0;
- if (copy_to_user(buff, buf, len))
+ if ((count < sizeof(buf)) || copy_to_user(buff, buf, len))
return -EFAULT;
*ppos += len; /* increase offset */
@@ -333,7 +333,7 @@
{
struct mdss_fudge_factor *factor = file->private_data;
int len = 0;
- char buf[32];
+ char buf[32] = {'\0'};
if (!factor)
return -ENODEV;
@@ -343,10 +343,10 @@
len = snprintf(buf, sizeof(buf), "%d/%d\n",
factor->numer, factor->denom);
- if (len < 0)
+ if (len < 0 || len >= sizeof(buf))
return 0;
- if (copy_to_user(buff, buf, len))
+ if ((count < sizeof(buf)) || copy_to_user(buff, buf, len))
return -EFAULT;
*ppos += len; /* increase offset */
@@ -377,6 +377,8 @@
if (copy_from_user(buf, user_buf, count))
return -EFAULT;
+ buf[count] = 0; /* end of string */
+
if (sscanf(buf, "%d", &perf_mode) != 1)
return -EFAULT;
@@ -397,7 +399,7 @@
{
struct mdss_perf_tune *perf_tune = file->private_data;
int len = 0;
- char buf[40];
+ char buf[40] = {'\0'};
if (!perf_tune)
return -ENODEV;
@@ -405,14 +407,12 @@
if (*ppos)
return 0; /* the end */
- buf[count] = 0;
-
len = snprintf(buf, sizeof(buf), "min_mdp_clk %lu min_bus_vote %llu\n",
perf_tune->min_mdp_clk, perf_tune->min_bus_vote);
- if (len < 0)
+ if (len < 0 || len >= sizeof(buf))
return 0;
- if (copy_to_user(buff, buf, len))
+ if ((count < sizeof(buf)) || copy_to_user(buff, buf, len))
return -EFAULT;
*ppos += len; /* increase offset */
@@ -432,7 +432,7 @@
{
struct mdss_data_type *mdata = file->private_data;
int len = 0;
- char buf[40];
+ char buf[40] = {'\0'};
if (!mdata)
return -ENODEV;
@@ -442,10 +442,10 @@
len = snprintf(buf, sizeof(buf), "%d\n",
!mdata->has_panic_ctrl);
- if (len < 0)
+ if (len < 0 || len >= sizeof(buf))
return 0;
- if (copy_to_user(buff, buf, len))
+ if ((count < sizeof(buf)) || copy_to_user(buff, buf, len))
return -EFAULT;
*ppos += len; /* increase offset */
@@ -508,9 +508,14 @@
if (!mdata)
return -EFAULT;
+ if (count >= sizeof(buf))
+ return -EFAULT;
+
if (copy_from_user(buf, user_buf, count))
return -EFAULT;
+ buf[count] = 0; /* end of string */
+
if (sscanf(buf, "%d", &disable_panic) != 1)
return -EFAULT;
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
index b8a49dd..c12a52e 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2015, 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
@@ -192,11 +192,56 @@
return 0;
}
-static int mdss_dsi_panel_power_ctrl(struct mdss_panel_data *pdata,
- int power_state)
+static int mdss_dsi_panel_power_ulp(struct mdss_panel_data *pdata,
+ int enable)
+{
+ int ret = 0, i;
+ struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+ u32 mode = enable ? DSS_REG_MODE_ULP : DSS_REG_MODE_ENABLE;
+
+ pr_debug("%s: +\n", __func__);
+ if (pdata == NULL) {
+ pr_err("%s: Invalid input data\n", __func__);
+ return -EINVAL;
+ }
+
+ ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+ panel_data);
+
+ for (i = 0; i < DSI_MAX_PM; i++) {
+ /*
+ * Core power module need to be controlled along with
+ * DSI core clocks.
+ */
+ if (DSI_CORE_PM == i)
+ continue;
+ ret = msm_dss_config_vreg_opt_mode(
+ ctrl_pdata->power_data[i].vreg_config,
+ ctrl_pdata->power_data[i].num_vreg, mode);
+ if (ret) {
+ pr_err("%s: failed to config lp opt mode for %s.rc=%d\n",
+ __func__, __mdss_dsi_pm_name(i), ret);
+ goto error;
+ }
+ }
+
+error:
+ if (ret) {
+ mode = enable ? DSS_REG_MODE_ENABLE : DSS_REG_MODE_ULP;
+ for (; i >= 0; i--)
+ msm_dss_config_vreg_opt_mode(
+ ctrl_pdata->power_data[i].vreg_config,
+ ctrl_pdata->power_data[i].num_vreg, mode);
+ }
+ pr_debug("%s: -\n", __func__);
+ return ret;
+}
+
+int mdss_dsi_panel_power_ctrl(struct mdss_panel_data *pdata, int power_state)
{
int ret;
struct mdss_panel_info *pinfo;
+ struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
if (pdata == NULL) {
pr_err("%s: Invalid input data\n", __func__);
@@ -204,7 +249,8 @@
}
pinfo = &pdata->panel_info;
- pr_debug("%s: cur_power_state=%d req_power_state=%d\n", __func__,
+ pr_debug("%pS-->%s: cur_power_state=%d req_power_state=%d\n",
+ __builtin_return_address(0), __func__,
pinfo->panel_power_state, power_state);
if (pinfo->panel_power_state == power_state) {
@@ -212,6 +258,9 @@
return 0;
}
+ ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+ panel_data);
+
/*
* If a dynamic mode switch is pending, the regulators should not
* be turned off or on.
@@ -224,14 +273,29 @@
ret = mdss_dsi_panel_power_off(pdata);
break;
case MDSS_PANEL_POWER_ON:
- if (mdss_dsi_is_panel_on_lp(pdata))
+ if (mdss_dsi_is_panel_on_ulp(pdata))
+ ret = mdss_dsi_panel_power_ulp(pdata, false);
+ else if (mdss_dsi_is_panel_on_lp(pdata))
ret = mdss_dsi_panel_power_lp(pdata, false);
else
ret = mdss_dsi_panel_power_on(pdata);
break;
case MDSS_PANEL_POWER_LP1:
+ if (mdss_dsi_is_panel_on_ulp(pdata))
+ ret = mdss_dsi_panel_power_ulp(pdata, false);
+ else
+ ret = mdss_dsi_panel_power_lp(pdata, true);
+ /*
+ * temp workaround until framework issues pertaining to LP2
+ * power state transitions are fixed. For now, we internally
+ * transition to LP2 state whenever core power is turned off
+ * in LP1 state
+ */
case MDSS_PANEL_POWER_LP2:
- ret = mdss_dsi_panel_power_lp(pdata, true);
+ if (!ctrl_pdata->core_power) {
+ power_state = MDSS_PANEL_POWER_LP2;
+ ret = mdss_dsi_panel_power_ulp(pdata, true);
+ }
break;
default:
pr_err("%s: unknown panel power state requested (%d)\n",
@@ -344,7 +408,7 @@
__func__, rc);
goto error;
}
- mp->vreg_config[i].enable_load = tmp;
+ mp->vreg_config[i].load[DSS_REG_MODE_ENABLE] = tmp;
/* disable-load */
rc = of_property_read_u32(supply_node,
@@ -354,7 +418,20 @@
__func__, rc);
goto error;
}
- mp->vreg_config[i].disable_load = tmp;
+ mp->vreg_config[i].load[DSS_REG_MODE_DISABLE] = tmp;
+
+ /* ulp-load */
+ rc = of_property_read_u32(supply_node,
+ "qcom,supply-ulp-load", &tmp);
+ if (rc) {
+ pr_debug("%s: error reading disable load. rc=%d\n",
+ __func__, rc);
+ rc = 0;
+ } else {
+ pr_debug("%s: ulp_load for %s=%d\n", __func__,
+ mp->vreg_config[i].vreg_name, tmp);
+ mp->vreg_config[i].load[DSS_REG_MODE_ULP] = tmp;
+ }
/* pre-sleep */
rc = of_property_read_u32(supply_node,
@@ -403,8 +480,8 @@
mp->vreg_config[i].vreg_name,
mp->vreg_config[i].min_voltage,
mp->vreg_config[i].max_voltage,
- mp->vreg_config[i].enable_load,
- mp->vreg_config[i].disable_load,
+ mp->vreg_config[i].load[DSS_REG_MODE_ENABLE],
+ mp->vreg_config[i].load[DSS_REG_MODE_DISABLE],
mp->vreg_config[i].pre_on_sleep,
mp->vreg_config[i].post_on_sleep,
mp->vreg_config[i].pre_off_sleep,
diff --git a/drivers/video/msm/mdss/mdss_dsi.h b/drivers/video/msm/mdss/mdss_dsi.h
index 794c7aa6..b1c5b38 100644
--- a/drivers/video/msm/mdss/mdss_dsi.h
+++ b/drivers/video/msm/mdss/mdss_dsi.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2015, 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
@@ -467,6 +467,7 @@
bool __mdss_dsi_clk_enabled(struct mdss_dsi_ctrl_pdata *ctrl, u8 clk_type);
void mdss_dsi_ctrl_setup(struct mdss_dsi_ctrl_pdata *ctrl);
void mdss_dsi_dln0_phy_err(struct mdss_dsi_ctrl_pdata *ctrl);
+int mdss_dsi_panel_power_ctrl(struct mdss_panel_data *pdata, int power_state);
int mdss_dsi_panel_init(struct device_node *node,
struct mdss_dsi_ctrl_pdata *ctrl_pdata,
@@ -560,6 +561,11 @@
return mdss_panel_is_power_on_lp(pdata->panel_info.panel_power_state);
}
+static inline bool mdss_dsi_is_panel_on_ulp(struct mdss_panel_data *pdata)
+{
+ return mdss_panel_is_power_on_ulp(pdata->panel_info.panel_power_state);
+}
+
static inline bool mdss_dsi_ulps_feature_enabled(
struct mdss_panel_data *pdata)
{
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
index 5146e4d..c73941a 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2015, 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
@@ -3743,7 +3743,7 @@
__func__, hdmi_tx_pm_name(module_type), rc);
goto error;
}
- mp->vreg_config[j].enable_load = val_array[i];
+ mp->vreg_config[j].load[DSS_REG_MODE_ENABLE] = val_array[i];
memset(val_array, 0, sizeof(u32) * dt_vreg_total);
rc = of_property_read_u32_array(of_node,
@@ -3754,15 +3754,15 @@
__func__, hdmi_tx_pm_name(module_type), rc);
goto error;
}
- mp->vreg_config[j].disable_load = val_array[i];
+ mp->vreg_config[j].load[DSS_REG_MODE_DISABLE] = val_array[i];
DEV_DBG("%s: %s min=%d, max=%d, enable=%d disable=%d\n",
__func__,
mp->vreg_config[j].vreg_name,
mp->vreg_config[j].min_voltage,
mp->vreg_config[j].max_voltage,
- mp->vreg_config[j].enable_load,
- mp->vreg_config[j].disable_load);
+ mp->vreg_config[j].load[DSS_REG_MODE_ENABLE],
+ mp->vreg_config[j].load[DSS_REG_MODE_DISABLE]);
ndx_mask >>= 1;
j++;
diff --git a/drivers/video/msm/mdss/mdss_io_util.c b/drivers/video/msm/mdss/mdss_io_util.c
index 849bf1d3..084bc64 100644
--- a/drivers/video/msm/mdss/mdss_io_util.c
+++ b/drivers/video/msm/mdss/mdss_io_util.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2015, 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
@@ -208,6 +208,52 @@
} /* msm_dss_config_vreg */
EXPORT_SYMBOL(msm_dss_config_vreg);
+int msm_dss_config_vreg_opt_mode(struct dss_vreg *in_vreg, int num_vreg,
+ enum dss_vreg_mode mode)
+{
+ int i = 0, rc = 0;
+
+ if (mode >= DSS_REG_MODE_MAX) {
+ pr_err("%pS->%s: invalid mode %d\n",
+ __builtin_return_address(0), __func__, mode);
+ rc = -EINVAL;
+ goto error;
+ }
+
+ for (i = 0; i < num_vreg; i++) {
+ rc = PTR_RET(in_vreg[i].vreg);
+ if (rc) {
+ DEV_ERR("%pS->%s: %s regulator error. rc=%d\n",
+ __builtin_return_address(0), __func__,
+ in_vreg[i].vreg_name, rc);
+ goto error;
+ }
+
+ DEV_DBG("%s: Setting optimum mode %d for %s (load=%d)\n",
+ __func__, mode, in_vreg[i].vreg_name,
+ in_vreg[i].load[mode]);
+ rc = regulator_set_optimum_mode(in_vreg[i].vreg,
+ in_vreg[i].load[mode]);
+ if (rc < 0) {
+ DEV_ERR("%pS->%s: %s set opt mode failed. rc=%d\n",
+ __builtin_return_address(0), __func__,
+ in_vreg[i].vreg_name, rc);
+ goto error;
+ } else {
+ /*
+ * regulator_set_optimum_mode can return non-zero
+ * value for success. However, this API is expected
+ * to return 0 for success.
+ */
+ rc = 0;
+ }
+ }
+
+error:
+ return rc;
+}
+EXPORT_SYMBOL(msm_dss_config_vreg_opt_mode);
+
int msm_dss_enable_vreg(struct dss_vreg *in_vreg, int num_vreg, int enable)
{
int i = 0, rc = 0;
@@ -223,7 +269,7 @@
if (in_vreg[i].pre_on_sleep)
msleep(in_vreg[i].pre_on_sleep);
rc = regulator_set_optimum_mode(in_vreg[i].vreg,
- in_vreg[i].enable_load);
+ in_vreg[i].load[DSS_REG_MODE_ENABLE]);
if (rc < 0) {
DEV_ERR("%pS->%s: %s set opt m fail\n",
__builtin_return_address(0), __func__,
@@ -246,7 +292,7 @@
if (in_vreg[i].pre_off_sleep)
msleep(in_vreg[i].pre_off_sleep);
regulator_set_optimum_mode(in_vreg[i].vreg,
- in_vreg[i].disable_load);
+ in_vreg[i].load[DSS_REG_MODE_DISABLE]);
regulator_disable(in_vreg[i].vreg);
if (in_vreg[i].post_off_sleep)
msleep(in_vreg[i].post_off_sleep);
@@ -255,14 +301,15 @@
return rc;
disable_vreg:
- regulator_set_optimum_mode(in_vreg[i].vreg, in_vreg[i].disable_load);
+ regulator_set_optimum_mode(in_vreg[i].vreg,
+ in_vreg[i].load[DSS_REG_MODE_DISABLE]);
vreg_set_opt_mode_fail:
for (i--; i >= 0; i--) {
if (in_vreg[i].pre_off_sleep)
msleep(in_vreg[i].pre_off_sleep);
regulator_set_optimum_mode(in_vreg[i].vreg,
- in_vreg[i].disable_load);
+ in_vreg[i].load[DSS_REG_MODE_DISABLE]);
regulator_disable(in_vreg[i].vreg);
if (in_vreg[i].post_off_sleep)
msleep(in_vreg[i].post_off_sleep);
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
index 2940604..c68a5d4 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
@@ -324,6 +324,7 @@
{
struct mdss_mdp_cmd_ctx *ctx = data;
unsigned long flags;
+ bool notify_frame_timeout = false;
if (!data) {
pr_err("%s: invalid ctx\n", __func__);
@@ -341,8 +342,12 @@
mdss_mdp_irq_disable_nosync(MDSS_MDP_IRQ_PING_PONG_COMP,
ctx->pp_num);
complete_all(&ctx->pp_comp);
+ notify_frame_timeout = true;
}
spin_unlock_irqrestore(&ctx->koff_lock, flags);
+
+ if (notify_frame_timeout)
+ mdss_mdp_ctl_notify(ctx->ctl, MDP_NOTIFY_FRAME_TIMEOUT);
}
static void mdss_mdp_cmd_pingpong_done(void *arg)
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index 6b44afc..7240021 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2016, 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
@@ -2040,18 +2040,27 @@
int mdss_mdp_overlay_vsync_ctrl(struct msm_fb_data_type *mfd, int en)
{
+ struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
int rc;
if (!ctl)
return -ENODEV;
- if (!ctl->add_vsync_handler || !ctl->remove_vsync_handler)
- return -EOPNOTSUPP;
+
+ mutex_lock(&mdp5_data->ov_lock);
+ if (!ctl->add_vsync_handler || !ctl->remove_vsync_handler) {
+ rc = -EOPNOTSUPP;
+ pr_err_once("fb%d vsync handlers are not registered\n",
+ mfd->index);
+ goto end;
+ }
+
if (!ctl->panel_data->panel_info.cont_splash_enabled
&& !mdss_mdp_ctl_is_power_on(ctl)) {
- pr_debug("fb%d vsync pending first update en=%d\n",
- mfd->index, en);
- return -EPERM;
+ pr_debug("fb%d vsync pending first update en=%d, ctl power state:%d\n",
+ mfd->index, en, ctl->power_state);
+ rc = -EPERM;
+ goto end;
}
pr_debug("fb%d vsync en=%d\n", mfd->index, en);
@@ -2063,6 +2072,8 @@
rc = ctl->remove_vsync_handler(ctl, &ctl->vsync_handler);
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
+end:
+ mutex_unlock(&mdp5_data->ov_lock);
return rc;
}
diff --git a/drivers/video/msm/mdss/msm_mdss_io_8974.c b/drivers/video/msm/mdss/msm_mdss_io_8974.c
index 668f2cb..8ab4b3e 100644
--- a/drivers/video/msm/mdss/msm_mdss_io_8974.c
+++ b/drivers/video/msm/mdss/msm_mdss_io_8974.c
@@ -1098,6 +1098,15 @@
ctrl->core_power = true;
}
+ /*
+ * temp workaround until framework issues pertaining to LP2
+ * power state transitions are fixed. For now, if we intend to
+ * send a frame update when in LP1, we have to explicitly exit
+ * LP2 state here
+ */
+ if (mdss_dsi_is_panel_on_ulp(pdata))
+ mdss_dsi_panel_power_ctrl(pdata, MDSS_PANEL_POWER_LP1);
+
rc = mdss_dsi_bus_clk_start(ctrl);
if (rc) {
pr_err("%s: Failed to start bus clocks. rc=%d\n",
@@ -1184,6 +1193,15 @@
ctrl->core_power = false;
}
}
+
+ /*
+ * temp workaround until framework issues pertaining to LP2
+ * power state transitions are fixed. For now, we internally
+ * transition to LP2 state whenever core power is turned off
+ * in LP1 state
+ */
+ if (mdss_dsi_is_panel_on_lp(pdata))
+ mdss_dsi_panel_power_ctrl(pdata, MDSS_PANEL_POWER_LP2);
}
return rc;
diff --git a/drivers/video/msm/vidc/common/dec/vdec.c b/drivers/video/msm/vidc/common/dec/vdec.c
new file mode 100755
index 0000000..0958e07
--- /dev/null
+++ b/drivers/video/msm/vidc/common/dec/vdec.c
@@ -0,0 +1,2709 @@
+/* Copyright (c) 2010-2013, 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/cdev.h>
+#include <linux/device.h>
+#include <linux/firmware.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/uaccess.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+
+#include <linux/clk.h>
+#include <linux/timer.h>
+#include <media/msm/vidc_type.h>
+#include <media/msm/vcd_api.h>
+#include <media/msm/vidc_init.h>
+#include <mach/iommu_domains.h>
+#include "vcd_res_tracker_api.h"
+#include "vdec_internal.h"
+
+
+
+#define DBG(x...) pr_debug(x)
+#define INFO(x...) pr_info(x)
+#define ERR(x...) pr_err(x)
+
+#define VID_DEC_NAME "msm_vidc_dec"
+#ifdef KW_TAINT_ANALYSIS 51
+ extern void * get_tainted_stuff();
+#endif
+static char *node_name[2] = {"", "_sec"};
+static struct vid_dec_dev *vid_dec_device_p;
+static dev_t vid_dec_dev_num;
+static struct class *vid_dec_class;
+
+static s32 vid_dec_get_empty_client_index(void)
+{
+ u32 i, found = false;
+
+ for (i = 0; i < VIDC_MAX_NUM_CLIENTS; i++) {
+ if (!vid_dec_device_p->vdec_clients[i].vcd_handle) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ ERR("%s():ERROR No space for new client\n", __func__);
+ return -ENOMEM;
+ } else {
+ DBG("%s(): available client index = %u\n", __func__, i);
+ return i;
+ }
+}
+
+u32 vid_dec_get_status(u32 status)
+{
+ u32 vdec_status;
+
+ switch (status) {
+ case VCD_ERR_SEQHDR_PARSE_FAIL:
+ case VCD_ERR_BITSTREAM_ERR:
+ vdec_status = VDEC_S_INPUT_BITSTREAM_ERR;
+ break;
+ case VCD_S_SUCCESS:
+ vdec_status = VDEC_S_SUCCESS;
+ break;
+ case VCD_ERR_FAIL:
+ vdec_status = VDEC_S_EFAIL;
+ break;
+ case VCD_ERR_ALLOC_FAIL:
+ vdec_status = VDEC_S_ENOSWRES;
+ break;
+ case VCD_ERR_ILLEGAL_OP:
+ vdec_status = VDEC_S_EINVALCMD;
+ break;
+ case VCD_ERR_ILLEGAL_PARM:
+ vdec_status = VDEC_S_EBADPARAM;
+ break;
+ case VCD_ERR_BAD_POINTER:
+ case VCD_ERR_BAD_HANDLE:
+ vdec_status = VDEC_S_EFATAL;
+ break;
+ case VCD_ERR_NOT_SUPPORTED:
+ vdec_status = VDEC_S_ENOTSUPP;
+ break;
+ case VCD_ERR_BAD_STATE:
+ vdec_status = VDEC_S_EINVALSTATE;
+ break;
+ case VCD_ERR_BUSY:
+ vdec_status = VDEC_S_BUSY;
+ break;
+ case VCD_ERR_MAX_CLIENT:
+ vdec_status = VDEC_S_ENOHWRES;
+ break;
+ default:
+ vdec_status = VDEC_S_EFAIL;
+ break;
+ }
+
+ return vdec_status;
+}
+
+static void vid_dec_notify_client(struct video_client_ctx *client_ctx)
+{
+ if (client_ctx)
+ complete(&client_ctx->event);
+}
+
+void vid_dec_vcd_open_done(struct video_client_ctx *client_ctx,
+ struct vcd_handle_container *handle_container)
+{
+ DBG("vid_dec_vcd_open_done\n");
+
+ if (client_ctx) {
+ if (handle_container)
+ client_ctx->vcd_handle = handle_container->handle;
+ else
+ ERR("%s(): ERROR. handle_container is NULL\n",
+ __func__);
+
+ vid_dec_notify_client(client_ctx);
+ } else
+ ERR("%s(): ERROR. client_ctx is NULL\n", __func__);
+}
+
+static void vid_dec_handle_field_drop(struct video_client_ctx *client_ctx,
+ u32 event, u32 status, int64_t time_stamp)
+{
+ struct vid_dec_msg *vdec_msg;
+
+ if (!client_ctx) {
+ ERR("%s() NULL pointer\n", __func__);
+ return;
+ }
+
+ vdec_msg = kzalloc(sizeof(struct vid_dec_msg), GFP_KERNEL);
+ if (!vdec_msg) {
+ ERR("%s(): cannot allocate vid_dec_msg "
+ " buffer\n", __func__);
+ return;
+ }
+ vdec_msg->vdec_msg_info.status_code = vid_dec_get_status(status);
+ if (event == VCD_EVT_IND_INFO_FIELD_DROPPED) {
+ vdec_msg->vdec_msg_info.msgcode =
+ VDEC_MSG_EVT_INFO_FIELD_DROPPED;
+ vdec_msg->vdec_msg_info.msgdata.output_frame.time_stamp
+ = time_stamp;
+ DBG("Send FIELD_DROPPED message to client = %p\n", client_ctx);
+ } else {
+ ERR("vid_dec_input_frame_done(): invalid event type: "
+ "%d\n", event);
+ vdec_msg->vdec_msg_info.msgcode = VDEC_MSG_INVALID;
+ }
+ vdec_msg->vdec_msg_info.msgdatasize =
+ sizeof(struct vdec_output_frameinfo);
+ mutex_lock(&client_ctx->msg_queue_lock);
+ list_add_tail(&vdec_msg->list, &client_ctx->msg_queue);
+ mutex_unlock(&client_ctx->msg_queue_lock);
+ wake_up(&client_ctx->msg_wait);
+}
+
+static void vid_dec_input_frame_done(struct video_client_ctx *client_ctx,
+ u32 event, u32 status,
+ struct vcd_frame_data *vcd_frame_data)
+{
+ struct vid_dec_msg *vdec_msg;
+
+ if (!client_ctx || !vcd_frame_data) {
+ ERR("vid_dec_input_frame_done() NULL pointer\n");
+ return;
+ }
+
+ kfree(vcd_frame_data->desc_buf);
+ vcd_frame_data->desc_buf = NULL;
+ vcd_frame_data->desc_size = 0;
+
+ vdec_msg = kzalloc(sizeof(struct vid_dec_msg), GFP_KERNEL);
+ if (!vdec_msg) {
+ ERR("vid_dec_input_frame_done(): cannot allocate vid_dec_msg "
+ " buffer\n");
+ return;
+ }
+
+ vdec_msg->vdec_msg_info.status_code = vid_dec_get_status(status);
+
+ if (event == VCD_EVT_RESP_INPUT_DONE) {
+ vdec_msg->vdec_msg_info.msgcode =
+ VDEC_MSG_RESP_INPUT_BUFFER_DONE;
+ DBG("Send INPUT_DON message to client = %p\n", client_ctx);
+
+ } else if (event == VCD_EVT_RESP_INPUT_FLUSHED) {
+ vdec_msg->vdec_msg_info.msgcode = VDEC_MSG_RESP_INPUT_FLUSHED;
+ DBG("Send INPUT_FLUSHED message to client = %p\n", client_ctx);
+ } else {
+ ERR("vid_dec_input_frame_done(): invalid event type: "
+ "%d\n", event);
+ vdec_msg->vdec_msg_info.msgcode = VDEC_MSG_INVALID;
+ }
+
+ vdec_msg->vdec_msg_info.msgdata.input_frame_clientdata =
+ (void *)vcd_frame_data->frm_clnt_data;
+ vdec_msg->vdec_msg_info.msgdatasize = sizeof(void *);
+
+ mutex_lock(&client_ctx->msg_queue_lock);
+ list_add_tail(&vdec_msg->list, &client_ctx->msg_queue);
+ mutex_unlock(&client_ctx->msg_queue_lock);
+ wake_up(&client_ctx->msg_wait);
+}
+
+static void vid_dec_output_frame_done(struct video_client_ctx *client_ctx,
+ u32 event, u32 status,
+ struct vcd_frame_data *vcd_frame_data)
+{
+ struct vid_dec_msg *vdec_msg;
+
+ unsigned long kernel_vaddr = 0, phy_addr = 0, user_vaddr = 0;
+ int pmem_fd;
+ struct file *file;
+ s32 buffer_index = -1;
+ enum vdec_picture pic_type;
+ u32 ion_flag = 0;
+ struct ion_handle *buff_handle = NULL;
+ struct vdec_output_frameinfo *output_frame;
+
+ if (!client_ctx || !vcd_frame_data) {
+ ERR("vid_dec_input_frame_done() NULL pointer\n");
+ return;
+ }
+
+ vdec_msg = kzalloc(sizeof(struct vid_dec_msg), GFP_KERNEL);
+ if (!vdec_msg) {
+ ERR("vid_dec_input_frame_done(): cannot allocate vid_dec_msg "
+ " buffer\n");
+ return;
+ }
+
+ vdec_msg->vdec_msg_info.status_code = vid_dec_get_status(status);
+
+ if (event == VCD_EVT_RESP_OUTPUT_DONE)
+ vdec_msg->vdec_msg_info.msgcode =
+ VDEC_MSG_RESP_OUTPUT_BUFFER_DONE;
+ else if (event == VCD_EVT_RESP_OUTPUT_FLUSHED)
+ vdec_msg->vdec_msg_info.msgcode = VDEC_MSG_RESP_OUTPUT_FLUSHED;
+ else {
+ ERR("QVD: vid_dec_output_frame_done invalid cmd type: "
+ "%d\n", event);
+ vdec_msg->vdec_msg_info.msgcode = VDEC_MSG_INVALID;
+ }
+
+ kernel_vaddr = (unsigned long)vcd_frame_data->virtual;
+
+ if (vidc_lookup_addr_table(client_ctx, BUFFER_TYPE_OUTPUT,
+ false, &user_vaddr, &kernel_vaddr,
+ &phy_addr, &pmem_fd, &file,
+ &buffer_index) ||
+ (vcd_frame_data->flags & VCD_FRAME_FLAG_EOS)) {
+
+ if (res_trk_check_for_sec_session() &&
+ event == VCD_EVT_RESP_OUTPUT_DONE) {
+ DBG("Buffer Index = %d", buffer_index);
+ if (buffer_index != -1) {
+ if (client_ctx->meta_addr_table[buffer_index].
+ kernel_vir_addr_iommu &&
+ client_ctx->
+ meta_addr_table[buffer_index].
+ kernel_vir_addr) {
+
+ memcpy(client_ctx->
+ meta_addr_table[buffer_index].
+ kernel_vir_addr_iommu,
+ client_ctx->
+ meta_addr_table[buffer_index].
+ kernel_vir_addr,
+ client_ctx->meta_buf_size);
+ DBG("Copying Meta Buffer from "\
+ "secure memory"
+ "kernel_virt_iommu = %p "
+ "kernel_virt = %p",
+ client_ctx->
+ meta_addr_table[buffer_index].
+ kernel_vir_addr_iommu,
+ client_ctx->
+ meta_addr_table[buffer_index].
+ kernel_vir_addr);
+ }
+ }
+ }
+
+ /* Buffer address in user space */
+ vdec_msg->vdec_msg_info.msgdata.output_frame.bufferaddr =
+ (u8 *) user_vaddr;
+ /* Data length */
+ vdec_msg->vdec_msg_info.msgdata.output_frame.len =
+ vcd_frame_data->data_len;
+ vdec_msg->vdec_msg_info.msgdata.output_frame.flags =
+ vcd_frame_data->flags;
+ /* Timestamp pass-through from input frame */
+ vdec_msg->vdec_msg_info.msgdata.output_frame.time_stamp =
+ vcd_frame_data->time_stamp;
+ /* Output frame client data */
+ vdec_msg->vdec_msg_info.msgdata.output_frame.client_data =
+ (void *)vcd_frame_data->frm_clnt_data;
+ /* Associated input frame client data */
+ vdec_msg->vdec_msg_info.msgdata.output_frame.
+ input_frame_clientdata =
+ (void *)vcd_frame_data->ip_frm_tag;
+ /* Decoded picture width and height */
+ vdec_msg->vdec_msg_info.msgdata.output_frame.framesize.
+ bottom =
+ vcd_frame_data->dec_op_prop.disp_frm.bottom;
+ vdec_msg->vdec_msg_info.msgdata.output_frame.framesize.left =
+ vcd_frame_data->dec_op_prop.disp_frm.left;
+ vdec_msg->vdec_msg_info.msgdata.output_frame.framesize.right =
+ vcd_frame_data->dec_op_prop.disp_frm.right;
+ vdec_msg->vdec_msg_info.msgdata.output_frame.framesize.top =
+ vcd_frame_data->dec_op_prop.disp_frm.top;
+ if (vcd_frame_data->interlaced) {
+ vdec_msg->vdec_msg_info.msgdata.
+ output_frame.interlaced_format =
+ VDEC_InterlaceInterleaveFrameTopFieldFirst;
+ } else {
+ vdec_msg->vdec_msg_info.msgdata.
+ output_frame.interlaced_format =
+ VDEC_InterlaceFrameProgressive;
+ }
+ /* Decoded picture type */
+ switch (vcd_frame_data->frame) {
+ case VCD_FRAME_I:
+ pic_type = PICTURE_TYPE_I;
+ break;
+ case VCD_FRAME_P:
+ pic_type = PICTURE_TYPE_P;
+ break;
+ case VCD_FRAME_B:
+ pic_type = PICTURE_TYPE_B;
+ break;
+ case VCD_FRAME_NOTCODED:
+ pic_type = PICTURE_TYPE_SKIP;
+ break;
+ case VCD_FRAME_IDR:
+ pic_type = PICTURE_TYPE_IDR;
+ break;
+ default:
+ pic_type = PICTURE_TYPE_UNKNOWN;
+ }
+ vdec_msg->vdec_msg_info.msgdata.output_frame.pic_type =
+ pic_type;
+ output_frame = &vdec_msg->vdec_msg_info.msgdata.output_frame;
+ output_frame->aspect_ratio_info.aspect_ratio =
+ vcd_frame_data->aspect_ratio_info.aspect_ratio;
+ output_frame->aspect_ratio_info.par_width =
+ vcd_frame_data->aspect_ratio_info.par_width;
+ output_frame->aspect_ratio_info.par_height =
+ vcd_frame_data->aspect_ratio_info.par_height;
+ vdec_msg->vdec_msg_info.msgdatasize =
+ sizeof(struct vdec_output_frameinfo);
+ } else {
+ ERR("vid_dec_output_frame_done UVA can not be found\n");
+ vdec_msg->vdec_msg_info.status_code = VDEC_S_EFATAL;
+ }
+ if (vcd_frame_data->data_len > 0) {
+ ion_flag = vidc_get_fd_info(client_ctx, BUFFER_TYPE_OUTPUT,
+ pmem_fd, kernel_vaddr, buffer_index,
+ &buff_handle);
+ if (ion_flag == ION_FLAG_CACHED && buff_handle) {
+ DBG("%s: Cache invalidate: vaddr (%p), "\
+ "size %u\n", __func__,
+ (void *)kernel_vaddr,
+ vcd_frame_data->alloc_len);
+ msm_ion_do_cache_op(client_ctx->user_ion_client,
+ buff_handle,
+ (unsigned long *) kernel_vaddr,
+ (unsigned long)vcd_frame_data->\
+ alloc_len,
+ ION_IOC_INV_CACHES);
+ }
+ }
+ mutex_lock(&client_ctx->msg_queue_lock);
+ list_add_tail(&vdec_msg->list, &client_ctx->msg_queue);
+ mutex_unlock(&client_ctx->msg_queue_lock);
+ wake_up(&client_ctx->msg_wait);
+}
+
+static void vid_dec_lean_event(struct video_client_ctx *client_ctx,
+ u32 event, u32 status)
+{
+ struct vid_dec_msg *vdec_msg;
+
+ if (!client_ctx) {
+ ERR("%s(): !client_ctx pointer\n", __func__);
+ return;
+ }
+
+ vdec_msg = kzalloc(sizeof(struct vid_dec_msg), GFP_KERNEL);
+ if (!vdec_msg) {
+ ERR("%s(): cannot allocate vid_dec_msg buffer\n", __func__);
+ return;
+ }
+
+ vdec_msg->vdec_msg_info.status_code = vid_dec_get_status(status);
+
+ switch (event) {
+ case VCD_EVT_IND_OUTPUT_RECONFIG:
+ DBG("msm_vidc_dec: Sending VDEC_MSG_EVT_CONFIG_CHANGED"
+ " to client");
+ vdec_msg->vdec_msg_info.msgcode = VDEC_MSG_EVT_CONFIG_CHANGED;
+ break;
+ case VCD_EVT_IND_RESOURCES_LOST:
+ DBG("msm_vidc_dec: Sending VDEC_EVT_RESOURCES_LOST"
+ " to client");
+ vdec_msg->vdec_msg_info.msgcode = VDEC_EVT_RESOURCES_LOST;
+ break;
+ case VCD_EVT_RESP_FLUSH_INPUT_DONE:
+ DBG("msm_vidc_dec: Sending VDEC_MSG_RESP_FLUSH_INPUT_DONE"
+ " to client");
+ vdec_msg->vdec_msg_info.msgcode =
+ VDEC_MSG_RESP_FLUSH_INPUT_DONE;
+ break;
+ case VCD_EVT_RESP_FLUSH_OUTPUT_DONE:
+ DBG("msm_vidc_dec: Sending VDEC_MSG_RESP_FLUSH_OUTPUT_DONE"
+ " to client");
+ vdec_msg->vdec_msg_info.msgcode =
+ VDEC_MSG_RESP_FLUSH_OUTPUT_DONE;
+ break;
+ case VCD_EVT_IND_HWERRFATAL:
+ DBG("msm_vidc_dec: Sending VDEC_MSG_EVT_HW_ERROR"
+ " to client");
+ vdec_msg->vdec_msg_info.msgcode = VDEC_MSG_EVT_HW_ERROR;
+ break;
+ case VCD_EVT_RESP_START:
+ DBG("msm_vidc_dec: Sending VDEC_MSG_RESP_START_DONE"
+ " to client");
+ vdec_msg->vdec_msg_info.msgcode = VDEC_MSG_RESP_START_DONE;
+ break;
+ case VCD_EVT_RESP_STOP:
+ DBG("msm_vidc_dec: Sending VDEC_MSG_RESP_STOP_DONE"
+ " to client");
+ vdec_msg->vdec_msg_info.msgcode = VDEC_MSG_RESP_STOP_DONE;
+ break;
+ case VCD_EVT_RESP_PAUSE:
+ DBG("msm_vidc_dec: Sending VDEC_MSG_RESP_PAUSE_DONE"
+ " to client");
+ vdec_msg->vdec_msg_info.msgcode = VDEC_MSG_RESP_PAUSE_DONE;
+ break;
+ case VCD_EVT_IND_INFO_OUTPUT_RECONFIG:
+ DBG("msm_vidc_dec: Sending VDEC_MSG_EVT_INFO_CONFIG_CHANGED"
+ " to client");
+ vdec_msg->vdec_msg_info.msgcode =
+ VDEC_MSG_EVT_INFO_CONFIG_CHANGED;
+ break;
+ default:
+ ERR("%s() : unknown event type\n", __func__);
+ break;
+ }
+
+ vdec_msg->vdec_msg_info.msgdatasize = 0;
+ if (client_ctx->stop_sync_cb &&
+ (event == VCD_EVT_RESP_STOP || event == VCD_EVT_IND_HWERRFATAL)) {
+ client_ctx->stop_sync_cb = false;
+ complete(&client_ctx->event);
+ kfree(vdec_msg);
+ return;
+ }
+ mutex_lock(&client_ctx->msg_queue_lock);
+ list_add_tail(&vdec_msg->list, &client_ctx->msg_queue);
+ mutex_unlock(&client_ctx->msg_queue_lock);
+ wake_up(&client_ctx->msg_wait);
+}
+
+
+void vid_dec_vcd_cb(u32 event, u32 status,
+ void *info, size_t sz, void *handle, void *const client_data)
+{
+ struct video_client_ctx *client_ctx =
+ (struct video_client_ctx *)client_data;
+
+ DBG("Entering %s()\n", __func__);
+
+ if (!client_ctx) {
+ ERR("%s(): client_ctx is NULL\n", __func__);
+ return;
+ }
+
+ client_ctx->event_status = status;
+
+ switch (event) {
+ case VCD_EVT_RESP_OPEN:
+ vid_dec_vcd_open_done(client_ctx,
+ (struct vcd_handle_container *)
+ info);
+ break;
+ case VCD_EVT_RESP_INPUT_DONE:
+ case VCD_EVT_RESP_INPUT_FLUSHED:
+ vid_dec_input_frame_done(client_ctx, event, status,
+ (struct vcd_frame_data *)info);
+ break;
+ case VCD_EVT_IND_INFO_FIELD_DROPPED:
+ if (info)
+ vid_dec_handle_field_drop(client_ctx, event,
+ status, *((int64_t *)info));
+ else
+ pr_err("Wrong Payload for Field dropped\n");
+ break;
+ case VCD_EVT_RESP_OUTPUT_DONE:
+ case VCD_EVT_RESP_OUTPUT_FLUSHED:
+ vid_dec_output_frame_done(client_ctx, event, status,
+ (struct vcd_frame_data *)info);
+ break;
+ case VCD_EVT_RESP_PAUSE:
+ case VCD_EVT_RESP_STOP:
+ case VCD_EVT_RESP_FLUSH_INPUT_DONE:
+ case VCD_EVT_RESP_FLUSH_OUTPUT_DONE:
+ case VCD_EVT_IND_OUTPUT_RECONFIG:
+ case VCD_EVT_IND_HWERRFATAL:
+ case VCD_EVT_IND_RESOURCES_LOST:
+ case VCD_EVT_IND_INFO_OUTPUT_RECONFIG:
+ vid_dec_lean_event(client_ctx, event, status);
+ break;
+ case VCD_EVT_RESP_START:
+ if (!client_ctx->seq_header_set)
+ vid_dec_lean_event(client_ctx, event, status);
+ else
+ vid_dec_notify_client(client_ctx);
+ break;
+ default:
+ ERR("%s() : Error - Invalid event type =%u\n", __func__,
+ event);
+ break;
+ }
+}
+
+static u32 vid_dec_set_codec(struct video_client_ctx *client_ctx,
+ enum vdec_codec *vdec_codec)
+{
+ u32 result = true;
+ struct vcd_property_hdr vcd_property_hdr;
+ struct vcd_property_codec codec;
+ u32 vcd_status = VCD_ERR_FAIL;
+
+ if (!client_ctx || !vdec_codec)
+ return false;
+
+ vcd_property_hdr.prop_id = VCD_I_CODEC;
+ vcd_property_hdr.sz = sizeof(struct vcd_property_codec);
+
+ switch (*vdec_codec) {
+ case VDEC_CODECTYPE_MPEG4:
+ codec.codec = VCD_CODEC_MPEG4;
+ break;
+ case VDEC_CODECTYPE_H264:
+ codec.codec = VCD_CODEC_H264;
+ break;
+ case VDEC_CODECTYPE_DIVX_3:
+ codec.codec = VCD_CODEC_DIVX_3;
+ break;
+ case VDEC_CODECTYPE_DIVX_4:
+ codec.codec = VCD_CODEC_DIVX_4;
+ break;
+ case VDEC_CODECTYPE_DIVX_5:
+ codec.codec = VCD_CODEC_DIVX_5;
+ break;
+ case VDEC_CODECTYPE_DIVX_6:
+ codec.codec = VCD_CODEC_DIVX_6;
+ break;
+ case VDEC_CODECTYPE_XVID:
+ codec.codec = VCD_CODEC_XVID;
+ break;
+ case VDEC_CODECTYPE_H263:
+ codec.codec = VCD_CODEC_H263;
+ break;
+ case VDEC_CODECTYPE_MPEG2:
+ codec.codec = VCD_CODEC_MPEG2;
+ break;
+ case VDEC_CODECTYPE_VC1:
+ codec.codec = VCD_CODEC_VC1;
+ break;
+ case VDEC_CODECTYPE_VC1_RCV:
+ codec.codec = VCD_CODEC_VC1_RCV;
+ break;
+ default:
+ result = false;
+ break;
+ }
+
+ if (result) {
+ vcd_status = vcd_set_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, &codec);
+ if (vcd_status)
+ result = false;
+ }
+ return result;
+}
+
+static u32 vid_dec_set_output_format(struct video_client_ctx *client_ctx,
+ enum vdec_output_fromat *output_format)
+{
+ u32 result = true;
+ struct vcd_property_hdr vcd_property_hdr;
+ struct vcd_property_buffer_format vcd_prop_buffer_format;
+ u32 vcd_status = VCD_ERR_FAIL;
+
+ if (!client_ctx || !output_format)
+ return false;
+
+ vcd_property_hdr.prop_id = VCD_I_BUFFER_FORMAT;;
+ vcd_property_hdr.sz =
+ sizeof(struct vcd_property_buffer_format);
+
+ switch (*output_format) {
+ case VDEC_YUV_FORMAT_NV12:
+ vcd_prop_buffer_format.buffer_format = VCD_BUFFER_FORMAT_NV12;
+ break;
+ case VDEC_YUV_FORMAT_TILE_4x2:
+ vcd_prop_buffer_format.buffer_format =
+ VCD_BUFFER_FORMAT_TILE_4x2;
+ break;
+ default:
+ result = false;
+ break;
+ }
+
+ if (result)
+ vcd_status = vcd_set_property(client_ctx->vcd_handle,
+ &vcd_property_hdr,
+ &vcd_prop_buffer_format);
+
+ if (vcd_status)
+ return false;
+ else
+ return true;
+}
+
+static u32 vid_dec_set_frame_resolution(struct video_client_ctx *client_ctx,
+ struct vdec_picsize *video_resoultion)
+{
+ struct vcd_property_hdr vcd_property_hdr;
+ struct vcd_property_frame_size frame_resolution;
+ u32 vcd_status = VCD_ERR_FAIL;
+
+ if (!client_ctx || !video_resoultion)
+ return false;
+
+ vcd_property_hdr.prop_id = VCD_I_FRAME_SIZE;
+ vcd_property_hdr.sz = sizeof(struct vcd_property_frame_size);
+ frame_resolution.width = video_resoultion->frame_width;
+ frame_resolution.height = video_resoultion->frame_height;
+ frame_resolution.stride = video_resoultion->stride;
+ frame_resolution.scan_lines = video_resoultion->scan_lines;
+
+ vcd_status = vcd_set_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, &frame_resolution);
+
+ if (vcd_status)
+ return false;
+ else
+ return true;
+}
+
+static u32 vid_dec_set_turbo_clk(struct video_client_ctx *client_ctx)
+{
+ struct vcd_property_hdr vcd_property_hdr;
+ u32 vcd_status = VCD_ERR_FAIL;
+ u32 dummy = 0;
+
+ if (!client_ctx)
+ return false;
+ vcd_property_hdr.prop_id = VCD_I_SET_TURBO_CLK;
+ vcd_property_hdr.sz = sizeof(struct vcd_property_frame_size);
+
+ vcd_status = vcd_set_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, &dummy);
+
+ if (vcd_status)
+ return false;
+ else
+ return true;
+}
+
+static u32 vid_dec_get_frame_resolution(struct video_client_ctx *client_ctx,
+ struct vdec_picsize *video_resoultion)
+{
+ struct vcd_property_hdr vcd_property_hdr;
+ struct vcd_property_frame_size frame_resolution;
+ u32 vcd_status = VCD_ERR_FAIL;
+
+ if (!client_ctx || !video_resoultion)
+ return false;
+
+ vcd_property_hdr.prop_id = VCD_I_FRAME_SIZE;
+ vcd_property_hdr.sz = sizeof(struct vcd_property_frame_size);
+
+ vcd_status = vcd_get_property(client_ctx->vcd_handle, &vcd_property_hdr,
+ &frame_resolution);
+
+ video_resoultion->frame_width = frame_resolution.width;
+ video_resoultion->frame_height = frame_resolution.height;
+ video_resoultion->scan_lines = frame_resolution.scan_lines;
+ video_resoultion->stride = frame_resolution.stride;
+
+ if (vcd_status)
+ return false;
+ else
+ return true;
+}
+
+static u32 vid_dec_get_progressive_only(struct video_client_ctx *client_ctx,
+ u32 *progressive_only)
+{
+ struct vcd_property_hdr vcd_property_hdr;
+ if (!client_ctx || !progressive_only)
+ return false;
+ vcd_property_hdr.prop_id = VCD_I_PROGRESSIVE_ONLY;
+ vcd_property_hdr.sz = sizeof(u32);
+ if (vcd_get_property(client_ctx->vcd_handle, &vcd_property_hdr,
+ progressive_only))
+ return false;
+ else
+ return true;
+}
+
+static u32 vid_dec_get_disable_dmx_support(struct video_client_ctx *client_ctx,
+ u32 *disable_dmx)
+{
+
+ struct vcd_property_hdr vcd_property_hdr;
+ if (!client_ctx || !disable_dmx)
+ return false;
+ vcd_property_hdr.prop_id = VCD_I_DISABLE_DMX_SUPPORT;
+ vcd_property_hdr.sz = sizeof(u32);
+ if (vcd_get_property(client_ctx->vcd_handle, &vcd_property_hdr,
+ disable_dmx))
+ return false;
+ else
+ return true;
+}
+static u32 vid_dec_get_disable_dmx(struct video_client_ctx *client_ctx,
+ u32 *disable_dmx)
+{
+
+ struct vcd_property_hdr vcd_property_hdr;
+ if (!client_ctx || !disable_dmx)
+ return false;
+ vcd_property_hdr.prop_id = VCD_I_DISABLE_DMX;
+ vcd_property_hdr.sz = sizeof(u32);
+ if (vcd_get_property(client_ctx->vcd_handle, &vcd_property_hdr,
+ disable_dmx))
+ return false;
+ else
+ return true;
+}
+
+static u32 vid_dec_set_disable_dmx(struct video_client_ctx *client_ctx)
+{
+
+ struct vcd_property_hdr vcd_property_hdr;
+ u32 vcd_disable_dmx;
+ if (!client_ctx)
+ return false;
+ vcd_property_hdr.prop_id = VCD_I_DISABLE_DMX;
+ vcd_property_hdr.sz = sizeof(u32);
+ vcd_disable_dmx = true;
+ DBG("%s() : Setting Disable DMX: %d\n",
+ __func__, vcd_disable_dmx);
+
+ if (vcd_set_property(client_ctx->vcd_handle, &vcd_property_hdr,
+ &vcd_disable_dmx))
+ return false;
+ else
+ return true;
+}
+
+static u32 vid_dec_set_picture_order(struct video_client_ctx *client_ctx,
+ u32 *picture_order)
+{
+ struct vcd_property_hdr vcd_property_hdr;
+ u32 vcd_status = VCD_ERR_FAIL, vcd_picture_order, ret = true;
+ if (!client_ctx || !picture_order)
+ return false;
+ vcd_property_hdr.prop_id = VCD_I_OUTPUT_ORDER;
+ vcd_property_hdr.sz = sizeof(u32);
+ if (*picture_order == VDEC_ORDER_DISPLAY)
+ vcd_picture_order = VCD_DEC_ORDER_DISPLAY;
+ else if (*picture_order == VDEC_ORDER_DECODE)
+ vcd_picture_order = VCD_DEC_ORDER_DECODE;
+ else
+ ret = false;
+ if (ret) {
+ DBG("%s() : Setting output picture order: %d\n",
+ __func__, vcd_picture_order);
+ vcd_status = vcd_set_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, &vcd_picture_order);
+ if (vcd_status != VCD_S_SUCCESS)
+ ret = false;
+ }
+ return ret;
+}
+
+static u32 vid_dec_set_frame_rate(struct video_client_ctx *client_ctx,
+ struct vdec_framerate *frame_rate)
+{
+ struct vcd_property_hdr vcd_property_hdr;
+ struct vcd_property_frame_rate vcd_frame_rate;
+ u32 vcd_status = VCD_ERR_FAIL;
+
+ if (!client_ctx || !frame_rate)
+ return false;
+
+ vcd_property_hdr.prop_id = VCD_I_FRAME_RATE;
+ vcd_property_hdr.sz = sizeof(struct vcd_property_frame_rate);
+ vcd_frame_rate.fps_numerator = frame_rate->fps_numerator;
+ vcd_frame_rate.fps_denominator = frame_rate->fps_denominator;
+
+ vcd_status = vcd_set_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, &vcd_frame_rate);
+
+ if (vcd_status)
+ return false;
+ else
+ return true;
+}
+
+static u32 vid_dec_set_extradata(struct video_client_ctx *client_ctx,
+ u32 *extradata_flag)
+{
+ struct vcd_property_hdr vcd_property_hdr;
+ struct vcd_property_meta_data_enable vcd_meta_data;
+ u32 vcd_status = VCD_ERR_FAIL;
+ if (!client_ctx || !extradata_flag)
+ return false;
+ vcd_property_hdr.prop_id = VCD_I_METADATA_ENABLE;
+ vcd_property_hdr.sz = sizeof(struct vcd_property_meta_data_enable);
+ vcd_meta_data.meta_data_enable_flag = *extradata_flag;
+ vcd_status = vcd_set_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, &vcd_meta_data);
+ if (vcd_status)
+ return false;
+ else
+ return true;
+}
+
+static u32 vid_dec_set_idr_only_decoding(struct video_client_ctx *client_ctx)
+{
+ struct vcd_property_hdr vcd_property_hdr;
+ u32 vcd_status = VCD_ERR_FAIL;
+ u32 enable = true;
+ if (!client_ctx)
+ return false;
+ vcd_property_hdr.prop_id = VCD_I_DEC_PICTYPE;
+ vcd_property_hdr.sz = sizeof(u32);
+ vcd_status = vcd_set_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, &enable);
+ if (vcd_status)
+ return false;
+ return true;
+}
+static u32 vid_dec_set_meta_buffers(struct video_client_ctx *client_ctx,
+ struct vdec_meta_buffers *meta_buffers)
+{
+ struct vcd_property_hdr vcd_property_hdr;
+ struct vcd_property_meta_buffer *vcd_meta_buffer = NULL;
+ u32 vcd_status = VCD_ERR_FAIL;
+ u32 len = 0, len_iommu = 0, buf_size = 0;
+ int rc = 0;
+ unsigned long ionflag = 0, ionflag_iommu = 0;
+ unsigned long buffer_size = 0, buffer_size_iommu = 0;
+ unsigned long iova = 0, iova_iommu = 0;
+ int index = -1, num_buffers = 0;
+ u8 *ker_vir_addr = NULL, *ker_vir_addr_iommu = NULL;
+
+ if (!client_ctx || !meta_buffers)
+ return false;
+
+ vcd_property_hdr.prop_id = VCD_I_SET_EXT_METABUFFER;
+ vcd_property_hdr.sz = sizeof(struct vcd_property_meta_buffer);
+ vcd_meta_buffer = &client_ctx->vcd_meta_buffer;
+
+ memset(&client_ctx->vcd_meta_buffer, 0,
+ sizeof(struct vcd_property_meta_buffer));
+ vcd_meta_buffer->size = meta_buffers->size;
+ vcd_meta_buffer->count = meta_buffers->count;
+ vcd_meta_buffer->pmem_fd = meta_buffers->pmem_fd;
+ vcd_meta_buffer->offset = meta_buffers->offset;
+ vcd_meta_buffer->pmem_fd_iommu = meta_buffers->pmem_fd_iommu;
+
+ if (meta_buffers->count > MAX_META_BUFFERS) {
+ ERR("meta buffers maximum count reached, count = %d",
+ meta_buffers->count);
+ return false;
+ }
+
+ if (!vcd_get_ion_status()) {
+ pr_err("PMEM Not available\n");
+ return false;
+ } else {
+ client_ctx->meta_buffer_ion_handle = ion_import_dma_buf(
+ client_ctx->user_ion_client,
+ vcd_meta_buffer->pmem_fd);
+ if (IS_ERR_OR_NULL(client_ctx->meta_buffer_ion_handle)) {
+ ERR("%s(): get_ION_handle failed\n", __func__);
+ goto import_ion_error;
+ }
+ rc = ion_handle_get_flags(client_ctx->user_ion_client,
+ client_ctx->meta_buffer_ion_handle,
+ &ionflag);
+ if (rc) {
+ ERR("%s():get_ION_flags fail\n",
+ __func__);
+ goto import_ion_error;
+ }
+ vcd_meta_buffer->kernel_virtual_addr =
+ (u8 *) ion_map_kernel(
+ client_ctx->user_ion_client,
+ client_ctx->meta_buffer_ion_handle);
+ if (!vcd_meta_buffer->kernel_virtual_addr) {
+ ERR("%s(): get_ION_kernel virtual addr failed\n",
+ __func__);
+ goto import_ion_error;
+ }
+ if (res_trk_check_for_sec_session() ||
+ (res_trk_get_core_type() == (u32)VCD_CORE_720P)) {
+ rc = ion_phys(client_ctx->user_ion_client,
+ client_ctx->meta_buffer_ion_handle,
+ (unsigned long *) (&(vcd_meta_buffer->
+ physical_addr)), &len);
+ if (rc) {
+ ERR("%s():get_ION_kernel physical addr fail\n",
+ __func__);
+ goto ion_map_error;
+ }
+ vcd_meta_buffer->client_data = NULL;
+ vcd_meta_buffer->dev_addr = (u8 *)
+ vcd_meta_buffer->physical_addr;
+ } else {
+ rc = ion_map_iommu(client_ctx->user_ion_client,
+ client_ctx->meta_buffer_ion_handle,
+ VIDEO_DOMAIN, VIDEO_MAIN_POOL,
+ SZ_4K, 0, (unsigned long *)&iova,
+ (unsigned long *)&buffer_size,
+ 0, 0);
+ if (rc || !iova) {
+ ERR("%s():get_ION_kernel physical addr fail,"\
+ " rc = %d iova = 0x%lx\n",
+ __func__, rc, iova);
+ goto ion_map_error;
+ }
+ vcd_meta_buffer->physical_addr = (u8 *) iova;
+ vcd_meta_buffer->client_data = NULL;
+ vcd_meta_buffer->dev_addr = (u8 *) iova;
+ }
+
+ client_ctx->meta_buffer_iommu_ion_handle = ion_import_dma_buf(
+ client_ctx->user_ion_client,
+ vcd_meta_buffer->pmem_fd_iommu);
+ if (IS_ERR_OR_NULL(client_ctx->meta_buffer_iommu_ion_handle)) {
+ ERR("%s(): get_ION_handle failed\n", __func__);
+ goto import_ion_error;
+ }
+ rc = ion_handle_get_flags(client_ctx->user_ion_client,
+ client_ctx->
+ meta_buffer_iommu_ion_handle,
+ &ionflag_iommu);
+ if (rc) {
+ ERR("%s():get_ION_flags fail\n",
+ __func__);
+ goto import_ion_error;
+ }
+ vcd_meta_buffer->kernel_virt_addr_iommu =
+ (u8 *) ion_map_kernel(
+ client_ctx->user_ion_client,
+ client_ctx->meta_buffer_iommu_ion_handle);
+ if (!vcd_meta_buffer->kernel_virt_addr_iommu) {
+ ERR("%s(): get_ION_kernel virtual addr failed\n",
+ __func__);
+ goto import_ion_error;
+ }
+ if (res_trk_get_core_type() == (u32)VCD_CORE_720P) {
+ rc = ion_phys(client_ctx->user_ion_client,
+ client_ctx->meta_buffer_iommu_ion_handle,
+ (unsigned long *) (&(vcd_meta_buffer->
+ physical_addr_iommu)), &len_iommu);
+ if (rc) {
+ ERR("%s():get_ION_kernel physical addr fail\n",
+ __func__);
+ goto ion_map_error_iommu;
+ }
+ vcd_meta_buffer->client_data_iommu = NULL;
+ vcd_meta_buffer->dev_addr_iommu = (u8 *)
+ vcd_meta_buffer->physical_addr_iommu;
+ } else {
+ rc = ion_map_iommu(client_ctx->user_ion_client,
+ client_ctx->meta_buffer_iommu_ion_handle,
+ VIDEO_DOMAIN, VIDEO_MAIN_POOL,
+ SZ_4K, 0, (unsigned long *)&iova_iommu,
+ (unsigned long *)&buffer_size_iommu,
+ 0, 0);
+ if (rc || !iova_iommu) {
+ ERR("%s():get_ION_kernel physical addr fail, "\
+ "rc = %d iova = 0x%lx\n",
+ __func__, rc, iova);
+ goto ion_map_error_iommu;
+ }
+ vcd_meta_buffer->physical_addr_iommu =
+ (u8 *) iova_iommu;
+ vcd_meta_buffer->client_data_iommu = NULL;
+ vcd_meta_buffer->dev_addr_iommu = (u8 *) iova_iommu;
+ }
+ }
+
+ /*fill the meta addr table*/
+ num_buffers = vcd_meta_buffer->count;
+ buf_size = vcd_meta_buffer->size/num_buffers;
+ ker_vir_addr = vcd_meta_buffer->kernel_virtual_addr;
+ ker_vir_addr_iommu = vcd_meta_buffer->kernel_virt_addr_iommu;
+ client_ctx->meta_buf_size = buf_size;
+ for (index = 0; index < num_buffers; index++) {
+ client_ctx->meta_addr_table[index].kernel_vir_addr =
+ ker_vir_addr;
+ client_ctx->meta_addr_table[index].kernel_vir_addr_iommu =
+ ker_vir_addr_iommu;
+ DBG("[%d] kernel_virtual = %p kernel_vir_iommu = %p",
+ index, ker_vir_addr, ker_vir_addr_iommu);
+ ker_vir_addr += buf_size;
+ ker_vir_addr_iommu += buf_size;
+ }
+
+ DBG("Meta Buffer: Virt: %p, Phys %p, fd: %d",
+ vcd_meta_buffer->kernel_virtual_addr,
+ vcd_meta_buffer->physical_addr,
+ vcd_meta_buffer->pmem_fd);
+ DBG("IOMMU Meta Buffer: Virt: %p, Phys %p, fd: %d",
+ vcd_meta_buffer->kernel_virt_addr_iommu,
+ vcd_meta_buffer->physical_addr_iommu,
+ vcd_meta_buffer->pmem_fd_iommu);
+ DBG("Meta_buffer: Dev addr %p", vcd_meta_buffer->dev_addr);
+ DBG("IOMMU Meta_buffer: Dev addr %p",
+ vcd_meta_buffer->dev_addr_iommu);
+ vcd_status = vcd_set_property(client_ctx->vcd_handle,
+ &vcd_property_hdr,
+ vcd_meta_buffer);
+
+ if (vcd_status)
+ return false;
+ else
+ return true;
+ion_map_error_iommu:
+ if (vcd_meta_buffer->kernel_virt_addr_iommu) {
+ ion_unmap_kernel(client_ctx->user_ion_client,
+ client_ctx->meta_buffer_iommu_ion_handle);
+ vcd_meta_buffer->kernel_virt_addr_iommu = NULL;
+ }
+ if (!IS_ERR_OR_NULL(client_ctx->meta_buffer_iommu_ion_handle)) {
+ ion_free(client_ctx->user_ion_client,
+ client_ctx->meta_buffer_iommu_ion_handle);
+ client_ctx->meta_buffer_iommu_ion_handle = NULL;
+ }
+ion_map_error:
+ if (vcd_meta_buffer->kernel_virtual_addr) {
+ ion_unmap_kernel(client_ctx->user_ion_client,
+ client_ctx->meta_buffer_ion_handle);
+ vcd_meta_buffer->kernel_virtual_addr = NULL;
+ }
+ if (!IS_ERR_OR_NULL(client_ctx->meta_buffer_ion_handle)) {
+ ion_free(client_ctx->user_ion_client,
+ client_ctx->meta_buffer_ion_handle);
+ client_ctx->meta_buffer_ion_handle = NULL;
+ }
+import_ion_error:
+ return false;
+}
+static u32 vid_dec_set_h264_mv_buffers(struct video_client_ctx *client_ctx,
+ struct vdec_h264_mv *mv_data)
+{
+ struct vcd_property_hdr vcd_property_hdr;
+ struct vcd_property_h264_mv_buffer *vcd_h264_mv_buffer = NULL;
+ u32 vcd_status = VCD_ERR_FAIL;
+ u32 len = 0;
+ int rc = 0;
+ unsigned long ionflag = 0;
+ unsigned long buffer_size = 0;
+ unsigned long iova = 0;
+
+ if (!client_ctx || !mv_data)
+ return false;
+
+ vcd_property_hdr.prop_id = VCD_I_H264_MV_BUFFER;
+ vcd_property_hdr.sz = sizeof(struct vcd_property_h264_mv_buffer);
+ vcd_h264_mv_buffer = &client_ctx->vcd_h264_mv_buffer;
+
+ memset(&client_ctx->vcd_h264_mv_buffer, 0,
+ sizeof(struct vcd_property_h264_mv_buffer));
+ vcd_h264_mv_buffer->size = mv_data->size;
+ vcd_h264_mv_buffer->count = mv_data->count;
+ vcd_h264_mv_buffer->pmem_fd = mv_data->pmem_fd;
+ vcd_h264_mv_buffer->offset = mv_data->offset;
+
+ if (mv_data->count > MAX_MV_BUFFERS) {
+ ERR("MV buffers maximum count reached, count = %d",
+ mv_data->count);
+ return false;
+ }
+
+ if (!vcd_get_ion_status()) {
+ pr_err("PMEM not available\n");
+ return false;
+ } else {
+ client_ctx->h264_mv_ion_handle = ion_import_dma_buf(
+ client_ctx->user_ion_client,
+ vcd_h264_mv_buffer->pmem_fd);
+ if (IS_ERR_OR_NULL(client_ctx->h264_mv_ion_handle)) {
+ ERR("%s(): get_ION_handle failed\n", __func__);
+ goto import_ion_error;
+ }
+ rc = ion_handle_get_flags(client_ctx->user_ion_client,
+ client_ctx->h264_mv_ion_handle,
+ &ionflag);
+ if (rc) {
+ ERR("%s():get_ION_flags fail\n",
+ __func__);
+ goto import_ion_error;
+ }
+ vcd_h264_mv_buffer->kernel_virtual_addr = (u8 *) ion_map_kernel(
+ client_ctx->user_ion_client,
+ client_ctx->h264_mv_ion_handle);
+ if (!vcd_h264_mv_buffer->kernel_virtual_addr) {
+ ERR("%s(): get_ION_kernel virtual addr failed\n",
+ __func__);
+ goto import_ion_error;
+ }
+ if (res_trk_check_for_sec_session() ||
+ (res_trk_get_core_type() == (u32)VCD_CORE_720P)) {
+ rc = ion_phys(client_ctx->user_ion_client,
+ client_ctx->h264_mv_ion_handle,
+ (unsigned long *) (&(vcd_h264_mv_buffer->
+ physical_addr)), &len);
+ if (rc) {
+ ERR("%s():get_ION_kernel physical addr fail\n",
+ __func__);
+ goto ion_map_error;
+ }
+ vcd_h264_mv_buffer->client_data = NULL;
+ vcd_h264_mv_buffer->dev_addr = (u8 *)
+ vcd_h264_mv_buffer->physical_addr;
+ } else {
+ rc = ion_map_iommu(client_ctx->user_ion_client,
+ client_ctx->h264_mv_ion_handle,
+ VIDEO_DOMAIN, VIDEO_MAIN_POOL,
+ SZ_4K, 0, (unsigned long *)&iova,
+ (unsigned long *)&buffer_size,
+ 0, 0);
+ if (rc || !iova) {
+ ERR(
+ "%s():get_ION_kernel physical addr fail, rc = %d iova = 0x%lx\n",
+ __func__, rc, iova);
+ goto ion_map_error;
+ }
+ vcd_h264_mv_buffer->physical_addr = (u8 *) iova;
+ vcd_h264_mv_buffer->client_data = NULL;
+ vcd_h264_mv_buffer->dev_addr = (u8 *) iova;
+ }
+ }
+ DBG("Virt: %p, Phys %p, fd: %d", vcd_h264_mv_buffer->
+ kernel_virtual_addr, vcd_h264_mv_buffer->physical_addr,
+ vcd_h264_mv_buffer->pmem_fd);
+ DBG("Dev addr %p", vcd_h264_mv_buffer->dev_addr);
+ vcd_status = vcd_set_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, vcd_h264_mv_buffer);
+
+ if (vcd_status)
+ return false;
+ else
+ return true;
+ion_map_error:
+ if (vcd_h264_mv_buffer->kernel_virtual_addr) {
+ ion_unmap_kernel(client_ctx->user_ion_client,
+ client_ctx->h264_mv_ion_handle);
+ vcd_h264_mv_buffer->kernel_virtual_addr = NULL;
+ }
+ if (!IS_ERR_OR_NULL(client_ctx->h264_mv_ion_handle)) {
+ ion_free(client_ctx->user_ion_client,
+ client_ctx->h264_mv_ion_handle);
+ client_ctx->h264_mv_ion_handle = NULL;
+ }
+import_ion_error:
+ return false;
+}
+
+static u32 vid_dec_set_cont_on_reconfig(struct video_client_ctx *client_ctx)
+{
+ struct vcd_property_hdr vcd_property_hdr;
+ u32 vcd_status = VCD_ERR_FAIL;
+ u32 enable = true;
+ if (!client_ctx)
+ return false;
+ vcd_property_hdr.prop_id = VCD_I_CONT_ON_RECONFIG;
+ vcd_property_hdr.sz = sizeof(u32);
+ vcd_status = vcd_set_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, &enable);
+ if (vcd_status)
+ return false;
+ return true;
+}
+
+static u32 vid_dec_get_h264_mv_buffer_size(struct video_client_ctx *client_ctx,
+ struct vdec_mv_buff_size *mv_buff)
+{
+ struct vcd_property_hdr vcd_property_hdr;
+ struct vcd_property_buffer_size h264_mv_buffer_size;
+ u32 vcd_status = VCD_ERR_FAIL;
+
+ if (!client_ctx || !mv_buff)
+ return false;
+
+ vcd_property_hdr.prop_id = VCD_I_GET_H264_MV_SIZE;
+ vcd_property_hdr.sz = sizeof(struct vcd_property_buffer_size);
+
+ h264_mv_buffer_size.width = mv_buff->width;
+ h264_mv_buffer_size.height = mv_buff->height;
+
+ vcd_status = vcd_get_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, &h264_mv_buffer_size);
+
+ mv_buff->width = h264_mv_buffer_size.width;
+ mv_buff->height = h264_mv_buffer_size.height;
+ mv_buff->size = h264_mv_buffer_size.size;
+ mv_buff->alignment = h264_mv_buffer_size.alignment;
+
+ if (vcd_status)
+ return false;
+ else
+ return true;
+}
+
+static u32 vid_dec_free_meta_buffers(struct video_client_ctx *client_ctx)
+{
+ struct vcd_property_hdr vcd_property_hdr;
+ struct vcd_property_buffer_size meta_buffer_size;
+ u32 vcd_status = VCD_ERR_FAIL;
+
+ if (!client_ctx)
+ return false;
+
+ vcd_property_hdr.prop_id = VCD_I_FREE_EXT_METABUFFER;
+ vcd_property_hdr.sz = sizeof(struct vcd_property_buffer_size);
+
+ vcd_status = vcd_set_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, &meta_buffer_size);
+
+ if (!IS_ERR_OR_NULL(client_ctx->meta_buffer_ion_handle)) {
+ ion_unmap_kernel(client_ctx->user_ion_client,
+ client_ctx->meta_buffer_ion_handle);
+ if (!res_trk_check_for_sec_session() &&
+ (res_trk_get_core_type() != (u32)VCD_CORE_720P)) {
+ ion_unmap_iommu(client_ctx->user_ion_client,
+ client_ctx->meta_buffer_ion_handle,
+ VIDEO_DOMAIN,
+ VIDEO_MAIN_POOL);
+ }
+ ion_free(client_ctx->user_ion_client,
+ client_ctx->meta_buffer_ion_handle);
+ client_ctx->meta_buffer_ion_handle = NULL;
+ }
+
+ if (!IS_ERR_OR_NULL(client_ctx->meta_buffer_iommu_ion_handle)) {
+ ion_unmap_kernel(client_ctx->user_ion_client,
+ client_ctx->meta_buffer_iommu_ion_handle);
+ if (res_trk_check_for_sec_session() &&
+ (res_trk_get_core_type() != (u32)VCD_CORE_720P)) {
+ ion_unmap_iommu(client_ctx->user_ion_client,
+ client_ctx->meta_buffer_iommu_ion_handle,
+ VIDEO_DOMAIN,
+ VIDEO_MAIN_POOL);
+ }
+ ion_free(client_ctx->user_ion_client,
+ client_ctx->meta_buffer_iommu_ion_handle);
+ client_ctx->meta_buffer_iommu_ion_handle = NULL;
+ }
+
+ if (vcd_status)
+ return false;
+ else
+ return true;
+}
+
+
+static u32 vid_dec_free_h264_mv_buffers(struct video_client_ctx *client_ctx)
+{
+ struct vcd_property_hdr vcd_property_hdr;
+ struct vcd_property_buffer_size h264_mv_buffer_size;
+ u32 vcd_status = VCD_ERR_FAIL;
+
+ if (!client_ctx)
+ return false;
+
+ vcd_property_hdr.prop_id = VCD_I_FREE_H264_MV_BUFFER;
+ vcd_property_hdr.sz = sizeof(struct vcd_property_buffer_size);
+
+ vcd_status = vcd_set_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, &h264_mv_buffer_size);
+
+ if (!IS_ERR_OR_NULL(client_ctx->h264_mv_ion_handle)) {
+ ion_unmap_kernel(client_ctx->user_ion_client,
+ client_ctx->h264_mv_ion_handle);
+ if (!res_trk_check_for_sec_session() &&
+ (res_trk_get_core_type() != (u32)VCD_CORE_720P)) {
+ ion_unmap_iommu(client_ctx->user_ion_client,
+ client_ctx->h264_mv_ion_handle,
+ VIDEO_DOMAIN,
+ VIDEO_MAIN_POOL);
+ }
+ ion_free(client_ctx->user_ion_client,
+ client_ctx->h264_mv_ion_handle);
+ client_ctx->h264_mv_ion_handle = NULL;
+ }
+
+ if (vcd_status)
+ return false;
+ else
+ return true;
+}
+
+static u32 vid_dec_get_buffer_req(struct video_client_ctx *client_ctx,
+ struct vdec_allocatorproperty *vdec_buf_req)
+{
+ u32 vcd_status = VCD_ERR_FAIL;
+ struct vcd_buffer_requirement vcd_buf_req;
+
+ if (!client_ctx || !vdec_buf_req)
+ return false;
+
+ if (vdec_buf_req->buffer_type == VDEC_BUFFER_TYPE_INPUT) {
+ vcd_status = vcd_get_buffer_requirements(client_ctx->vcd_handle,
+ VCD_BUFFER_INPUT,
+ &vcd_buf_req);
+ } else {
+ vcd_status = vcd_get_buffer_requirements(client_ctx->vcd_handle,
+ VCD_BUFFER_OUTPUT,
+ &vcd_buf_req);
+ }
+
+ if (vcd_status) {
+ return false;
+ } else {
+ vdec_buf_req->mincount = vcd_buf_req.min_count;
+ vdec_buf_req->maxcount = vcd_buf_req.max_count;
+ vdec_buf_req->actualcount = vcd_buf_req.actual_count;
+ vdec_buf_req->buffer_size = vcd_buf_req.sz;
+ vdec_buf_req->alignment = vcd_buf_req.align;
+ vdec_buf_req->buf_poolid = vcd_buf_req.buf_pool_id;
+ vdec_buf_req->meta_buffer_size = vcd_buf_req.meta_buffer_size;
+
+ return true;
+ }
+}
+
+static u32 vid_dec_set_buffer(struct video_client_ctx *client_ctx,
+ struct vdec_setbuffer_cmd *buffer_info)
+{
+ enum vcd_buffer_type buffer = VCD_BUFFER_INPUT;
+ enum buffer_dir dir_buffer = BUFFER_TYPE_INPUT;
+ u32 vcd_status = VCD_ERR_FAIL;
+ unsigned long kernel_vaddr, buf_adr_offset = 0, length;
+
+ if (!client_ctx || !buffer_info)
+ return false;
+
+ if (buffer_info->buffer_type == VDEC_BUFFER_TYPE_OUTPUT) {
+ dir_buffer = BUFFER_TYPE_OUTPUT;
+ buffer = VCD_BUFFER_OUTPUT;
+ buf_adr_offset = (unsigned long)buffer_info->buffer.offset;
+ }
+ length = buffer_info->buffer.buffer_len;
+ /*If buffer cannot be set, ignore */
+ if (!vidc_insert_addr_table(client_ctx, dir_buffer,
+ (unsigned long)buffer_info->buffer.bufferaddr,
+ &kernel_vaddr, buffer_info->buffer.pmem_fd,
+ buf_adr_offset, MAX_VIDEO_NUM_OF_BUFF, length)) {
+ DBG("%s() : user_virt_addr = %p cannot be set.",
+ __func__, buffer_info->buffer.bufferaddr);
+ return false;
+ }
+ vcd_status = vcd_set_buffer(client_ctx->vcd_handle,
+ buffer, (u8 *) kernel_vaddr,
+ buffer_info->buffer.buffer_len);
+
+ if (!vcd_status)
+ return true;
+ else
+ return false;
+}
+
+
+static u32 vid_dec_free_buffer(struct video_client_ctx *client_ctx,
+ struct vdec_setbuffer_cmd *buffer_info)
+{
+ enum vcd_buffer_type buffer = VCD_BUFFER_INPUT;
+ enum buffer_dir dir_buffer = BUFFER_TYPE_INPUT;
+ u32 vcd_status = VCD_ERR_FAIL;
+ unsigned long kernel_vaddr;
+
+ if (!client_ctx || !buffer_info)
+ return false;
+
+ if (buffer_info->buffer_type == VDEC_BUFFER_TYPE_OUTPUT) {
+ dir_buffer = BUFFER_TYPE_OUTPUT;
+ buffer = VCD_BUFFER_OUTPUT;
+ }
+
+ /*If buffer NOT set, ignore */
+ if (!vidc_delete_addr_table(client_ctx, dir_buffer,
+ (unsigned long)buffer_info->buffer.bufferaddr,
+ &kernel_vaddr)) {
+ DBG("%s() : user_virt_addr = %p has not been set.",
+ __func__, buffer_info->buffer.bufferaddr);
+ return true;
+ }
+ vcd_status = vcd_free_buffer(client_ctx->vcd_handle, buffer,
+ (u8 *)kernel_vaddr);
+
+ if (!vcd_status)
+ return true;
+ else
+ return false;
+}
+
+static u32 vid_dec_pause_resume(struct video_client_ctx *client_ctx, u32 pause)
+{
+ u32 vcd_status;
+
+ if (!client_ctx) {
+ ERR("\n %s(): Invalid client_ctx", __func__);
+ return false;
+ }
+
+ if (pause) {
+ DBG("msm_vidc_dec: PAUSE command from client = %p\n",
+ client_ctx);
+ vcd_status = vcd_pause(client_ctx->vcd_handle);
+ } else{
+ DBG("msm_vidc_dec: RESUME command from client = %p\n",
+ client_ctx);
+ vcd_status = vcd_resume(client_ctx->vcd_handle);
+ }
+
+ if (vcd_status)
+ return false;
+
+ return true;
+
+}
+
+static u32 vid_dec_start_stop(struct video_client_ctx *client_ctx, u32 start)
+{
+ struct vid_dec_msg *vdec_msg = NULL;
+ u32 vcd_status;
+
+ DBG("msm_vidc_dec: Inside %s()", __func__);
+ if (!client_ctx) {
+ ERR("\n Invalid client_ctx");
+ return false;
+ }
+
+ if (start) {
+ if (client_ctx->seq_header_set) {
+ DBG("%s(): Seq Hdr set: Send START_DONE to client",
+ __func__);
+ vdec_msg = kzalloc(sizeof(*vdec_msg), GFP_KERNEL);
+ if (!vdec_msg) {
+ ERR("vid_dec_start_stop: cannot allocate"
+ "buffer\n");
+ return false;
+ }
+ vdec_msg->vdec_msg_info.msgcode =
+ VDEC_MSG_RESP_START_DONE;
+ vdec_msg->vdec_msg_info.status_code = VDEC_S_SUCCESS;
+ vdec_msg->vdec_msg_info.msgdatasize = 0;
+ mutex_lock(&client_ctx->msg_queue_lock);
+ list_add_tail(&vdec_msg->list, &client_ctx->msg_queue);
+ mutex_unlock(&client_ctx->msg_queue_lock);
+
+ wake_up(&client_ctx->msg_wait);
+
+ DBG("Send START_DONE message to client = %p\n",
+ client_ctx);
+
+ } else {
+ DBG("%s(): Calling decode_start()", __func__);
+ vcd_status =
+ vcd_decode_start(client_ctx->vcd_handle, NULL);
+
+ if (vcd_status) {
+ ERR("%s(): vcd_decode_start failed."
+ " vcd_status = %u\n", __func__, vcd_status);
+ return false;
+ }
+ }
+ } else {
+ DBG("%s(): Calling vcd_stop()", __func__);
+ mutex_lock(&vid_dec_device_p->lock);
+ vcd_status = VCD_ERR_FAIL;
+ if (!client_ctx->stop_called) {
+ client_ctx->stop_called = true;
+ vcd_status = vcd_stop(client_ctx->vcd_handle);
+ }
+ if (vcd_status) {
+ ERR("%s(): vcd_stop failed. vcd_status = %u\n",
+ __func__, vcd_status);
+ mutex_unlock(&vid_dec_device_p->lock);
+ return false;
+ }
+ DBG("Send STOP_DONE message to client = %p\n", client_ctx);
+ mutex_unlock(&vid_dec_device_p->lock);
+ }
+ return true;
+}
+
+static u32 vid_dec_decode_frame(struct video_client_ctx *client_ctx,
+ struct vdec_input_frameinfo *input_frame_info,
+ u8 *desc_buf, u32 desc_size)
+{
+ struct vcd_frame_data vcd_input_buffer;
+ unsigned long kernel_vaddr, phy_addr, user_vaddr;
+ int pmem_fd;
+ struct file *file;
+ s32 buffer_index = -1;
+ u32 vcd_status = VCD_ERR_FAIL;
+ u32 ion_flag = 0;
+ struct ion_handle *buff_handle = NULL;
+
+ if (!client_ctx || !input_frame_info)
+ return false;
+
+ user_vaddr = (unsigned long)input_frame_info->bufferaddr;
+
+ if (vidc_lookup_addr_table(client_ctx, BUFFER_TYPE_INPUT,
+ true, &user_vaddr, &kernel_vaddr,
+ &phy_addr, &pmem_fd, &file,
+ &buffer_index)) {
+
+ /* kernel_vaddr is found. send the frame to VCD */
+ memset((void *)&vcd_input_buffer, 0,
+ sizeof(struct vcd_frame_data));
+ vcd_input_buffer.virtual =
+ (u8 *) (kernel_vaddr + input_frame_info->pmem_offset);
+ vcd_input_buffer.offset = input_frame_info->offset;
+ vcd_input_buffer.frm_clnt_data =
+ (u32) input_frame_info->client_data;
+ vcd_input_buffer.ip_frm_tag =
+ (u32) input_frame_info->client_data;
+ vcd_input_buffer.data_len = input_frame_info->datalen;
+ vcd_input_buffer.time_stamp = input_frame_info->timestamp;
+ /* Rely on VCD using the same flags as OMX */
+ vcd_input_buffer.flags = input_frame_info->flags;
+ vcd_input_buffer.desc_buf = desc_buf;
+ vcd_input_buffer.desc_size = desc_size;
+ if (vcd_input_buffer.data_len > 0) {
+ ion_flag = vidc_get_fd_info(client_ctx,
+ BUFFER_TYPE_INPUT,
+ pmem_fd,
+ kernel_vaddr,
+ buffer_index,
+ &buff_handle);
+ if (ion_flag == ION_FLAG_CACHED && buff_handle) {
+ msm_ion_do_cache_op(client_ctx->user_ion_client,
+ buff_handle,
+ (unsigned long *)kernel_vaddr,
+ (unsigned long) vcd_input_buffer.data_len,
+ ION_IOC_CLEAN_CACHES);
+ }
+ }
+ vcd_status = vcd_decode_frame(client_ctx->vcd_handle,
+ &vcd_input_buffer);
+ if (!vcd_status)
+ return true;
+ else {
+ ERR("%s(): vcd_decode_frame failed = %u\n", __func__,
+ vcd_status);
+ return false;
+ }
+
+ } else {
+ ERR("%s(): kernel_vaddr not found\n", __func__);
+ return false;
+ }
+}
+
+static u32 vid_dec_fill_output_buffer(struct video_client_ctx *client_ctx,
+ struct vdec_fillbuffer_cmd *fill_buffer_cmd)
+{
+ unsigned long kernel_vaddr, phy_addr, user_vaddr;
+ int pmem_fd;
+ struct file *file;
+ s32 buffer_index = -1;
+ u32 vcd_status = VCD_ERR_FAIL;
+ struct ion_handle *buff_handle = NULL;
+
+ struct vcd_frame_data vcd_frame;
+
+ if (!client_ctx || !fill_buffer_cmd)
+ return false;
+
+ user_vaddr = (unsigned long)fill_buffer_cmd->buffer.bufferaddr;
+
+ if (vidc_lookup_addr_table(client_ctx, BUFFER_TYPE_OUTPUT,
+ true, &user_vaddr, &kernel_vaddr,
+ &phy_addr, &pmem_fd, &file,
+ &buffer_index)) {
+
+ memset((void *)&vcd_frame, 0,
+ sizeof(struct vcd_frame_data));
+ vcd_frame.virtual = (u8 *) kernel_vaddr;
+ vcd_frame.frm_clnt_data = (u32) fill_buffer_cmd->client_data;
+ vcd_frame.alloc_len = fill_buffer_cmd->buffer.buffer_len;
+ vcd_frame.ion_flag = vidc_get_fd_info(client_ctx,
+ BUFFER_TYPE_OUTPUT,
+ pmem_fd, kernel_vaddr,
+ buffer_index,
+ &buff_handle);
+ vcd_frame.buff_ion_handle = buff_handle;
+ vcd_status = vcd_fill_output_buffer(client_ctx->vcd_handle,
+ &vcd_frame);
+ if (!vcd_status)
+ return true;
+ else {
+ ERR("%s(): vcd_fill_output_buffer failed = %u\n",
+ __func__, vcd_status);
+ return false;
+ }
+ } else {
+ ERR("%s(): kernel_vaddr not found\n", __func__);
+ return false;
+ }
+}
+
+
+static u32 vid_dec_flush(struct video_client_ctx *client_ctx,
+ enum vdec_bufferflush flush_dir)
+{
+ u32 vcd_status = VCD_ERR_FAIL;
+
+ DBG("msm_vidc_dec: %s() called with dir = %u", __func__,
+ flush_dir);
+ if (!client_ctx) {
+ ERR("\n Invalid client_ctx");
+ return false;
+ }
+
+ switch (flush_dir) {
+ case VDEC_FLUSH_TYPE_INPUT:
+ vcd_status = vcd_flush(client_ctx->vcd_handle, VCD_FLUSH_INPUT);
+ break;
+ case VDEC_FLUSH_TYPE_OUTPUT:
+ vcd_status = vcd_flush(client_ctx->vcd_handle,
+ VCD_FLUSH_OUTPUT);
+ break;
+ case VDEC_FLUSH_TYPE_ALL:
+ vcd_status = vcd_flush(client_ctx->vcd_handle, VCD_FLUSH_ALL);
+ break;
+ default:
+ ERR("%s(): Inavlid flush cmd. flush_dir = %u\n", __func__,
+ flush_dir);
+ return false;
+ break;
+ }
+
+ if (!vcd_status)
+ return true;
+ else {
+ ERR("%s(): vcd_flush failed. vcd_status = %u "
+ " flush_dir = %u\n", __func__, vcd_status, flush_dir);
+ return false;
+ }
+}
+
+static u32 vid_dec_msg_pending(struct video_client_ctx *client_ctx)
+{
+ u32 islist_empty = 0;
+ mutex_lock(&client_ctx->msg_queue_lock);
+ islist_empty = list_empty(&client_ctx->msg_queue);
+ mutex_unlock(&client_ctx->msg_queue_lock);
+
+ if (islist_empty) {
+ DBG("%s(): vid_dec msg queue empty\n", __func__);
+ if (client_ctx->stop_msg) {
+ DBG("%s(): List empty and Stop Msg set\n",
+ __func__);
+ return client_ctx->stop_msg;
+ }
+ } else
+ DBG("%s(): vid_dec msg queue Not empty\n", __func__);
+
+ return !islist_empty;
+}
+
+static int vid_dec_get_next_msg(struct video_client_ctx *client_ctx,
+ struct vdec_msginfo *vdec_msg_info)
+{
+ int rc;
+ struct vid_dec_msg *vid_dec_msg = NULL;
+
+ if (!client_ctx)
+ return false;
+
+ rc = wait_event_interruptible(client_ctx->msg_wait,
+ vid_dec_msg_pending(client_ctx));
+ if (rc < 0) {
+ DBG("rc = %d, stop_msg = %u\n", rc, client_ctx->stop_msg);
+ return rc;
+ } else if (client_ctx->stop_msg) {
+ DBG("rc = %d, stop_msg = %u\n", rc, client_ctx->stop_msg);
+ return -EIO;
+ }
+
+ mutex_lock(&client_ctx->msg_queue_lock);
+ if (!list_empty(&client_ctx->msg_queue)) {
+ DBG("%s(): After Wait\n", __func__);
+ vid_dec_msg = list_first_entry(&client_ctx->msg_queue,
+ struct vid_dec_msg, list);
+ list_del(&vid_dec_msg->list);
+ memcpy(vdec_msg_info, &vid_dec_msg->vdec_msg_info,
+ sizeof(struct vdec_msginfo));
+ kfree(vid_dec_msg);
+ }
+ mutex_unlock(&client_ctx->msg_queue_lock);
+ return 0;
+}
+
+static long vid_dec_ioctl(struct file *file,
+ unsigned cmd, unsigned long u_arg)
+{
+ struct video_client_ctx *client_ctx = NULL;
+ struct vdec_ioctl_msg vdec_msg;
+ u32 vcd_status;
+ unsigned long kernel_vaddr, phy_addr, len;
+ unsigned long ker_vaddr;
+ u32 result = true;
+ #ifdef KW_TAINT_ANALYSIS
+ void __user *arg = (void __user *) get_tainted_stuff();
+ #else
+ void __user *arg = (void __user *)u_arg;
+ #endif
+ int rc = 0;
+ size_t ion_len;
+
+ DBG("%s\n", __func__);
+ if (_IOC_TYPE(cmd) != VDEC_IOCTL_MAGIC)
+ return -ENOTTY;
+
+ client_ctx = (struct video_client_ctx *)file->private_data;
+ if (!client_ctx) {
+ ERR("!client_ctx. Cannot attach to device handle\n");
+ return -ENODEV;
+ }
+
+ switch (cmd) {
+ case VDEC_IOCTL_SET_CODEC:
+ {
+ enum vdec_codec vdec_codec;
+ DBG("VDEC_IOCTL_SET_CODEC\n");
+ if (copy_from_user(&vdec_msg, arg, sizeof(vdec_msg)))
+ return -EFAULT;
+ if (copy_from_user(&vdec_codec, vdec_msg.in,
+ sizeof(vdec_codec)))
+ return -EFAULT;
+ DBG("setting code type = %u\n", vdec_codec);
+ result = vid_dec_set_codec(client_ctx, &vdec_codec);
+ if (!result)
+ return -EIO;
+ break;
+ }
+ case VDEC_IOCTL_SET_OUTPUT_FORMAT:
+ {
+ enum vdec_output_fromat output_format;
+ DBG("VDEC_IOCTL_SET_OUTPUT_FORMAT\n");
+ if (copy_from_user(&vdec_msg, arg, sizeof(vdec_msg)))
+ return -EFAULT;
+ if (copy_from_user(&output_format, vdec_msg.in,
+ sizeof(output_format)))
+ return -EFAULT;
+
+ result = vid_dec_set_output_format(client_ctx, &output_format);
+
+ if (!result)
+ return -EIO;
+ break;
+ }
+ case VDEC_IOCTL_SET_PICRES:
+ {
+ struct vdec_picsize video_resoultion;
+ DBG("VDEC_IOCTL_SET_PICRES\n");
+ if (copy_from_user(&vdec_msg, arg, sizeof(vdec_msg)))
+ return -EFAULT;
+ if (copy_from_user(&video_resoultion, vdec_msg.in,
+ sizeof(video_resoultion)))
+ return -EFAULT;
+ result =
+ vid_dec_set_frame_resolution(client_ctx, &video_resoultion);
+ if (!result)
+ return -EIO;
+ break;
+ }
+ case VDEC_IOCTL_GET_PICRES:
+ {
+ struct vdec_picsize video_resoultion;
+ DBG("VDEC_IOCTL_GET_PICRES\n");
+ if (copy_from_user(&vdec_msg, arg, sizeof(vdec_msg)))
+ return -EFAULT;
+ if (copy_from_user(&video_resoultion, vdec_msg.out,
+ sizeof(video_resoultion)))
+ return -EFAULT;
+
+ result = vid_dec_get_frame_resolution(client_ctx,
+ &video_resoultion);
+
+ if (result) {
+ if (copy_to_user(vdec_msg.out, &video_resoultion,
+ sizeof(video_resoultion)))
+ return -EFAULT;
+ } else
+ return -EIO;
+ break;
+ }
+ case VDEC_IOCTL_SET_BUFFER_REQ:
+ {
+ struct vdec_allocatorproperty vdec_buf_req;
+ struct vcd_buffer_requirement buffer_req;
+ DBG("VDEC_IOCTL_SET_BUFFER_REQ\n");
+ if (copy_from_user(&vdec_msg, arg, sizeof(vdec_msg)))
+ return -EFAULT;
+
+ if (copy_from_user(&vdec_buf_req, vdec_msg.in,
+ sizeof(vdec_buf_req)))
+ return -EFAULT;
+
+ buffer_req.actual_count = vdec_buf_req.actualcount;
+ buffer_req.align = vdec_buf_req.alignment;
+ buffer_req.max_count = vdec_buf_req.maxcount;
+ buffer_req.min_count = vdec_buf_req.mincount;
+ buffer_req.sz = vdec_buf_req.buffer_size;
+
+ switch (vdec_buf_req.buffer_type) {
+ case VDEC_BUFFER_TYPE_INPUT:
+ vcd_status =
+ vcd_set_buffer_requirements(client_ctx->vcd_handle,
+ VCD_BUFFER_INPUT, &buffer_req);
+ break;
+ case VDEC_BUFFER_TYPE_OUTPUT:
+ vcd_status =
+ vcd_set_buffer_requirements(client_ctx->vcd_handle,
+ VCD_BUFFER_OUTPUT, &buffer_req);
+ break;
+ default:
+ vcd_status = VCD_ERR_BAD_POINTER;
+ break;
+ }
+
+ if (vcd_status)
+ return -EFAULT;
+ break;
+ }
+ case VDEC_IOCTL_GET_BUFFER_REQ:
+ {
+ struct vdec_allocatorproperty vdec_buf_req;
+ DBG("VDEC_IOCTL_GET_BUFFER_REQ\n");
+ if (copy_from_user(&vdec_msg, arg, sizeof(vdec_msg)))
+ return -EFAULT;
+ if (copy_from_user(&vdec_buf_req, vdec_msg.out,
+ sizeof(vdec_buf_req)))
+ return -EFAULT;
+
+ result = vid_dec_get_buffer_req(client_ctx, &vdec_buf_req);
+
+ if (result) {
+ if (copy_to_user(vdec_msg.out, &vdec_buf_req,
+ sizeof(vdec_buf_req)))
+ return -EFAULT;
+ } else
+ return -EIO;
+ break;
+ }
+ case VDEC_IOCTL_SET_BUFFER:
+ {
+ struct vdec_setbuffer_cmd setbuffer;
+ DBG("VDEC_IOCTL_SET_BUFFER\n");
+ if (copy_from_user(&vdec_msg, arg, sizeof(vdec_msg)))
+ return -EFAULT;
+ if (copy_from_user(&setbuffer, vdec_msg.in,
+ sizeof(setbuffer)))
+ return -EFAULT;
+ result = vid_dec_set_buffer(client_ctx, &setbuffer);
+ if (!result)
+ return -EIO;
+ break;
+ }
+ case VDEC_IOCTL_FREE_BUFFER:
+ {
+ struct vdec_setbuffer_cmd setbuffer;
+ DBG("VDEC_IOCTL_FREE_BUFFER\n");
+ if (copy_from_user(&vdec_msg, arg, sizeof(vdec_msg)))
+ return -EFAULT;
+ if (copy_from_user(&setbuffer, vdec_msg.in,
+ sizeof(setbuffer)))
+ return -EFAULT;
+ result = vid_dec_free_buffer(client_ctx, &setbuffer);
+ if (!result)
+ return -EIO;
+ break;
+ }
+ case VDEC_IOCTL_CMD_START:
+ {
+ DBG(" VDEC_IOCTL_CMD_START\n");
+ result = vid_dec_start_stop(client_ctx, true);
+ if (!result)
+ return -EIO;
+ break;
+ }
+ case VDEC_IOCTL_CMD_STOP:
+ {
+ DBG("VDEC_IOCTL_CMD_STOP\n");
+ result = vid_dec_start_stop(client_ctx, false);
+ if (!result)
+ return -EIO;
+ break;
+ }
+ case VDEC_IOCTL_CMD_PAUSE:
+ {
+ result = vid_dec_pause_resume(client_ctx, true);
+ if (!result)
+ return -EIO;
+ break;
+ }
+ case VDEC_IOCTL_CMD_RESUME:
+ {
+ DBG("VDEC_IOCTL_CMD_PAUSE\n");
+ result = vid_dec_pause_resume(client_ctx, false);
+
+ if (!result)
+ return -EIO;
+ break;
+ }
+ case VDEC_IOCTL_DECODE_FRAME:
+ {
+ struct vdec_input_frameinfo input_frame_info;
+ u8 *desc_buf = NULL;
+ u32 desc_size = 0;
+ DBG("VDEC_IOCTL_DECODE_FRAME\n");
+ if (copy_from_user(&vdec_msg, arg, sizeof(vdec_msg)))
+ return -EFAULT;
+ if (copy_from_user(&input_frame_info, vdec_msg.in,
+ sizeof(input_frame_info)))
+ return -EFAULT;
+ if (client_ctx->dmx_disable) {
+ if (input_frame_info.desc_addr) {
+ desc_size = input_frame_info.desc_size;
+ desc_buf = kzalloc(desc_size, GFP_KERNEL);
+ if (desc_buf) {
+ if (copy_from_user(desc_buf,
+ input_frame_info.desc_addr,
+ desc_size)) {
+ kfree(desc_buf);
+ desc_buf = NULL;
+ return -EFAULT;
+ }
+ }
+ } else
+ return -EINVAL;
+ }
+ result = vid_dec_decode_frame(client_ctx, &input_frame_info,
+ desc_buf, desc_size);
+
+ if (!result) {
+ kfree(desc_buf);
+ desc_buf = NULL;
+ return -EIO;
+ }
+ break;
+ }
+ case VDEC_IOCTL_SET_PERF_CLK:
+ {
+ vid_dec_set_turbo_clk(client_ctx);
+ break;
+ }
+ case VDEC_IOCTL_FILL_OUTPUT_BUFFER:
+ {
+ struct vdec_fillbuffer_cmd fill_buffer_cmd;
+ DBG("VDEC_IOCTL_FILL_OUTPUT_BUFFER\n");
+ if (copy_from_user(&vdec_msg, arg, sizeof(vdec_msg)))
+ return -EFAULT;
+ if (copy_from_user(&fill_buffer_cmd, vdec_msg.in,
+ sizeof(fill_buffer_cmd)))
+ return -EFAULT;
+ result = vid_dec_fill_output_buffer(client_ctx,
+ &fill_buffer_cmd);
+ if (!result)
+ return -EIO;
+ break;
+ }
+ case VDEC_IOCTL_CMD_FLUSH:
+ {
+ enum vdec_bufferflush flush_dir;
+ DBG("VDEC_IOCTL_CMD_FLUSH\n");
+ if (copy_from_user(&vdec_msg, arg, sizeof(vdec_msg)))
+ return -EFAULT;
+ if (copy_from_user(&flush_dir, vdec_msg.in,
+ sizeof(flush_dir)))
+ return -EFAULT;
+ result = vid_dec_flush(client_ctx, flush_dir);
+ if (!result)
+ return -EIO;
+ break;
+ }
+ case VDEC_IOCTL_GET_NEXT_MSG:
+ {
+ struct vdec_msginfo vdec_msg_info;
+ DBG("VDEC_IOCTL_GET_NEXT_MSG\n");
+ if (copy_from_user(&vdec_msg, arg, sizeof(vdec_msg)))
+ return -EFAULT;
+ result = vid_dec_get_next_msg(client_ctx, &vdec_msg_info);
+ if (result)
+ return result;
+ if (copy_to_user(vdec_msg.out, &vdec_msg_info,
+ sizeof(vdec_msg_info)))
+ return -EFAULT;
+ break;
+ }
+ case VDEC_IOCTL_STOP_NEXT_MSG:
+ {
+ DBG("VDEC_IOCTL_STOP_NEXT_MSG\n");
+ client_ctx->stop_msg = 1;
+ wake_up(&client_ctx->msg_wait);
+ break;
+ }
+ case VDEC_IOCTL_SET_SEQUENCE_HEADER:
+ {
+ struct vdec_seqheader seq_header;
+ struct vcd_sequence_hdr vcd_seq_hdr;
+ unsigned long ionflag;
+ DBG("VDEC_IOCTL_SET_SEQUENCE_HEADER\n");
+ if (copy_from_user(&vdec_msg, arg, sizeof(vdec_msg))) {
+ ERR("Copy from user vdec_msg failed\n");
+ return -EFAULT;
+ }
+ if (copy_from_user(&seq_header, vdec_msg.in,
+ sizeof(seq_header))) {
+ ERR("Copy from user seq_header failed\n");
+ return -EFAULT;
+ }
+ if (!seq_header.seq_header_len) {
+ ERR("Seq Len is Zero\n");
+ return -EFAULT;
+ }
+
+ if (!vcd_get_ion_status()) {
+ pr_err("PMEM Not available\n");
+ return -EINVAL;
+ } else {
+ client_ctx->seq_hdr_ion_handle = ion_import_dma_buf(
+ client_ctx->user_ion_client,
+ seq_header.pmem_fd);
+ if (!client_ctx->seq_hdr_ion_handle) {
+ ERR("%s(): get_ION_handle failed\n", __func__);
+ return false;
+ }
+ rc = ion_handle_get_flags(client_ctx->user_ion_client,
+ client_ctx->seq_hdr_ion_handle,
+ &ionflag);
+ if (rc) {
+ ERR("%s():get_ION_flags fail\n",
+ __func__);
+ ion_free(client_ctx->user_ion_client,
+ client_ctx->seq_hdr_ion_handle);
+ return false;
+ }
+ ker_vaddr = (unsigned long) ion_map_kernel(
+ client_ctx->user_ion_client,
+ client_ctx->seq_hdr_ion_handle);
+ if (!ker_vaddr) {
+ ERR("%s():get_ION_kernel virtual addr fail\n",
+ __func__);
+ ion_free(client_ctx->user_ion_client,
+ client_ctx->seq_hdr_ion_handle);
+ return false;
+ }
+ kernel_vaddr = ker_vaddr;
+ rc = ion_phys(client_ctx->user_ion_client,
+ client_ctx->seq_hdr_ion_handle,
+ &phy_addr, &ion_len);
+ if (rc) {
+ ERR("%s():get_ION_kernel physical addr fail\n",
+ __func__);
+ ion_unmap_kernel(client_ctx->user_ion_client,
+ client_ctx->seq_hdr_ion_handle);
+ ion_free(client_ctx->user_ion_client,
+ client_ctx->seq_hdr_ion_handle);
+ return false;
+ }
+ len = ion_len;
+ }
+ vcd_seq_hdr.sequence_header_len = seq_header.seq_header_len;
+ kernel_vaddr += (unsigned long)seq_header.pmem_offset;
+ vcd_seq_hdr.sequence_header = (u8 *)kernel_vaddr;
+ if (!vcd_seq_hdr.sequence_header) {
+ ERR("Sequence Header pointer failed\n");
+ return -EFAULT;
+ }
+ client_ctx->seq_header_set = true;
+ if (vcd_decode_start(client_ctx->vcd_handle, &vcd_seq_hdr)) {
+ ERR("Decode start Failed\n");
+ client_ctx->seq_header_set = false;
+ return -EFAULT;
+ }
+ DBG("Wait Client completion Sequence Header\n");
+ wait_for_completion(&client_ctx->event);
+ vcd_seq_hdr.sequence_header = NULL;
+ if (client_ctx->event_status) {
+ ERR("Set Seq Header status is failed");
+ return -EFAULT;
+ }
+ if (vcd_get_ion_status()) {
+ if (client_ctx->seq_hdr_ion_handle) {
+ ion_unmap_kernel(client_ctx->user_ion_client,
+ client_ctx->seq_hdr_ion_handle);
+ ion_free(client_ctx->user_ion_client,
+ client_ctx->seq_hdr_ion_handle);
+ }
+ }
+ break;
+ }
+ case VDEC_IOCTL_GET_NUMBER_INSTANCES:
+ {
+ DBG("VDEC_IOCTL_GET_NUMBER_INSTANCES\n");
+ if (copy_from_user(&vdec_msg, arg, sizeof(vdec_msg)))
+ return -EFAULT;
+ if (copy_to_user(vdec_msg.out,
+ &vid_dec_device_p->num_clients, sizeof(u32)))
+ return -EFAULT;
+ break;
+ }
+ case VDEC_IOCTL_GET_INTERLACE_FORMAT:
+ {
+ u32 progressive_only, interlace_format;
+ DBG("VDEC_IOCTL_GET_INTERLACE_FORMAT\n");
+ if (copy_from_user(&vdec_msg, arg, sizeof(vdec_msg)))
+ return -EFAULT;
+ result = vid_dec_get_progressive_only(client_ctx,
+ &progressive_only);
+ if (result) {
+ interlace_format = progressive_only ?
+ VDEC_InterlaceFrameProgressive :
+ VDEC_InterlaceInterleaveFrameTopFieldFirst;
+ if (copy_to_user(vdec_msg.out, &interlace_format,
+ sizeof(u32)))
+ return -EFAULT;
+ } else
+ return -EIO;
+ break;
+ }
+
+ case VDEC_IOCTL_GET_DISABLE_DMX_SUPPORT:
+ {
+ u32 disable_dmx;
+ DBG("VDEC_IOCTL_GET_DISABLE_DMX_SUPPORT\n");
+ if (copy_from_user(&vdec_msg, arg, sizeof(vdec_msg)))
+ return -EFAULT;
+ result = vid_dec_get_disable_dmx_support(client_ctx,
+ &disable_dmx);
+ if (result) {
+ if (copy_to_user(vdec_msg.out, &disable_dmx,
+ sizeof(u32)))
+ return -EFAULT;
+ } else
+ return -EIO;
+ break;
+ }
+ case VDEC_IOCTL_GET_DISABLE_DMX:
+ {
+ u32 disable_dmx;
+ DBG("VDEC_IOCTL_GET_DISABLE_DMX\n");
+ if (copy_from_user(&vdec_msg, arg, sizeof(vdec_msg)))
+ return -EFAULT;
+ result = vid_dec_get_disable_dmx(client_ctx,
+ &disable_dmx);
+ if (result) {
+ if (copy_to_user(vdec_msg.out, &disable_dmx,
+ sizeof(u32)))
+ return -EFAULT;
+ } else
+ return -EIO;
+ break;
+ }
+ case VDEC_IOCTL_SET_DISABLE_DMX:
+ {
+ DBG("VDEC_IOCTL_SET_DISABLE_DMX\n");
+ result = vid_dec_set_disable_dmx(client_ctx);
+ if (!result)
+ return -EIO;
+ client_ctx->dmx_disable = 1;
+ break;
+ }
+ case VDEC_IOCTL_SET_PICTURE_ORDER:
+ {
+ u32 picture_order;
+ DBG("VDEC_IOCTL_SET_PICTURE_ORDER\n");
+ if (copy_from_user(&vdec_msg, arg, sizeof(vdec_msg)))
+ return -EFAULT;
+ if (copy_from_user(&picture_order, vdec_msg.in,
+ sizeof(u32)))
+ return -EFAULT;
+ result = vid_dec_set_picture_order(client_ctx, &picture_order);
+ if (!result)
+ return -EIO;
+ break;
+ }
+ case VDEC_IOCTL_SET_FRAME_RATE:
+ {
+ struct vdec_framerate frame_rate;
+ DBG("VDEC_IOCTL_SET_FRAME_RATE\n");
+ if (copy_from_user(&vdec_msg, arg, sizeof(vdec_msg)))
+ return -EFAULT;
+ if (copy_from_user(&frame_rate, vdec_msg.in,
+ sizeof(frame_rate)))
+ return -EFAULT;
+ result = vid_dec_set_frame_rate(client_ctx, &frame_rate);
+ if (!result)
+ return -EIO;
+ break;
+ }
+ case VDEC_IOCTL_SET_EXTRADATA:
+ {
+ u32 extradata_flag;
+ DBG("VDEC_IOCTL_SET_EXTRADATA\n");
+ if (copy_from_user(&vdec_msg, arg, sizeof(vdec_msg)))
+ return -EFAULT;
+ if (copy_from_user(&extradata_flag, vdec_msg.in,
+ sizeof(u32)))
+ return -EFAULT;
+ result = vid_dec_set_extradata(client_ctx, &extradata_flag);
+ if (!result)
+ return -EIO;
+ break;
+ }
+ case VDEC_IOCTL_SET_META_BUFFERS:
+ {
+ struct vdec_meta_buffers meta_buffers;
+ DBG("VDEC_IOCTL_SET_META_BUFFERS\n");
+ if (copy_from_user(&vdec_msg, arg, sizeof(vdec_msg)))
+ return -EFAULT;
+ if (copy_from_user(&meta_buffers, vdec_msg.in,
+ sizeof(meta_buffers)))
+ return -EFAULT;
+ result = vid_dec_set_meta_buffers(client_ctx, &meta_buffers);
+
+ if (!result)
+ return -EIO;
+ break;
+ }
+ case VDEC_IOCTL_FREE_META_BUFFERS:
+ {
+ DBG("VDEC_IOCTL_FREE_META_BUFFERS\n");
+ result = vid_dec_free_meta_buffers(client_ctx);
+ if (!result)
+ return -EIO;
+ break;
+ }
+ case VDEC_IOCTL_SET_H264_MV_BUFFER:
+ {
+ struct vdec_h264_mv mv_data;
+ DBG("VDEC_IOCTL_SET_H264_MV_BUFFER\n");
+ if (copy_from_user(&vdec_msg, arg, sizeof(vdec_msg)))
+ return -EFAULT;
+ if (copy_from_user(&mv_data, vdec_msg.in,
+ sizeof(mv_data)))
+ return -EFAULT;
+ result = vid_dec_set_h264_mv_buffers(client_ctx, &mv_data);
+
+ if (!result)
+ return -EIO;
+ break;
+ }
+ case VDEC_IOCTL_FREE_H264_MV_BUFFER:
+ {
+ DBG("VDEC_IOCTL_FREE_H264_MV_BUFFER\n");
+ result = vid_dec_free_h264_mv_buffers(client_ctx);
+ if (!result)
+ return -EIO;
+ break;
+ }
+ case VDEC_IOCTL_GET_MV_BUFFER_SIZE:
+ {
+ struct vdec_mv_buff_size mv_buff;
+ DBG("VDEC_IOCTL_GET_MV_BUFFER_SIZE\n");
+ if (copy_from_user(&vdec_msg, arg, sizeof(vdec_msg)))
+ return -EFAULT;
+ if (copy_from_user(&mv_buff, vdec_msg.out,
+ sizeof(mv_buff)))
+ return -EFAULT;
+ result = vid_dec_get_h264_mv_buffer_size(client_ctx, &mv_buff);
+ if (result) {
+ DBG(" Returning W: %d, H: %d, S: %d, A: %d",
+ mv_buff.width, mv_buff.height,
+ mv_buff.size, mv_buff.alignment);
+ if (copy_to_user(vdec_msg.out, &mv_buff,
+ sizeof(mv_buff)))
+ return -EFAULT;
+ } else
+ return -EIO;
+ break;
+ }
+ case VDEC_IOCTL_SET_IDR_ONLY_DECODING:
+ {
+ result = vid_dec_set_idr_only_decoding(client_ctx);
+ if (!result)
+ return -EIO;
+ break;
+ }
+ case VDEC_IOCTL_SET_CONT_ON_RECONFIG:
+ {
+ result = vid_dec_set_cont_on_reconfig(client_ctx);
+ if (!result)
+ return -EIO;
+ break;
+ }
+ default:
+ ERR("%s(): Unsupported ioctl\n", __func__);
+ return -ENOTTY;
+ break;
+ }
+
+ return 0;
+}
+
+static u32 vid_dec_close_client(struct video_client_ctx *client_ctx)
+{
+ struct vid_dec_msg *vdec_msg;
+ u32 vcd_status;
+
+ DBG("msm_vidc_dec: Inside %s()", __func__);
+ if (!client_ctx || (!client_ctx->vcd_handle)) {
+ ERR("\n Invalid client_ctx");
+ return false;
+ }
+
+ mutex_lock(&vid_dec_device_p->lock);
+ if (!client_ctx->stop_called) {
+ client_ctx->stop_called = true;
+ client_ctx->stop_sync_cb = true;
+ vcd_status = vcd_stop(client_ctx->vcd_handle);
+ DBG("\n Stuck at the stop call");
+ if (!vcd_status)
+ wait_for_completion(&client_ctx->event);
+ DBG("\n Came out of wait event");
+ }
+ mutex_lock(&client_ctx->msg_queue_lock);
+ while (!list_empty(&client_ctx->msg_queue)) {
+ DBG("%s(): Delete remaining entries\n", __func__);
+ vdec_msg = list_first_entry(&client_ctx->msg_queue,
+ struct vid_dec_msg, list);
+ if (vdec_msg) {
+ list_del(&vdec_msg->list);
+ kfree(vdec_msg);
+ }
+ }
+ mutex_unlock(&client_ctx->msg_queue_lock);
+ vcd_status = vcd_close(client_ctx->vcd_handle);
+
+ client_ctx->user_ion_client = NULL;
+ memset((void *)client_ctx, 0, sizeof(struct video_client_ctx));
+ vid_dec_device_p->num_clients--;
+ mutex_unlock(&vid_dec_device_p->lock);
+ return true;
+}
+
+int vid_dec_open_client(struct video_client_ctx **vid_clnt_ctx, int flags)
+{
+ int rc = 0;
+ s32 client_index;
+ struct video_client_ctx *client_ctx = NULL;
+ u8 client_count;
+
+ if (!vid_clnt_ctx) {
+ ERR("Invalid input\n");
+ return -EINVAL;
+ }
+ *vid_clnt_ctx = NULL;
+ client_count = vcd_get_num_of_clients();
+ if (client_count == VIDC_MAX_NUM_CLIENTS) {
+ ERR("ERROR : vid_dec_open() max number of clients"
+ "limit reached\n");
+ rc = -ENOMEM;
+ goto client_failure;
+ }
+
+ DBG(" Virtual Address of ioremap is %p\n", vid_dec_device_p->virt_base);
+ if (!vid_dec_device_p->num_clients) {
+ if (!vidc_load_firmware()) {
+ rc = -ENOMEM;
+ goto client_failure;
+ }
+ }
+
+ client_index = vid_dec_get_empty_client_index();
+ if (client_index < 0) {
+ ERR("%s() : No free clients client_index == -1\n", __func__);
+ rc = -ENOMEM;
+ goto client_failure;
+ }
+ client_ctx = &vid_dec_device_p->vdec_clients[client_index];
+ vid_dec_device_p->num_clients++;
+ init_completion(&client_ctx->event);
+ mutex_init(&client_ctx->msg_queue_lock);
+ mutex_init(&client_ctx->enrty_queue_lock);
+ INIT_LIST_HEAD(&client_ctx->msg_queue);
+ init_waitqueue_head(&client_ctx->msg_wait);
+ client_ctx->stop_msg = 0;
+ client_ctx->stop_called = false;
+ client_ctx->stop_sync_cb = false;
+ client_ctx->dmx_disable = 0;
+ if (vcd_get_ion_status()) {
+ client_ctx->user_ion_client = vcd_get_ion_client();
+ if (!client_ctx->user_ion_client) {
+ ERR("vcd_open ion client get failed");
+ rc = -ENOMEM;
+ goto client_failure;
+ }
+ }
+ rc = vcd_open(vid_dec_device_p->device_handle, true,
+ vid_dec_vcd_cb, client_ctx, flags);
+ if (!rc) {
+ wait_for_completion(&client_ctx->event);
+ if (client_ctx->event_status) {
+ ERR("callback for vcd_open returned error: %u",
+ client_ctx->event_status);
+ rc = -ENODEV;
+ goto client_failure;
+ }
+ } else {
+ ERR("vcd_open returned error: %u", rc);
+ goto client_failure;
+ }
+ client_ctx->seq_header_set = false;
+ *vid_clnt_ctx = client_ctx;
+client_failure:
+ return rc;
+}
+
+static int vid_dec_open_secure(struct inode *inode, struct file *file)
+{
+ int rc = 0;
+ struct video_client_ctx *client_ctx;
+ mutex_lock(&vid_dec_device_p->lock);
+ rc = vid_dec_open_client(&client_ctx, VCD_CP_SESSION);
+ if (rc)
+ goto error;
+ if (!client_ctx) {
+ rc = -ENOMEM;
+ goto error;
+ }
+
+ file->private_data = client_ctx;
+ if (res_trk_open_secure_session()) {
+ ERR("Secure session operation failure\n");
+ rc = -EACCES;
+ goto error;
+ }
+ mutex_unlock(&vid_dec_device_p->lock);
+ return 0;
+error:
+ mutex_unlock(&vid_dec_device_p->lock);
+ return rc;
+}
+
+static int vid_dec_open(struct inode *inode, struct file *file)
+{
+ int rc = 0;
+ struct video_client_ctx *client_ctx;
+ INFO("msm_vidc_dec: Inside %s()", __func__);
+ mutex_lock(&vid_dec_device_p->lock);
+ rc = vid_dec_open_client(&client_ctx, 0);
+ if (rc) {
+ mutex_unlock(&vid_dec_device_p->lock);
+ return rc;
+ }
+ if (!client_ctx) {
+ mutex_unlock(&vid_dec_device_p->lock);
+ return -ENOMEM;
+ }
+
+ file->private_data = client_ctx;
+ mutex_unlock(&vid_dec_device_p->lock);
+ return rc;
+}
+
+static int vid_dec_release_secure(struct inode *inode, struct file *file)
+{
+ struct video_client_ctx *client_ctx = file->private_data;
+
+ INFO("msm_vidc_dec: Inside %s()", __func__);
+ vidc_cleanup_addr_table(client_ctx, BUFFER_TYPE_OUTPUT);
+ vidc_cleanup_addr_table(client_ctx, BUFFER_TYPE_INPUT);
+ vid_dec_close_client(client_ctx);
+ vidc_release_firmware();
+#ifndef USE_RES_TRACKER
+ vidc_disable_clk();
+#endif
+ INFO("msm_vidc_dec: Return from %s()", __func__);
+ return 0;
+}
+
+static int vid_dec_release(struct inode *inode, struct file *file)
+{
+ struct video_client_ctx *client_ctx = file->private_data;
+
+ INFO("msm_vidc_dec: Inside %s()", __func__);
+ vidc_cleanup_addr_table(client_ctx, BUFFER_TYPE_OUTPUT);
+ vidc_cleanup_addr_table(client_ctx, BUFFER_TYPE_INPUT);
+ vid_dec_close_client(client_ctx);
+ vidc_release_firmware();
+#ifndef USE_RES_TRACKER
+ vidc_disable_clk();
+#endif
+ INFO("msm_vidc_dec: Return from %s()", __func__);
+ return 0;
+}
+
+static const struct file_operations vid_dec_fops[2] = {
+ {
+ .owner = THIS_MODULE,
+ .open = vid_dec_open,
+ .release = vid_dec_release,
+ .unlocked_ioctl = vid_dec_ioctl,
+ },
+ {
+ .owner = THIS_MODULE,
+ .open = vid_dec_open_secure,
+ .release = vid_dec_release_secure,
+ .unlocked_ioctl = vid_dec_ioctl,
+ },
+
+};
+
+void vid_dec_interrupt_deregister(void)
+{
+}
+
+void vid_dec_interrupt_register(void *device_name)
+{
+}
+
+void vid_dec_interrupt_clear(void)
+{
+}
+
+void *vid_dec_map_dev_base_addr(void *device_name)
+{
+ return vid_dec_device_p->virt_base;
+}
+
+static int vid_dec_vcd_init(void)
+{
+ int rc;
+ struct vcd_init_config vcd_init_config;
+ u32 i;
+
+ /* init_timer(&hw_timer); */
+ DBG("msm_vidc_dec: Inside %s()", __func__);
+ vid_dec_device_p->num_clients = 0;
+
+ for (i = 0; i < VIDC_MAX_NUM_CLIENTS; i++) {
+ memset((void *)&vid_dec_device_p->vdec_clients[i], 0,
+ sizeof(vid_dec_device_p->vdec_clients[i]));
+ }
+
+ mutex_init(&vid_dec_device_p->lock);
+ vid_dec_device_p->virt_base = vidc_get_ioaddr();
+ DBG("%s() : base address for VIDC core %u\n", __func__, \
+ (int)vid_dec_device_p->virt_base);
+
+ if (!vid_dec_device_p->virt_base) {
+ ERR("%s() : ioremap failed\n", __func__);
+ return -ENOMEM;
+ }
+
+ vcd_init_config.device_name = "VIDC";
+ vcd_init_config.map_dev_base_addr = vid_dec_map_dev_base_addr;
+ vcd_init_config.interrupt_clr = vid_dec_interrupt_clear;
+ vcd_init_config.register_isr = vid_dec_interrupt_register;
+ vcd_init_config.deregister_isr = vid_dec_interrupt_deregister;
+ vcd_init_config.timer_create = vidc_timer_create;
+ vcd_init_config.timer_release = vidc_timer_release;
+ vcd_init_config.timer_start = vidc_timer_start;
+ vcd_init_config.timer_stop = vidc_timer_stop;
+
+ rc = vcd_init(&vcd_init_config, &vid_dec_device_p->device_handle);
+
+ if (rc) {
+ ERR("%s() : vcd_init failed\n", __func__);
+ return -ENODEV;
+ }
+ return 0;
+}
+
+static int __init vid_dec_init(void)
+{
+ int rc = 0, i = 0, j = 0;
+ struct device *class_devp;
+
+ DBG("msm_vidc_dec: Inside %s()", __func__);
+ vid_dec_device_p = kzalloc(sizeof(struct vid_dec_dev), GFP_KERNEL);
+ if (!vid_dec_device_p) {
+ ERR("%s Unable to allocate memory for vid_dec_dev\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ rc = alloc_chrdev_region(&vid_dec_dev_num, 0, NUM_OF_DRIVER_NODES,
+ VID_DEC_NAME);
+ if (rc < 0) {
+ ERR("%s: alloc_chrdev_region Failed rc = %d\n",
+ __func__, rc);
+ goto error_vid_dec_alloc_chrdev_region;
+ }
+
+ vid_dec_class = class_create(THIS_MODULE, VID_DEC_NAME);
+ if (IS_ERR(vid_dec_class)) {
+ rc = PTR_ERR(vid_dec_class);
+ ERR("%s: couldn't create vid_dec_class rc = %d\n",
+ __func__, rc);
+
+ goto error_vid_dec_class_create;
+ }
+ for (i = 0; i < NUM_OF_DRIVER_NODES; i++) {
+ class_devp = device_create(vid_dec_class, NULL,
+ (vid_dec_dev_num + i),
+ NULL, VID_DEC_NAME "%s",
+ node_name[i]);
+
+ if (IS_ERR(class_devp)) {
+ rc = PTR_ERR(class_devp);
+ ERR("%s: class device_create failed %d\n",
+ __func__, rc);
+ if (!i)
+ goto error_vid_dec_class_device_create;
+ else
+ goto error_vid_dec_cdev_add;
+ }
+
+ vid_dec_device_p->device[i] = class_devp;
+
+ cdev_init(&vid_dec_device_p->cdev[i], &vid_dec_fops[i]);
+ vid_dec_device_p->cdev[i].owner = THIS_MODULE;
+ rc = cdev_add(&(vid_dec_device_p->cdev[i]),
+ (vid_dec_dev_num+i), 1);
+
+ if (rc < 0) {
+ ERR("%s: cdev_add failed %d\n", __func__, rc);
+ goto error_vid_dec_cdev_add;
+ }
+ }
+ vid_dec_vcd_init();
+ return 0;
+
+error_vid_dec_cdev_add:
+ for (j = i-1; j >= 0; j--)
+ cdev_del(&(vid_dec_device_p->cdev[j]));
+ device_destroy(vid_dec_class, vid_dec_dev_num);
+error_vid_dec_class_device_create:
+ class_destroy(vid_dec_class);
+error_vid_dec_class_create:
+ unregister_chrdev_region(vid_dec_dev_num, NUM_OF_DRIVER_NODES);
+error_vid_dec_alloc_chrdev_region:
+ kfree(vid_dec_device_p);
+ return rc;
+}
+
+static void __exit vid_dec_exit(void)
+{
+ int i = 0;
+ INFO("msm_vidc_dec: Inside %s()", __func__);
+ for (i = 0; i < NUM_OF_DRIVER_NODES; i++)
+ cdev_del(&(vid_dec_device_p->cdev[i]));
+ device_destroy(vid_dec_class, vid_dec_dev_num);
+ class_destroy(vid_dec_class);
+ unregister_chrdev_region(vid_dec_dev_num, NUM_OF_DRIVER_NODES);
+ kfree(vid_dec_device_p);
+ DBG("msm_vidc_dec: Return from %s()", __func__);
+}
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Video decoder driver");
+MODULE_VERSION("1.0");
+
+module_init(vid_dec_init);
+module_exit(vid_dec_exit);
diff --git a/include/linux/mdss_io_util.h b/include/linux/mdss_io_util.h
index ea88cf6..4f6ba44 100644
--- a/include/linux/mdss_io_util.h
+++ b/include/linux/mdss_io_util.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012, 2015, 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
@@ -47,13 +47,20 @@
DSS_REG_VS,
};
+enum dss_vreg_mode {
+ DSS_REG_MODE_ENABLE,
+ DSS_REG_MODE_DISABLE,
+ DSS_REG_MODE_LP,
+ DSS_REG_MODE_ULP,
+ DSS_REG_MODE_MAX,
+};
+
struct dss_vreg {
struct regulator *vreg; /* vreg handle */
char vreg_name[32];
int min_voltage;
int max_voltage;
- int enable_load;
- int disable_load;
+ u32 load[DSS_REG_MODE_MAX];
int pre_on_sleep;
int post_on_sleep;
int pre_off_sleep;
@@ -99,6 +106,8 @@
int num_vreg, int config);
int msm_dss_enable_vreg(struct dss_vreg *in_vreg, int num_vreg, int enable);
void msm_dss_set_vreg_idle(struct dss_vreg *in_vreg, int num_vreg, bool idle);
+int msm_dss_config_vreg_opt_mode(struct dss_vreg *in_vreg, int num_vreg,
+ enum dss_vreg_mode mode);
int msm_dss_get_clk(struct device *dev, struct dss_clk *clk_arry, int num_clk);
void msm_dss_put_clk(struct dss_clk *clk_arry, int num_clk);
diff --git a/include/media/msm/vidc_init.h b/include/media/msm/vidc_init.h
new file mode 100644
index 0000000..9c9a270
--- /dev/null
+++ b/include/media/msm/vidc_init.h
@@ -0,0 +1,112 @@
+/* Copyright (c) 2010-2012, 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.
+ *
+ */
+
+#ifndef VIDC_INIT_H
+#define VIDC_INIT_H
+#include <linux/msm_ion.h>
+#include <media/msm/vidc_type.h>
+#include <media/msm/vcd_property.h>
+
+#define VIDC_MAX_NUM_CLIENTS 4
+#define MAX_VIDEO_NUM_OF_BUFF 100
+#define MAX_META_BUFFERS 32
+#define MAX_MV_BUFFERS 32
+
+enum buffer_dir {
+ BUFFER_TYPE_INPUT,
+ BUFFER_TYPE_OUTPUT
+};
+
+struct buf_addr_table {
+ unsigned long user_vaddr;
+ unsigned long kernel_vaddr;
+ unsigned long phy_addr;
+ unsigned long buff_ion_flag;
+ struct ion_handle *buff_ion_handle;
+ int pmem_fd;
+ struct file *file;
+ unsigned long dev_addr;
+ void *client_data;
+};
+
+struct meta_buffer_addr_table {
+ u8 *kernel_vir_addr;
+ u8 *kernel_vir_addr_iommu;
+};
+
+struct video_client_ctx {
+ void *vcd_handle;
+ u32 num_of_input_buffers;
+ u32 num_of_output_buffers;
+ struct buf_addr_table input_buf_addr_table[MAX_VIDEO_NUM_OF_BUFF];
+ struct buf_addr_table output_buf_addr_table[MAX_VIDEO_NUM_OF_BUFF];
+ struct list_head msg_queue;
+ struct mutex msg_queue_lock;
+ struct mutex enrty_queue_lock;
+ wait_queue_head_t msg_wait;
+ struct completion event;
+ struct vcd_property_h264_mv_buffer vcd_h264_mv_buffer;
+ struct vcd_property_meta_buffer vcd_meta_buffer;
+ struct vcd_property_enc_recon_buffer recon_buffer[4];
+ u32 event_status;
+ u32 seq_header_set;
+ u32 stop_msg;
+ u32 stop_called;
+ u32 stop_sync_cb;
+ size_t meta_buf_size;
+ struct ion_client *user_ion_client;
+ struct ion_handle *seq_hdr_ion_handle;
+ struct ion_handle *h264_mv_ion_handle;
+ struct ion_handle *recon_buffer_ion_handle[4];
+ struct ion_handle *meta_buffer_ion_handle;
+ struct ion_handle *meta_buffer_iommu_ion_handle;
+ u32 dmx_disable;
+ struct meta_buffer_addr_table meta_addr_table[MAX_META_BUFFERS];
+};
+
+void __iomem *vidc_get_ioaddr(void);
+int vidc_load_firmware(void);
+void vidc_release_firmware(void);
+u32 vidc_get_fd_info(struct video_client_ctx *client_ctx,
+ enum buffer_dir buffer, int pmem_fd,
+ unsigned long kvaddr, int index,
+ struct ion_handle **buff_handle);
+u32 vidc_lookup_addr_table(struct video_client_ctx *client_ctx,
+ enum buffer_dir buffer, u32 search_with_user_vaddr,
+ unsigned long *user_vaddr, unsigned long *kernel_vaddr,
+ unsigned long *phy_addr, int *pmem_fd, struct file **file,
+ s32 *buffer_index);
+u32 vidc_insert_addr_table(struct video_client_ctx *client_ctx,
+ enum buffer_dir buffer, unsigned long user_vaddr,
+ unsigned long *kernel_vaddr, int pmem_fd,
+ unsigned long buffer_addr_offset,
+ unsigned int max_num_buffers, unsigned long length);
+u32 vidc_insert_addr_table_kernel(struct video_client_ctx *client_ctx,
+ enum buffer_dir buffer, unsigned long user_vaddr,
+ unsigned long kernel_vaddr, unsigned long phys_addr,
+ unsigned int max_num_buffers,
+ unsigned long length);
+u32 vidc_delete_addr_table(struct video_client_ctx *client_ctx,
+ enum buffer_dir buffer, unsigned long user_vaddr,
+ unsigned long *kernel_vaddr);
+void vidc_cleanup_addr_table(struct video_client_ctx *client_ctx,
+ enum buffer_dir buffer);
+
+u32 vidc_timer_create(void (*timer_handler)(void *),
+ void *user_data, void **timer_handle);
+void vidc_timer_release(void *timer_handle);
+void vidc_timer_start(void *timer_handle, u32 time_out);
+void vidc_timer_stop(void *timer_handle);
+
+
+#endif
diff --git a/include/uapi/asm-generic/unistd.h b/include/uapi/asm-generic/unistd.h
index 56d3422..b422ad5 100644
--- a/include/uapi/asm-generic/unistd.h
+++ b/include/uapi/asm-generic/unistd.h
@@ -692,12 +692,14 @@
__SYSCALL(__NR_kcmp, sys_kcmp)
#define __NR_finit_module 273
__SYSCALL(__NR_finit_module, sys_finit_module)
-#define __NR_sched_setattr 274
+/* Backporting seccomp, skip a few ...
+ * #define __NR_sched_setattr 274
__SYSCALL(__NR_sched_setattr, sys_sched_setattr)
-#define __NR_sched_getattr 275
+ * #define __NR_sched_getattr 275
__SYSCALL(__NR_sched_getattr, sys_sched_getattr)
-#define __NR_renameat2 276
+ * #define __NR_renameat2 276
__SYSCALL(__NR_renameat2, sys_renameat2)
+ */
#define __NR_seccomp 277
__SYSCALL(__NR_seccomp, sys_seccomp)
diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
index 71dcc2a..b5da5a4 100644
--- a/kernel/sched/rt.c
+++ b/kernel/sched/rt.c
@@ -1423,6 +1423,15 @@
rt_rq = group_rt_rq(rt_se);
} while (rt_rq);
+ /*
+ * Force update of rq->clock_task in case we failed to do so in
+ * put_prev_task. A stale value can cause us to over-charge execution
+ * time to real-time task, that could trigger throttling unnecessarily
+ */
+ if (rq->skip_clock_update > 0) {
+ rq->skip_clock_update = 0;
+ update_rq_clock(rq);
+ }
p = rt_task_of(rt_se);
p->se.exec_start = rq->clock_task;
diff --git a/kernel/seccomp.c b/kernel/seccomp.c
index 13ed9d2..e60ae23 100644
--- a/kernel/seccomp.c
+++ b/kernel/seccomp.c
@@ -219,7 +219,6 @@
*/
for (; f; f = f->prev) {
u32 cur_ret = sk_run_filter(NULL, f->insns);
-
if ((cur_ret & SECCOMP_RET_ACTION) < (ret & SECCOMP_RET_ACTION))
ret = cur_ret;
}
@@ -774,7 +773,7 @@
}
SYSCALL_DEFINE3(seccomp, unsigned int, op, unsigned int, flags,
- const char __user *, uargs)
+ const char __user *, uargs)
{
return do_seccomp(op, flags, uargs);
}
diff --git a/kernel/sys.c b/kernel/sys.c
index 407abee..0b08c9f 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -2187,7 +2187,7 @@
tmp = end;
/* Here vma->vm_start <= start < tmp <= (end|vma->vm_end). */
- error = prctl_update_vma_anon_name(vma, &prev, start, end,
+ error = prctl_update_vma_anon_name(vma, &prev, start, tmp,
(const char __user *)arg);
if (error)
return error;
diff --git a/kernel/trace/msm_rtb.c b/kernel/trace/msm_rtb.c
index 8d288c8..2033a17 100644
--- a/kernel/trace/msm_rtb.c
+++ b/kernel/trace/msm_rtb.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * 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
@@ -35,20 +35,22 @@
#define RTB_COMPAT_STR "qcom,msm-rtb"
/* Write
- * 1) 11 bytes sentinel
+ * 1) 3 bytes sentinel
* 2) 1 bytes of log type
* 3) 8 bytes of where the caller came from
* 4) 4 bytes index
* 4) 8 bytes extra data from the caller
+ * 5) 8 bytes of timestamp
*
* Total = 32 bytes.
*/
struct msm_rtb_layout {
- unsigned char sentinel[11];
+ unsigned char sentinel[3];
unsigned char log_type;
uint32_t idx;
uint64_t caller;
uint64_t data;
+ uint64_t timestamp;
} __attribute__ ((__packed__));
@@ -124,6 +126,11 @@
start->data = data;
}
+static void msm_rtb_write_timestamp(struct msm_rtb_layout *start)
+{
+ start->timestamp = sched_clock();
+}
+
static void uncached_logk_pc_idx(enum logk_event_type log_type, uint64_t caller,
uint64_t data, int idx)
{
@@ -136,6 +143,7 @@
msm_rtb_write_caller(caller, start);
msm_rtb_write_idx(idx, start);
msm_rtb_write_data(data, start);
+ msm_rtb_write_timestamp(start);
mb();
return;
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index cdd7716..2bc6c11 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -700,7 +700,7 @@
NEIGH_CACHE_STAT_INC(neigh->tbl, destroys);
if (!neigh->dead) {
- pr_warn("Destroying alive neighbour %p\n", neigh);
+ pr_warn("Destroying alive neighbour %pK\n", neigh);
dump_stack();
return;
}
@@ -1317,7 +1317,7 @@
out:
return rc;
discard:
- neigh_dbg(1, "%s: dst=%p neigh=%p\n", __func__, dst, neigh);
+ neigh_dbg(1, "%s: dst=%pK neigh=%pK\n", __func__, dst, neigh);
out_kfree_skb:
rc = -EINVAL;
kfree_skb(skb);
diff --git a/net/ipc_router/ipc_router_core.c b/net/ipc_router/ipc_router_core.c
index f3c98f0..e181233 100644
--- a/net/ipc_router/ipc_router_core.c
+++ b/net/ipc_router/ipc_router_core.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2014, 2016, 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
@@ -2904,7 +2904,7 @@
int msm_ipc_router_bind_control_port(struct msm_ipc_port *port_ptr)
{
- if (!port_ptr)
+ if (unlikely(!port_ptr || port_ptr->type != CLIENT_PORT))
return -EINVAL;
down_write(&local_ports_lock_lha2);
diff --git a/net/ipc_router/ipc_router_socket.c b/net/ipc_router/ipc_router_socket.c
index 9dbbe61..ea46fd5 100644
--- a/net/ipc_router/ipc_router_socket.c
+++ b/net/ipc_router/ipc_router_socket.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2014, 2016, 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
@@ -519,13 +519,18 @@
ret = copy_to_user((void *)arg, &server_arg,
sizeof(server_arg));
- if (srv_info_sz) {
+
+ n = min(server_arg.num_entries_found,
+ server_arg.num_entries_in_array);
+
+ if (ret == 0 && n) {
ret = copy_to_user((void *)(arg + sizeof(server_arg)),
- srv_info, srv_info_sz);
- if (ret)
- ret = -EFAULT;
- kfree(srv_info);
+ srv_info, n * sizeof(*srv_info));
}
+
+ if (ret)
+ ret = -EFAULT;
+ kfree(srv_info);
break;
case IPC_ROUTER_IOCTL_BIND_CONTROL_PORT:
diff --git a/net/rmnet_data/rmnet_data_handlers.c b/net/rmnet_data/rmnet_data_handlers.c
index b680637..72b26e3 100644
--- a/net/rmnet_data/rmnet_data_handlers.c
+++ b/net/rmnet_data/rmnet_data_handlers.c
@@ -103,9 +103,10 @@
if (!printlen)
return;
- pr_err("[%s][%c] - PKT skb->len=%d skb->head=%p skb->data=%p skb->tail=%p skb->end=%p\n",
- dev, dir, skb->len, (void *)skb->head, (void *)skb->data,
- skb_tail_pointer(skb), skb_end_pointer(skb));
+ pr_err("[%s][%c] - PKT skb->len=%d skb->head=%pK skb->data=%pK\n",
+ dev, dir, skb->len, (void *)skb->head, (void *)skb->data);
+ pr_err("[%s][%c] - PKT skb->tail=%pK skb->end=%pK\n",
+ dev, dir, skb_tail_pointer(skb), skb_end_pointer(skb));
if (skb->len > 0)
len = skb->len;
diff --git a/net/rmnet_data/rmnet_data_trace.h b/net/rmnet_data/rmnet_data_trace.h
index 98a6ed5..dee46a0 100644
--- a/net/rmnet_data/rmnet_data_trace.h
+++ b/net/rmnet_data/rmnet_data_trace.h
@@ -39,8 +39,8 @@
__assign_str(name, skb->dev->name);
),
- TP_printk("dev=%s skbaddr=%p len=%u",
- __get_str(name), __entry->skbaddr, __entry->len)
+ TP_printk("dev=%s skbaddr=%pK len=%u",
+ __get_str(name), __entry->skbaddr, __entry->len)
)
DEFINE_EVENT(rmnet_handler_template, rmnet_egress_handler,
@@ -128,8 +128,9 @@
__entry->num = num_agg_pakcets;
),
- TP_printk("dev=%s skbaddr=%p len=%u agg_count: %d",
- __get_str(name), __entry->skbaddr, __entry->len, __entry->num)
+ TP_printk("dev=%s skbaddr=%pK len=%u agg_count: %d",
+ __get_str(name), __entry->skbaddr, __entry->len,
+ __entry->num)
)
DEFINE_EVENT(rmnet_aggregation_template, rmnet_map_aggregate,
diff --git a/net/rmnet_data/rmnet_data_vnd.c b/net/rmnet_data/rmnet_data_vnd.c
index e9843c5a..7b75dd6 100644
--- a/net/rmnet_data/rmnet_data_vnd.c
+++ b/net/rmnet_data/rmnet_data_vnd.c
@@ -811,7 +811,7 @@
itm->tc_flow_valid[i] = 1;
itm->tc_flow_id[i] = tc_flow;
rc = RMNET_VND_UPDATE_FLOW_OK;
- LOGD("{%p}->tc_flow_id[%d]=%08X",
+ LOGD("{%pK}->tc_flow_id[%d]=%08X",
itm, i, tc_flow);
break;
}
@@ -827,7 +827,7 @@
itm->tc_flow_valid[i] = 0;
itm->tc_flow_id[i] = 0;
j++;
- LOGD("{%p}->tc_flow_id[%d]=0", itm, i);
+ LOGD("{%pK}->tc_flow_id[%d]=0", itm, i);
}
} else {
j++;
@@ -972,7 +972,7 @@
if (r == RMNET_VND_UPDATE_FLOW_NO_VALID_LEFT) {
if (itm)
- LOGD("Removed flow mapping [%s][0x%08X]@%p",
+ LOGD("Removed flow mapping [%s][0x%08X]@%pK",
dev->name, itm->map_flow_id, itm);
kfree(itm);
}
diff --git a/sound/soc/msm/msm8226-wear.c b/sound/soc/msm/msm8226-wear.c
index d24c4df..952fa83 100644
--- a/sound/soc/msm/msm8226-wear.c
+++ b/sound/soc/msm/msm8226-wear.c
@@ -688,6 +688,10 @@
snd_soc_dapm_ignore_suspend(dapm, "Analog Mic4");
snd_soc_dapm_ignore_suspend(dapm, "AMIC3");
snd_soc_dapm_ignore_suspend(dapm, "AMIC4");
+ snd_soc_dapm_ignore_suspend(dapm, "SPK_OUT");
+ snd_soc_dapm_ignore_suspend(dapm, "BE_IN");
+ snd_soc_dapm_ignore_suspend(dapm, "BE_OUT");
+
snd_soc_dapm_sync(dapm);
codec_clk = clk_get(cpu_dai->dev, "osr_clk");
diff --git a/sound/soc/msm/msm8226.c b/sound/soc/msm/msm8226.c
index 19a5e1c..9111c35 100644
--- a/sound/soc/msm/msm8226.c
+++ b/sound/soc/msm/msm8226.c
@@ -1041,6 +1041,29 @@
snd_soc_dapm_new_controls(dapm, msm8226_dapm_widgets,
ARRAY_SIZE(msm8226_dapm_widgets));
+ snd_soc_dapm_ignore_suspend(dapm, "Handset Mic");
+ snd_soc_dapm_ignore_suspend(dapm, "Headset Mic");
+ snd_soc_dapm_ignore_suspend(dapm, "ANCRight Headset Mic");
+ snd_soc_dapm_ignore_suspend(dapm, "ANCLeft Headset Mic");
+ snd_soc_dapm_ignore_suspend(dapm, "Digital Mic1");
+ snd_soc_dapm_ignore_suspend(dapm, "Digital Mic2");
+ snd_soc_dapm_ignore_suspend(dapm, "Digital Mic3");
+ snd_soc_dapm_ignore_suspend(dapm, "Digital Mic4");
+ snd_soc_dapm_ignore_suspend(dapm, "DMIC1");
+ snd_soc_dapm_ignore_suspend(dapm, "DMIC2");
+ snd_soc_dapm_ignore_suspend(dapm, "DMIC3");
+ snd_soc_dapm_ignore_suspend(dapm, "DMIC4");
+ snd_soc_dapm_ignore_suspend(dapm, "Analog Mic3");
+ snd_soc_dapm_ignore_suspend(dapm, "Analog Mic4");
+ snd_soc_dapm_ignore_suspend(dapm, "AMIC1");
+ snd_soc_dapm_ignore_suspend(dapm, "AMIC2");
+ snd_soc_dapm_ignore_suspend(dapm, "AMIC3");
+ snd_soc_dapm_ignore_suspend(dapm, "AMIC4");
+ snd_soc_dapm_ignore_suspend(dapm, "AMIC5");
+ snd_soc_dapm_ignore_suspend(dapm, "SPK_OUT");
+ snd_soc_dapm_ignore_suspend(dapm, "BE_IN");
+ snd_soc_dapm_ignore_suspend(dapm, "BE_OUT");
+
snd_soc_dapm_sync(dapm);
codec_clk = clk_get(cpu_dai->dev, "osr_clk");
diff --git a/sound/soc/msm/qdsp6v2/msm-audio-effects-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-audio-effects-q6-v2.c
index bd1feea..cf96e2c 100644
--- a/sound/soc/msm/qdsp6v2/msm-audio-effects-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-audio-effects-q6-v2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2016, 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
@@ -16,19 +16,39 @@
#include <sound/compress_params.h>
#include "msm-audio-effects-q6-v2.h"
+#define MAX_ENABLE_CMD_SIZE 32
+
+#define GET_NEXT(ptr, upper_limit, rc) \
+({ \
+ if (((ptr) + 1) > (upper_limit)) { \
+ pr_err("%s: param list out of boundary\n", __func__); \
+ (rc) = -EINVAL; \
+ } \
+ ((rc) == 0) ? *(ptr)++ : -EINVAL; \
+})
+
+#define CHECK_PARAM_LEN(len, max_len, tag, rc) \
+do { \
+ if ((len) > (max_len)) { \
+ pr_err("%s: params length overflows\n", (tag)); \
+ (rc) = -EINVAL; \
+ } \
+} while (0)
+
int msm_audio_effects_virtualizer_handler(struct audio_client *ac,
struct virtualizer_params *virtualizer,
long *values)
{
- int devices = *values++;
- int num_commands = *values++;
- char *params;
+ long *param_max_offset = values + MAX_PP_PARAMS_SZ - 1;
+ char *params = NULL;
+ int rc = 0;
+ int devices = GET_NEXT(values, param_max_offset, rc);
+ int num_commands = GET_NEXT(values, param_max_offset, rc);
int *updt_params, i, prev_enable_flag;
uint32_t params_length = (MAX_INBAND_PARAM_SZ);
- int rc = 0;
pr_debug("%s\n", __func__);
- if (!ac) {
+ if (!ac || (devices == -EINVAL) || (num_commands == -EINVAL)) {
pr_err("%s: cannot set audio effects\n", __func__);
return -EINVAL;
}
@@ -41,10 +61,14 @@
updt_params = (int *)params;
params_length = 0;
for (i = 0; i < num_commands; i++) {
- uint32_t command_id = *values++;
- uint32_t command_config_state = *values++;
- uint32_t index_offset = *values++;
- uint32_t length = *values++;
+ uint32_t command_id =
+ GET_NEXT(values, param_max_offset, rc);
+ uint32_t command_config_state =
+ GET_NEXT(values, param_max_offset, rc);
+ uint32_t index_offset =
+ GET_NEXT(values, param_max_offset, rc);
+ uint32_t length =
+ GET_NEXT(values, param_max_offset, rc);
switch (command_id) {
case VIRTUALIZER_ENABLE:
if (length != 1 || index_offset != 0) {
@@ -53,17 +77,26 @@
goto invalid_config;
}
prev_enable_flag = virtualizer->enable_flag;
- virtualizer->enable_flag = *values++;
+ virtualizer->enable_flag =
+ GET_NEXT(values, param_max_offset, rc);
pr_debug("%s:VIRT ENABLE prev:%d, new:%d\n", __func__,
prev_enable_flag, virtualizer->enable_flag);
if (prev_enable_flag != virtualizer->enable_flag) {
- *updt_params++ = AUDPROC_MODULE_ID_VIRTUALIZER;
- *updt_params++ =
- AUDPROC_PARAM_ID_VIRTUALIZER_ENABLE;
- *updt_params++ = VIRTUALIZER_ENABLE_PARAM_SZ;
- *updt_params++ = virtualizer->enable_flag;
params_length += COMMAND_PAYLOAD_SZ +
VIRTUALIZER_ENABLE_PARAM_SZ;
+ CHECK_PARAM_LEN(params_length,
+ MAX_INBAND_PARAM_SZ,
+ "VIRT ENABLE", rc);
+ if (rc != 0)
+ break;
+ *updt_params++ =
+ AUDPROC_MODULE_ID_VIRTUALIZER;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_VIRTUALIZER_ENABLE;
+ *updt_params++ =
+ VIRTUALIZER_ENABLE_PARAM_SZ;
+ *updt_params++ =
+ virtualizer->enable_flag;
}
break;
case VIRTUALIZER_STRENGTH:
@@ -72,17 +105,26 @@
rc = -EINVAL;
goto invalid_config;
}
- virtualizer->strength = *values++;
+ virtualizer->strength =
+ GET_NEXT(values, param_max_offset, rc);
pr_debug("%s: VIRT STRENGTH val: %d\n",
__func__, virtualizer->strength);
if (command_config_state == CONFIG_SET) {
- *updt_params++ = AUDPROC_MODULE_ID_VIRTUALIZER;
- *updt_params++ =
- AUDPROC_PARAM_ID_VIRTUALIZER_STRENGTH;
- *updt_params++ = VIRTUALIZER_STRENGTH_PARAM_SZ;
- *updt_params++ = virtualizer->strength;
params_length += COMMAND_PAYLOAD_SZ +
VIRTUALIZER_STRENGTH_PARAM_SZ;
+ CHECK_PARAM_LEN(params_length,
+ MAX_INBAND_PARAM_SZ,
+ "VIRT STRENGTH", rc);
+ if (rc != 0)
+ break;
+ *updt_params++ =
+ AUDPROC_MODULE_ID_VIRTUALIZER;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_VIRTUALIZER_STRENGTH;
+ *updt_params++ =
+ VIRTUALIZER_STRENGTH_PARAM_SZ;
+ *updt_params++ =
+ virtualizer->strength;
}
break;
case VIRTUALIZER_OUT_TYPE:
@@ -91,17 +133,26 @@
rc = -EINVAL;
goto invalid_config;
}
- virtualizer->out_type = *values++;
+ virtualizer->out_type =
+ GET_NEXT(values, param_max_offset, rc);
pr_debug("%s: VIRT OUT_TYPE val:%d\n",
__func__, virtualizer->out_type);
if (command_config_state == CONFIG_SET) {
- *updt_params++ = AUDPROC_MODULE_ID_VIRTUALIZER;
- *updt_params++ =
- AUDPROC_PARAM_ID_VIRTUALIZER_OUT_TYPE;
- *updt_params++ = VIRTUALIZER_OUT_TYPE_PARAM_SZ;
- *updt_params++ = virtualizer->out_type;
params_length += COMMAND_PAYLOAD_SZ +
VIRTUALIZER_OUT_TYPE_PARAM_SZ;
+ CHECK_PARAM_LEN(params_length,
+ MAX_INBAND_PARAM_SZ,
+ "VIRT OUT_TYPE", rc);
+ if (rc != 0)
+ break;
+ *updt_params++ =
+ AUDPROC_MODULE_ID_VIRTUALIZER;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_VIRTUALIZER_OUT_TYPE;
+ *updt_params++ =
+ VIRTUALIZER_OUT_TYPE_PARAM_SZ;
+ *updt_params++ =
+ virtualizer->out_type;
}
break;
case VIRTUALIZER_GAIN_ADJUST:
@@ -110,18 +161,26 @@
rc = -EINVAL;
goto invalid_config;
}
- virtualizer->gain_adjust = *values++;
+ virtualizer->gain_adjust =
+ GET_NEXT(values, param_max_offset, rc);
pr_debug("%s: VIRT GAIN_ADJUST val:%d\n",
__func__, virtualizer->gain_adjust);
if (command_config_state == CONFIG_SET) {
- *updt_params++ = AUDPROC_MODULE_ID_VIRTUALIZER;
- *updt_params++ =
- AUDPROC_PARAM_ID_VIRTUALIZER_GAIN_ADJUST;
- *updt_params++ =
- VIRTUALIZER_GAIN_ADJUST_PARAM_SZ;
- *updt_params++ = virtualizer->gain_adjust;
params_length += COMMAND_PAYLOAD_SZ +
VIRTUALIZER_GAIN_ADJUST_PARAM_SZ;
+ CHECK_PARAM_LEN(params_length,
+ MAX_INBAND_PARAM_SZ,
+ "VIRT GAIN_ADJUST", rc);
+ if (rc != 0)
+ break;
+ *updt_params++ =
+ AUDPROC_MODULE_ID_VIRTUALIZER;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_VIRTUALIZER_GAIN_ADJUST;
+ *updt_params++ =
+ VIRTUALIZER_GAIN_ADJUST_PARAM_SZ;
+ *updt_params++ =
+ virtualizer->gain_adjust;
}
break;
default:
@@ -129,7 +188,7 @@
break;
}
}
- if (params_length)
+ if (params_length && (rc == 0))
q6asm_send_audio_effects_params(ac, params,
params_length);
invalid_config:
@@ -141,15 +200,16 @@
struct reverb_params *reverb,
long *values)
{
- int devices = *values++;
- int num_commands = *values++;
- char *params;
+ long *param_max_offset = values + MAX_PP_PARAMS_SZ - 1;
+ char *params = NULL;
+ int rc = 0;
+ int devices = GET_NEXT(values, param_max_offset, rc);
+ int num_commands = GET_NEXT(values, param_max_offset, rc);
int *updt_params, i, prev_enable_flag;
uint32_t params_length = (MAX_INBAND_PARAM_SZ);
- int rc = 0;
pr_debug("%s\n", __func__);
- if (!ac) {
+ if (!ac || (devices == -EINVAL) || (num_commands == -EINVAL)) {
pr_err("%s: cannot set audio effects\n", __func__);
return -EINVAL;
}
@@ -162,10 +222,14 @@
updt_params = (int *)params;
params_length = 0;
for (i = 0; i < num_commands; i++) {
- uint32_t command_id = *values++;
- uint32_t command_config_state = *values++;
- uint32_t index_offset = *values++;
- uint32_t length = *values++;
+ uint32_t command_id =
+ GET_NEXT(values, param_max_offset, rc);
+ uint32_t command_config_state =
+ GET_NEXT(values, param_max_offset, rc);
+ uint32_t index_offset =
+ GET_NEXT(values, param_max_offset, rc);
+ uint32_t length =
+ GET_NEXT(values, param_max_offset, rc);
switch (command_id) {
case REVERB_ENABLE:
if (length != 1 || index_offset != 0) {
@@ -174,16 +238,26 @@
goto invalid_config;
}
prev_enable_flag = reverb->enable_flag;
- reverb->enable_flag = *values++;
+ reverb->enable_flag =
+ GET_NEXT(values, param_max_offset, rc);
pr_debug("%s:REVERB_ENABLE prev:%d,new:%d\n", __func__,
prev_enable_flag, reverb->enable_flag);
if (prev_enable_flag != reverb->enable_flag) {
- *updt_params++ = AUDPROC_MODULE_ID_REVERB;
- *updt_params++ = AUDPROC_PARAM_ID_REVERB_ENABLE;
- *updt_params++ = REVERB_ENABLE_PARAM_SZ;
- *updt_params++ = reverb->enable_flag;
params_length += COMMAND_PAYLOAD_SZ +
REVERB_ENABLE_PARAM_SZ;
+ CHECK_PARAM_LEN(params_length,
+ MAX_INBAND_PARAM_SZ,
+ "REVERB_ENABLE", rc);
+ if (rc != 0)
+ break;
+ *updt_params++ =
+ AUDPROC_MODULE_ID_REVERB;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_REVERB_ENABLE;
+ *updt_params++ =
+ REVERB_ENABLE_PARAM_SZ;
+ *updt_params++ =
+ reverb->enable_flag;
}
break;
case REVERB_MODE:
@@ -192,16 +266,26 @@
rc = -EINVAL;
goto invalid_config;
}
- reverb->mode = *values++;
+ reverb->mode =
+ GET_NEXT(values, param_max_offset, rc);
pr_debug("%s: REVERB_MODE val:%d\n",
__func__, reverb->mode);
if (command_config_state == CONFIG_SET) {
- *updt_params++ = AUDPROC_MODULE_ID_REVERB;
- *updt_params++ = AUDPROC_PARAM_ID_REVERB_MODE;
- *updt_params++ = REVERB_MODE_PARAM_SZ;
- *updt_params++ = reverb->mode;
params_length += COMMAND_PAYLOAD_SZ +
REVERB_MODE_PARAM_SZ;
+ CHECK_PARAM_LEN(params_length,
+ MAX_INBAND_PARAM_SZ,
+ "REVERB_MODE", rc);
+ if (rc != 0)
+ break;
+ *updt_params++ =
+ AUDPROC_MODULE_ID_REVERB;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_REVERB_MODE;
+ *updt_params++ =
+ REVERB_MODE_PARAM_SZ;
+ *updt_params++ =
+ reverb->mode;
}
break;
case REVERB_PRESET:
@@ -210,16 +294,26 @@
rc = -EINVAL;
goto invalid_config;
}
- reverb->preset = *values++;
+ reverb->preset =
+ GET_NEXT(values, param_max_offset, rc);
pr_debug("%s: REVERB_PRESET val:%d\n",
__func__, reverb->preset);
if (command_config_state == CONFIG_SET) {
- *updt_params++ = AUDPROC_MODULE_ID_REVERB;
- *updt_params++ = AUDPROC_PARAM_ID_REVERB_PRESET;
- *updt_params++ = REVERB_PRESET_PARAM_SZ;
- *updt_params++ = reverb->preset;
params_length += COMMAND_PAYLOAD_SZ +
REVERB_PRESET_PARAM_SZ;
+ CHECK_PARAM_LEN(params_length,
+ MAX_INBAND_PARAM_SZ,
+ "REVERB_PRESET", rc);
+ if (rc != 0)
+ break;
+ *updt_params++ =
+ AUDPROC_MODULE_ID_REVERB;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_REVERB_PRESET;
+ *updt_params++ =
+ REVERB_PRESET_PARAM_SZ;
+ *updt_params++ =
+ reverb->preset;
}
break;
case REVERB_WET_MIX:
@@ -228,17 +322,26 @@
rc = -EINVAL;
goto invalid_config;
}
- reverb->wet_mix = *values++;
+ reverb->wet_mix =
+ GET_NEXT(values, param_max_offset, rc);
pr_debug("%s: REVERB_WET_MIX val:%d\n",
__func__, reverb->wet_mix);
if (command_config_state == CONFIG_SET) {
- *updt_params++ = AUDPROC_MODULE_ID_REVERB;
- *updt_params++ =
- AUDPROC_PARAM_ID_REVERB_WET_MIX;
- *updt_params++ = REVERB_WET_MIX_PARAM_SZ;
- *updt_params++ = reverb->wet_mix;
params_length += COMMAND_PAYLOAD_SZ +
REVERB_WET_MIX_PARAM_SZ;
+ CHECK_PARAM_LEN(params_length,
+ MAX_INBAND_PARAM_SZ,
+ "REVERB_WET_MIX", rc);
+ if (rc != 0)
+ break;
+ *updt_params++ =
+ AUDPROC_MODULE_ID_REVERB;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_REVERB_WET_MIX;
+ *updt_params++ =
+ REVERB_WET_MIX_PARAM_SZ;
+ *updt_params++ =
+ reverb->wet_mix;
}
break;
case REVERB_GAIN_ADJUST:
@@ -247,17 +350,26 @@
rc = -EINVAL;
goto invalid_config;
}
- reverb->gain_adjust = *values++;
+ reverb->gain_adjust =
+ GET_NEXT(values, param_max_offset, rc);
pr_debug("%s: REVERB_GAIN_ADJUST val:%d\n",
__func__, reverb->gain_adjust);
if (command_config_state == CONFIG_SET) {
- *updt_params++ = AUDPROC_MODULE_ID_REVERB;
- *updt_params++ =
- AUDPROC_PARAM_ID_REVERB_GAIN_ADJUST;
- *updt_params++ = REVERB_GAIN_ADJUST_PARAM_SZ;
- *updt_params++ = reverb->gain_adjust;
params_length += COMMAND_PAYLOAD_SZ +
REVERB_GAIN_ADJUST_PARAM_SZ;
+ CHECK_PARAM_LEN(params_length,
+ MAX_INBAND_PARAM_SZ,
+ "REVERB_GAIN_ADJUST", rc);
+ if (rc != 0)
+ break;
+ *updt_params++ =
+ AUDPROC_MODULE_ID_REVERB;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_REVERB_GAIN_ADJUST;
+ *updt_params++ =
+ REVERB_GAIN_ADJUST_PARAM_SZ;
+ *updt_params++ =
+ reverb->gain_adjust;
}
break;
case REVERB_ROOM_LEVEL:
@@ -266,17 +378,26 @@
rc = -EINVAL;
goto invalid_config;
}
- reverb->room_level = *values++;
+ reverb->room_level =
+ GET_NEXT(values, param_max_offset, rc);
pr_debug("%s: REVERB_ROOM_LEVEL val:%d\n",
__func__, reverb->room_level);
if (command_config_state == CONFIG_SET) {
- *updt_params++ = AUDPROC_MODULE_ID_REVERB;
- *updt_params++ =
- AUDPROC_PARAM_ID_REVERB_ROOM_LEVEL;
- *updt_params++ = REVERB_ROOM_LEVEL_PARAM_SZ;
- *updt_params++ = reverb->room_level;
params_length += COMMAND_PAYLOAD_SZ +
REVERB_ROOM_LEVEL_PARAM_SZ;
+ CHECK_PARAM_LEN(params_length,
+ MAX_INBAND_PARAM_SZ,
+ "REVERB_ROOM_LEVEL", rc);
+ if (rc != 0)
+ break;
+ *updt_params++ =
+ AUDPROC_MODULE_ID_REVERB;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_REVERB_ROOM_LEVEL;
+ *updt_params++ =
+ REVERB_ROOM_LEVEL_PARAM_SZ;
+ *updt_params++ =
+ reverb->room_level;
}
break;
case REVERB_ROOM_HF_LEVEL:
@@ -285,17 +406,26 @@
rc = -EINVAL;
goto invalid_config;
}
- reverb->room_hf_level = *values++;
+ reverb->room_hf_level =
+ GET_NEXT(values, param_max_offset, rc);
pr_debug("%s: REVERB_ROOM_HF_LEVEL val%d\n",
__func__, reverb->room_hf_level);
if (command_config_state == CONFIG_SET) {
- *updt_params++ = AUDPROC_MODULE_ID_REVERB;
- *updt_params++ =
- AUDPROC_PARAM_ID_REVERB_ROOM_HF_LEVEL;
- *updt_params++ = REVERB_ROOM_HF_LEVEL_PARAM_SZ;
- *updt_params++ = reverb->room_hf_level;
params_length += COMMAND_PAYLOAD_SZ +
REVERB_ROOM_HF_LEVEL_PARAM_SZ;
+ CHECK_PARAM_LEN(params_length,
+ MAX_INBAND_PARAM_SZ,
+ "REVERB_ROOM_HF_LEVEL", rc);
+ if (rc != 0)
+ break;
+ *updt_params++ =
+ AUDPROC_MODULE_ID_REVERB;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_REVERB_ROOM_HF_LEVEL;
+ *updt_params++ =
+ REVERB_ROOM_HF_LEVEL_PARAM_SZ;
+ *updt_params++ =
+ reverb->room_hf_level;
}
break;
case REVERB_DECAY_TIME:
@@ -304,17 +434,26 @@
rc = -EINVAL;
goto invalid_config;
}
- reverb->decay_time = *values++;
+ reverb->decay_time =
+ GET_NEXT(values, param_max_offset, rc);
pr_debug("%s: REVERB_DECAY_TIME val:%d\n",
__func__, reverb->decay_time);
if (command_config_state == CONFIG_SET) {
- *updt_params++ = AUDPROC_MODULE_ID_REVERB;
- *updt_params++ =
- AUDPROC_PARAM_ID_REVERB_DECAY_TIME;
- *updt_params++ = REVERB_DECAY_TIME_PARAM_SZ;
- *updt_params++ = reverb->decay_time;
params_length += COMMAND_PAYLOAD_SZ +
REVERB_DECAY_TIME_PARAM_SZ;
+ CHECK_PARAM_LEN(params_length,
+ MAX_INBAND_PARAM_SZ,
+ "REVERB_DECAY_TIME", rc);
+ if (rc != 0)
+ break;
+ *updt_params++ =
+ AUDPROC_MODULE_ID_REVERB;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_REVERB_DECAY_TIME;
+ *updt_params++ =
+ REVERB_DECAY_TIME_PARAM_SZ;
+ *updt_params++ =
+ reverb->decay_time;
}
break;
case REVERB_DECAY_HF_RATIO:
@@ -323,17 +462,26 @@
rc = -EINVAL;
goto invalid_config;
}
- reverb->decay_hf_ratio = *values++;
+ reverb->decay_hf_ratio =
+ GET_NEXT(values, param_max_offset, rc);
pr_debug("%s: REVERB_DECAY_HF_RATIO val%d\n",
__func__, reverb->decay_hf_ratio);
if (command_config_state == CONFIG_SET) {
- *updt_params++ = AUDPROC_MODULE_ID_REVERB;
- *updt_params++ =
- AUDPROC_PARAM_ID_REVERB_DECAY_HF_RATIO;
- *updt_params++ = REVERB_DECAY_HF_RATIO_PARAM_SZ;
- *updt_params++ = reverb->decay_hf_ratio;
params_length += COMMAND_PAYLOAD_SZ +
REVERB_DECAY_HF_RATIO_PARAM_SZ;
+ CHECK_PARAM_LEN(params_length,
+ MAX_INBAND_PARAM_SZ,
+ "REVERB_DECAY_HF_RATIO", rc);
+ if (rc != 0)
+ break;
+ *updt_params++ =
+ AUDPROC_MODULE_ID_REVERB;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_REVERB_DECAY_HF_RATIO;
+ *updt_params++ =
+ REVERB_DECAY_HF_RATIO_PARAM_SZ;
+ *updt_params++ =
+ reverb->decay_hf_ratio;
}
break;
case REVERB_REFLECTIONS_LEVEL:
@@ -342,18 +490,26 @@
rc = -EINVAL;
goto invalid_config;
}
- reverb->reflections_level = *values++;
+ reverb->reflections_level =
+ GET_NEXT(values, param_max_offset, rc);
pr_debug("%s: REVERB_REFLECTIONS_LEVEL val:%d\n",
__func__, reverb->reflections_level);
if (command_config_state == CONFIG_SET) {
- *updt_params++ = AUDPROC_MODULE_ID_REVERB;
- *updt_params++ =
- AUDPROC_PARAM_ID_REVERB_REFLECTIONS_LEVEL;
- *updt_params++ =
- REVERB_REFLECTIONS_LEVEL_PARAM_SZ;
- *updt_params++ = reverb->reflections_level;
params_length += COMMAND_PAYLOAD_SZ +
REVERB_REFLECTIONS_LEVEL_PARAM_SZ;
+ CHECK_PARAM_LEN(params_length,
+ MAX_INBAND_PARAM_SZ,
+ "REVERB_REFLECTIONS_LEVEL", rc);
+ if (rc != 0)
+ break;
+ *updt_params++ =
+ AUDPROC_MODULE_ID_REVERB;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_REVERB_REFLECTIONS_LEVEL;
+ *updt_params++ =
+ REVERB_REFLECTIONS_LEVEL_PARAM_SZ;
+ *updt_params++ =
+ reverb->reflections_level;
}
break;
case REVERB_REFLECTIONS_DELAY:
@@ -362,18 +518,26 @@
rc = -EINVAL;
goto invalid_config;
}
- reverb->reflections_delay = *values++;
+ reverb->reflections_delay =
+ GET_NEXT(values, param_max_offset, rc);
pr_debug("%s: REVERB_REFLECTIONS_DELAY val:%d\n",
__func__, reverb->reflections_delay);
if (command_config_state == CONFIG_SET) {
- *updt_params++ = AUDPROC_MODULE_ID_REVERB;
- *updt_params++ =
- AUDPROC_PARAM_ID_REVERB_REFLECTIONS_DELAY;
- *updt_params++ =
- REVERB_REFLECTIONS_DELAY_PARAM_SZ;
- *updt_params++ = reverb->reflections_delay;
params_length += COMMAND_PAYLOAD_SZ +
REVERB_REFLECTIONS_DELAY_PARAM_SZ;
+ CHECK_PARAM_LEN(params_length,
+ MAX_INBAND_PARAM_SZ,
+ "REVERB_REFLECTIONS_DELAY", rc);
+ if (rc != 0)
+ break;
+ *updt_params++ =
+ AUDPROC_MODULE_ID_REVERB;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_REVERB_REFLECTIONS_DELAY;
+ *updt_params++ =
+ REVERB_REFLECTIONS_DELAY_PARAM_SZ;
+ *updt_params++ =
+ reverb->reflections_delay;
}
break;
case REVERB_LEVEL:
@@ -382,16 +546,26 @@
rc = -EINVAL;
goto invalid_config;
}
- reverb->level = *values++;
+ reverb->level =
+ GET_NEXT(values, param_max_offset, rc);
pr_debug("%s: REVERB_LEVEL val:%d\n",
__func__, reverb->level);
if (command_config_state == CONFIG_SET) {
- *updt_params++ = AUDPROC_MODULE_ID_REVERB;
- *updt_params++ = AUDPROC_PARAM_ID_REVERB_LEVEL;
- *updt_params++ = REVERB_LEVEL_PARAM_SZ;
- *updt_params++ = reverb->level;
params_length += COMMAND_PAYLOAD_SZ +
REVERB_LEVEL_PARAM_SZ;
+ CHECK_PARAM_LEN(params_length,
+ MAX_INBAND_PARAM_SZ,
+ "REVERB_LEVEL", rc);
+ if (rc != 0)
+ break;
+ *updt_params++ =
+ AUDPROC_MODULE_ID_REVERB;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_REVERB_LEVEL;
+ *updt_params++ =
+ REVERB_LEVEL_PARAM_SZ;
+ *updt_params++ =
+ reverb->level;
}
break;
case REVERB_DELAY:
@@ -400,16 +574,26 @@
rc = -EINVAL;
goto invalid_config;
}
- reverb->delay = *values++;
+ reverb->delay =
+ GET_NEXT(values, param_max_offset, rc);
pr_debug("%s:REVERB_DELAY val:%d\n",
__func__, reverb->delay);
if (command_config_state == CONFIG_SET) {
- *updt_params++ = AUDPROC_MODULE_ID_REVERB;
- *updt_params++ = AUDPROC_PARAM_ID_REVERB_DELAY;
- *updt_params++ = REVERB_DELAY_PARAM_SZ;
- *updt_params++ = reverb->delay;
params_length += COMMAND_PAYLOAD_SZ +
REVERB_DELAY_PARAM_SZ;
+ CHECK_PARAM_LEN(params_length,
+ MAX_INBAND_PARAM_SZ,
+ "REVERB_DELAY", rc);
+ if (rc != 0)
+ break;
+ *updt_params++ =
+ AUDPROC_MODULE_ID_REVERB;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_REVERB_DELAY;
+ *updt_params++ =
+ REVERB_DELAY_PARAM_SZ;
+ *updt_params++ =
+ reverb->delay;
}
break;
case REVERB_DIFFUSION:
@@ -418,17 +602,26 @@
rc = -EINVAL;
goto invalid_config;
}
- reverb->diffusion = *values++;
+ reverb->diffusion =
+ GET_NEXT(values, param_max_offset, rc);
pr_debug("%s: REVERB_DIFFUSION val:%d\n",
__func__, reverb->diffusion);
if (command_config_state == CONFIG_SET) {
- *updt_params++ = AUDPROC_MODULE_ID_REVERB;
- *updt_params++ =
- AUDPROC_PARAM_ID_REVERB_DIFFUSION;
- *updt_params++ = REVERB_DIFFUSION_PARAM_SZ;
- *updt_params++ = reverb->diffusion;
params_length += COMMAND_PAYLOAD_SZ +
REVERB_DIFFUSION_PARAM_SZ;
+ CHECK_PARAM_LEN(params_length,
+ MAX_INBAND_PARAM_SZ,
+ "REVERB_DIFFUSION", rc);
+ if (rc != 0)
+ break;
+ *updt_params++ =
+ AUDPROC_MODULE_ID_REVERB;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_REVERB_DIFFUSION;
+ *updt_params++ =
+ REVERB_DIFFUSION_PARAM_SZ;
+ *updt_params++ =
+ reverb->diffusion;
}
break;
case REVERB_DENSITY:
@@ -437,17 +630,26 @@
rc = -EINVAL;
goto invalid_config;
}
- reverb->density = *values++;
+ reverb->density =
+ GET_NEXT(values, param_max_offset, rc);
pr_debug("%s: REVERB_DENSITY val:%d\n",
__func__, reverb->density);
if (command_config_state == CONFIG_SET) {
- *updt_params++ = AUDPROC_MODULE_ID_REVERB;
- *updt_params++ =
- AUDPROC_PARAM_ID_REVERB_DENSITY;
- *updt_params++ = REVERB_DENSITY_PARAM_SZ;
- *updt_params++ = reverb->density;
params_length += COMMAND_PAYLOAD_SZ +
REVERB_DENSITY_PARAM_SZ;
+ CHECK_PARAM_LEN(params_length,
+ MAX_INBAND_PARAM_SZ,
+ "REVERB_DENSITY", rc);
+ if (rc != 0)
+ break;
+ *updt_params++ =
+ AUDPROC_MODULE_ID_REVERB;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_REVERB_DENSITY;
+ *updt_params++ =
+ REVERB_DENSITY_PARAM_SZ;
+ *updt_params++ =
+ reverb->density;
}
break;
default:
@@ -455,7 +657,7 @@
break;
}
}
- if (params_length)
+ if (params_length && (rc == 0))
q6asm_send_audio_effects_params(ac, params,
params_length);
invalid_config:
@@ -467,15 +669,16 @@
struct bass_boost_params *bass_boost,
long *values)
{
- int devices = *values++;
- int num_commands = *values++;
- char *params;
+ long *param_max_offset = values + MAX_PP_PARAMS_SZ - 1;
+ char *params = NULL;
+ int rc = 0;
+ int devices = GET_NEXT(values, param_max_offset, rc);
+ int num_commands = GET_NEXT(values, param_max_offset, rc);
int *updt_params, i, prev_enable_flag;
uint32_t params_length = (MAX_INBAND_PARAM_SZ);
- int rc = 0;
pr_debug("%s\n", __func__);
- if (!ac) {
+ if (!ac || (devices == -EINVAL) || (num_commands == -EINVAL)) {
pr_err("%s: cannot set audio effects\n", __func__);
return -EINVAL;
}
@@ -488,10 +691,14 @@
updt_params = (int *)params;
params_length = 0;
for (i = 0; i < num_commands; i++) {
- uint32_t command_id = *values++;
- uint32_t command_config_state = *values++;
- uint32_t index_offset = *values++;
- uint32_t length = *values++;
+ uint32_t command_id =
+ GET_NEXT(values, param_max_offset, rc);
+ uint32_t command_config_state =
+ GET_NEXT(values, param_max_offset, rc);
+ uint32_t index_offset =
+ GET_NEXT(values, param_max_offset, rc);
+ uint32_t length =
+ GET_NEXT(values, param_max_offset, rc);
switch (command_id) {
case BASS_BOOST_ENABLE:
if (length != 1 || index_offset != 0) {
@@ -500,18 +707,27 @@
goto invalid_config;
}
prev_enable_flag = bass_boost->enable_flag;
- bass_boost->enable_flag = *values++;
+ bass_boost->enable_flag =
+ GET_NEXT(values, param_max_offset, rc);
pr_debug("%s: BASS_BOOST_ENABLE prev:%d new:%d\n",
__func__, prev_enable_flag,
bass_boost->enable_flag);
if (prev_enable_flag != bass_boost->enable_flag) {
- *updt_params++ = AUDPROC_MODULE_ID_BASS_BOOST;
- *updt_params++ =
- AUDPROC_PARAM_ID_BASS_BOOST_ENABLE;
- *updt_params++ = BASS_BOOST_ENABLE_PARAM_SZ;
- *updt_params++ = bass_boost->enable_flag;
params_length += COMMAND_PAYLOAD_SZ +
BASS_BOOST_ENABLE_PARAM_SZ;
+ CHECK_PARAM_LEN(params_length,
+ MAX_INBAND_PARAM_SZ,
+ "BASS_BOOST_ENABLE", rc);
+ if (rc != 0)
+ break;
+ *updt_params++ =
+ AUDPROC_MODULE_ID_BASS_BOOST;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_BASS_BOOST_ENABLE;
+ *updt_params++ =
+ BASS_BOOST_ENABLE_PARAM_SZ;
+ *updt_params++ =
+ bass_boost->enable_flag;
}
break;
case BASS_BOOST_MODE:
@@ -520,17 +736,26 @@
rc = -EINVAL;
goto invalid_config;
}
- bass_boost->mode = *values++;
+ bass_boost->mode =
+ GET_NEXT(values, param_max_offset, rc);
pr_debug("%s: BASS_BOOST_MODE val:%d\n",
__func__, bass_boost->mode);
if (command_config_state == CONFIG_SET) {
- *updt_params++ = AUDPROC_MODULE_ID_BASS_BOOST;
- *updt_params++ =
- AUDPROC_PARAM_ID_BASS_BOOST_MODE;
- *updt_params++ = BASS_BOOST_MODE_PARAM_SZ;
- *updt_params++ = bass_boost->mode;
params_length += COMMAND_PAYLOAD_SZ +
BASS_BOOST_MODE_PARAM_SZ;
+ CHECK_PARAM_LEN(params_length,
+ MAX_INBAND_PARAM_SZ,
+ "BASS_BOOST_MODE", rc);
+ if (rc != 0)
+ break;
+ *updt_params++ =
+ AUDPROC_MODULE_ID_BASS_BOOST;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_BASS_BOOST_MODE;
+ *updt_params++ =
+ BASS_BOOST_MODE_PARAM_SZ;
+ *updt_params++ =
+ bass_boost->mode;
}
break;
case BASS_BOOST_STRENGTH:
@@ -539,17 +764,26 @@
rc = -EINVAL;
goto invalid_config;
}
- bass_boost->strength = *values++;
- pr_debug("%s: BASS_BOOST_STRENGTHi val:%d\n",
+ bass_boost->strength =
+ GET_NEXT(values, param_max_offset, rc);
+ pr_debug("%s: BASS_BOOST_STRENGTH val:%d\n",
__func__, bass_boost->strength);
if (command_config_state == CONFIG_SET) {
- *updt_params++ = AUDPROC_MODULE_ID_BASS_BOOST;
- *updt_params++ =
- AUDPROC_PARAM_ID_BASS_BOOST_STRENGTH;
- *updt_params++ = BASS_BOOST_STRENGTH_PARAM_SZ;
- *updt_params++ = bass_boost->strength;
params_length += COMMAND_PAYLOAD_SZ +
BASS_BOOST_STRENGTH_PARAM_SZ;
+ CHECK_PARAM_LEN(params_length,
+ MAX_INBAND_PARAM_SZ,
+ "BASS_BOOST_STRENGTH", rc);
+ if (rc != 0)
+ break;
+ *updt_params++ =
+ AUDPROC_MODULE_ID_BASS_BOOST;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_BASS_BOOST_STRENGTH;
+ *updt_params++ =
+ BASS_BOOST_STRENGTH_PARAM_SZ;
+ *updt_params++ =
+ bass_boost->strength;
}
break;
default:
@@ -557,9 +791,11 @@
break;
}
}
- if (params_length)
+ if (params_length && (rc == 0))
q6asm_send_audio_effects_params(ac, params,
params_length);
+ else
+ pr_debug("%s: did not send pp params\n", __func__);
invalid_config:
kfree(params);
return rc;
@@ -569,15 +805,16 @@
struct eq_params *eq,
long *values)
{
- int devices = *values++;
- int num_commands = *values++;
- char *params;
+ long *param_max_offset = values + MAX_PP_PARAMS_SZ - 1;
+ char *params = NULL;
+ int rc = 0;
+ int devices = GET_NEXT(values, param_max_offset, rc);
+ int num_commands = GET_NEXT(values, param_max_offset, rc);
int *updt_params, i, prev_enable_flag;
uint32_t params_length = (MAX_INBAND_PARAM_SZ);
- int rc = 0;
pr_debug("%s\n", __func__);
- if (!ac) {
+ if (!ac || (devices == -EINVAL) || (num_commands == -EINVAL)) {
pr_err("%s: cannot set audio effects\n", __func__);
return -EINVAL;
}
@@ -590,11 +827,16 @@
updt_params = (int *)params;
params_length = 0;
for (i = 0; i < num_commands; i++) {
- uint32_t command_id = *values++;
- uint32_t command_config_state = *values++;
- uint32_t index_offset = *values++;
- uint32_t length = *values++;
- int idx, j;
+ uint32_t command_id =
+ GET_NEXT(values, param_max_offset, rc);
+ uint32_t command_config_state =
+ GET_NEXT(values, param_max_offset, rc);
+ uint32_t index_offset =
+ GET_NEXT(values, param_max_offset, rc);
+ uint32_t length =
+ GET_NEXT(values, param_max_offset, rc);
+ uint32_t idx;
+ int j;
switch (command_id) {
case EQ_ENABLE:
if (length != 1 || index_offset != 0) {
@@ -603,17 +845,26 @@
goto invalid_config;
}
prev_enable_flag = eq->enable_flag;
- eq->enable_flag = *values++;
+ eq->enable_flag =
+ GET_NEXT(values, param_max_offset, rc);
pr_debug("%s: EQ_ENABLE prev:%d new:%d\n", __func__,
prev_enable_flag, eq->enable_flag);
if (prev_enable_flag != eq->enable_flag) {
- *updt_params++ =
- AUDPROC_MODULE_ID_POPLESS_EQUALIZER;
- *updt_params++ = AUDPROC_PARAM_ID_EQ_ENABLE;
- *updt_params++ = EQ_ENABLE_PARAM_SZ;
- *updt_params++ = eq->enable_flag;
params_length += COMMAND_PAYLOAD_SZ +
EQ_ENABLE_PARAM_SZ;
+ CHECK_PARAM_LEN(params_length,
+ MAX_INBAND_PARAM_SZ,
+ "EQ_ENABLE", rc);
+ if (rc != 0)
+ break;
+ *updt_params++ =
+ AUDPROC_MODULE_ID_POPLESS_EQUALIZER;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_EQ_ENABLE;
+ *updt_params++ =
+ EQ_ENABLE_PARAM_SZ;
+ *updt_params++ =
+ eq->enable_flag;
}
break;
case EQ_CONFIG:
@@ -627,9 +878,12 @@
eq->config.eq_pregain, eq->config.preset_id);
for (idx = 0; idx < MAX_EQ_BANDS; idx++)
eq->per_band_cfg[idx].band_idx = -1;
- eq->config.eq_pregain = *values++;
- eq->config.preset_id = *values++;
- eq->config.num_bands = *values++;
+ eq->config.eq_pregain =
+ GET_NEXT(values, param_max_offset, rc);
+ eq->config.preset_id =
+ GET_NEXT(values, param_max_offset, rc);
+ eq->config.num_bands =
+ GET_NEXT(values, param_max_offset, rc);
if (eq->config.num_bands > MAX_EQ_BANDS) {
pr_err("EQ_CONFIG:invalid num of bands\n");
rc = -EINVAL;
@@ -644,48 +898,59 @@
goto invalid_config;
}
for (j = 0; j < eq->config.num_bands; j++) {
- idx = *values++;
+ idx = GET_NEXT(values, param_max_offset, rc);
if (idx >= MAX_EQ_BANDS) {
pr_err("EQ_CONFIG:invalid band index\n");
rc = -EINVAL;
goto invalid_config;
}
eq->per_band_cfg[idx].band_idx = idx;
- eq->per_band_cfg[idx].filter_type = *values++;
+ eq->per_band_cfg[idx].filter_type =
+ GET_NEXT(values, param_max_offset, rc);
eq->per_band_cfg[idx].freq_millihertz =
- *values++;
+ GET_NEXT(values, param_max_offset, rc);
eq->per_band_cfg[idx].gain_millibels =
- *values++;
+ GET_NEXT(values, param_max_offset, rc);
eq->per_band_cfg[idx].quality_factor =
- *values++;
+ GET_NEXT(values, param_max_offset, rc);
}
if (command_config_state == CONFIG_SET) {
int config_param_length = EQ_CONFIG_PARAM_SZ +
(EQ_CONFIG_PER_BAND_PARAM_SZ*
eq->config.num_bands);
+ params_length += COMMAND_PAYLOAD_SZ +
+ config_param_length;
+ CHECK_PARAM_LEN(params_length,
+ MAX_INBAND_PARAM_SZ,
+ "EQ_CONFIG", rc);
+ if (rc != 0)
+ break;
*updt_params++ =
AUDPROC_MODULE_ID_POPLESS_EQUALIZER;
- *updt_params++ = AUDPROC_PARAM_ID_EQ_CONFIG;
- *updt_params++ = config_param_length;
- *updt_params++ = eq->config.eq_pregain;
- *updt_params++ = eq->config.preset_id;
- *updt_params++ = eq->config.num_bands;
+ *updt_params++ =
+ AUDPROC_PARAM_ID_EQ_CONFIG;
+ *updt_params++ =
+ config_param_length;
+ *updt_params++ =
+ eq->config.eq_pregain;
+ *updt_params++ =
+ eq->config.preset_id;
+ *updt_params++ =
+ eq->config.num_bands;
for (idx = 0; idx < MAX_EQ_BANDS; idx++) {
if (eq->per_band_cfg[idx].band_idx < 0)
continue;
*updt_params++ =
- eq->per_band_cfg[idx].filter_type;
+ eq->per_band_cfg[idx].filter_type;
*updt_params++ =
- eq->per_band_cfg[idx].freq_millihertz;
+ eq->per_band_cfg[idx].freq_millihertz;
*updt_params++ =
- eq->per_band_cfg[idx].gain_millibels;
+ eq->per_band_cfg[idx].gain_millibels;
*updt_params++ =
- eq->per_band_cfg[idx].quality_factor;
+ eq->per_band_cfg[idx].quality_factor;
*updt_params++ =
- eq->per_band_cfg[idx].band_idx;
+ eq->per_band_cfg[idx].band_idx;
}
- params_length += COMMAND_PAYLOAD_SZ +
- config_param_length;
}
break;
case EQ_BAND_INDEX:
@@ -694,7 +959,7 @@
rc = -EINVAL;
goto invalid_config;
}
- idx = *values++;
+ idx = GET_NEXT(values, param_max_offset, rc);
if (idx > MAX_EQ_BANDS) {
pr_err("EQ_BAND_INDEX:invalid band index\n");
rc = -EINVAL;
@@ -704,14 +969,21 @@
pr_debug("%s: EQ_BAND_INDEX val:%d\n",
__func__, eq->band_index);
if (command_config_state == CONFIG_SET) {
+ params_length += COMMAND_PAYLOAD_SZ +
+ EQ_BAND_INDEX_PARAM_SZ;
+ CHECK_PARAM_LEN(params_length,
+ MAX_INBAND_PARAM_SZ,
+ "EQ_BAND_INDEX", rc);
+ if (rc != 0)
+ break;
*updt_params++ =
AUDPROC_MODULE_ID_POPLESS_EQUALIZER;
*updt_params++ =
AUDPROC_PARAM_ID_EQ_BAND_INDEX;
- *updt_params++ = EQ_BAND_INDEX_PARAM_SZ;
- *updt_params++ = eq->band_index;
- params_length += COMMAND_PAYLOAD_SZ +
+ *updt_params++ =
EQ_BAND_INDEX_PARAM_SZ;
+ *updt_params++ =
+ eq->band_index;
}
break;
case EQ_SINGLE_BAND_FREQ:
@@ -724,18 +996,26 @@
pr_err("EQ_SINGLE_BAND_FREQ:invalid index\n");
break;
}
- eq->freq_millihertz = *values++;
+ eq->freq_millihertz =
+ GET_NEXT(values, param_max_offset, rc);
pr_debug("%s: EQ_SINGLE_BAND_FREQ idx:%d, val:%d\n",
__func__, eq->band_index, eq->freq_millihertz);
if (command_config_state == CONFIG_SET) {
+ params_length += COMMAND_PAYLOAD_SZ +
+ EQ_SINGLE_BAND_FREQ_PARAM_SZ;
+ CHECK_PARAM_LEN(params_length,
+ MAX_INBAND_PARAM_SZ,
+ "EQ_SINGLE_BAND_FREQ", rc);
+ if (rc != 0)
+ break;
*updt_params++ =
AUDPROC_MODULE_ID_POPLESS_EQUALIZER;
*updt_params++ =
AUDPROC_PARAM_ID_EQ_SINGLE_BAND_FREQ;
- *updt_params++ = EQ_SINGLE_BAND_FREQ_PARAM_SZ;
- *updt_params++ = eq->freq_millihertz;
- params_length += COMMAND_PAYLOAD_SZ +
+ *updt_params++ =
EQ_SINGLE_BAND_FREQ_PARAM_SZ;
+ *updt_params++ =
+ eq->freq_millihertz;
}
break;
default:
@@ -743,9 +1023,11 @@
break;
}
}
- if (params_length)
+ if (params_length && (rc == 0))
q6asm_send_audio_effects_params(ac, params,
params_length);
+ else
+ pr_debug("%s: did not send pp params\n", __func__);
invalid_config:
kfree(params);
return rc;
diff --git a/sound/soc/msm/qdsp6v2/msm-audio-effects-q6-v2.h b/sound/soc/msm/qdsp6v2/msm-audio-effects-q6-v2.h
index 3d2e6d4..64c92fb 100644
--- a/sound/soc/msm/qdsp6v2/msm-audio-effects-q6-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-audio-effects-q6-v2.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013, 2016, 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
@@ -16,6 +16,8 @@
#include <sound/audio_effects.h>
+#define MAX_PP_PARAMS_SZ 128
+
int msm_audio_effects_reverb_handler(struct audio_client *ac,
struct reverb_params *reverb,
long *values);
diff --git a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
index 70f5f60..d549c49 100644
--- a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
@@ -2082,7 +2082,7 @@
struct snd_ctl_elem_info *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->count = 128;
+ uinfo->count = MAX_PP_PARAMS_SZ;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = 0xFFFFFFFF;
return 0;
diff --git a/sound/soc/msm/qdsp6v2/msm-lsm-client.c b/sound/soc/msm/qdsp6v2/msm-lsm-client.c
index 83d5416..6c7bf4e 100644
--- a/sound/soc/msm/qdsp6v2/msm-lsm-client.c
+++ b/sound/soc/msm/qdsp6v2/msm-lsm-client.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2015, Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2016, 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
@@ -34,7 +34,7 @@
#include "msm-pcm-routing-v2.h"
#define CAPTURE_MIN_NUM_PERIODS 2
-#define CAPTURE_MAX_NUM_PERIODS 8
+#define CAPTURE_MAX_NUM_PERIODS 32
#define CAPTURE_MAX_PERIOD_SIZE 4096
#define CAPTURE_MIN_PERIOD_SIZE 320
#define LISTEN_MAX_STATUS_PAYLOAD_SIZE 256
@@ -589,6 +589,9 @@
dev_err(rtd->dev,
"%s: Failed to set det_mode param, err = %d\n",
__func__, rc);
+
+ q6lsm_snd_model_buf_free(prtd->lsm_client);
+
return rc;
}
@@ -960,6 +963,7 @@
"%s: Stopping LSM client session\n",
__func__);
if (prtd->lsm_client->started) {
+ int i;
if (prtd->lsm_client->lab_enable) {
atomic_set(&prtd->read_abort, 1);
if (prtd->lsm_client->lab_started) {
@@ -969,6 +973,9 @@
"%s: stop lab failed ret %d\n",
__func__, ret);
prtd->lsm_client->lab_started = false;
+ for (i = 0; i < prtd->lsm_client->hw_params.period_count; i++)
+ memset(prtd->lsm_client->lab_buffer[i].data, 0,
+ prtd->lsm_client->lab_buffer[i].size);
}
}
ret = q6lsm_stop(prtd->lsm_client, true);
@@ -1032,6 +1039,7 @@
dev_dbg(rtd->dev, "%s: stopping LAB\n", __func__);
if (prtd->lsm_client->lab_enable &&
prtd->lsm_client->lab_started) {
+ int i;
atomic_set(&prtd->read_abort, 1);
rc = q6lsm_stop_lab(prtd->lsm_client);
if (rc)
@@ -1040,6 +1048,9 @@
__func__,
prtd->lsm_client->session, rc);
prtd->lsm_client->lab_started = false;
+ for (i = 0; i < prtd->lsm_client->hw_params.period_count; i++)
+ memset(prtd->lsm_client->lab_buffer[i].data, 0,
+ prtd->lsm_client->lab_buffer[i].size);
}
break;
default:
@@ -1872,7 +1883,7 @@
return 0;
}
rc = wait_event_timeout(prtd->period_wait,
- (atomic_read(&prtd->buf_count) |
+ (atomic_read(&prtd->buf_count) ||
atomic_read(&prtd->read_abort)), (2 * HZ));
if (!rc) {
dev_err(rtd->dev,
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c
index 293b3a9..511476b 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c
@@ -330,13 +330,12 @@
dev_dbg(rtd->platform->dev, "%s: ASM loopback\n", __func__);
- return snd_pcm_lib_alloc_vmalloc_buffer(substream,
- params_buffer_bytes(params));
+ return 0;
}
static int msm_pcm_hw_free(struct snd_pcm_substream *substream)
{
- return snd_pcm_lib_free_vmalloc_buffer(substream);
+ return 0;
}
static struct snd_pcm_ops msm_pcm_ops = {
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
index 0f445ad..d8d71256 100644
--- a/sound/soc/msm/qdsp6v2/q6adm.c
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -836,7 +836,7 @@
idx) &&
(ARRAY_SIZE(adm_get_parameters) >=
1+adm_get_parameters[idx]+idx) &&
- (params_length/sizeof(int) >=
+ (params_length/sizeof(uint32_t) >=
adm_get_parameters[idx])) {
for (i = 0; i < adm_get_parameters[idx]; i++)
params_data[i] = adm_get_parameters[1+i+idx];
@@ -1070,17 +1070,23 @@
idx = ADM_GET_PARAMETER_LENGTH * copp_idx;
if ((payload[0] == 0) && (data->payload_size >
(4 * sizeof(*payload))) &&
- (data->payload_size/sizeof(*payload)-4 >=
+ (data->payload_size - 4 >=
payload[3]) &&
(ARRAY_SIZE(adm_get_parameters) >
idx) &&
(ARRAY_SIZE(adm_get_parameters)-idx-1 >=
payload[3])) {
- adm_get_parameters[idx] = payload[3];
+ adm_get_parameters[idx] = payload[3] /
+ sizeof(uint32_t);
+ /*
+ * payload[3] is param_size which is
+ * expressed in number of bytes
+ */
pr_debug("%s: GET_PP PARAM:received parameter length: 0x%x\n",
__func__, adm_get_parameters[idx]);
/* storing param size then params */
- for (i = 0; i < payload[3]; i++)
+ for (i = 0; i < payload[3] /
+ sizeof(uint32_t); i++)
adm_get_parameters[idx+1+i] =
payload[4+i];
} else {
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index 3e38e69..618efed 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2014, 2016, The Linux Foundation. All rights reserved.
* Author: Brian Swetland <swetland@google.com>
*
* This software is licensed under the terms of the GNU General Public
@@ -1141,6 +1141,12 @@
ac->port[dir].buf = buf;
+ /* check for integer overflow */
+ if ((bufcnt > 0) && ((INT_MAX / bufcnt) < bufsz)) {
+ pr_err("%s: integer overflow\n", __func__);
+ mutex_unlock(&ac->cmd_lock);
+ goto fail;
+ }
bytes_to_alloc = bufsz * bufcnt;
/* The size to allocate should be multiple of 4K bytes */