Merge "ASoC: msm: qdsp6v2: Fix memory leaks/access issues"
diff --git a/Documentation/ABI/testing/sysfs-bus-msm_subsys b/Documentation/ABI/testing/sysfs-bus-msm_subsys
index fcfb1d4..f915a46 100644
--- a/Documentation/ABI/testing/sysfs-bus-msm_subsys
+++ b/Documentation/ABI/testing/sysfs-bus-msm_subsys
@@ -16,3 +16,16 @@
This file supports poll(3) to detect when a subsystem changes
state. Use POLLPRI to detect state changes.
+
+What: /sys/bus/msm_subsys/devices/.../restart_level
+Date: December 2012
+Contact: Stephen Boyd <sboyd@codeaurora.org>
+Description:
+ Shows the restart level of a subsystem. The level is taken into
+ account when the subsystem is restarted via
+ subsystem_restart{_dev}(). Current supported states are:
+
+ SYSTEM - reset the entire system
+ RELATED - reset this subsystem and the other subsystems
+ related to this one. Having no other
+ subsystems related to this subsystem is valid.
diff --git a/Documentation/ABI/testing/sysfs-class-devfreq b/Documentation/ABI/testing/sysfs-class-devfreq
index 23d78b5..0ba6ea2 100644
--- a/Documentation/ABI/testing/sysfs-class-devfreq
+++ b/Documentation/ABI/testing/sysfs-class-devfreq
@@ -11,7 +11,7 @@
Date: September 2011
Contact: MyungJoo Ham <myungjoo.ham@samsung.com>
Description:
- The /sys/class/devfreq/.../governor shows the name of the
+ The /sys/class/devfreq/.../governor show or set the name of the
governor used by the corresponding devfreq object.
What: /sys/class/devfreq/.../cur_freq
@@ -19,15 +19,16 @@
Contact: MyungJoo Ham <myungjoo.ham@samsung.com>
Description:
The /sys/class/devfreq/.../cur_freq shows the current
- frequency of the corresponding devfreq object.
+ frequency of the corresponding devfreq object. Same as
+ target_freq when get_cur_freq() is not implemented by
+ devfreq driver.
-What: /sys/class/devfreq/.../central_polling
-Date: September 2011
-Contact: MyungJoo Ham <myungjoo.ham@samsung.com>
+What: /sys/class/devfreq/.../target_freq
+Date: September 2012
+Contact: Rajagopal Venkat <rajagopal.venkat@linaro.org>
Description:
- The /sys/class/devfreq/.../central_polling shows whether
- the devfreq ojbect is using devfreq-provided central
- polling mechanism or not.
+ The /sys/class/devfreq/.../target_freq shows the next governor
+ predicted target frequency of the corresponding devfreq object.
What: /sys/class/devfreq/.../polling_interval
Date: September 2011
@@ -43,6 +44,17 @@
(/sys/class/devfreq/.../central_polling is 0), this value
may be useless.
+What: /sys/class/devfreq/.../trans_stat
+Date: October 2012
+Contact: MyungJoo Ham <myungjoo.ham@samsung.com>
+Descrtiption:
+ This ABI shows the statistics of devfreq behavior on a
+ specific device. It shows the time spent in each state and
+ the number of transitions between states.
+ In order to activate this ABI, the devfreq target device
+ driver should provide the list of available frequencies
+ with its profile.
+
What: /sys/class/devfreq/.../userspace/set_freq
Date: September 2011
Contact: MyungJoo Ham <myungjoo.ham@samsung.com>
@@ -50,3 +62,19 @@
The /sys/class/devfreq/.../userspace/set_freq shows and
sets the requested frequency for the devfreq object if
userspace governor is in effect.
+
+What: /sys/class/devfreq/.../available_frequencies
+Date: October 2012
+Contact: Nishanth Menon <nm@ti.com>
+Description:
+ The /sys/class/devfreq/.../available_frequencies shows
+ the available frequencies of the corresponding devfreq object.
+ This is a snapshot of available frequencies and not limited
+ by the min/max frequency restrictions.
+
+What: /sys/class/devfreq/.../available_governors
+Date: October 2012
+Contact: Nishanth Menon <nm@ti.com>
+Description:
+ The /sys/class/devfreq/.../available_governors shows
+ currently available governors in the system.
diff --git a/Documentation/arm/msm/n_smux.txt b/Documentation/arm/msm/n_smux.txt
new file mode 100644
index 0000000..c9123ad
--- /dev/null
+++ b/Documentation/arm/msm/n_smux.txt
@@ -0,0 +1,630 @@
+Introduction
+============
+
+The Serial Mux (SMUX) is a TTY Line Discipline that multiplexes
+multiple logical channels onto a single TTY serial channel. The
+logical channels are exposed through a kernel API.
+
+Companion adaptation drivers use the kernel API to expose logical
+channels as character devices (SMUX CTL - smux_ctl.c) to the user-space
+and as net devices (SMUX RMNET - msm_rmnet_smux.c) to the TCP/IP stack.
+
+Power control calls are supported to the physical serial driver to
+optimize power usage.
+
+
+Software description
+====================
+
+The Serial Mux driver will be similar in design to the SDIO DMUX and
+BAM DMUX drivers and will use the same multiplexing protocol with
+additional commands to support inactivity timeouts along with
+power-down and wake-up handshaking. Companion adaptation drivers will
+support data-plane traffic through TCP/IP (SMUX_RMNET) and control
+plane traffic through SMUX_CTL.
+
+
+ ttyHS0 RMNET[0..N] smuxctl[0..M]
+ | | |
+ | | |
+ | ------------------ -------------------
+ | | IP Framework | | VFS Framework |
+ | ------------------ -------------------
+ | | | | |
+ | | | | |
+ | ------- ------- ------- -------
+ | | Rmnet | | Rmnet | | CDEV | | CDEV |
+ | | Dev 0 |...| Dev N | | Dev 0 |...| Dev M |
+ | --------------------- --------------------- -------------
+ | | | | | | Other |
+ | | msm_rmnet_smux | | smux_ctl | | Kernel-only |
+ | | | | | | Clients |
+ | --------------------- --------------------- -------------
+ | | | | | |
+ | | | | | |
+ | | | | | |
+ | | | | | |
+ | ---------------------------------------------------
+ | |
+ | |
+ | |
+ | |
+ --------------- --------------------
+ | | | |
+ | TTY Framework | <- Line Discipline -> | SMUX |
+ | | | |
+ --------------- --------------------
+ | |
+ | |
+ --------------- |
+ | | |
+ | HS UART |<---------- Power API -----------
+ | |
+ ---------------
+ |
+ V
+ To Remote System
+
+
+Each logical channel will contain package management structures
+including a watermark to ensure fair usage of the physical layer by
+competing logical channels. All data for logical channels will be
+processed in FIFO order.
+
+Once data has been queued with SMUX, processing, copying of data, and
+notification to clients will be done using a combination of the TTY
+framework notification context and a workqueue. The lifetime of all
+buffers is controlled by the clients with SMUX taking temporary
+ownership of the buffers for read and write operations.
+
+The physical transport is assumed to be perfect and all errors will be
+handled by notifying the client of the failure. Watermark support and
+round-robin scheduling ensure that individual logical channels do not
+starve other logical channels.
+
+Data stalls caused by failure of the remote system are handled by
+Subsystem Restart. The restart logic will notify clients of the
+failure and all read and write buffers will be returned to the client
+with an error notification.
+
+Design
+======
+
+The goals for SMUX are to:
+ 1) multiplex multiple logical channels into a single physical
+ channel
+ 2) support a kernel API
+ 3) provide power control of the physical layer
+
+In addition, the companion adapter modules have the goals:
+ 1) support userspace character-device clients (smux_ctl)
+ 2) support net devices through the TCP/IP stack (msm_rmnet_smux)
+
+Alternate designs consider including 3GPP 27.010 MUX protocol
+implementations and existing SDIO CMUX/DMUX implementations.
+
+The 3GPP 27.010 MUX protocol as implemented in both n_gsm.c and OpenEZX
+looked promising at first glance. However, upon further inspection,
+the implementations did not fully implement the power-control portions
+of the 27.010 MUX protocol. They also did not support kernel clients
+as they were designed to work only with userspace through TTY devices.
+The code was reviewed to determine the effort to add power-control
+signaling to the physical transport driver and to add a kernel API, but
+it was deemed that adding the API to support both of these behaviors
+would be difficult to do in a generic way such that it would be
+accepted by the upstream community.
+
+The SDIO CMUX/DMUX drivers do not have power control in them and the
+CMUX and DMUX drivers both require a separate physical channel. To use
+them, we would need to create an additional mux layer that would sit
+between CMUX/DMUX and the HS UART driver which would add another MUX
+header.
+
+Design - MUX Protocol
+=====================
+The MUX packet consists of a header (detailed below) and a payload.
+All values are in little-endian format and all reserved fields are set
+to zero unless otherwise mentioned in the individual command
+descriptions.
+
+Invalid commands and malformed commands will be logged to the kernel log
+as an error and ignored.
+
+ -----------------------------------------
+ |31 24| 16| 8| 0|
+ |----------|---------|----------|---------|
+ | Magic Number | Flags | CMD |
+ |----------|---------|----------|---------|
+ | Pad Len | LCID | Packet Length (N) |
+ |-----------------------------------------|
+ | Data Payload (0..N bytes) |
+ |-----------------------------------------|
+ | Pad Data (0..Pad Len bytes) |
+ -----------------------------------------
+
+Field definitions:
+ * Magic Number - always 0x33FC
+ * Flags - flags for individual commands
+ * CMD - SMUX command
+ * Pad Len - Padding in bytes at the end of the payload
+ * LCID - Logical channel ID
+ * Packet Length - Length of the data payload in bytes
+
+Commands
+ 0x0 - Data
+ 0x1 - Open Logical Channel
+ 0x2 - Close Logical Channel
+ 0x3 - Status
+ 0x4 - Power Control
+
+Data Command
+------------
+The Data command sends data on an already fully-opened logical channel.
+
+Flags:
+ * Bits 0:7 - Reserved
+
+Open Logical Channel Command
+----------------------------
+The Open command is a request to open a logical channel. Each channel
+will have a local and remote open flag. The remote open flag will be
+set to open when receiving an open command and responding with an open
+ACK. The local open flag is set to open when sending an open command
+and receiving an ACK.
+
+ Remote Side | Local Side
+ |
+ SMUX Client SMUX SMUX SMUX Client
+ | | | |
+ | Open | | |
+ |--------->| | |
+ | | Open Logical Channel | |
+ | |---------------------->| |
+ | | |--- |
+ | | | | Set Remote Open |
+ | | |<-- |
+ | | Open ACK | |
+ | |<----------------------| |
+ | |--- | |
+ | | | Set Local Open | |
+ | |<-- | |
+ | ... ... ...
+ | | | msm_smux_open() |
+ | | |<-----------------------|
+ | | Open Logical Channel | |
+ | |<----------------------| |
+ | | | |
+ | |--- | |
+ | | | Set Remote Open | |
+ | |<-- | |
+ | | Open ACK | |
+ | |---------------------->| |
+ | | |--- |
+ | | | | Set Local Open |
+ | | |<-- |
+ | | | notify(SMUX_CONNECTED) |
+ | | |----------------------->|
+
+
+ Logical channel is now fully open and can receive
+ and transmit data.
+
+No data shall be transmitted over the physical link for the logical
+channel unless the channel is open.
+
+Flags:
+ * Bit 0 - 1 = ACK
+ * Bit 1 - Power Collapse Enable
+ * Bit 2 - Remote Loopback Enable
+ * Bits 3:7 - Reserved
+
+Power Collapse Enable (bit 1) enables power-collapse handshaking when
+processing an open command. The first logical channel open command
+received from the remote side will set the global power control state
+and all subsequent open commands should use the same value of the Power
+Collapse bit. The value of this bit can be changed during runtime by
+closing all logical channels and then re-opening them with the new
+global state.
+
+If the protocol stack does not support power collapse and it receives
+an open command with the Power Collapse Enable bit set, then it
+shall respond with an open command with the Power Collapse Enable bit
+cleared.
+
+If Power Collapse is disabled, then Power Control Commands should not
+be sent.
+
+Remote Loopback Enable (bit 2) enables loopback support when data is
+received from the remote side. In this case, SMUX should echo the
+received data packet back to the sender.
+
+Close Logical Channel Command
+-----------------------------
+The Close command closes the logical channel and updates the internal
+open state flags. The remote open flag will be set to closed when
+receiving a close command and responding with an close ACK. The local
+open flag is set to closed when sending a close command and receiving an
+ACK.
+
+No data shall be transmitted over the physical link for the logical
+channel after receiving a close command and responding with the close
+ACK.
+
+Flags:
+ * Bit 0 - ACK (when set to 1)
+ * Bits 1:7 - Reserved
+
+
+Status Command
+--------------
+The Status Command updates the channel status signals which include four
+ITU v.24 status bits in the lower nibble of the flags field along with a
+logical channel flow-control signal. The v.24 signals are pass-through
+and do not affect the state of SMUX.
+
+The Logical Channel Flow Control bit will disable TX on the logical
+channel when set and send a flow-control notification to the logical
+channel client. Any further attempts to transmit will result in an
+error return code.
+
+Flags:
+ * Bit 0 - RTC (DTR/DSR)
+ * Bit 1 - RTR (RTS/CTS)
+ * Bit 2 - RI
+ * Bit 3 - DCD
+ * Bit 4 - Logical Channel Flow Control
+ * Bits 5:7 - Reserved
+
+
+Power Control Command
+---------------------
+The physical layer requires a variable amount of time to wakeup from
+power collapse, reconfigure the hardware, and start processing data.
+Data may be lost until the wakeup has been completed. Because of this,
+a character-based wakeup method will be used to ensure that the remote
+side is active and ready before sending SMUX commands.
+
+If the remote side has previously requested power-down (boot-up state),
+then a wakeup request character is sent at periodic intervals (1 ms or
+8 character-widths, whichever is larger) until a wakeup-acknowledge character
+has been received. Normal transmit operations can then be performed. Once an
+activity timeout occurs, then a sleep vote should be sent to the remote side to
+let it know that the channel is no longer needed. The remote side should
+respond with an ACK.
+
+The following state diagram shows the full sequence of power state transitions.
+This state machine is identical on both the local and remote sides. The states
+marked "(internal)" are transitional states used in this driver that are not
+part of the power states tracked by the remote side. The edges are labeled
+using the format CONDITION:ACTION where condition is the guard condition that
+must be true for the edge to be taken and ACTION is the action that will be
+taken.
+
+ +--------------+ RX Sleep ACK || RX Sleep Request
+ :Flush and power-down | Powering |<---------+
+ UART +---------+ Down Flush | |
+ | | (internal) | |
+ | +--------------+ |
+ | ^ |
+ | | +-------+------+
+ v | | | |
+ +--------------+ | | Powering |
+ | | | | Down |<-----+
+Init --->| OFF | | | | |
+ | |------+ | +--------------+ |
+ | | | | |
+ +------+-------+ | | TX Sleep Request
+ | | | Complete
+ | | | |
+ Data ready to send | | |
+ :TX Wakeup Request | |RX Sleep Request |
+ | | |:TX Sleep ACK |
+ | | +------------+ +-------+------+
+ | | | | Turning Off^|
+ | | | | Flush |
+ | | | | (internal) |
+ | |RX Wakeup Request | +--------------+
+ | |:TX Wakeup ACK | ^
+ | | | |
+ | | | Inactivity Timeout
+ | +--------------+ | :TX Sleep Request
+ | | | |
+ v v | |
+ +--------------+ RX Wakeup ACK +-------+------+ |
+ | +------------------>| UP |+-----+
+ | Powering | | |
+ | Up +------------------>| Packet TX/RX |
+ +----->| | RX Wakeup Request | is now active|<------+
+ | +--+-----------+ :TX Wakeup ACK +----------+---+ |
+ | | | |
+ +---------+ +-----------+
+ Wakeup Request Timeout RX Wakeup Request
+ :TX Wakeup Request :TX Wakeup ACK
+
+
+In-band wakeup bytes:
+ * 0xfd - Wakeup Request
+ * 0xfe - Wakeup Acknowledge
+
+Flags:
+ * Bit 0 - ACK (when set to 1)
+ * Bit 1 - 1 = Sleep Request
+ * Bits 2:7 - Reserved
+
+Initial SMUX State
+------------------
+The boot-up state of SMUX is in power-disabled mode and all logical
+channels closed. Before sending any commands to open logical channels,
+the remote SMUX must be woken up.
+
+Power Management
+================
+
+Power management will consist of wakeup and shutdown control of the
+physical layer based upon an activity timeout. Wakelocks will be
+utilized to prevent the system from going to sleep while the transport
+is active. The activity timeout is anticipated to be 500 ms, but this
+is subject to tuning to meet power and performance specifications.
+
+SMP/multi-core
+==============
+
+Locking and synchronization will be done using mutexes or spinlocks
+where appropriate. The software will be structured such that locking
+can be kept to a minimum by only locking when items are added and
+removed from lists.
+
+Security
+========
+
+No new security issues are anticipated as communication with userspace
+is done through the existing TCP/IP and CDEV frameworks.
+
+Performance
+===========
+
+The throughput requirements for this design are on the order of 250Kbps
+so throughput concerns are not expected to be an issue. However, in
+the hope that this driver can be leveraged in the future instead of
+writing yet another multiplexing layer, performance will be considered
+when making design decisions.
+
+Interface
+=========
+
+The kernel API consists of commands to read and write data, vote for
+power, and verify the state of the logical channels.
+
+
+Open
+----
+int msm_smux_open(uint32_t lcid, void *priv,
+ void (*notify)(void *priv, int event_type, void *metadata),
+ int (*get_rx_buffer)(void *priv, void **pkt_priv,
+ void **buffer, int size))
+
+Open a logical channel. The channel will be first opened locally and
+an open command will be sent to the remote processor. Once the remote
+processor sends an open command, then the port will be fully open and
+ready for data operations -- the client will be notified with an
+SMUX_CONNECTED notification.
+
+For receive notifications, the driver will read the SMUX header into
+temporary storage and then when the logical channel and size are both
+known, the driver will call the get_rx_buffer() function to request a
+buffer for the data. The client should return 0 upon success or < 0
+using standard Linux error codes if an error occurred. If the error
+code is EAGAIN, then the call to get_rx_buffer() will be retried once,
+otherwise the data will be discarded by the driver and a kernel error
+message logged.
+
+Once the receive data has been processed, the notify() function will be
+called with metadata pointing to an instance of struct smux_meta_read
+and the event type will either be SMUX_READ_DONE for successful cases or
+SMUX_READ_FAIL for failure cases.
+
+/*
+ * Notification events that are passed to the notify() function.
+ *
+ * If the @metadata argument in the notifier is non-null, then it will
+ * point to the associated struct smux_meta_* structure.
+ */
+enum {
+ SMUX_CONNECTED, /* @metadata is null */
+ SMUX_DISCONNECTED,
+ SMUX_READ_DONE,
+ SMUX_READ_FAIL,
+ SMUX_WRITE_DONE,
+ SMUX_WRITE_FAIL,
+ SMUX_TIOCM_UPDATE,
+ SMUX_LOW_WM_HIT, /* @metadata is NULL */
+ SMUX_HIGH_WM_HIT, /* @metadata is NULL */
+};
+
+/*
+ * Metadata for SMUX_READ_DONE/SMUX_READ_FAIL notification
+ *
+ * @pkt_priv: Packet-specific private data
+ * @buffer: Buffer pointer passed into msm_smux_write
+ * @len: Buffer length passed into msm_smux_write
+ */
+struct smux_meta_read {
+ void *pkt_priv;
+ void *buffer;
+ int len;
+};
+
+Close
+-----
+int msm_smux_close(uint32_t lcid)
+
+Closes a logical channel locally and sends a close command to the
+remote host.
+
+If there is pending transmit or receive data, then SMUX_WRITE_FAIL and
+SMUX_READ_FAIL notifications will be made to return ownership of the
+buffers to the client.
+
+Once the remote side of the port has been closed, the notify function
+will be called with the event SMUX_DISCONNECTED and metadata pointing
+to a struct smux_meta_disconnected structure. After this point, no
+further notifications will be performed.
+
+/*
+ * Metadata for SMUX_DISCONNECTED notification
+ *
+ * @is_ssr: Disconnect caused by subsystem restart
+ */
+struct smux_meta_disconnected {
+ int is_ssr;
+};
+
+
+Write
+-----
+int msm_smux_write(uint32_t lcid, void *pkt_priv, void *data, int len)
+
+Queues data for transmit. Once the data has been transmitted, the
+SMUX_WRITE_DONE or SMUX_WRITE_FAIL notifications will be sent with
+metadata pointing to an instance of struct smux_meta_write.
+
+If the high watermark has been exceeded, then further writes will
+return -EAGAIN.
+
+Data may be written as soon as the local side of the port has been
+opened, but the data will not be transmitted until the channel has been
+fully opened and the SMUX_CONNECTED event has been sent.
+
+/*
+ * Metadata for SMUX_WRITE_DONE/SMUX_WRITE_FAIL notification
+ *
+ * @pkt_priv: Packet-specific private data
+ * @buffer: Buffer pointer returned by get_rx_buffer()
+ * @len: Buffer length returned by get_rx_buffer()
+ */
+struct smux_meta_write {
+ void *pkt_priv;
+ void *buffer;
+ int len;
+};
+
+Watermark
+---------
+ int msm_smux_is_ch_full(uint32_t lcid)
+ int msm_smux_is_ch_low(uint32_t lcid)
+
+A channel watermark is used to keep individual clients from using
+excessive internal resources. The client may call
+msm_smux_is_ch_full() after every msm_smux_write() operation and if the
+watermark is high, it should not queue any more packets for
+transmission. As an alternative, the client may base this decision
+upon receiving an SMUX_HIGH_WM_HIT notification.
+
+Likewise, the client may call msm_smux_is_ch_low() after every
+SMUX_WRITE_DONE or SMUX_WRITE_FAIL notification and if the watermark is
+low, then new transmit operations can be started. As an alternative,
+the client may base this decision upon receiving an SMUX_LOW_WM_HIT
+notification.
+
+Control Signals
+---------------
+ long msm_smux_tiocm_get(uint32_t lcid)
+ long msm_smux_tiocm_set(uint32_t lcid, uint32_t set, uint32_t clear)
+
+The TIOCM bits do not affect the SMUX internal state as they are
+pass-through for the clients. The client can receive notifications of
+state changes through the SMUX_TIOCM_UPDATE command.
+
+See the "Status Command" section for details on the TIOCM bits.
+
+/*
+ * Metadata for SMUX_TIOCM_UPDATE notification
+ *
+ * @previous: Previous TIOCM state
+ * @current: Current TIOCM state
+ *
+ */
+struct smux_meta_tiocm {
+ uint32_t previous;
+ uint32_t current;
+};
+
+Subsystem Restart
+-----------------
+Subsystem restart is handled by sending a disconnect notification
+followed by sending read and write fail notifications to each client.
+This returns ownership of the read and write buffers to the clients for
+client-appropriate handling.
+
+The sequence of notifications shall be:
+ 1) SMUX_DISCONNECTED notification with @metadata->is_ssr == 1
+ 2) SMUX_WRITE_FAIL for each packet in TX queue
+ 3) SMUX_READ_FAIL for any RX packet in progress
+
+After the completion of the sequence, the client should call msm_smux_close()
+followed by a call to msm_smux_open() to re-open the port.
+
+
+Debug / Testing
+---------------
+
+Several debugfs nodes will be exported under the n_gsm directory for
+testing and debugging.
+ * tbl - prints table of logical channels
+ * stats - prints transfer statistics
+ * enable_local_loopback - echo LCID to enable loopback
+ * disable_local_loopback - echo LCID to enable loopback
+ * enable_remote_loopback - echo LCID to enable loopback
+ * disable_remote_loopback - echo LCID to enable loopback
+
+Driver parameters
+=================
+
+A module parameter called debug_mask will be exported to allow a user
+to set the log level for debugging.
+
+Config options
+==============
+
+No configuration options are planned.
+
+Dependencies
+============
+
+The msm_rmnet_smux and smux_ctl drivers are part of this project and
+are used to interface with the Linux TCP/IP framework and user space.
+
+The physical transport is the HS UART driver which will be extended to
+add a kernel API (the current interface is a TTY interface).
+
+Initialization of dependency drivers is handled using the platform
+device framework. When SMUX is loaded as a line discipline of the TTY
+Framework, it will register separate device drivers with the following
+device names:
+ * SMUX_CTL
+ * SMUX_RMNET
+ * SMUX_DUN_DATA_HSUART
+ * SMUX_RMNET_DATA_HSUART
+ * SMUX_RMNET_CTL_HSUART
+ * SMUX_DIAG
+
+The drivers are removed when SMUX is unloaded from the line discipline.
+
+
+User space utilities
+====================
+
+No userspace utilities are planned aside from testing and example
+applications.
+
+Known issues
+============
+
+None.
+
+To do
+=====
+Once completed, benchmark to determine if FIFO packet scheduling is
+sufficient or if a different scheduling algorithm such as deficit
+round-robin or deficit FIFO scheduling is needed to fairly handle
+variable-sized packets.
diff --git a/Documentation/cgroups/cpuacct.txt b/Documentation/cgroups/cpuacct.txt
index e21a932..9d73cc0 100644
--- a/Documentation/cgroups/cpuacct.txt
+++ b/Documentation/cgroups/cpuacct.txt
@@ -39,13 +39,6 @@
user and system are in USER_HZ unit.
-cpuacct.cpufreq file gives CPU time (in nanoseconds) spent at each CPU
-frequency. Platform hooks must be implemented inorder to properly track
-time at each CPU frequency.
-
-cpuacct.power file gives CPU power consumed (in milliWatt seconds). Platform
-must provide and implement power callback functions.
-
cpuacct controller uses percpu_counter interface to collect user and
system times. This has two side effects:
diff --git a/Documentation/devicetree/bindings/arm/msm/core_sleep_status.txt b/Documentation/devicetree/bindings/arm/msm/core_sleep_status.txt
new file mode 100644
index 0000000..6ac80f1
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/core_sleep_status.txt
@@ -0,0 +1,29 @@
+* MSM Sleep status
+
+MSM Sleep status device is used to check the power collapsed status of a
+offlined core. The core that initiates the hotplug would wait on the
+sleep status device before CPU_DEAD notifications are sent out. Some hardware
+devices require that the offlined core is power collapsed before turning off
+the resources that are used by the offlined core.
+
+This device is dependent on the pm-8x60 device, which configures the low power
+mode of respective cores. The sleep status is only valid when the core enters
+a low power mode. The device is a child node to pm-8x60 node which is documented
+in Documentation/devicetree/bindings/arm/msm/pm-8x60.txt
+
+The required properties of sleep status device are:
+
+- compatible: qcom,cpu-sleep-status
+- reg: physical address of the sleep status register for Core 0
+- qcom,cpu-alias-addr - On MSM chipset, the each cores registers are at a
+ fixed offset each other.
+- qcom,cpu-sleep-status-mask - The bit mask within the status register that
+ indicates the Core's sleep state.
+
+Example:
+ qcom,cpu-sleep-status@f9088008 {
+ compatible = "qcom,cpu-sleep-status";
+ reg = <0xf9088008 0x4>;
+ qcom,cpu-alias-addr = <0x10000>;
+ qcom,sleep-status-mask= <0x80000>;
+ };
diff --git a/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt b/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt
index 6d22003..195a98d 100644
--- a/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt
+++ b/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt
@@ -8,17 +8,24 @@
lpm-level. The units for voltage are dependent on the PMIC used on the target
and are in uV.
-The optional properties are:
-
-- qcom,use-qtimer: Indicates whether the target uses the synchronized QTimer.
-
The required nodes for lpm-levels are:
- compatible: "qcom,lpm-levels"
- reg: The numeric level id
-- qcom,mode: The sleep mode of the processor
-- qcom,xo: The state of XO clock.
-- qcom,l2: The state of L2 cache.
+- qcom,mode: The sleep mode of the processor, values for the property are:
+ "wfi" - Wait for Interrupt
+ "ramp_down_and_wfi" - Ramp down and wait for interrupt
+ "standalone_pc" - Standalone power collapse
+ "pc" - Power Collapse
+ "retention" - Retention
+ "pc_suspend" - Suspended Power Collapse
+ "pc_no_xo_shutdown" - Power Collapse with no XO shutdown
+- qcom,xo: The state of XO clock. Values are "xo_on" and "xo_off"
+- qcom,l2: The state of L2 cache. Values are:
+ "l2_cache_pc" - L2 cache in power collapse
+ "l2_cache_retenetion" - L2 cache in retention
+ "l2_cache_gdhs" - L2 cache in GDHS
+ "l2_cache_active" - L2 cache in active mode
- qcom,vdd-mem-upper-bound: The upper bound value of mem voltage in uV
- qcom,vdd-mem-lower-bound: The lower bound value of mem voltage in uV
- qcom,vdd-dig-upper-bound: The upper bound value of dig voltage in uV
@@ -41,6 +48,7 @@
- qcom,gpio-detectable: The field indicates whether the GPIOs can be detected
by the GPIO interrupt controller during a given low
power mode.
+- qcom,use-qtimer: Indicates whether the target uses the synchronized QTimer.
Example:
@@ -48,9 +56,9 @@
qcom,use-qtimer;
qcom,lpm-level@0 {
reg = <0>;
- qcom,mode = <0>; /* MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT */
- qcom,xo = <1>; /* ON */
- qcom,l2 = <3>; /* ACTIVE */
+ qcom,mode = "wfi";
+ qcom,xo = "xo_on";
+ qcom,l2 = "l2_cache_active";
qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
qcom,vdd-dig-upper-bound = <5>; /* MAX */
diff --git a/Documentation/devicetree/bindings/arm/msm/lpm-resources.txt b/Documentation/devicetree/bindings/arm/msm/lpm-resources.txt
index ccb3465..7b5fda3 100644
--- a/Documentation/devicetree/bindings/arm/msm/lpm-resources.txt
+++ b/Documentation/devicetree/bindings/arm/msm/lpm-resources.txt
@@ -20,10 +20,9 @@
- reg: The numeric level id
- qcom,name: The name of the low power resource represented
as a string.
-- qcom,resource-type: The type of the LPM resource.
- MSM_LPM_RPM_RS_TYPE = 0
- MSM_LPM_LOCAL_RS_TYPE = 1
-- qcom,init-value: Initialization value of the LPM resource.
+- qcom,init-value: Initialization value of the LPM resource represented as
+ decimal value for vdd-dig and vdd-mem resources and
+ as string for pxo and l2 resources.
Optional Nodes:
@@ -33,12 +32,13 @@
- qcom,id: The id representing a device within a resource type.
- qcom,key: The key is the specific attribute of the resource being
monitored represented as a hex value.
+- qcom,local-resource-type: The property exists only for locally managed
+ resource and is represented as a bool.
Example:
qcom,lpm-resources@0 {
reg = <0x0>;
qcom,name = "vdd-dig";
- qcom,resource-type = <0>;
qcom,type = <0x62706d73>; /* "smpb" */
qcom,id = <0x02>;
qcom,key = <0x6e726f63>; /* "corn" */
diff --git a/Documentation/devicetree/bindings/arm/msm/pm-8x60.txt b/Documentation/devicetree/bindings/arm/msm/pm-8x60.txt
index a372912..c741514 100644
--- a/Documentation/devicetree/bindings/arm/msm/pm-8x60.txt
+++ b/Documentation/devicetree/bindings/arm/msm/pm-8x60.txt
@@ -18,10 +18,10 @@
- reg: physical IMEM address reserved for PC counters and the size
- qcom,use-sync-timer: Indicates whether the target uses the synchronized QTimer.
- qcom,pc-mode: Indicates the type of power collapse used by the target. The
- valid values for this are:
- 0 (Power collapse terminates in TZ; integrated L2 cache controller)
- 1, (Power collapse doesn't terminate in TZ; external L2 cache controller)
- 2 (Power collapse terminates in TZ; external L2 cache controller)
+ valid values for this are:
+ "tz_l2_int" (Power collapse terminates in TZ; integrated L2 cache controller)
+ "no_tz_l2_ext", (Power collapse doesn't terminate in TZ; external L2 cache controller)
+ "tz_l2_ext" (Power collapse terminates in TZ; external L2 cache controller)
- qcom,saw-turns-off-pll: Version of SAW2.1 or can turn off the HFPLL, when
doing power collapse and so the core need to switch to Global PLL before
PC.
@@ -31,6 +31,6 @@
qcom,pm-8x60@fe800664 {
compatible = "qcom,pm-8x60";
reg = <0xfe800664 0x40>;
- qcom,pc-mode = <0>;
+ qcom,pc-mode = "tz_l2_int";
qcom,use-sync-timer;
};
diff --git a/Documentation/devicetree/bindings/arm/msm/pm-boot.txt b/Documentation/devicetree/bindings/arm/msm/pm-boot.txt
index cce9d0e..7ba8a6d 100644
--- a/Documentation/devicetree/bindings/arm/msm/pm-boot.txt
+++ b/Documentation/devicetree/bindings/arm/msm/pm-boot.txt
@@ -16,10 +16,10 @@
- compatible: Must be "qcom,pm-boot"
- qcom,mode: The mode that the target will use for booting
- MSM_PM_BOOT_CONFIG_TZ = 0,
- MSM_PM_BOOT_CONFIG_RESET_VECTOR_PHYS = 1,
- MSM_PM_BOOT_CONFIG_RESET_VECTOR_VIRT = 2,
- MSM_PM_BOOT_CONFIG_REMAP_BOOT_ADDR = 3,
+ "tz" = MSM_PM_BOOT_CONFIG_TZ,
+ "reset_vector_phys" = MSM_PM_BOOT_CONFIG_RESET_VECTOR_PHYS,
+ "reset_vector_virt" = MSM_PM_BOOT_CONFIG_RESET_VECTOR_VIRT,
+ "remap_boot_addr" = MSM_PM_BOOT_CONFIG_REMAP_BOOT_ADDR,
Optional parameters (based on the mode chosen):
@@ -36,5 +36,5 @@
qcom,pm-boot {
compatible = "qcom,pm-boot";
- qcom,mode = <0>; /* MSM_PM_BOOT_CONFIG_TZ */
+ qcom,mode = "tz"; /* MSM_PM_BOOT_CONFIG_TZ */
};
diff --git a/Documentation/devicetree/bindings/arm/msm/qcom-wdog-debug.txt b/Documentation/devicetree/bindings/arm/msm/qcom-wdog-debug.txt
deleted file mode 100644
index e5fd1b2..0000000
--- a/Documentation/devicetree/bindings/arm/msm/qcom-wdog-debug.txt
+++ /dev/null
@@ -1,16 +0,0 @@
-* Qualcomm's Watchdog Debug Image Controller
-
-The Qualcomm's Watchdog debug image controller is used for enabling/disabling of
-watchdog debug image feature.
-
-Required properties:
-- compatible : should be "qcom,msm-wdog-debug"
-- reg : base page aligned physical base address of the controller and length of
- memory mapped region.
-
-Example:
-
- qcom,msm-wdog-debug@fc401000 {
- compatible = "qcom,msm-wdogi-debug";
- reg = <0xfc401000 0x1000>;
- };
diff --git a/Documentation/devicetree/bindings/arm/msm/smp2p.txt b/Documentation/devicetree/bindings/arm/msm/smp2p.txt
index 7a5f506..a7af9e7 100644
--- a/Documentation/devicetree/bindings/arm/msm/smp2p.txt
+++ b/Documentation/devicetree/bindings/arm/msm/smp2p.txt
@@ -2,9 +2,7 @@
Required properties:
-compatible : should be "qcom,smp2p"
--reg : the location and offset of the irq register base memory
--reg-names : "irq-reg-base", "irq-reg-offset" - string to identify the irq
- register region and offset values
+-reg : the location of the irq register base memory
-qcom,remote-pid : the SMP2P remote processor ID (see smp2p_private_api.h)
-qcom,irq-bitmask : the sending irq bitmask
-interrupts : the receiving interrupt line
@@ -13,8 +11,7 @@
qcom,smp2p-modem {
compatible = "qcom,smp2p";
- reg = <0xfa006000 0x1000>, <0x8 0x0>;
- reg-names = "irq-reg-base", "irq-reg-offset";
+ reg = <0xf9011008 0x4>;
qcom,remote-pid = <1>;
qcom,irq-bitmask = <0x4000>;
interrupts = <0 27 1>;
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-ctrl.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-ctrl.txt
index 7d19c03..5c426f2 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi-ctrl.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi-ctrl.txt
@@ -8,22 +8,45 @@
- cell-index: Specifies the controller used among the two controllers.
- reg: offset and length of the register set for the device.
- vdd-supply: Phandle for vdd regulator device node.
-- vdd-io-supply: Phandle for vdd-io regulator device node.
-- vreg-supply: Phandle for vreg regulator device node.
+- vddio-supply: Phandle for vdd-io regulator device node.
+- vdda-supply: Phandle for vreg regulator device node.
- qcom,mdss-fb-map: pHandle that specifies the framebuffer to which the
interface is mapped.
Optional properties:
- label: A string used to describe the controller used.
+- qcom,supply-names: A list of strings that lists the names of the
+ regulator supplies.
+- qcom,supply-type: A list of strings that list the type of supply(ies)
+ mentioned above. This list maps in the order of
+ the supply names listed above.
+ regulator = supply with controlled output
+ switch = supply without controlled output. i.e.
+ voltage switch
+- qcom,supply-min-voltage-level: A list that specifies minimum voltage level
+ of supply(ies) mentioned above. This list maps
+ in the order of the supply names listed above.
+- qcom,supply-max-voltage-level: A list that specifies maximum voltage level of
+ supply(ies) mentioned above. This list maps in
+ the order of the supply names listed above.
+- qcom,supply-peak-current: A list that specifies the peak current that will
+ be drawn from the supply(ies) mentioned above. This
+ list maps in the order of the supply names listed above.
+
Example:
mdss_dsi0: qcom,mdss_dsi@fd922800 {
- compatible = "qcom,mdss-dsi-ctrl";
- label = "MDSS DSI CTRL->0";
- cell-index = <0>;
- reg = <0xfd922800 0x600>;
- vdd-supply = <&pm8941_l22>;
- vdd_io-supply = <&pm8941_l12>;
- vreg-supply = <&pm8941_l2>;
+ compatible = "qcom,mdss-dsi-ctrl";
+ label = "MDSS DSI CTRL->0";
+ cell-index = <0>;
+ reg = <0xfd922800 0x600>;
+ vdd-supply = <&pm8226_l15>;
+ vddio-supply = <&pm8226_l8>;
+ vdda-supply = <&pm8226_l4>;
+ qcom,supply-names = "vdd", "vddio", "vdda";
+ qcom,supply-type = "regulator", "regulator", "regulator";
+ qcom,supply-min-voltage-level = <2800000 1800000 1200000>;
+ qcom,supply-max-voltage-level = <2800000 1800000 1200000>;
+ qcom,supply-peak-current = <150000 100000 100000>;
qcom,mdss-fb-map = <&mdss_fb0>;
};
diff --git a/Documentation/devicetree/bindings/fb/mdss-qpic-panel.txt b/Documentation/devicetree/bindings/fb/mdss-qpic-panel.txt
new file mode 100644
index 0000000..95f0fa4
--- /dev/null
+++ b/Documentation/devicetree/bindings/fb/mdss-qpic-panel.txt
@@ -0,0 +1,37 @@
+Qualcomm mdss-qpic-panel
+
+mdss-qpic-panel is a panel device which can be driven by qpic.
+
+Required properties:
+- compatible: Must be "qcom,mdss-qpic-panel"
+- qcom,mdss-pan-res: A two dimensional array that specifies the panel
+ resolution.
+- qcom,mdss-pan-bpp: Specifies the panel bits per pixel.
+- qcom,refresh_rate: Panel refresh rate
+- vdd-supply: Phandle for vdd regulator device node.
+- avdd-supply: Phandle for avdd regulator device node.
+- qcom,cs-gpio: Phandle for cs gpio device node.
+- qcom,te-gpio: Phandle for te gpio device node.
+- qcom,rst-gpio: Phandle for rst gpio device node.
+- qcom,ad8-gpio: Phandle for ad8 gpio device node.
+
+Optional properties:
+- label: A string used as a descriptive name of the panel
+
+
+Example:
+/ {
+ qcom,mdss_lcdc_ili9341_qvga {
+ compatible = "qcom,mdss-qpic-panel";
+ label = "ili qvga lcdc panel";
+ vdd-supply = <&pm8019_l11>;
+ avdd-supply = <&pm8019_l14>;
+ qcom,cs-gpio = <&msmgpio 21 0>;
+ qcom,te-gpio = <&msmgpio 22 0>;
+ qcom,rst-gpio = <&msmgpio 23 0>;
+ qcom,ad8-gpio = <&msmgpio 20 0>;
+ qcom,mdss-pan-res = <240 320>;
+ qcom,mdss-pan-bpp = <18>;
+ qcom,refresh_rate = <60>;
+ };
+};
diff --git a/Documentation/devicetree/bindings/fb/mdss-qpic.txt b/Documentation/devicetree/bindings/fb/mdss-qpic.txt
new file mode 100644
index 0000000..0fa3a32
--- /dev/null
+++ b/Documentation/devicetree/bindings/fb/mdss-qpic.txt
@@ -0,0 +1,18 @@
+Qualcomm mdss-qpic
+
+mdss-qpic is a qpic controller device which supports dma transmission to MIPI
+and LCDC panel.
+
+Required properties:
+- compatible: must be "qcom,mdss_qpic"
+- reg: offset and length of the register set for the device.
+- reg-names : names to refer to register sets related to this device
+- interrupts: IRQ line
+
+Example:
+ qcom,msm_qpic@f9ac0000 {
+ compatible = "qcom,mdss_qpic";
+ reg = <0xf9ac0000 0x24000>;
+ reg-names = "qpic_base";
+ interrupts = <0 251 0>;
+ };
diff --git a/Documentation/devicetree/bindings/media/video/msm-vidc.txt b/Documentation/devicetree/bindings/media/video/msm-vidc.txt
index f97e063..bebdb5a 100644
--- a/Documentation/devicetree/bindings/media/video/msm-vidc.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-vidc.txt
@@ -39,6 +39,7 @@
- qcom,buffer-type-tz-usage-table : a key-value pair, mapping a buffer type
(enum hal_buffer) to its corresponding TZ usage. The TZ usages are defined
as "enum cp_mem_usage" in include/linux/msm_ion.h
+- qcom,has-ocmem: indicate the target has ocmem if this property exists
Example:
@@ -55,6 +56,7 @@
<243000 133330000>,
<108000 100000000>,
<36000 50000000>;
+ qcom,has-ocmem;
qcom,hfi = "venus";
qcom,reg-presets = <0x80004 0x1>,
<0x80178 0x00001FFF>;
diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
index a0c7037..d5937cf 100644
--- a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
+++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
@@ -20,6 +20,24 @@
Optional Properties:
- interrupt-names - "status_irq". This status_irq will be used for card
detection.
+ - cd-gpios: specify GPIO for card detection. If this property is
+ defined, then it means SDHC device has more than one interrupt
+ parent and hence, it is required to define the following properties
+ to configure interrupts from multiple parents -
+
+ interrupt-parent - This must provide reference to the current
+ device node.
+ #address-cells - Should provide a value of 0.
+ interrupts - Should be <0 1 2> and it is an index to the
+ interrupt-map.
+ #interrupt-cells - should provide a value of 1.
+ #interrupt-mask - should provide a value of 0xffffffff.
+ interrupt-map - Must create mapping for the number of interrupts
+ that are defined in above interrupts property.
+ For SDHC device node, it must define 3 mappings for
+ hc_irq, pwr_irq and status_irq in the format
+ mentioned in below example node of sdhc_2.
+
- qcom,bus-width - defines the bus I/O width that controller supports.
Units - number of bits. The valid bus-width values are
1, 4 and 8.
@@ -109,8 +127,17 @@
compatible = "qcom,sdhci-msm";
reg = <0xf9824900 0x11c>, <0xf9824000 0x800>;
reg-names = "hc_mem", "core_mem";
- interrupts = <0 123 0>, <0 138 0>;
- interrupt-names = "hc_irq", "pwr_irq";
+
+ #address-cells = <0>;
+ interrupt-parent = <&sdhc_2>;
+ interrupts = <0 1 2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-map = <0 &intc 0 125 0
+ 1 &intc 0 221 0
+ 2 &msmgpio 62 0x3>;
+ interrupt-names = "hc_irq", "pwr_irq", "status_irq";
+ cd-gpios = <&msmgpio 62 0x1>;
vdd-supply = <&pm8941_l21>;
vdd-io-supply = <&pm8941_l13>;
diff --git a/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt b/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt
index 2764657..70f8b55 100644
--- a/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt
+++ b/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt
@@ -10,7 +10,7 @@
- reg: Pairs of physical base addresses and region sizes of
memory mapped registers.
- reg-names: Names of the bases for the above registers. "qdsp6_base"
- and "halt_base" are expected.
+ "halt_base", and "restart_reg" are expected.
- interrupts: The lpass watchdog interrupt
- vdd_cx-supply: Reference to the regulator that supplies the vdd_cx domain.
- qcom,firmware-name: Base name of the firmware image. Ex. "lpass"
@@ -23,8 +23,9 @@
qcom,lpass@fe200000 {
compatible = "qcom,pil-q6v5-lpass";
reg = <0xfe200000 0x00100>,
- <0xfd485100 0x00010>;
- reg-names = "qdsp6_base", "halt_base";
+ <0xfd485100 0x00010>,
+ <0xfc4016c0 0x00004>;
+ reg-names = "qdsp6_base", "halt_base", "restart_reg";
interrupts = <0 194 1>;
vdd_cx-supply = <&pm8841_s2>;
qcom,firmware-name = "lpass";
diff --git a/Documentation/devicetree/bindings/power/opp.txt b/Documentation/devicetree/bindings/power/opp.txt
new file mode 100644
index 0000000..74499e5
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/opp.txt
@@ -0,0 +1,25 @@
+* Generic OPP Interface
+
+SoCs have a standard set of tuples consisting of frequency and
+voltage pairs that the device will support per voltage domain. These
+are called Operating Performance Points or OPPs.
+
+Properties:
+- operating-points: An array of 2-tuples items, and each item consists
+ of frequency and voltage like <freq-kHz vol-uV>.
+ freq: clock frequency in kHz
+ vol: voltage in microvolt
+
+Examples:
+
+cpu@0 {
+ compatible = "arm,cortex-a9";
+ reg = <0>;
+ next-level-cache = <&L2>;
+ operating-points = <
+ /* kHz uV */
+ 792000 1100000
+ 396000 950000
+ 198000 850000
+ >;
+};
diff --git a/Documentation/devicetree/bindings/power/qpnp-bms.txt b/Documentation/devicetree/bindings/power/qpnp-bms.txt
index 708ada1..5b22752 100644
--- a/Documentation/devicetree/bindings/power/qpnp-bms.txt
+++ b/Documentation/devicetree/bindings/power/qpnp-bms.txt
@@ -40,13 +40,16 @@
The bms will not accept new ocvs between these
thresholds.
- qcom,low-soc-calculate-soc-threshold : The SoC threshold for when
- the period calculate_soc work speeds up. This ensures
+ the periodic calculate_soc work speeds up. This ensures
SoC is updated in userspace constantly when we are near
shutdown.
+- qcom,low-voltage-threshold : The battery voltage threshold in micro-volts for
+ when the BMS tries to wake up and hold a wakelock to
+ ensure a clean shutdown.
- qcom,low-soc-calculate-soc-ms : The time period between subsequent
-
SoC recalculations when the current SoC is below
- qcom,low-soc-calculate-soc-threshold.
+ qcom,low-soc-calculate-soc-threshold or when battery
+ voltage is below qcom,low-voltage-threshold.
- qcom,soc-calculate-soc-ms : The time period between subsequent SoC
recalculations when the current SoC is above or equal
qcom,low-soc-calculate-soc-threshold.
@@ -107,6 +110,7 @@
qcom,adjust-soc-low-threshold = <25>;
qcom,adjust-soc-high-threshold = <45>;
qcom,low-soc-calculate-soc-threshold = <15>;
+ qcom,low-voltage-threshold = <3420000>;
qcom,low-soc-calculate-soc-ms = <5000>;
qcom,calculate-soc-ms = <20000>;
qcom,chg-term-ua = <100000>;
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index 4cd9f99..a4c05d4 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -96,6 +96,12 @@
is 8, which indicates the rx path used for audio playback
on HDMI device.
+* msm-lsm-client
+
+Required properties:
+
+ - compatible : "qcom,msm-lsm-client"
+
* msm-dai-q6
[First Level Nodes]
diff --git a/Documentation/devicetree/bindings/thermal/tsens.txt b/Documentation/devicetree/bindings/thermal/tsens.txt
index 67a986b..1388b7d 100644
--- a/Documentation/devicetree/bindings/thermal/tsens.txt
+++ b/Documentation/devicetree/bindings/thermal/tsens.txt
@@ -38,7 +38,11 @@
Optional properties:
- qcom,calibration-less-mode : If present the pre-characterized data for offsets
are used else it defaults to use calibration data from QFPROM.
-
+- qcom,tsens-local-init : If the flag is present the TSENS control registers are
+ initialized. If the boot configures the control register there is
+ no need to re-initialize them. The control registers are also
+ under a secure domain which can prevent them from being initialized
+ locally.
Example:
tsens@fc4a8000 {
diff --git a/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt b/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
index 1885e8a..9f8bbd9 100644
--- a/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
+++ b/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
@@ -15,7 +15,10 @@
"wakeup" : Wakeup interrupt from HSIC during suspend (or XO shutdown).
- hsic,<gpio-name>-gpio : handle to the GPIO node, see "gpios property"
in Documentation/devicetree/bindings/gpio/gpio.txt.
- Optional "gpio-name" can be "strobe" and "data".
+ Optional "gpio-name" can be "strobe", "data" and "resume".
+- hsic,resume-gpio : if present then periperal connected to hsic controller
+ cannot wakeup from XO shutdown using in-band hsic resume. Use resume
+ gpio to wakeup peripheral
- hsic,ignore-cal-pad-config : If present then HSIC CAL PAD configuration
using TLMM is not performed.
- hsic,strobe-pad-offset : Offset of TLMM register for configuring HSIC
diff --git a/Documentation/devicetree/bindings/usb/msm-hsusb.txt b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
index df88caa..02c2871 100644
--- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
@@ -172,115 +172,90 @@
If SSUSB_BAM is used, "ssusb" should be present.
If HSUSB_BAM is used, "hsusb" should be present.
If HSIC_BAM is used, "hsic" should be present.
-- qcom,usb-active-bam: active BAM type. Can be one of
- 0 - SSUSB_BAM
- 1 - HSUSB_BAM
- 2 - HSIC_BAM
-- qcom,usb-total-bam-num: total number of BAMs that are supported
- qcom,usb-bam-num-pipes: max number of pipes that can be used
- qcom,usb-base-address: physical base address of the BAM
A number of USB BAM pipe parameters are represented as sub-nodes:
Subnode Required:
-- label: a string describing the pipe's direction and BAM instance under use
-- qcom,usb-bam-type: BAM type. Can be one of
- 0 - SSUSB_BAM
- 1 - HSUSB_BAM
- 2 - HSIC_BAM
+- label: a string describing uniquely the usb bam pipe. The string can be
+ constracted as follows: <core>-<peer>-<direction>-<pipe num>.
+ core options: hsusb, ssusb/dwc3, hsic
+ peer options: qdss, ipa, a2
+ direction options: in (from peer to usb), out (from usb to peer)
+ pipe num options: 0..127
- qcom,usb-bam-mem-type: Type of memory used by this PIPE. Can be one of
0 - Uses SPS's dedicated pipe memory
1 - USB's private memory residing @ 'qcom,usb-base-address'
2 - System RAM allocated by driver
-- qcom,src-bam-physical-address: source BAM physical address
-- qcom,src-bam-pipe-index: source BAM pipe index
-- qcom,dst-bam-physical-address: destination BAM physical address
-- qcom,dst-bam-pipe-index: destination BAM pipe index
-- qcom,data-fifo-offset: data fifo offset address
+- qcom,bam-type: BAM type can be one of
+ 0 - SSUSB_BAM
+ 1 - HSUSB_BAM
+ 2 - HSIC_BAM
+- qcom,dir: pipe direction
+ 0 - from usb (out)
+ 1 - to usb (in)
+- qcom,pipe-num: pipe number
+- qcom,peer-bam: peer BAM can be one of
+ 0 - A2_P_BAM
+ 1 - QDSS_P_BAM
+ 2 - IPA_P_BAM
- qcom,data-fifo-size: data fifo size
-- qcom,descriptor-fifo-offset: descriptor fifo offset address
- qcom,descriptor-fifo-size: descriptor fifo size
Optional Properties for Subnode:
- qcom,reset-bam-on-connect: If present then BAM is RESET before connecting
pipe. This may be required if BAM peripheral is also reset before connect.
+- qcom,dst-bam-physical-address: destination BAM physical address
+- qcom,dst-bam-pipe-index: destination BAM pipe index
+- qcom,src-bam-physical-address: source BAM physical address
+- qcom,src-bam-pipe-index: source BAM pipe index
+- qcom,data-fifo-offset: data fifo offset address
+- qcom,descriptor-fifo-offset: descriptor fifo offset address
Optional properties :
- qcom,ignore-core-reset-ack: If present then BAM ignores ACK from USB core
while performing PIPE RESET
- qcom,disable-clk-gating: If present then disable BAM clock gating.
-
Example USB BAM controller device node:
- qcom,usbbam@f9304000 {
+ qcom,usbbam@f9a44000 {
compatible = "qcom,usb-bam-msm";
- reg = <0xf9304000 0x5000>,
- <0xf9a44000 0x11000>,
- <0xf92f880c 0x4>;
- reg-names = "ssusb", "hsusb", "qscratch_ram1_reg";
- interrupts = <0 132 0 0 135 0>;
- interrupt-names = "ssusb", "hsusb";
- qcom,usb-active-bam = <0>;
- qcom,usb-total-bam-num = <2>;
+ reg = <0xf9a44000 0x11000>;
+ reg-names = "hsusb";
+ interrupts = <0 135 0>;
+ interrupt-names = "hsusb";
qcom,usb-bam-num-pipes = <16>;
- qcom,usb-base-address = <0xf9200000>;
qcom,ignore-core-reset-ack;
+ qcom,disable-clk-gating;
+ qcom,pipe0 {
+ label = "hsusb-ipa-out-0";
+ qcom,usb-bam-mem-type = <0>;
+ qcom,bam-type = <1>;
+ qcom,dir = <0>;
+ qcom,pipe-num = <0>;
+ qcom,peer-bam = <2>;
+ qcom,src-bam-physical-address = <0xf9a44000>;
+ qcom,src-bam-pipe-index = <1>;
+ qcom,data-fifo-offset = <0x2200>;
+ qcom,data-fifo-size = <0x1e00>;
+ qcom,descriptor-fifo-offset = <0x2100>;
+ qcom,descriptor-fifo-size = <0x100>;
+ };
qcom,pipe1 {
- label = "usb-to-peri-qdss-dwc3";
- qcom,usb-bam-type = <0>;
- qcom,usb-bam-mem-type = <1>;
- qcom,src-bam-physical-address = <0>;
- qcom,src-bam-pipe-index = <0>;
- qcom,dst-bam-physical-address = <0>;
- qcom,dst-bam-pipe-index = <0>;
- qcom,data-fifo-offset = <0>;
- qcom,data-fifo-size = <0>;
- qcom,descriptor-fifo-offset = <0>;
- qcom,descriptor-fifo-size = <0>;
- };
-
- qcom,pipe2 {
- label = "peri-to-usb-qdss-dwc3";
- qcom,usb-bam-type = <0>;
- qcom,usb-bam-mem-type = <1>;
- qcom,src-bam-physical-address = <0xfc37C000>;
- qcom,src-bam-pipe-index = <0>;
- qcom,dst-bam-physical-address = <0xf9304000>;
- qcom,dst-bam-pipe-index = <2>;
- qcom,data-fifo-offset = <0xf0000>;
- qcom,data-fifo-size = <0x4000>;
- qcom,descriptor-fifo-offset = <0xf4000>;
- qcom,descriptor-fifo-size = <0x1400>;
- qcom,reset-bam-on-connect;
- };
-
- qcom,pipe3 {
- label = "usb-to-peri-qdss-hsusb";
- qcom,usb-bam-type = <1>;
- qcom,usb-bam-mem-type = <1>;
- qcom,src-bam-physical-address = <0>;
- qcom,src-bam-pipe-index = <0>;
- qcom,dst-bam-physical-address = <0>;
- qcom,dst-bam-pipe-index = <0>;
- qcom,data-fifo-offset = <0>;
- qcom,data-fifo-size = <0>;
- qcom,descriptor-fifo-offset = <0>;
- qcom,descriptor-fifo-size = <0>;
- };
-
- qcom,pipe4 {
- label = "peri-to-usb-qdss-hsusb";
- qcom,usb-bam-type = <1>;
- qcom,usb-bam-mem-type = <1>;
- qcom,src-bam-physical-address = <0xfc37c000>;
- qcom,src-bam-pipe-index = <0>;
+ label = "hsusb-ipa-in-0";
+ qcom,usb-bam-mem-type = <0>;
+ qcom,bam-type = <1>;
+ qcom,dir = <1>;
+ qcom,pipe-num = <0>;
+ qcom,peer-bam = <2>;
qcom,dst-bam-physical-address = <0xf9a44000>;
- qcom,dst-bam-pipe-index = <2>;
- qcom,data-fifo-offset = <0xf4000>;
- qcom,data-fifo-size = <0x1000>;
- qcom,descriptor-fifo-offset = <0xf5000>;
- qcom,descriptor-fifo-size = <0x400>;
+ qcom,dst-bam-pipe-index = <0>;
+ qcom,data-fifo-offset = <0x300>;
+ qcom,data-fifo-size = <0x1e00>;
+ qcom,descriptor-fifo-offset = <0>;
+ qcom,descriptor-fifo-size = <0x300>;
};
};
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 6839263..17a44b3 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1830,13 +1830,6 @@
Enable hardware performance counter support for perf events. If
disabled, perf events will use software events only.
-config VMALLOC_RESERVE
- hex "Reserved vmalloc space"
- default 0x08000000
- depends on MMU
- help
- Reserved vmalloc space if not specified on the kernel commandline.
-
source "mm/Kconfig"
config ARCH_MEMORY_PROBE
diff --git a/arch/arm/boot/dts/msm-pm8110.dtsi b/arch/arm/boot/dts/msm-pm8110.dtsi
index 2f58185..ec42cfc 100644
--- a/arch/arm/boot/dts/msm-pm8110.dtsi
+++ b/arch/arm/boot/dts/msm-pm8110.dtsi
@@ -21,6 +21,73 @@
reg = <0x0>;
#address-cells = <1>;
#size-cells = <1>;
+
+ pm8110_vadc: vadc@3100 {
+ compatible = "qcom,qpnp-vadc";
+ reg = <0x3100 0x100>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0x0 0x31 0x0>;
+ interrupt-names = "eoc-int-en-set";
+ qcom,adc-bit-resolution = <15>;
+ qcom,adc-vdd-reference = <1800>;
+
+ chan@8 {
+ label = "die_temp";
+ reg = <8>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <3>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@9 {
+ label = "ref_625mv";
+ reg = <9>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@a {
+ label = "ref_1250v";
+ reg = <0xa>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+ };
+
+ iadc@3600 {
+ compatible = "qcom,qpnp-iadc";
+ reg = <0x3600 0x100>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0x0 0x36 0x0>;
+ interrupt-names = "eoc-int-en-set";
+ qcom,adc-bit-resolution = <16>;
+ qcom,adc-vdd-reference = <1800>;
+ qcom,rsense = <1500>;
+
+ chan@0 {
+ label = "internal_rsense";
+ reg = <0>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <1>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+ };
};
qcom,pm8110@1 {
@@ -28,5 +95,225 @@
reg = <0x1>;
#address-cells = <1>;
#size-cells = <1>;
+
+ regulator@1400 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "8110_s1";
+ spmi-dev-container;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0x1400 0x300>;
+ status = "disabled";
+
+ qcom,ctl@1400 {
+ reg = <0x1400 0x100>;
+ };
+ qcom,ps@1500 {
+ reg = <0x1500 0x100>;
+ };
+ qcom,freq@1600 {
+ reg = <0x1600 0x100>;
+ };
+ };
+
+ regulator@1700 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "8110_s2";
+ spmi-dev-container;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0x1700 0x300>;
+ status = "disabled";
+
+ qcom,ctl@1700 {
+ reg = <0x1700 0x100>;
+ };
+ qcom,ps@1800 {
+ reg = <0x1800 0x100>;
+ };
+ qcom,freq@1900 {
+ reg = <0x1900 0x100>;
+ };
+ };
+
+ regulator@1a00 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "8110_s3";
+ spmi-dev-container;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0x1a00 0x300>;
+ status = "disabled";
+
+ qcom,ctl@1a00 {
+ reg = <0x1a00 0x100>;
+ };
+ qcom,ps@1b00 {
+ reg = <0x1b00 0x100>;
+ };
+ qcom,freq@1c00 {
+ reg = <0x1c00 0x100>;
+ };
+ };
+
+ regulator@1d00 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "8110_s4";
+ spmi-dev-container;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0x1d00 0x300>;
+ status = "disabled";
+
+ qcom,ctl@1d00 {
+ reg = <0x1d00 0x100>;
+ };
+ qcom,ps@1e00 {
+ reg = <0x1e00 0x100>;
+ };
+ qcom,freq@1f00 {
+ reg = <0x1f00 0x100>;
+ };
+ };
+
+ regulator@4000 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "8110_l1";
+ reg = <0x4000 0x100>;
+ status = "disabled";
+ };
+
+ regulator@4100 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "8110_l2";
+ reg = <0x4100 0x100>;
+ status = "disabled";
+ };
+
+ regulator@4200 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "8110_l3";
+ reg = <0x4200 0x100>;
+ status = "disabled";
+ };
+
+ regulator@4300 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "8110_l4";
+ reg = <0x4300 0x100>;
+ status = "disabled";
+ };
+
+ regulator@4400 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "8110_l5";
+ reg = <0x4400 0x100>;
+ status = "disabled";
+ };
+
+ regulator@4500 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "8110_l6";
+ reg = <0x4500 0x100>;
+ status = "disabled";
+ };
+
+ regulator@4600 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "8110_l7";
+ reg = <0x4600 0x100>;
+ status = "disabled";
+ };
+
+ regulator@4700 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "8110_l8";
+ reg = <0x4700 0x100>;
+ status = "disabled";
+ };
+
+ regulator@4800 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "8110_l9";
+ reg = <0x4800 0x100>;
+ status = "disabled";
+ };
+
+ regulator@4900 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "8110_l10";
+ reg = <0x4900 0x100>;
+ status = "disabled";
+ };
+
+ regulator@4b00 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "8110_l12";
+ reg = <0x4b00 0x100>;
+ status = "disabled";
+ };
+
+ regulator@4d00 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "8110_l14";
+ reg = <0x4d00 0x100>;
+ status = "disabled";
+ };
+
+ regulator@4e00 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "8110_l15";
+ reg = <0x4e00 0x100>;
+ status = "disabled";
+ };
+
+ regulator@4f00 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "8110_l16";
+ reg = <0x4f00 0x100>;
+ status = "disabled";
+ };
+
+ regulator@5000 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "8110_l17";
+ reg = <0x5000 0x100>;
+ status = "disabled";
+ };
+
+ regulator@5100 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "8110_l18";
+ reg = <0x5100 0x100>;
+ status = "disabled";
+ };
+
+ regulator@5200 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "8110_l19";
+ reg = <0x5200 0x100>;
+ status = "disabled";
+ };
+
+ regulator@5300 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "8110_l20";
+ reg = <0x5300 0x100>;
+ status = "disabled";
+ };
+
+ regulator@5400 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "8110_l21";
+ reg = <0x5400 0x100>;
+ status = "disabled";
+ };
+
+ regulator@5500 {
+ compatible = "qcom,qpnp-regulator";
+ regulator-name = "8110_l22";
+ reg = <0x5500 0x100>;
+ status = "disabled";
+ };
};
};
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index d456303..320c3e4a 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -111,6 +111,7 @@
qcom,calculate-soc-ms = <20000>;
qcom,chg-term-ua = <100000>;
qcom,batt-type = <0>;
+ qcom,low-voltage-threshold = <3420000>;
qcom,bms-iadc@3800 {
reg = <0x3800 0x100>;
diff --git a/arch/arm/boot/dts/msm8226-cdp.dts b/arch/arm/boot/dts/msm8226-cdp.dts
index c6af08e..800cd8f 100644
--- a/arch/arm/boot/dts/msm8226-cdp.dts
+++ b/arch/arm/boot/dts/msm8226-cdp.dts
@@ -74,6 +74,24 @@
debounce-interval = <15>;
};
};
+
+ spi@f9923000 {
+ ethernet-switch@3 {
+ compatible = "micrel,ks8851";
+ reg = <3>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <0 115 0>;
+ spi-max-frequency = <4800000>;
+ rst-gpio = <&msmgpio 114 0>;
+ vdd-io-supply = <&pm8226_lvs1>;
+ vdd-phy-supply = <&pm8226_lvs1>;
+ };
+ };
+
+ sound {
+ qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
+ qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>;
+ };
};
&sdcc1 {
@@ -165,9 +183,24 @@
&pm8226_gpios {
gpio@c000 { /* GPIO 1 */
+ /* XO_PMIC_CDC_MCLK enable for tapan codec */
+ qcom,mode = <1>; /* Digital output */
+ qcom,output-type = <0>; /* CMOS logic */
+ qcom,pull = <5>; /* QPNP_PIN_PULL_NO*/
+ qcom,vin-sel = <2>; /* QPNP_PIN_VIN2 */
+ qcom,out-strength = <3>;/* QPNP_PIN_OUT_STRENGTH_HIGH */
+ qcom,src-sel = <2>; /* QPNP_PIN_SEL_FUNC_1 */
+ qcom,master-en = <1>; /* Enable GPIO */
};
gpio@c100 { /* GPIO 2 */
+ qcom,mode = <1>;
+ qcom,output-type = <0>;
+ qcom,pull = <5>;
+ qcom,vin-sel = <2>;
+ qcom,out-strength = <3>;
+ qcom,src-sel = <2>;
+ qcom,master-en = <1>;
};
gpio@c200 { /* GPIO 3 */
@@ -214,3 +247,8 @@
mpp@a700 { /* MPP 8 */
};
};
+
+&pm8226_chg {
+ qcom,chg-charging-disabled;
+ qcom,chg-use-default-batt-values;
+};
diff --git a/arch/arm/boot/dts/msm8226-coresight.dtsi b/arch/arm/boot/dts/msm8226-coresight.dtsi
index 8d5d23c..b891d3d 100644
--- a/arch/arm/boot/dts/msm8226-coresight.dtsi
+++ b/arch/arm/boot/dts/msm8226-coresight.dtsi
@@ -23,6 +23,7 @@
coresight-id = <0>;
coresight-name = "coresight-tmc-etr";
coresight-nr-inports = <1>;
+ coresight-ctis = <&cti0 &cti8>;
};
tpiu: tpiu@fc318000 {
@@ -60,6 +61,7 @@
coresight-child-list = <&replicator>;
coresight-child-ports = <0>;
coresight-default-sink;
+ coresight-ctis = <&cti0 &cti8>;
};
funnel_merg: funnel@fc31b000 {
@@ -142,15 +144,215 @@
coresight-child-ports = <7>;
};
+ etm0: etm@fc33c000 {
+ compatible = "arm,coresight-etm";
+ reg = <0xfc33c000 0x1000>;
+ reg-names = "etm0-base";
+
+ coresight-id = <10>;
+ coresight-name = "coresight-etm0";
+ coresight-nr-inports = <0>;
+ coresight-outports = <0>;
+ coresight-child-list = <&funnel_a7ss>;
+ coresight-child-ports = <0>;
+
+ qcom,round-robin;
+ };
+
+ etm1: etm@fc33d000 {
+ compatible = "arm,coresight-etm";
+ reg = <0xfc33d000 0x1000>;
+ reg-names = "etm1-base";
+
+ coresight-id = <11>;
+ coresight-name = "coresight-etm1";
+ coresight-nr-inports = <0>;
+ coresight-outports = <0>;
+ coresight-child-list = <&funnel_a7ss>;
+ coresight-child-ports = <1>;
+
+ qcom,round-robin;
+ };
+
+ etm2: etm@fc33e000 {
+ compatible = "arm,coresight-etm";
+ reg = <0xfc33e000 0x1000>;
+ reg-names = "etm2-base";
+
+ coresight-id = <12>;
+ coresight-name = "coresight-etm2";
+ coresight-nr-inports = <0>;
+ coresight-outports = <0>;
+ coresight-child-list = <&funnel_a7ss>;
+ coresight-child-ports = <2>;
+
+ qcom,round-robin;
+ };
+
+ etm3: etm@fc33f000 {
+ compatible = "arm,coresight-etm";
+ reg = <0xfc33f000 0x1000>;
+ reg-names = "etm3-base";
+
+ coresight-id = <13>;
+ coresight-name = "coresight-etm3";
+ coresight-nr-inports = <0>;
+ coresight-outports = <0>;
+ coresight-child-list = <&funnel_a7ss>;
+ coresight-child-ports = <3>;
+
+ qcom,round-robin;
+ };
+
csr: csr@fc302000 {
compatible = "qcom,coresight-csr";
reg = <0xfc302000 0x1000>;
reg-names = "csr-base";
- coresight-id = <10>;
+ coresight-id = <14>;
coresight-name = "coresight-csr";
coresight-nr-inports = <0>;
qcom,blk-size = <3>;
};
+
+ cti0: cti@fc308000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc308000 0x1000>;
+ reg-names = "cti0-base";
+
+ coresight-id = <15>;
+ coresight-name = "coresight-cti0";
+ coresight-nr-inports = <0>;
+ };
+
+ cti1: cti@fc309000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc309000 0x1000>;
+ reg-names = "cti1-base";
+
+ coresight-id = <16>;
+ coresight-name = "coresight-cti1";
+ coresight-nr-inports = <0>;
+ };
+
+ cti2: cti@fc30a000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc30a000 0x1000>;
+ reg-names = "cti2-base";
+
+ coresight-id = <17>;
+ coresight-name = "coresight-cti2";
+ coresight-nr-inports = <0>;
+ };
+
+ cti3: cti@fc30b000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc30b000 0x1000>;
+ reg-names = "cti3-base";
+
+ coresight-id = <18>;
+ coresight-name = "coresight-cti3";
+ coresight-nr-inports = <0>;
+ };
+
+ cti4: cti@fc30c000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc30c000 0x1000>;
+ reg-names = "cti4-base";
+
+ coresight-id = <19>;
+ coresight-name = "coresight-cti4";
+ coresight-nr-inports = <0>;
+ };
+
+ cti5: cti@fc30d000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc30d000 0x1000>;
+ reg-names = "cti5-base";
+
+ coresight-id = <20>;
+ coresight-name = "coresight-cti5";
+ coresight-nr-inports = <0>;
+ };
+
+ cti6: cti@fc30e000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc30e000 0x1000>;
+ reg-names = "cti6-base";
+
+ coresight-id = <21>;
+ coresight-name = "coresight-cti6";
+ coresight-nr-inports = <0>;
+ };
+
+ cti7: cti@fc30f000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc30f000 0x1000>;
+ reg-names = "cti7-base";
+
+ coresight-id = <22>;
+ coresight-name = "coresight-cti7";
+ coresight-nr-inports = <0>;
+ };
+
+ cti8: cti@fc310000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc310000 0x1000>;
+ reg-names = "cti8-base";
+
+ coresight-id = <23>;
+ coresight-name = "coresight-cti8";
+ coresight-nr-inports = <0>;
+ };
+
+ cti_l2: cti@fc340000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc340000 0x1000>;
+ reg-names = "cti-l2-base";
+
+ coresight-id = <24>;
+ coresight-name = "coresight-cti-l2";
+ coresight-nr-inports = <0>;
+ };
+
+ cti_cpu0: cti@fc341000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc341000 0x1000>;
+ reg-names = "cti-cpu0-base";
+
+ coresight-id = <25>;
+ coresight-name = "coresight-cti-cpu0";
+ coresight-nr-inports = <0>;
+ };
+
+ cti_cpu1: cti@fc342000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc342000 0x1000>;
+ reg-names = "cti-cpu1-base";
+
+ coresight-id = <26>;
+ coresight-name = "coresight-cti-cpu1";
+ coresight-nr-inports = <0>;
+ };
+
+ cti_cpu2: cti@fc343000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc343000 0x1000>;
+ reg-names = "cti-cpu2-base";
+
+ coresight-id = <27>;
+ coresight-name = "coresight-cti-cpu2";
+ coresight-nr-inports = <0>;
+ };
+
+ cti_cpu3: cti@fc344000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc344000 0x1000>;
+ reg-names = "cti-cpu3-base";
+
+ coresight-id = <28>;
+ coresight-name = "coresight-cti-cpu3";
+ coresight-nr-inports = <0>;
+ };
};
diff --git a/arch/arm/boot/dts/msm8226-iommu-domains.dtsi b/arch/arm/boot/dts/msm8226-iommu-domains.dtsi
new file mode 100644
index 0000000..6ea5b9e
--- /dev/null
+++ b/arch/arm/boot/dts/msm8226-iommu-domains.dtsi
@@ -0,0 +1,31 @@
+/* Copyright (c) 2013, 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.
+ */
+
+/ {
+ qcom,iommu-domains {
+ compatible = "qcom,iommu-domains";
+
+ venus_domain_ns: qcom,iommu-domain1 {
+ label = "venus_ns";
+ qcom,iommu-contexts = <&venus_ns>;
+ qcom,virtual-addr-pool = <0x40000000 0x3f000000
+ 0x7f000000 0x1000000>;
+ };
+
+ venus_domain_cp: qcom,iommu-domain2 {
+ label = "venus_cp";
+ qcom,iommu-contexts = <&venus_cp>;
+ qcom,virtual-addr-pool = <0x1000000 0x3f000000>;
+ qcom,secure-domain;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/msm8226-ion.dtsi b/arch/arm/boot/dts/msm8226-ion.dtsi
index b06ad42..9a35507 100644
--- a/arch/arm/boot/dts/msm8226-ion.dtsi
+++ b/arch/arm/boot/dts/msm8226-ion.dtsi
@@ -24,8 +24,7 @@
compatible = "qcom,msm-ion-reserve";
reg = <8>;
qcom,heap-align = <0x1000>;
- qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
- qcom,memory-reservation-size = <0x3800000>;
+ linux,contiguous-region = <&secure_mem>;
};
qcom,ion-heap@25 { /* IOMMU HEAP */
diff --git a/arch/arm/boot/dts/msm8226-mdss.dtsi b/arch/arm/boot/dts/msm8226-mdss.dtsi
index 30a89ef..21ed66a 100644
--- a/arch/arm/boot/dts/msm8226-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8226-mdss.dtsi
@@ -59,8 +59,13 @@
cell-index = <0>;
reg = <0xfd922800 0x600>;
vdd-supply = <&pm8226_l15>;
- vdd_io-supply = <&pm8226_l8>;
- vreg-supply = <&pm8226_l4>;
+ vddio-supply = <&pm8226_l8>;
+ vdda-supply = <&pm8226_l4>;
+ qcom,supply-names = "vdd", "vddio", "vdda";
+ qcom,supply-type = "regulator", "regulator", "regulator";
+ qcom,supply-min-voltage-level = <2800000 1800000 1200000>;
+ qcom,supply-max-voltage-level = <2800000 1800000 1200000>;
+ qcom,supply-peak-current = <150000 100000 100000>;
qcom,mdss-fb-map = <&mdss_fb0>;
};
diff --git a/arch/arm/boot/dts/msm8226-mtp.dts b/arch/arm/boot/dts/msm8226-mtp.dts
index f55165b..3d1fe19 100644
--- a/arch/arm/boot/dts/msm8226-mtp.dts
+++ b/arch/arm/boot/dts/msm8226-mtp.dts
@@ -74,6 +74,24 @@
debounce-interval = <15>;
};
};
+
+ spi@f9923000 {
+ ethernet-switch@3 {
+ compatible = "micrel,ks8851";
+ reg = <3>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <0 115 0>;
+ spi-max-frequency = <4800000>;
+ rst-gpio = <&msmgpio 114 0>;
+ vdd-io-supply = <&pm8226_lvs1>;
+ vdd-phy-supply = <&pm8226_lvs1>;
+ };
+ };
+
+ sound {
+ qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
+ qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>;
+ };
};
&sdcc1 {
@@ -162,9 +180,24 @@
&pm8226_gpios {
gpio@c000 { /* GPIO 1 */
+ /* XO_PMIC_CDC_MCLK enable for tapan codec */
+ qcom,mode = <1>; /* Digital output */
+ qcom,output-type = <0>; /* CMOS logic */
+ qcom,pull = <5>; /* QPNP_PIN_PULL_NO*/
+ qcom,vin-sel = <2>; /* QPNP_PIN_VIN2 */
+ qcom,out-strength = <3>;/* QPNP_PIN_OUT_STRENGTH_HIGH */
+ qcom,src-sel = <2>; /* QPNP_PIN_SEL_FUNC_1 */
+ qcom,master-en = <1>; /* Enable GPIO */
};
gpio@c100 { /* GPIO 2 */
+ qcom,mode = <1>;
+ qcom,output-type = <0>;
+ qcom,pull = <5>;
+ qcom,vin-sel = <2>;
+ qcom,out-strength = <3>;
+ qcom,src-sel = <2>;
+ qcom,master-en = <1>;
};
gpio@c200 { /* GPIO 3 */
diff --git a/arch/arm/boot/dts/msm8226-pm.dtsi b/arch/arm/boot/dts/msm8226-pm.dtsi
index 6348f5a..34283e8 100644
--- a/arch/arm/boot/dts/msm8226-pm.dtsi
+++ b/arch/arm/boot/dts/msm8226-pm.dtsi
@@ -22,7 +22,7 @@
qcom,saw2-ver-reg = <0xfd0>;
qcom,saw2-cfg = <0x01>;
qcom,saw2-spm-dly= <0x3c102800>;
- qcom,saw2-spm-ctl = <0x1>;
+ qcom,saw2-spm-ctl = <0x0>;
qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
qcom,saw2-spm-cmd-spc = [00 20 10 80 30 90 5b 60 03 60 3b 76 76
0b 94 5b 80 10 2b 06 26 30 0f];
@@ -39,7 +39,7 @@
qcom,saw2-ver-reg = <0xfd0>;
qcom,saw2-cfg = <0x01>;
qcom,saw2-spm-dly= <0x3c102800>;
- qcom,saw2-spm-ctl = <0x1>;
+ qcom,saw2-spm-ctl = <0x0>;
qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
qcom,saw2-spm-cmd-spc = [00 20 10 80 30 90 5b 60 03 60 3b 76 76
0b 94 5b 80 10 2b 06 26 30 0f];
@@ -56,7 +56,7 @@
qcom,saw2-ver-reg = <0xfd0>;
qcom,saw2-cfg = <0x01>;
qcom,saw2-spm-dly= <0x3c102800>;
- qcom,saw2-spm-ctl = <0x1>;
+ qcom,saw2-spm-ctl = <0x0>;
qcom,saw2-spm-cmd-wfi = [60 03 60 76 76 0b 0f];
qcom,saw2-spm-cmd-spc = [00 20 10 80 30 90 5b 60 03 60 3b 76 76
0b 94 5b 80 10 2b 06 26 30 0f];
@@ -73,7 +73,7 @@
qcom,saw2-ver-reg = <0xfd0>;
qcom,saw2-cfg = <0x01>;
qcom,saw2-spm-dly= <0x3c102800>;
- qcom,saw2-spm-ctl = <0x1>;
+ qcom,saw2-spm-ctl = <0x0>;
qcom,saw2-spm-cmd-wfi = [60 03 60 76 76 0b 0f];
qcom,saw2-spm-cmd-spc = [00 20 10 80 30 90 5b 60 03 60 3b 76 76
0b 94 5b 80 10 2b 06 26 30 0f];
@@ -90,7 +90,7 @@
qcom,saw2-ver-reg = <0xfd0>;
qcom,saw2-cfg = <0x14>;
qcom,saw2-spm-dly= <0x3c102800>;
- qcom,saw2-spm-ctl = <0x1>;
+ qcom,saw2-spm-ctl = <0x0>;
qcom,saw2-pmic-data0 = <0x0400009c>;
qcom,saw2-pmic-data1 = <0x0000001c>;
qcom,vctl-timeout-us = <50>;
@@ -114,9 +114,8 @@
qcom,lpm-resources@0 {
reg = <0x0>;
qcom,name = "vdd-dig";
- qcom,resource-type = <0>;
- qcom,type = <0x62706d73>; /* "smpb" */
- qcom,id = <0x02>;
+ qcom,type = <0x61706d73>; /* "smpa" */
+ qcom,id = <0x01>;
qcom,key = <0x6e726f63>; /* "corn" */
qcom,init-value = <5>; /* Super Turbo */
};
@@ -124,9 +123,8 @@
qcom,lpm-resources@1 {
reg = <0x1>;
qcom,name = "vdd-mem";
- qcom,resource-type = <0>;
- qcom,type = <0x62706d73>; /* "smpb" */
- qcom,id = <0x01>;
+ qcom,type = <0x616F646C>; /* "ldoa" */
+ qcom,id = <0x03>;
qcom,key = <0x7675>; /* "uv" */
qcom,init-value = <1050000>; /* Super Turbo */
};
@@ -134,18 +132,17 @@
qcom,lpm-resources@2 {
reg = <0x2>;
qcom,name = "pxo";
- qcom,resource-type = <0>;
qcom,type = <0x306b6c63>; /* "clk0" */
qcom,id = <0x00>;
qcom,key = <0x62616e45>; /* "Enab" */
- qcom,init-value = <1>; /* On */
+ qcom,init-value = "xo_on";
};
qcom,lpm-resources@3 {
reg = <0x3>;
qcom,name = "l2";
- qcom,resource-type = <1>;
- qcom,init-value = <2>; /* Retention */
+ qcom,local-resource-type;
+ qcom,init-value = "l2_cache_retention";
};
};
@@ -156,9 +153,9 @@
qcom,lpm-level@0 {
reg = <0x0>;
- qcom,mode = <0>; /* MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT */
- qcom,xo = <1>; /* ON */
- qcom,l2 = <3>; /* ACTIVE */
+ qcom,mode = "wfi";
+ qcom,xo = "xo_on";
+ qcom,l2 = "l2_cache_active";
qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
qcom,vdd-dig-upper-bound = <5>; /* MAX */
@@ -171,9 +168,9 @@
qcom,lpm-level@1 {
reg = <0x1>;
- qcom,mode = <4>; /* MSM_PM_SLEEP_MODE_RETENTION*/
- qcom,xo = <1>; /* ON */
- qcom,l2 = <3>; /* ACTIVE */
+ qcom,mode = "retention";
+ qcom,xo = "xo_on";
+ qcom,l2 = "l2_cache_active";
qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
qcom,vdd-dig-upper-bound = <5>; /* MAX */
@@ -187,9 +184,9 @@
qcom,lpm-level@2 {
reg = <0x2>;
- qcom,mode = <2>; /* MSM_PM_SLEEP_MODE_STANDALONE_POWER_COLLAPSE */
- qcom,xo = <1>; /* ON */
- qcom,l2 = <3>; /* ACTIVE */
+ qcom,mode = "standalone_pc";
+ qcom,xo = "xo_on";
+ qcom,l2 = "l2_cache_active";
qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
qcom,vdd-dig-upper-bound = <5>; /* MAX */
@@ -202,9 +199,9 @@
qcom,lpm-level@3 {
reg = <0x3>;
- qcom,mode = <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
- qcom,xo = <1>; /* ON */
- qcom,l2 = <1>; /* GDHS */
+ qcom,mode = "pc";
+ qcom,xo = "xo_on";
+ qcom,l2 = "l2_cache_gdhs";
qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
qcom,vdd-dig-upper-bound = <5>; /* MAX */
@@ -217,9 +214,9 @@
qcom,lpm-level@4 {
reg = <0x4>;
- qcom,mode = <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
- qcom,xo = <1>; /* ON */
- qcom,l2 = <0>; /* OFF */
+ qcom,mode = "pc";
+ qcom,xo = "xo_on";
+ qcom,l2 = "l2_cache_pc";
qcom,vdd-mem-upper-bound = <1050000>; /* ACTIVE */
qcom,vdd-mem-lower-bound = <750000>; /* RETENTION HIGH */
qcom,vdd-dig-upper-bound = <3>; /* ACTIVE */
@@ -232,9 +229,9 @@
qcom,lpm-level@5 {
reg = <0x5>;
- qcom,mode = <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
- qcom,xo = <0>; /* OFF */
- qcom,l2 = <1>; /* GDHS */
+ qcom,mode = "pc";
+ qcom,xo = "xo_off";
+ qcom,l2 = "l2_cache_gdhs";
qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
qcom,vdd-dig-upper-bound = <5>; /* MAX */
@@ -247,9 +244,9 @@
qcom,lpm-level@6 {
reg = <0x6>;
- qcom,mode = <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
- qcom,xo = <0>; /* OFF */
- qcom,l2 = <0>; /* OFF */
+ qcom,mode = "pc";
+ qcom,xo = "xo_off";
+ qcom,l2 = "l2_cache_pc";
qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
qcom,vdd-dig-upper-bound = <5>; /* MAX */
@@ -262,9 +259,9 @@
qcom,lpm-level@7 {
reg = <0x7>;
- qcom,mode= <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
- qcom,xo = <0>; /* OFF */
- qcom,l2 = <0>; /* OFF */
+ qcom,mode = "pc";
+ qcom,xo = "xo_off";
+ qcom,l2 = "l2_cache_pc";
qcom,vdd-mem-upper-bound = <1050000>; /* ACTIVE */
qcom,vdd-mem-lower-bound = <750000>; /* RETENTION HIGH */
qcom,vdd-dig-upper-bound = <3>; /* ACTIVE */
@@ -277,9 +274,9 @@
qcom,lpm-level@8 {
reg = <0x8>;
- qcom,mode= <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
- qcom,xo = <0>; /* OFF */
- qcom,l2 = <0>; /* OFF */
+ qcom,mode = "pc";
+ qcom,xo = "xo_off";
+ qcom,l2 = "l2_cache_pc";
qcom,vdd-mem-upper-bound = <750000>; /* RETENTION HIGH */
qcom,vdd-mem-lower-bound = <750000>; /* RETENTION LOW */
qcom,vdd-dig-upper-bound = <2>; /* RETENTION HIGH */
@@ -293,7 +290,7 @@
qcom,pm-boot {
compatible = "qcom,pm-boot";
- qcom,mode = <0>; /* MSM_PM_BOOT_CONFIG_TZ */
+ qcom,mode = "tz";
};
qcom,mpm@fc4281d0 {
@@ -392,7 +389,7 @@
qcom,pm-8x60@fe805664 {
compatible = "qcom,pm-8x60";
reg = <0xfe805664 0x40>;
- qcom,pc-mode = <0>; /*MSM_PC_TZ_L2_INT */
+ qcom,pc-mode = "tz_l2_int";
qcom,use-sync-timer;
};
diff --git a/arch/arm/boot/dts/msm8226-qrd.dts b/arch/arm/boot/dts/msm8226-qrd.dts
index f283fbb..4fa37d6 100644
--- a/arch/arm/boot/dts/msm8226-qrd.dts
+++ b/arch/arm/boot/dts/msm8226-qrd.dts
@@ -74,6 +74,24 @@
debounce-interval = <15>;
};
};
+
+ spi@f9923000 {
+ ethernet-switch@3 {
+ compatible = "micrel,ks8851";
+ reg = <3>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <0 115 0>;
+ spi-max-frequency = <4800000>;
+ rst-gpio = <&msmgpio 114 0>;
+ vdd-io-supply = <&pm8226_lvs1>;
+ vdd-phy-supply = <&pm8226_lvs1>;
+ };
+ };
+
+ sound {
+ qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
+ qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>;
+ };
};
&sdcc1 {
@@ -165,9 +183,24 @@
&pm8226_gpios {
gpio@c000 { /* GPIO 1 */
+ /* XO_PMIC_CDC_MCLK enable for tapan codec */
+ qcom,mode = <1>; /* Digital output */
+ qcom,output-type = <0>; /* CMOS logic */
+ qcom,pull = <5>; /* QPNP_PIN_PULL_NO*/
+ qcom,vin-sel = <2>; /* QPNP_PIN_VIN2 */
+ qcom,out-strength = <3>;/* QPNP_PIN_OUT_STRENGTH_HIGH */
+ qcom,src-sel = <2>; /* QPNP_PIN_SEL_FUNC_1 */
+ qcom,master-en = <1>; /* Enable GPIO */
};
gpio@c100 { /* GPIO 2 */
+ qcom,mode = <1>;
+ qcom,output-type = <0>;
+ qcom,pull = <5>;
+ qcom,vin-sel = <2>;
+ qcom,out-strength = <3>;
+ qcom,src-sel = <2>;
+ qcom,master-en = <1>;
};
gpio@c200 { /* GPIO 3 */
diff --git a/arch/arm/boot/dts/msm8226-smp2p.dtsi b/arch/arm/boot/dts/msm8226-smp2p.dtsi
index 60f63a8..1b08246 100644
--- a/arch/arm/boot/dts/msm8226-smp2p.dtsi
+++ b/arch/arm/boot/dts/msm8226-smp2p.dtsi
@@ -12,8 +12,7 @@
/ {
qcom,smp2p-modem {
compatible = "qcom,smp2p";
- reg = <0xfa006000 0x1000>, <0x8 0x0>;
- reg-names = "irq-reg-base", "irq-reg-offset";
+ reg = <0xf9011008 0x4>;
qcom,remote-pid = <1>;
qcom,irq-bitmask = <0x4000>;
interrupts = <0 27 1>;
@@ -21,8 +20,7 @@
qcom,smp2p-adsp {
compatible = "qcom,smp2p";
- reg = <0xfa006000 0x1000>, <0x8 0x0>;
- reg-names = "irq-reg-base", "irq-reg-offset";
+ reg = <0xf9011008 0x4>;
qcom,remote-pid = <2>;
qcom,irq-bitmask = <0x400>;
interrupts = <0 158 1>;
@@ -30,8 +28,7 @@
qcom,smp2p-wcnss {
compatible = "qcom,smp2p";
- reg = <0xfa006000 0x1000>, <0x8 0x0>;
- reg-names = "irq-reg-base", "irq-reg-offset";
+ reg = <0xf9011008 0x4>;
qcom,remote-pid = <4>;
qcom,irq-bitmask = <0x40000>;
interrupts = <0 143 1>;
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index f0cddfb..f975a08 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -20,7 +20,7 @@
/include/ "msm8226-bus.dtsi"
/include/ "msm8226-mdss.dtsi"
/include/ "msm8226-coresight.dtsi"
-
+/include/ "msm8226-iommu-domains.dtsi"
/ {
model = "Qualcomm MSM 8226";
compatible = "qcom,msm8226";
@@ -50,12 +50,57 @@
spi0 = &spi_0;
};
+ memory {
+ secure_mem: secure_region {
+ linux,contiguous-region;
+ reg = <0 0x3800000>;
+ label = "secure_mem";
+ };
+ };
+
timer {
compatible = "arm,armv7-timer";
interrupts = <1 2 0 1 3 0>;
clock-frequency = <19200000>;
};
+ qcom,vidc@fdc00000 {
+ compatible = "qcom,msm-vidc";
+ reg = <0xfdc00000 0xff000>;
+ interrupts = <0 44 0>;
+ qcom,load-freq-tbl = <352800 160000000>,
+ <244800 133330000>,
+ <108000 66700000>;
+ qcom,hfi = "venus";
+ qcom,bus-ports = <1>;
+ qcom,reg-presets = <0xE0024 0x0>,
+ <0x80124 0x3>,
+ <0xE0020 0x5555556>,
+ <0x800B0 0x10101001>,
+ <0x800B4 0x00101010>,
+ <0x800C0 0x1010100f>,
+ <0x800C4 0x00101010>,
+ <0x800D0 0x00000010>,
+ <0x800D4 0x00000010>,
+ <0x800D8 0x00000707>;
+ qcom,enc-ddr-ab-ib = <0 0>,
+ <129000 142000>,
+ <384000 422000>,
+ <866000 953000>;
+ qcom,dec-ddr-ab-ib = <0 0>,
+ <103000 134000>,
+ <268000 348000>,
+ <505000 657000>;
+ qcom,iommu-groups = <&venus_domain_ns &venus_domain_cp>;
+ qcom,iommu-group-buffer-types = <0xfff 0x1ff>;
+ qcom,buffer-type-tz-usage-table = <0x1 0x1>,
+ <0x1fe 0x2>;
+ };
+
+ qcom,wfd {
+ compatible = "qcom,msm-wfd";
+ };
+
serial@f991f000 {
compatible = "qcom,msm-lsuart-v14";
reg = <0xf991f000 0x1000>;
@@ -186,6 +231,8 @@
qcom,audio-routing =
"RX_BIAS", "MCLK",
"LDO_H", "MCLK",
+ "SPK_OUT", "MCLK",
+ "SPK_OUT", "EXT_VDD_SPKR",
"AMIC1", "MIC BIAS1 Internal1",
"MIC BIAS1 Internal1", "Handset Mic",
"AMIC2", "MIC BIAS2 External",
@@ -201,22 +248,26 @@
"DMIC3", "MIC BIAS3 External",
"MIC BIAS3 External", "Digital Mic3",
"DMIC4", "MIC BIAS3 External",
- "MIC BIAS3 External", "Digital Mic4",
- "DMIC5", "MIC BIAS4 External",
- "MIC BIAS4 External", "Digital Mic5",
- "DMIC6", "MIC BIAS4 External",
- "MIC BIAS4 External", "Digital Mic6";
+ "MIC BIAS3 External", "Digital Mic4";
+
qcom,tapan-mclk-clk-freq = <9600000>;
};
qcom,msm-pcm {
compatible = "qcom,msm-pcm-dsp";
+ qcom,msm-pcm-dsp-id = <0>;
};
qcom,msm-pcm-routing {
compatible = "qcom,msm-pcm-routing";
};
+ qcom,msm-pcm-low-latency {
+ compatible = "qcom,msm-pcm-dsp";
+ qcom,msm-pcm-dsp-id = <1>;
+ qcom,msm-pcm-low-latency;
+ };
+
qcom,msm-pcm-lpa {
compatible = "qcom,msm-pcm-lpa";
};
@@ -331,6 +382,21 @@
compatible = "qcom,msm-dai-q6-dev";
qcom,msm-dai-q6-dev-id = <240>;
};
+
+ qcom,msm-dai-q6-incall-record-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <32771>;
+ };
+
+ qcom,msm-dai-q6-incall-record-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <32772>;
+ };
+
+ qcom,msm-dai-q6-incall-music-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <32773>;
+ };
};
qcom,msm-pcm-hostless {
@@ -418,7 +484,6 @@
compatible = "qcom,rpm-smd";
rpm-channel-name = "rpm_requests";
rpm-channel-type = <15>; /* SMD_APPS_RPM */
- rpm-standalone;
};
sdcc1: qcom,sdcc@f9824000 {
@@ -461,7 +526,6 @@
/* 190,ee0_krait_hlos_spmi_periph_irq */
/* 187,channel_0_krait_hlos_trans_done_irq */
interrupts = <0 190 0>, <0 187 0>;
- qcom,not-wakeup;
qcom,pmic-arb-ee = <0>;
qcom,pmic-arb-channel = <0>;
};
@@ -547,8 +611,9 @@
qcom,lpass@fe200000 {
compatible = "qcom,pil-q6v5-lpass";
reg = <0xfe200000 0x00100>,
- <0xfd485100 0x00010>;
- reg-names = "qdsp6_base", "halt_base";
+ <0xfd485100 0x00010>,
+ <0xfc4016c0 0x00004>;
+ reg-names = "qdsp6_base", "halt_base", "restart_reg";
vdd_cx-supply = <&pm8226_s1_corner>;
interrupts = <0 162 1>;
@@ -617,7 +682,7 @@
gpios = <&msmgpio 3 0>, /* CLK */
<&msmgpio 1 0>, /* MISO */
<&msmgpio 0 0>; /* MOSI */
- cs-gpios = <&msmgpio 2 0>;
+ cs-gpios = <&msmgpio 22 0>;
qcom,infinite-mode = <0>;
qcom,use-bam;
@@ -637,11 +702,51 @@
qcom,memory-reservation-type = "EBI1";
qcom,memory-reservation-size = <0x100000>; /* 1M EBI1 buffer */
};
+
qcom,msm-rng@f9bff000 {
compatible = "qcom,msm-rng";
reg = <0xf9bff000 0x200>;
qcom,msm-rng-iface-clk;
};
+
+ qcom,tz-log@fc5b82c {
+ compatible = "qcom,tz-log";
+ reg = <0x0fc5b82c 0x1000>;
+ };
+
+ jtag_mm0: jtagmm@fc33c000 {
+ compatible = "qcom,jtag-mm";
+ reg = <0xfc33c000 0x1000>,
+ <0xfc330000 0x1000>;
+ reg-names = "etm-base","debug-base";
+ };
+
+ jtag_mm1: jtagmm@fc33d000 {
+ compatible = "qcom,jtag-mm";
+ reg = <0xfc33d000 0x1000>,
+ <0xfc332000 0x1000>;
+ reg-names = "etm-base","debug-base";
+ };
+
+ jtag_mm2: jtagmm@fc33e000 {
+ compatible = "qcom,jtag-mm";
+ reg = <0xfc33e000 0x1000>,
+ <0xfc334000 0x1000>;
+ reg-names = "etm-base","debug-base";
+ };
+
+ jtag_mm3: jtagmm@fc33f000 {
+ compatible = "qcom,jtag-mm";
+ reg = <0xfc33f000 0x1000>,
+ <0xfc336000 0x1000>;
+ reg-names = "etm-base","debug-base";
+ };
+
+ qcom,ipc-spinlock@fd484000 {
+ compatible = "qcom,ipc-spinlock-sfpb";
+ reg = <0xfd484000 0x400>;
+ qcom,num-locks = <8>;
+ };
};
&gdsc_venus {
@@ -766,9 +871,6 @@
&pm8226_chg {
status = "ok";
- qcom,chg-charging-disabled;
- qcom,chg-use-default-batt-values;
-
qcom,chg-chgr@1000 {
status = "ok";
};
@@ -777,6 +879,10 @@
status = "ok";
};
+ qcom,chg-bat-if@1200 {
+ status = "ok";
+ };
+
qcom,chg-usb-chgpth@1300 {
status = "ok";
};
diff --git a/arch/arm/boot/dts/msm8610-coresight.dtsi b/arch/arm/boot/dts/msm8610-coresight.dtsi
new file mode 100644
index 0000000..298cb68
--- /dev/null
+++ b/arch/arm/boot/dts/msm8610-coresight.dtsi
@@ -0,0 +1,142 @@
+/* Copyright (c) 2013, 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.
+ */
+
+/ {
+ tmc_etr: tmc@fc326000 {
+ compatible = "arm,coresight-tmc";
+ reg = <0xfc326000 0x1000>,
+ <0xfc37c000 0x3000>;
+ reg-names = "tmc-etr-base", "tmc-etr-bam-base";
+
+ qcom,memory-reservation-type = "EBI1";
+ qcom,memory-reservation-size = <0x100000>; /* 1M EBI1 buffer */
+
+ coresight-id = <0>;
+ coresight-name = "coresight-tmc-etr";
+ coresight-nr-inports = <1>;
+ };
+
+ tpiu: tpiu@fc320000 {
+ compatible = "arm,coresight-tpiu";
+ reg = <0xfc320000 0x1000>;
+ reg-names = "tpiu-base";
+
+ coresight-id = <1>;
+ coresight-name = "coresight-tpiu";
+ coresight-nr-inports = <1>;
+ };
+
+ replicator: replicator@fc324000 {
+ compatible = "qcom,coresight-replicator";
+ reg = <0xfc324000 0x1000>;
+ reg-names = "replicator-base";
+
+ coresight-id = <2>;
+ coresight-name = "coresight-replicator";
+ coresight-nr-inports = <1>;
+ coresight-outports = <0 1>;
+ coresight-child-list = <&tmc_etr &tpiu>;
+ coresight-child-ports = <0 0>;
+ };
+
+ tmc_etf: tmc@fc325000 {
+ compatible = "arm,coresight-tmc";
+ reg = <0xfc325000 0x1000>;
+ reg-names = "tmc-etf-base";
+
+ coresight-id = <3>;
+ coresight-name = "coresight-tmc-etf";
+ coresight-nr-inports = <1>;
+ coresight-outports = <0>;
+ coresight-child-list = <&replicator>;
+ coresight-child-ports = <0>;
+ coresight-default-sink;
+ };
+
+ funnel_merg: funnel@fc323000 {
+ compatible = "arm,coresight-funnel";
+ reg = <0xfc323000 0x1000>;
+ reg-names = "funnel-merg-base";
+
+ coresight-id = <4>;
+ coresight-name = "coresight-funnel-merg";
+ coresight-nr-inports = <2>;
+ coresight-outports = <0>;
+ coresight-child-list = <&tmc_etf>;
+ coresight-child-ports = <0>;
+ };
+
+ funnel_in0: funnel@fc321000 {
+ compatible = "arm,coresight-funnel";
+ reg = <0xfc321000 0x1000>;
+ reg-names = "funnel-in0-base";
+
+ coresight-id = <5>;
+ coresight-name = "coresight-funnel-in0";
+ coresight-nr-inports = <8>;
+ coresight-outports = <0>;
+ coresight-child-list = <&funnel_merg>;
+ coresight-child-ports = <0>;
+ };
+
+ funnel_in1: funnel@fc322000 {
+ compatible = "arm,coresight-funnel";
+ reg = <0xfc322000 0x1000>;
+ reg-names = "funnel-in1-base";
+
+ coresight-id = <6>;
+ coresight-name = "coresight-funnel-in1";
+ coresight-nr-inports = <8>;
+ coresight-outports = <0>;
+ coresight-child-list = <&funnel_merg>;
+ coresight-child-ports = <1>;
+ };
+
+ funnel_a7ss: funnel@fc355000 {
+ compatible = "arm,coresight-funnel";
+ reg = <0xfc355000 0x1000>;
+ reg-names = "funnel-a7ss-base";
+
+ coresight-id = <7>;
+ coresight-name = "coresight-funnel-a7ss";
+ coresight-nr-inports = <4>;
+ coresight-outports = <0>;
+ coresight-child-list = <&funnel_in1>;
+ coresight-child-ports = <5>;
+ };
+
+ stm: stm@fc302000 {
+ compatible = "arm,coresight-stm";
+ reg = <0xfc302000 0x1000>,
+ <0xfa280000 0x180000>;
+ reg-names = "stm-base", "stm-data-base";
+
+ coresight-id = <8>;
+ coresight-name = "coresight-stm";
+ coresight-nr-inports = <0>;
+ coresight-outports = <0>;
+ coresight-child-list = <&funnel_in1>;
+ coresight-child-ports = <7>;
+ };
+
+ csr: csr@fc301000 {
+ compatible = "qcom,coresight-csr";
+ reg = <0xfc301000 0x1000>;
+ reg-names = "csr-base";
+
+ coresight-id = <9>;
+ coresight-name = "coresight-csr";
+ coresight-nr-inports = <0>;
+
+ qcom,blk-size = <3>;
+ };
+};
diff --git a/arch/arm/boot/dts/msm8610-pm.dtsi b/arch/arm/boot/dts/msm8610-pm.dtsi
index feb3087..ff16b8d 100644
--- a/arch/arm/boot/dts/msm8610-pm.dtsi
+++ b/arch/arm/boot/dts/msm8610-pm.dtsi
@@ -114,7 +114,6 @@
qcom,lpm-resources@0 {
reg = <0x0>;
qcom,name = "vdd-dig";
- qcom,resource-type = <0>;
qcom,type = <0x62706d73>; /* "smpb" */
qcom,id = <0x02>;
qcom,key = <0x6e726f63>; /* "corn" */
@@ -124,7 +123,6 @@
qcom,lpm-resources@1 {
reg = <0x1>;
qcom,name = "vdd-mem";
- qcom,resource-type = <0>;
qcom,type = <0x62706d73>; /* "smpb" */
qcom,id = <0x01>;
qcom,key = <0x7675>; /* "uv" */
@@ -134,18 +132,17 @@
qcom,lpm-resources@2 {
reg = <0x2>;
qcom,name = "pxo";
- qcom,resource-type = <0>;
qcom,type = <0x306b6c63>; /* "clk0" */
qcom,id = <0x00>;
qcom,key = <0x62616e45>; /* "Enab" */
- qcom,init-value = <1>; /* On */
+ qcom,init-value = "xo_on";
};
qcom,lpm-resources@3 {
reg = <0x3>;
qcom,name = "l2";
- qcom,resource-type = <1>;
- qcom,init-value = <2>; /* Retention */
+ qcom,local-resource-type;
+ qcom,init-value = "l2_cache_retention";
};
};
@@ -156,9 +153,9 @@
qcom,lpm-level@0 {
reg = <0x0>;
- qcom,mode = <0>; /* MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT */
- qcom,xo = <1>; /* ON */
- qcom,l2 = <3>; /* ACTIVE */
+ qcom,mode = "wfi";
+ qcom,xo = "xo_on";
+ qcom,l2 = "l2_cache_active";
qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
qcom,vdd-dig-upper-bound = <5>; /* MAX */
@@ -171,9 +168,9 @@
qcom,lpm-level@1 {
reg = <0x1>;
- qcom,mode = <4>; /* MSM_PM_SLEEP_MODE_RETENTION*/
- qcom,xo = <1>; /* ON */
- qcom,l2 = <3>; /* ACTIVE */
+ qcom,mode = "retention";
+ qcom,xo = "xo_on";
+ qcom,l2 = "l2_cache_active";
qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
qcom,vdd-dig-upper-bound = <5>; /* MAX */
@@ -187,9 +184,9 @@
qcom,lpm-level@2 {
reg = <0x2>;
- qcom,mode = <2>; /* MSM_PM_SLEEP_MODE_STANDALONE_POWER_COLLAPSE */
- qcom,xo = <1>; /* ON */
- qcom,l2 = <3>; /* ACTIVE */
+ qcom,mode = "standalone_pc";
+ qcom,xo = "xo_on";
+ qcom,l2 = "l2_cache_active";
qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
qcom,vdd-dig-upper-bound = <5>; /* MAX */
@@ -202,9 +199,9 @@
qcom,lpm-level@3 {
reg = <0x3>;
- qcom,mode = <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
- qcom,xo = <1>; /* ON */
- qcom,l2 = <1>; /* GDHS */
+ qcom,mode = "pc";
+ qcom,xo = "xo_on";
+ qcom,l2 = "l2_cache_gdhs";
qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
qcom,vdd-dig-upper-bound = <5>; /* MAX */
@@ -217,9 +214,9 @@
qcom,lpm-level@4 {
reg = <0x4>;
- qcom,mode = <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
- qcom,xo = <1>; /* ON */
- qcom,l2 = <0>; /* OFF */
+ qcom,mode = "pc";
+ qcom,xo = "xo_on";
+ qcom,l2 = "l2_cache_pc";
qcom,vdd-mem-upper-bound = <1050000>; /* ACTIVE */
qcom,vdd-mem-lower-bound = <750000>; /* RETENTION HIGH */
qcom,vdd-dig-upper-bound = <3>; /* ACTIVE */
@@ -232,9 +229,9 @@
qcom,lpm-level@5 {
reg = <0x5>;
- qcom,mode = <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
- qcom,xo = <0>; /* OFF */
- qcom,l2 = <1>; /* GDHS */
+ qcom,mode = "pc";
+ qcom,xo = "xo_off";
+ qcom,l2 = "l2_cache_gdhs";
qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
qcom,vdd-dig-upper-bound = <5>; /* MAX */
@@ -247,9 +244,9 @@
qcom,lpm-level@6 {
reg = <0x6>;
- qcom,mode = <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
- qcom,xo = <0>; /* OFF */
- qcom,l2 = <0>; /* OFF */
+ qcom,mode = "pc";
+ qcom,xo = "xo_off";
+ qcom,l2 = "l2_cache_pc";
qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
qcom,vdd-dig-upper-bound = <5>; /* MAX */
@@ -262,9 +259,9 @@
qcom,lpm-level@7 {
reg = <0x7>;
- qcom,mode= <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
- qcom,xo = <0>; /* OFF */
- qcom,l2 = <0>; /* OFF */
+ qcom,mode = "pc";
+ qcom,xo = "xo_off";
+ qcom,l2 = "l2_cache_pc";
qcom,vdd-mem-upper-bound = <1050000>; /* ACTIVE */
qcom,vdd-mem-lower-bound = <750000>; /* RETENTION HIGH */
qcom,vdd-dig-upper-bound = <3>; /* ACTIVE */
@@ -277,9 +274,9 @@
qcom,lpm-level@8 {
reg = <0x8>;
- qcom,mode= <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
- qcom,xo = <0>; /* OFF */
- qcom,l2 = <0>; /* OFF */
+ qcom,mode = "pc";
+ qcom,xo = "xo_off";
+ qcom,l2 = "l2_cache_pc";
qcom,vdd-mem-upper-bound = <750000>; /* RETENTION HIGH */
qcom,vdd-mem-lower-bound = <750000>; /* RETENTION LOW */
qcom,vdd-dig-upper-bound = <2>; /* RETENTION HIGH */
@@ -293,7 +290,7 @@
qcom,pm-boot {
compatible = "qcom,pm-boot";
- qcom,mode = <0>; /* MSM_PM_BOOT_CONFIG_TZ */
+ qcom,mode = "tz";
};
qcom,mpm@fc4281d0 {
@@ -309,10 +306,12 @@
qcom,gic-map = <47 172>, /* usb2_hsic_async_wakeup_irq */
<53 104>, /* mdss_irq */
<62 222>, /* ee0_krait_hlos_spmi_periph_irq */
+ <0xff 56>, /* q6_wdog_expired_irq */
<0xff 57>, /* mss_to_apps_irq(0) */
<0xff 58>, /* mss_to_apps_irq(1) */
<0xff 59>, /* mss_to_apps_irq(2) */
<0xff 60>, /* mss_to_apps_irq(3) */
+ <0xff 61>, /* mss_a2_bam_irq */
<0xff 173>, /* o_wcss_apss_smd_hi */
<0xff 174>, /* o_wcss_apss_smd_med */
<0xff 175>, /* o_wcss_apss_smd_low */
@@ -320,17 +319,17 @@
<0xff 177>, /* o_wcss_apss_wlan_data_xfer_done */
<0xff 178>, /* o_wcss_apss_wlan_rx_data_avail */
<0xff 179>, /* o_wcss_apss_asic_intr
-
+ <0xff 181>, /* o_wcss_apss_wdog_bite_and_reset_rdy */
+ <0xff 161>, /* lpass_irq_out_spare[4] /
+ <0xff 162>, /* lpass_irq_out_spare[5]*/
+ <0xff 234>, /* lpass_irq_out_spare[6]*/
+ <0xff 235>, /* lpass_irq_out_spare[7]*/
<0xff 188>, /* lpass_irq_out_apcs(0) */
<0xff 189>, /* lpass_irq_out_apcs(1) */
<0xff 190>, /* lpass_irq_out_apcs(2) */
<0xff 191>, /* lpass_irq_out_apcs(3) */
<0xff 192>, /* lpass_irq_out_apcs(4) */
- <0xff 193>, /* lpass_irq_out_apcs(5) */
<0xff 194>, /* lpass_irq_out_apcs(6) */
- <0xff 195>, /* lpass_irq_out_apcs(7) */
- <0xff 196>, /* lpass_irq_out_apcs(8) */
- <0xff 197>, /* lpass_irq_out_apcs(9) */
<0xff 200>, /* rpm_ipc(4) */
<0xff 201>, /* rpm_ipc(5) */
<0xff 202>, /* rpm_ipc(6) */
@@ -339,53 +338,60 @@
<0xff 205>, /* rpm_ipc(25) */
<0xff 206>, /* rpm_ipc(26) */
<0xff 207>, /* rpm_ipc(27) */
+ <0xff 258>, /* rpm_ipc(28) */
+ <0xff 259>, /* rpm_ipc(29) */
+ <0xff 275>, /* rpm_ipc(30) */
+ <0xff 276>, /* rpm_ipc(31) */
+ <0xff 269>, /* rpm_wdog_expired_irq */
<0xff 240>; /* summary_irq_kpss */
qcom,gpio-parent = <&msmgpio>;
- qcom,gpio-map = <3 102>,
- <4 1 >,
+ qcom,gpio-map = <3 1>,
+ <4 4 >,
<5 5 >,
<6 9 >,
- <7 18>,
- <8 20>,
- <9 24>,
+ <7 13>,
+ <8 17>,
+ <9 21>,
<10 27>,
- <11 28>,
- <12 34>,
- <13 35>,
- <14 37>,
- <15 42>,
- <16 44>,
- <17 46>,
- <18 50>,
- <19 54>,
- <20 59>,
- <21 61>,
- <22 62>,
- <23 64>,
- <24 65>,
- <25 66>,
- <26 67>,
- <27 68>,
- <28 71>,
- <29 72>,
- <30 73>,
- <31 74>,
- <32 75>,
- <33 77>,
- <34 79>,
- <35 80>,
- <36 82>,
- <37 86>,
- <38 92>,
- <39 93>,
- <40 95>;
+ <11 29>,
+ <12 31>,
+ <13 33>,
+ <14 35>,
+ <15 37>,
+ <16 38>,
+ <17 39>,
+ <18 41>,
+ <19 46>,
+ <20 48>,
+ <21 49>,
+ <22 50>,
+ <23 51>,
+ <24 52>,
+ <25 54>,
+ <26 62>,
+ <27 63>,
+ <28 64>,
+ <29 65>,
+ <30 66>,
+ <31 67>,
+ <32 68>,
+ <33 69>,
+ <34 71>,
+ <35 72>,
+ <36 106>,
+ <37 107>,
+ <38 108>,
+ <39 109>,
+ <40 110>,
+ <54 111>,
+ <55 113>;
};
qcom,pm-8x60@fe805664 {
compatible = "qcom,pm-8x60";
reg = <0xfe805664 0x40>;
- qcom,pc-mode = <0>; /*MSM_PC_TZ_L2_INT */
+ qcom,pc-mode = "tz_l2_int";
qcom,use-sync-timer;
};
diff --git a/arch/arm/boot/dts/msm8610-regulator.dtsi b/arch/arm/boot/dts/msm8610-regulator.dtsi
index 362d126..f11f04b 100644
--- a/arch/arm/boot/dts/msm8610-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8610-regulator.dtsi
@@ -12,216 +12,215 @@
/* Stub Regulators */
- / {
- pm8110_s1: regulator-s1 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8110_s1";
- qcom,hpm-min-load = <100000>;
- regulator-min-microvolt = <1150000>;
- regulator-max-microvolt = <1150000>;
- };
-
+/ {
pm8110_s1_corner: regulator-s1-corner {
compatible = "qcom,stub-regulator";
regulator-name = "8110_s1_corner";
+ qcom,hpm-min-load = <100000>;
regulator-min-microvolt = <1>;
regulator-max-microvolt = <7>;
qcom,consumer-supplies = "vdd_dig", "";
};
+};
- pm8110_s2: regulator-s2 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8110_s2";
- qcom,hpm-min-load = <100000>;
- regulator-min-microvolt = <1050000>;
- regulator-max-microvolt = <1050000>;
- };
+/* QPNP controlled regulators: */
- pm8110_s3: regulator-s3 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8110_s3";
- qcom,hpm-min-load = <100000>;
- regulator-min-microvolt = <1350000>;
- regulator-max-microvolt = <1350000>;
- };
+&spmi_bus {
- pm8110_s4: regulator-s4 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8110_s4";
- qcom,hpm-min-load = <100000>;
- regulator-min-microvolt = <2150000>;
- regulator-max-microvolt = <2150000>;
- };
+ qcom,pm8110@1 {
- pm8110_l1: regulator-l1 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8110_l1";
- parent-supply = <&pm8110_s3>;
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1225000>;
- regulator-max-microvolt = <1225000>;
- };
+ pm8110_s1: regulator@1400 {
+ status = "okay";
+ regulator-min-microvolt = <1150000>;
+ regulator-max-microvolt = <1150000>;
+ qcom,enable-time = <500>;
+ qcom,system-load = <100000>;
+ regulator-always-on;
+ };
- pm8110_l2: regulator-l2 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8110_l2";
- parent-supply = <&pm8110_s3>;
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1200000>;
- regulator-max-microvolt = <1200000>;
- };
+ pm8110_s2: regulator@1700 {
+ status = "okay";
+ regulator-min-microvolt = <1050000>;
+ regulator-max-microvolt = <1150000>;
+ qcom,enable-time = <500>;
+ qcom,system-load = <100000>;
+ regulator-always-on;
+ };
- pm8110_l3: regulator-l3 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8110_l3";
- parent-supply = <&pm8110_s3>;
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1150000>;
- regulator-max-microvolt = <1150000>;
- };
+ pm8110_s3: regulator@1a00 {
+ status = "okay";
+ regulator-min-microvolt = <1350000>;
+ regulator-max-microvolt = <1350000>;
+ qcom,enable-time = <500>;
+ qcom,system-load = <100000>;
+ regulator-always-on;
+ };
- pm8110_l4: regulator-l4 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8110_l4";
- parent-supply = <&pm8110_s3>;
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1200000>;
- regulator-max-microvolt = <1200000>;
- };
+ pm8110_s4: regulator@1d00 {
+ status = "okay";
+ regulator-min-microvolt = <2150000>;
+ regulator-max-microvolt = <2150000>;
+ qcom,enable-time = <500>;
+ qcom,system-load = <100000>;
+ regulator-always-on;
+ };
- pm8110_l5: regulator-l5 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8110_l5";
- parent-supply = <&pm8110_s3>;
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1300000>;
- regulator-max-microvolt = <1300000>;
- };
+ pm8110_l1: regulator@4000 {
+ status = "okay";
+ parent-supply = <&pm8110_s3>;
+ regulator-min-microvolt = <1225000>;
+ regulator-max-microvolt = <1225000>;
+ qcom,enable-time = <200>;
+ };
- pm8110_l6: regulator-l6 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8110_l6";
- parent-supply = <&pm8110_s4>;
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- };
+ pm8110_l2: regulator@4100 {
+ status = "okay";
+ parent-supply = <&pm8110_s3>;
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ qcom,enable-time = <200>;
+ qcom,system-load = <10000>;
+ regulator-always-on;
+ };
- pm8110_l7: regulator-l7 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8110_l7";
- parent-supply = <&pm8110_s4>;
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <2050000>;
- regulator-max-microvolt = <2050000>;
- };
+ pm8110_l3: regulator@4200 {
+ status = "okay";
+ parent-supply = <&pm8110_s3>;
+ regulator-min-microvolt = <1150000>;
+ regulator-max-microvolt = <1150000>;
+ qcom,enable-time = <200>;
+ qcom,system-load = <10000>;
+ regulator-always-on;
+ };
- pm8110_l8: regulator-l8 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8110_l8";
- parent-supply = <&pm8110_s4>;
- qcom,hpm-min-load = <5000>;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- };
+ pm8110_l4: regulator@4300 {
+ status = "okay";
+ parent-supply = <&pm8110_s3>;
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ qcom,enable-time = <200>;
+ };
- pm8110_l9: regulator-l9 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8110_l9";
- parent-supply = <&pm8110_s4>;
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <2050000>;
- regulator-max-microvolt = <2050000>;
- };
+ pm8110_l5: regulator@4400 {
+ status = "okay";
+ parent-supply = <&pm8110_s3>;
+ regulator-min-microvolt = <1300000>;
+ regulator-max-microvolt = <1300000>;
+ qcom,enable-time = <200>;
+ };
- pm8110_l10: regulator-l10 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8110_l10";
- parent-supply = <&pm8110_s4>;
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- qcom,consumer-supplies = "vdd_sr2_pll", "";
- };
+ pm8110_l6: regulator@4500 {
+ status = "okay";
+ parent-supply = <&pm8110_s4>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,enable-time = <200>;
+ qcom,system-load = <10000>;
+ regulator-always-on;
+ };
- pm8110_l12: regulator-l12 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8110_l12";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <3300000>;
- };
+ pm8110_l7: regulator@4600 {
+ status = "okay";
+ parent-supply = <&pm8110_s4>;
+ regulator-min-microvolt = <2050000>;
+ regulator-max-microvolt = <2050000>;
+ qcom,enable-time = <200>;
+ };
- pm8110_l14: regulator-l14 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8110_l14";
- parent-supply = <&pm8110_s4>;
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- };
+ pm8110_l8: regulator@4700 {
+ status = "okay";
+ parent-supply = <&pm8110_s4>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,enable-time = <200>;
+ };
- pm8110_l15: regulator-l15 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8110_l15";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <3300000>;
- };
+ pm8110_l9: regulator@4800 {
+ status = "okay";
+ parent-supply = <&pm8110_s4>;
+ regulator-min-microvolt = <2050000>;
+ regulator-max-microvolt = <2050000>;
+ qcom,enable-time = <200>;
+ };
- pm8110_l16: regulator-l16 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8110_l16";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <3000000>;
- regulator-max-microvolt = <3000000>;
- };
+ pm8110_l10: regulator@4900 {
+ status = "okay";
+ parent-supply = <&pm8110_s4>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,enable-time = <200>;
+ qcom,consumer-supplies = "vdd_sr2_pll", "";
+ };
- pm8110_l17: regulator-l17 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8110_l17";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <2900000>;
- regulator-max-microvolt = <2900000>;
- };
+ pm8110_l12: regulator@4b00 {
+ status = "okay";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ qcom,enable-time = <200>;
+ };
- pm8110_l18: regulator-l18 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8110_l18";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <2950000>;
- };
+ pm8110_l14: regulator@4d00 {
+ status = "okay";
+ parent-supply = <&pm8110_s4>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,enable-time = <200>;
+ };
- pm8110_l19: regulator-l19 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8110_l19";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <2850000>;
- regulator-max-microvolt = <2850000>;
- };
+ pm8110_l15: regulator@4e00 {
+ status = "okay";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ qcom,enable-time = <200>;
+ };
- pm8110_l20: regulator-l20 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8110_l20";
- qcom,hpm-min-load = <5000>;
- regulator-min-microvolt = <3075000>;
- regulator-max-microvolt = <3075000>;
- };
+ pm8110_l16: regulator@4f00 {
+ status = "okay";
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ qcom,enable-time = <200>;
+ };
- pm8110_l21: regulator-l21 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8110_l21";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <2950000>;
- };
+ pm8110_l17: regulator@5000 {
+ status = "okay";
+ regulator-min-microvolt = <2900000>;
+ regulator-max-microvolt = <2900000>;
+ qcom,enable-time = <200>;
+ };
- pm8110_l22: regulator-l22 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8110_l22";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <3300000>;
+ pm8110_l18: regulator@5100 {
+ status = "okay";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+ qcom,enable-time = <200>;
+ };
+
+ pm8110_l19: regulator@5200 {
+ status = "okay";
+ regulator-min-microvolt = <2850000>;
+ regulator-max-microvolt = <2850000>;
+ qcom,enable-time = <200>;
+ };
+
+ pm8110_l20: regulator@5300 {
+ status = "okay";
+ regulator-min-microvolt = <3075000>;
+ regulator-max-microvolt = <3075000>;
+ qcom,enable-time = <200>;
+ };
+
+ pm8110_l21: regulator@5400 {
+ status = "okay";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+ qcom,enable-time = <200>;
+ };
+
+ pm8110_l22: regulator@5500 {
+ status = "okay";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ qcom,enable-time = <200>;
+ };
};
};
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index fe0ebf9..18f3df9 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -14,6 +14,7 @@
/include/ "msm-iommu-v0.dtsi"
/include/ "msm8610-ion.dtsi"
/include/ "msm-gdsc.dtsi"
+/include/ "msm8610-coresight.dtsi"
/include/ "msm8610-pm.dtsi"
/ {
@@ -235,7 +236,6 @@
compatible = "qcom,rpm-smd";
rpm-channel-name = "rpm_requests";
rpm-channel-type = <15>; /* SMD_APPS_RPM */
- rpm-standalone;
};
qcom,msm-mem-hole {
@@ -431,8 +431,9 @@
qcom,lpass@fe200000 {
compatible = "qcom,pil-q6v5-lpass";
reg = <0xfe200000 0x00100>,
- <0xfd485100 0x00010>;
- reg-names = "qdsp6_base", "halt_base";
+ <0xfd485100 0x00010>,
+ <0xfc4016c0 0x00004>;
+ reg-names = "qdsp6_base", "halt_base", "restart_reg";
interrupts = <0 162 1>;
vdd_cx-supply = <&pm8110_s1_corner>;
qcom,firmware-name = "adsp";
@@ -448,6 +449,7 @@
qcom,slope = <2901 2846>;
qcom,calib-mode = "fuse_map2";
qcom,calibration-less-mode;
+ qcom,tsens-local-init;
};
};
@@ -486,5 +488,97 @@
/include/ "msm8610-iommu-domains.dtsi"
-/include/ "msm8610-regulator.dtsi"
/include/ "msm-pm8110.dtsi"
+/include/ "msm8610-regulator.dtsi"
+
+&pm8110_vadc {
+ chan@0 {
+ label = "usb_in";
+ reg = <0>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <4>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@2 {
+ label = "vchg_sns";
+ reg = <2>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <3>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@5 {
+ label = "vcoin";
+ reg = <5>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <1>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@6 {
+ label = "vbat_sns";
+ reg = <6>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <1>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@7 {
+ label = "vph_pwr";
+ reg = <7>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <1>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@30 {
+ label = "batt_therm";
+ reg = <0x30>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <1>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@31 {
+ label = "batt_id";
+ reg = <0x31>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@b2 {
+ label = "xo_therm_pu2";
+ reg = <0xb2>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <4>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ };
+};
+
+
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-cdp-mtp.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-cdp-mtp.dtsi
index 24438f0..15a549c 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-cdp-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-cdp-mtp.dtsi
@@ -61,6 +61,44 @@
status = "ok";
};
+ qcom,camera@20 {
+ compatible = "qcom,imx135";
+ reg = <0x20>;
+ qcom,slave-id = <0x20 0x0 0x1210>;
+ qcom,csiphy-sd-index = <0>;
+ qcom,csid-sd-index = <0>;
+ qcom,mount-angle = <90>;
+ qcom,sensor-name = "imx135";
+ cam_vdig-supply = <&pm8941_l3>;
+ cam_vana-supply = <&pm8941_l17>;
+ cam_vio-supply = <&pm8941_lvs3>;
+ cam_vaf-supply = <&pm8941_l23>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+ "cam_vaf";
+ qcom,cam-vreg-type = <0 1 0 0>;
+ qcom,cam-vreg-min-voltage = <1225000 0 2850000 3000000>;
+ qcom,cam-vreg-max-voltage = <1225000 0 2850000 3000000>;
+ qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
+ qcom,gpio-no-mux = <0>;
+ gpios = <&msmgpio 15 0>,
+ <&msmgpio 90 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-req-tbl-num = <0 1>;
+ qcom,gpio-req-tbl-flags = <1 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK", "CAM_RESET1";
+ qcom,gpio-set-tbl-num = <1 1>;
+ qcom,gpio-set-tbl-flags = <0 2>;
+ qcom,gpio-set-tbl-delay = <1000 30000>;
+ qcom,csi-lane-assign = <0x4320>;
+ qcom,csi-lane-mask = <0x1F>;
+ qcom,sensor-position = <0>;
+ qcom,sensor-mode = <0>;
+ qcom,sensor-type = <0>;
+ qcom,cci-master = <0>;
+ status = "ok";
+ };
+
+
qcom,camera@6c {
compatible = "qcom,ov2720";
reg = <0x6c>;
diff --git a/arch/arm/boot/dts/msm8974-cdp.dtsi b/arch/arm/boot/dts/msm8974-cdp.dtsi
index ad26061..2c513e8 100644
--- a/arch/arm/boot/dts/msm8974-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8974-cdp.dtsi
@@ -22,6 +22,7 @@
qcom,mdss_dsi_toshiba_720p_video {
status = "ok";
+ qcom,cont-splash-enabled;
};
qcom,mdss_dsi_orise_720p_video {
@@ -213,6 +214,7 @@
HSIC_GDSC-supply = <&gdsc_usb_hsic>;
hsic,strobe-gpio = <&msmgpio 144 0x00>;
hsic,data-gpio = <&msmgpio 145 0x00>;
+ hsic,resume-gpio = <&msmgpio 80 0x00>;
hsic,ignore-cal-pad-config;
hsic,strobe-pad-offset = <0x2050>;
hsic,data-pad-offset = <0x2054>;
@@ -314,6 +316,17 @@
};
&sdhc_2 {
+ #address-cells = <0>;
+ interrupt-parent = <&sdhc_2>;
+ interrupts = <0 1 2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-map = <0 &intc 0 125 0
+ 1 &intc 0 221 0
+ 2 &msmgpio 62 0x3>;
+ interrupt-names = "hc_irq", "pwr_irq", "status_irq";
+ cd-gpios = <&msmgpio 62 0x1>;
+
vdd-supply = <&pm8941_l21>;
vdd-io-supply = <&pm8941_l13>;
@@ -346,9 +359,6 @@
&pm8941_chg {
status = "ok";
- qcom,chg-charging-disabled;
- qcom,chg-use-default-batt-values;
-
qcom,chg-chgr@1000 {
status = "ok";
};
@@ -357,10 +367,6 @@
status = "ok";
};
- qcom,chg-bat-if@1200 {
- status = "ok";
- };
-
qcom,chg-usb-chgpth@1300 {
status = "ok";
};
diff --git a/arch/arm/boot/dts/msm8974-fluid.dtsi b/arch/arm/boot/dts/msm8974-fluid.dtsi
index dbb8958..b18bf88 100644
--- a/arch/arm/boot/dts/msm8974-fluid.dtsi
+++ b/arch/arm/boot/dts/msm8974-fluid.dtsi
@@ -21,6 +21,7 @@
qcom,mdss_dsi_toshiba_720p_video {
status = "ok";
+ qcom,cont-splash-enabled;
};
qcom,hdmi_tx@fd922100 {
@@ -311,6 +312,17 @@
};
&sdhc_2 {
+ #address-cells = <0>;
+ interrupt-parent = <&sdhc_2>;
+ interrupts = <0 1 2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-map = <0 &intc 0 125 0
+ 1 &intc 0 221 0
+ 2 &msmgpio 62 0x3>;
+ interrupt-names = "hc_irq", "pwr_irq", "status_irq";
+ cd-gpios = <&msmgpio 62 0x1>;
+
vdd-supply = <&pm8941_l21>;
vdd-io-supply = <&pm8941_l13>;
diff --git a/arch/arm/boot/dts/msm8974-liquid.dtsi b/arch/arm/boot/dts/msm8974-liquid.dtsi
index 985b307..a35b9d2 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-liquid.dtsi
@@ -370,6 +370,14 @@
hsic,ignore-cal-pad-config;
hsic,strobe-pad-offset = <0x2050>;
hsic,data-pad-offset = <0x2054>;
+
+ qcom,msm-bus,name = "hsic";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,active-only = <0>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <85 512 0 0>,
+ <85 512 40000 160000>;
};
};
};
diff --git a/arch/arm/boot/dts/msm8974-mdss.dtsi b/arch/arm/boot/dts/msm8974-mdss.dtsi
index f382c3e..2f9adbb 100644
--- a/arch/arm/boot/dts/msm8974-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8974-mdss.dtsi
@@ -75,8 +75,8 @@
cell-index = <0>;
reg = <0xfd922800 0x600>;
vdd-supply = <&pm8941_l22>;
- vdd_io-supply = <&pm8941_l12>;
- vreg-supply = <&pm8941_l2>;
+ vddio-supply = <&pm8941_l12>;
+ vdda-supply = <&pm8941_l2>;
qcom,mdss-fb-map = <&mdss_fb0>;
};
@@ -86,8 +86,8 @@
cell-index = <1>;
reg = <0xfd922e00 0x600>;
vdd-supply = <&pm8941_l22>;
- vdd_io-supply = <&pm8941_l12>;
- vreg-supply = <&pm8941_l2>;
+ vddio-supply = <&pm8941_l12>;
+ vdda-supply = <&pm8941_l2>;
qcom,mdss-fb-map = <&mdss_fb0>;
};
diff --git a/arch/arm/boot/dts/msm8974-mtp.dtsi b/arch/arm/boot/dts/msm8974-mtp.dtsi
index d3d53dd..4f0469c 100644
--- a/arch/arm/boot/dts/msm8974-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974-mtp.dtsi
@@ -21,6 +21,7 @@
qcom,mdss_dsi_toshiba_720p_video {
status = "ok";
+ qcom,cont-splash-enabled;
};
qcom,hdmi_tx@fd922100 {
@@ -282,6 +283,17 @@
};
&sdhc_2 {
+ #address-cells = <0>;
+ interrupt-parent = <&sdhc_2>;
+ interrupts = <0 1 2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-map = <0 &intc 0 125 0
+ 1 &intc 0 221 0
+ 2 &msmgpio 62 0x3>;
+ interrupt-names = "hc_irq", "pwr_irq", "status_irq";
+ cd-gpios = <&msmgpio 62 0x1>;
+
vdd-supply = <&pm8941_l21>;
vdd-io-supply = <&pm8941_l13>;
diff --git a/arch/arm/boot/dts/msm8974-smp2p.dtsi b/arch/arm/boot/dts/msm8974-smp2p.dtsi
index 511f91f..964eecb 100644
--- a/arch/arm/boot/dts/msm8974-smp2p.dtsi
+++ b/arch/arm/boot/dts/msm8974-smp2p.dtsi
@@ -12,8 +12,7 @@
/ {
qcom,smp2p-modem {
compatible = "qcom,smp2p";
- reg = <0xfa006000 0x1000>, <0x8 0x0>;
- reg-names = "irq-reg-base", "irq-reg-offset";
+ reg = <0xf9011008 0x4>;
qcom,remote-pid = <1>;
qcom,irq-bitmask = <0x4000>;
interrupts = <0 27 1>;
@@ -21,8 +20,7 @@
qcom,smp2p-adsp {
compatible = "qcom,smp2p";
- reg = <0xfa006000 0x1000>, <0x8 0x0>;
- reg-names = "irq-reg-base", "irq-reg-offset";
+ reg = <0xf9011008 0x4>;
qcom,remote-pid = <2>;
qcom,irq-bitmask = <0x400>;
interrupts = <0 158 1>;
@@ -30,8 +28,7 @@
qcom,smp2p-wcnss {
compatible = "qcom,smp2p";
- reg = <0xfa006000 0x1000>, <0x8 0x0>;
- reg-names = "irq-reg-base", "irq-reg-offset";
+ reg = <0xf9011008 0x4>;
qcom,remote-pid = <4>;
qcom,irq-bitmask = <0x40000>;
interrupts = <0 143 1>;
diff --git a/arch/arm/boot/dts/msm8974-v1-cdp.dts b/arch/arm/boot/dts/msm8974-v1-cdp.dts
index 8db99b2..33bd1fb 100644
--- a/arch/arm/boot/dts/msm8974-v1-cdp.dts
+++ b/arch/arm/boot/dts/msm8974-v1-cdp.dts
@@ -19,10 +19,6 @@
model = "Qualcomm MSM 8974 CDP";
compatible = "qcom,msm8974-cdp", "qcom,msm8974";
qcom,msm-id = <126 1 0>;
-
- qcom,mdss_dsi_toshiba_720p_video {
- qcom,cont-splash-enabled;
- };
};
&ehci {
diff --git a/arch/arm/boot/dts/msm8974-v1-fluid.dts b/arch/arm/boot/dts/msm8974-v1-fluid.dts
index 683fe18..9fb287c 100644
--- a/arch/arm/boot/dts/msm8974-v1-fluid.dts
+++ b/arch/arm/boot/dts/msm8974-v1-fluid.dts
@@ -20,9 +20,6 @@
compatible = "qcom,msm8974-fluid", "qcom,msm8974";
qcom,msm-id = <126 3 0>;
- qcom,mdss_dsi_toshiba_720p_video {
- qcom,cont-splash-enabled;
- };
};
&pm8941_chg {
diff --git a/arch/arm/boot/dts/msm8974-v1-mtp.dts b/arch/arm/boot/dts/msm8974-v1-mtp.dts
index 0e5d2ae..205ee24 100644
--- a/arch/arm/boot/dts/msm8974-v1-mtp.dts
+++ b/arch/arm/boot/dts/msm8974-v1-mtp.dts
@@ -19,10 +19,6 @@
model = "Qualcomm MSM 8974 MTP";
compatible = "qcom,msm8974-mtp", "qcom,msm8974";
qcom,msm-id = <126 8 0>;
-
- qcom,mdss_dsi_toshiba_720p_video {
- qcom,cont-splash-enabled;
- };
};
&pm8941_chg {
diff --git a/arch/arm/boot/dts/msm8974-v1-pm.dtsi b/arch/arm/boot/dts/msm8974-v1-pm.dtsi
index 0b6fa8c..a0b9be6 100644
--- a/arch/arm/boot/dts/msm8974-v1-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974-v1-pm.dtsi
@@ -139,7 +139,6 @@
qcom,lpm-resources@0 {
reg = <0x0>;
qcom,name = "vdd-dig";
- qcom,resource-type = <0>;
qcom,type = <0x62706d73>; /* "smpb" */
qcom,id = <0x02>;
qcom,key = <0x6e726f63>; /* "corn" */
@@ -149,7 +148,6 @@
qcom,lpm-resources@1 {
reg = <0x1>;
qcom,name = "vdd-mem";
- qcom,resource-type = <0>;
qcom,type = <0x62706d73>; /* "smpb" */
qcom,id = <0x01>;
qcom,key = <0x7675>; /* "uv" */
@@ -159,18 +157,17 @@
qcom,lpm-resources@2 {
reg = <0x2>;
qcom,name = "pxo";
- qcom,resource-type = <0>;
qcom,type = <0x306b6c63>; /* "clk0" */
qcom,id = <0x00>;
qcom,key = <0x62616e45>; /* "Enab" */
- qcom,init-value = <1>; /* On */
+ qcom,init-value = "xo_on";
};
qcom,lpm-resources@3 {
reg = <0x3>;
qcom,name = "l2";
- qcom,resource-type = <1>;
- qcom,init-value = <2>; /* Retention */
+ qcom,local-resource-type;
+ qcom,init-value = "l2_cache_retention";
};
};
@@ -183,9 +180,9 @@
qcom,lpm-level@0 {
reg = <0x0>;
- qcom,mode = <0>; /* MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT */
- qcom,xo = <1>; /* ON */
- qcom,l2 = <3>; /* ACTIVE */
+ qcom,mode = "wfi";
+ qcom,xo = "xo_on";
+ qcom,l2 = "l2_cache_active";
qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
@@ -200,9 +197,9 @@
qcom,lpm-level@1 {
reg = <0x1>;
- qcom,mode = <4>; /* MSM_PM_SLEEP_MODE_RETENTION*/
- qcom,xo = <1>; /* ON */
- qcom,l2 = <3>; /* ACTIVE */
+ qcom,mode = "retention";
+ qcom,xo = "xo_on";
+ qcom,l2 = "l2_cache_active";
qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
@@ -218,9 +215,9 @@
qcom,lpm-level@2 {
reg = <0x2>;
- qcom,mode = <2>; /* MSM_PM_SLEEP_MODE_STANDALONE_POWER_COLLAPSE */
- qcom,xo = <1>; /* ON */
- qcom,l2 = <3>; /* ACTIVE */
+ qcom,mode = "standalone_pc";
+ qcom,xo = "xo_on";
+ qcom,l2 = "l2_cache_active";
qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
@@ -235,9 +232,9 @@
qcom,lpm-level@3 {
reg = <0x3>;
- qcom,mode = <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
- qcom,xo = <1>; /* ON */
- qcom,l2 = <1>; /* GDHS */
+ qcom,mode = "pc";
+ qcom,xo = "xo_on";
+ qcom,l2 = "l2_cache_gdhs";
qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
@@ -252,9 +249,9 @@
qcom,lpm-level@4 {
reg = <0x4>;
- qcom,mode = <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
- qcom,xo = <1>; /* ON */
- qcom,l2 = <0>; /* OFF */
+ qcom,mode = "pc";
+ qcom,xo = "xo_on";
+ qcom,l2 = "l2_cache_pc";
qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
qcom,vdd-mem-lower-bound = <950000>; /* SVS SOC */
qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
@@ -269,9 +266,9 @@
qcom,lpm-level@5 {
reg = <0x5>;
- qcom,mode = <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
- qcom,xo = <0>; /* OFF */
- qcom,l2 = <1>; /* GDHS */
+ qcom,mode = "pc";
+ qcom,xo = "xo_off";
+ qcom,l2 = "l2_cache_gdhs";
qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
@@ -284,9 +281,9 @@
qcom,lpm-level@6 {
reg = <0x6>;
- qcom,mode = <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
- qcom,xo = <0>; /* OFF */
- qcom,l2 = <0>; /* OFF */
+ qcom,mode = "pc";
+ qcom,xo = "xo_off";
+ qcom,l2 = "l2_cache_pc";
qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
@@ -299,9 +296,9 @@
qcom,lpm-level@7 {
reg = <0x7>;
- qcom,mode= <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
- qcom,xo = <0>; /* OFF */
- qcom,l2 = <0>; /* OFF */
+ qcom,mode= "pc";
+ qcom,xo = "xo_off";
+ qcom,l2 = "l2_cache_pc";
qcom,vdd-mem-upper-bound = <950000>; /* NORMAL */
qcom,vdd-mem-lower-bound = <950000>; /* SVS SOC */
qcom,vdd-dig-upper-bound = <4>; /* NORMAL */
@@ -314,9 +311,9 @@
qcom,lpm-level@8 {
reg = <0x8>;
- qcom,mode= <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
- qcom,xo = <0>; /* OFF */
- qcom,l2 = <0>; /* OFF */
+ qcom,mode= "pc";
+ qcom,xo = "xo_off";
+ qcom,l2 = "l2_cache_pc";
qcom,vdd-mem-upper-bound = <950000>; /* SVS SOC */
qcom,vdd-mem-lower-bound = <675000>; /* RETENTION */
qcom,vdd-dig-upper-bound = <3>; /* SVS SOC */
@@ -330,7 +327,7 @@
qcom,pm-boot {
compatible = "qcom,pm-boot";
- qcom,mode = <0>; /* MSM_PM_BOOT_CONFIG_TZ */
+ qcom,mode = "tz";
};
qcom,mpm@fc4281d0 {
@@ -343,7 +340,8 @@
qcom,ipc-bit-offset = <1>;
qcom,gic-parent = <&intc>;
- qcom,gic-map = <47 172>, /* usb2_hsic_async_wakeup_irq */
+ qcom,gic-map = <47 165>, /* usb30_hs_phy_irq */
+ <50 172>, /* usb1_hs_async_wakeup_irq */
<53 104>, /* mdss_irq */
<62 222>, /* ee0_krait_hlos_spmi_periph_irq */
<0xff 57>, /* mss_to_apps_irq(0) */
@@ -422,9 +420,19 @@
qcom,pm-8x60@fe805664 {
compatible = "qcom,pm-8x60";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
reg = <0xfe805664 0x40>;
- qcom,pc-mode = <0>; /*MSM_PC_TZ_L2_INT */
+ qcom,pc-mode = "tz_l2_int";
qcom,use-sync-timer;
+
+ qcom,cpu-sleep-status@f9088008 {
+ compatible = "qcom,cpu-sleep-status";
+ reg = <0xf9088008 0x4>;
+ qcom,cpu-alias-addr = <0x10000>;
+ qcom,sleep-status-mask= <0x80000>;
+ };
};
qcom,rpm-log@fc19dc00 {
diff --git a/arch/arm/boot/dts/msm8974-v2-pm.dtsi b/arch/arm/boot/dts/msm8974-v2-pm.dtsi
index 8cc497b..2cfb192 100644
--- a/arch/arm/boot/dts/msm8974-v2-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2-pm.dtsi
@@ -15,8 +15,8 @@
/ {
qcom,spm@f9089000 {
compatible = "qcom,spm-v2";
- #address-cells = <1>;
- #size-cells = <1>;
+ #address-cells = <1>;
+ #size-cells = <1>;
reg = <0xf9089000 0x1000>;
qcom,core-id = <0>;
qcom,saw2-ver-reg = <0xfd0>;
@@ -29,10 +29,10 @@
qcom,saw2-spm-ctl = <0x1>;
qcom,saw2-spm-cmd-wfi = [03 0b 0f];
qcom,saw2-spm-cmd-ret = [42 1b 00 d0 03 d4 5b 0b 00 42 1b 0f];
- qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 E0 03 6E 70 3B
- E4 5B 82 3F 50 10 0B 30 06 26 30 0F];
+ qcom,saw2-spm-cmd-spc = [00 20 80 10 E0 03 3B E4 5B 82 10 0B
+ 30 06 26 30 0F];
qcom,saw2-spm-cmd-pc = [00 20 50 80 60 70 10 E0 07 6E 70 3B
- E4 5B 82 3F 50 10 0B 30 06 26 30 0F];
+ E4 5B 82 3F 50 10 0B 30 06 26 30 0F];
};
qcom,spm@f9099000 {
@@ -51,8 +51,8 @@
qcom,saw2-spm-ctl = <0x1>;
qcom,saw2-spm-cmd-wfi = [03 0b 0f];
qcom,saw2-spm-cmd-ret = [42 1b 00 d0 03 d4 5b 0b 00 42 1b 0f];
- qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 E0 03 6E 70 3B
- E4 5B 82 3F 50 10 0B 30 06 26 30 0F];
+ qcom,saw2-spm-cmd-spc = [00 20 80 10 E0 03 3B E4 5B 82 10 0B
+ 30 06 26 30 0F];
qcom,saw2-spm-cmd-pc = [00 20 50 80 60 70 10 E0 07 6E 70 3B
E4 5B 82 3F 50 10 0B 30 06 26 30 0F];
};
@@ -73,8 +73,8 @@
qcom,saw2-spm-ctl = <0x1>;
qcom,saw2-spm-cmd-wfi = [03 0b 0f];
qcom,saw2-spm-cmd-ret = [42 1b 00 d0 03 d4 5b 0b 00 42 1b 0f];
- qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 E0 03 6E 70 3B
- E4 5B 82 3F 50 10 0B 30 06 26 30 0F];
+ qcom,saw2-spm-cmd-spc = [00 20 80 10 E0 03 3B E4 5B 82 10 0B
+ 30 06 26 30 0F];
qcom,saw2-spm-cmd-pc = [00 20 50 80 60 70 10 E0 07 6E 70 3B
E4 5B 82 3F 50 10 0B 30 06 26 30 0F];
};
@@ -95,8 +95,8 @@
qcom,saw2-spm-ctl = <0x1>;
qcom,saw2-spm-cmd-wfi = [03 0b 0f];
qcom,saw2-spm-cmd-ret = [42 1b 00 d0 03 d4 5b 0b 00 42 1b 0f];
- qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 E0 03 6E 70 3B
- E4 5B 82 3F 50 10 0B 30 06 26 30 0F];
+ qcom,saw2-spm-cmd-spc = [00 20 80 10 E0 03 3B E4 5B 82 10 0B
+ 30 06 26 30 0F];
qcom,saw2-spm-cmd-pc = [00 20 50 80 60 70 10 E0 07 6E 70 3B
E4 5B 82 3F 50 10 0B 30 06 26 30 0F];
};
@@ -136,7 +136,6 @@
qcom,lpm-resources@0 {
reg = <0x0>;
qcom,name = "vdd-dig";
- qcom,resource-type = <0>;
qcom,type = <0x62706d73>; /* "smpb" */
qcom,id = <0x02>;
qcom,key = <0x6e726f63>; /* "corn" */
@@ -146,7 +145,6 @@
qcom,lpm-resources@1 {
reg = <0x1>;
qcom,name = "vdd-mem";
- qcom,resource-type = <0>;
qcom,type = <0x62706d73>; /* "smpb" */
qcom,id = <0x01>;
qcom,key = <0x7675>; /* "uv" */
@@ -156,18 +154,17 @@
qcom,lpm-resources@2 {
reg = <0x2>;
qcom,name = "pxo";
- qcom,resource-type = <0>;
qcom,type = <0x306b6c63>; /* "clk0" */
qcom,id = <0x00>;
qcom,key = <0x62616e45>; /* "Enab" */
- qcom,init-value = <1>; /* On */
+ qcom,init-value = "xo_on";
};
qcom,lpm-resources@3 {
reg = <0x3>;
qcom,name = "l2";
- qcom,resource-type = <1>;
- qcom,init-value = <2>; /* Retention */
+ qcom,local-resource-type;
+ qcom,init-value = "l2_cache_retention";
};
};
@@ -180,9 +177,9 @@
qcom,lpm-level@0 {
reg = <0x0>;
- qcom,mode = <0>; /* MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT */
- qcom,xo = <1>; /* ON */
- qcom,l2 = <3>; /* ACTIVE */
+ qcom,mode = "wfi";
+ qcom,xo = "xo_on";
+ qcom,l2 = "l2_cache_active";
qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
@@ -197,9 +194,9 @@
qcom,lpm-level@1 {
reg = <0x1>;
- qcom,mode = <4>; /* MSM_PM_SLEEP_MODE_RETENTION*/
- qcom,xo = <1>; /* ON */
- qcom,l2 = <3>; /* ACTIVE */
+ qcom,mode = "retention";
+ qcom,xo = "xo_on";
+ qcom,l2 = "l2_cache_active";
qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
@@ -215,9 +212,9 @@
qcom,lpm-level@2 {
reg = <0x2>;
- qcom,mode = <2>; /* MSM_PM_SLEEP_MODE_STANDALONE_POWER_COLLAPSE */
- qcom,xo = <1>; /* ON */
- qcom,l2 = <3>; /* ACTIVE */
+ qcom,mode = "standalone_pc";
+ qcom,xo = "xo_on";
+ qcom,l2 = "l2_cache_active";
qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
@@ -232,9 +229,9 @@
qcom,lpm-level@3 {
reg = <0x3>;
- qcom,mode = <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
- qcom,xo = <1>; /* ON */
- qcom,l2 = <1>; /* GDHS */
+ qcom,mode = "pc";
+ qcom,xo = "xo_on";
+ qcom,l2 = "l2_cache_gdhs";
qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
@@ -249,9 +246,9 @@
qcom,lpm-level@4 {
reg = <0x4>;
- qcom,mode = <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
- qcom,xo = <1>; /* ON */
- qcom,l2 = <0>; /* OFF */
+ qcom,mode = "pc";
+ qcom,xo = "xo_on";
+ qcom,l2 = "l2_cache_pc";
qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
qcom,vdd-mem-lower-bound = <950000>; /* SVS SOC */
qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
@@ -266,9 +263,9 @@
qcom,lpm-level@5 {
reg = <0x5>;
- qcom,mode = <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
- qcom,xo = <0>; /* OFF */
- qcom,l2 = <1>; /* GDHS */
+ qcom,mode = "pc";
+ qcom,xo = "xo_off";
+ qcom,l2 = "l2_cache_gdhs";
qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
@@ -281,9 +278,9 @@
qcom,lpm-level@6 {
reg = <0x6>;
- qcom,mode = <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
- qcom,xo = <0>; /* OFF */
- qcom,l2 = <0>; /* OFF */
+ qcom,mode = "pc";
+ qcom,xo = "xo_off";
+ qcom,l2 = "l2_cache_pc";
qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
@@ -296,9 +293,9 @@
qcom,lpm-level@7 {
reg = <0x7>;
- qcom,mode= <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
- qcom,xo = <0>; /* OFF */
- qcom,l2 = <0>; /* OFF */
+ qcom,mode= "pc";
+ qcom,xo = "xo_off";
+ qcom,l2 = "l2_cache_pc";
qcom,vdd-mem-upper-bound = <950000>; /* NORMAL */
qcom,vdd-mem-lower-bound = <950000>; /* SVS SOC */
qcom,vdd-dig-upper-bound = <4>; /* NORMAL */
@@ -311,9 +308,9 @@
qcom,lpm-level@8 {
reg = <0x8>;
- qcom,mode= <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
- qcom,xo = <0>; /* OFF */
- qcom,l2 = <0>; /* OFF */
+ qcom,mode= "pc";
+ qcom,xo = "xo_off";
+ qcom,l2 = "l2_cache_pc";
qcom,vdd-mem-upper-bound = <950000>; /* SVS SOC */
qcom,vdd-mem-lower-bound = <675000>; /* RETENTION */
qcom,vdd-dig-upper-bound = <3>; /* SVS SOC */
@@ -327,7 +324,7 @@
qcom,pm-boot {
compatible = "qcom,pm-boot";
- qcom,mode = <0>; /* MSM_PM_BOOT_CONFIG_TZ */
+ qcom,mode = "tz";
};
qcom,mpm@fc4281d0 {
@@ -340,7 +337,8 @@
qcom,ipc-bit-offset = <1>;
qcom,gic-parent = <&intc>;
- qcom,gic-map = <47 172>, /* usb2_hsic_async_wakeup_irq */
+ qcom,gic-map = <47 165>, /* usb30_hs_phy_irq */
+ <50 172>, /* usb1_hs_async_wakeup_irq */
<53 104>, /* mdss_irq */
<62 222>, /* ee0_krait_hlos_spmi_periph_irq */
<0xff 57>, /* mss_to_apps_irq(0) */
@@ -419,10 +417,20 @@
qcom,pm-8x60@fe805664 {
compatible = "qcom,pm-8x60";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
reg = <0xfe805664 0x40>;
- qcom,pc-mode = <0>; /*MSM_PC_TZ_L2_INT */
+ qcom,pc-mode = "tz_l2_int";
qcom,use-sync-timer;
qcom,saw-turns-off-pll;
+
+ qcom,cpu-sleep-status@f9088008{
+ compatible = "qcom,cpu-sleep-status";
+ reg = <0xf9088008 0x100>;
+ qcom,cpu-alias-addr = <0x10000>;
+ qcom,sleep-status-mask= <0x80000>;
+ };
};
qcom,rpm-log@fc19dc00 {
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 3ebdbb6..00518a0 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -36,13 +36,13 @@
memory {
- secure_mem: region@0 {
+ secure_mem: secure_region {
linux,contiguous-region;
reg = <0 0x7800000>;
label = "secure_mem";
};
- adsp_mem: region@0 {
+ adsp_mem: adsp_region {
linux,contiguous-region;
reg = <0 0x2000000>;
label = "adsp_mem";
@@ -95,6 +95,7 @@
reg = <0xfdc00000 0xff000>;
interrupts = <0 44 0>;
qcom,hfi = "venus";
+ qcom,has-ocmem;
};
qcom,wfd {
@@ -590,6 +591,7 @@
qcom,audio-routing =
"RX_BIAS", "MCLK",
"LDO_H", "MCLK",
+ "AIF4 MAD", "MCLK",
"AMIC1", "MIC BIAS1 Internal1",
"MIC BIAS1 Internal1", "Handset Mic",
"AMIC2", "MIC BIAS2 External",
@@ -739,8 +741,9 @@
qcom,lpass@fe200000 {
compatible = "qcom,pil-q6v5-lpass";
reg = <0xfe200000 0x00100>,
- <0xfd485100 0x00010>;
- reg-names = "qdsp6_base", "halt_base";
+ <0xfd485100 0x00010>,
+ <0xfc4016c0 0x00004>;
+ reg-names = "qdsp6_base", "halt_base", "restart_reg";
vdd_cx-supply = <&pm8841_s2_corner>;
interrupts = <0 162 1>;
@@ -800,6 +803,10 @@
qcom,msm-dai-q6-dev-id = <8>;
};
+ qcom,msm-lsm-client {
+ compatible = "qcom,msm-lsm-client";
+ };
+
qcom,msm-dai-q6 {
compatible = "qcom,msm-dai-q6";
qcom,msm-dai-q6-sb-0-rx {
@@ -852,6 +859,11 @@
qcom,msm-dai-q6-dev-id = <16393>;
};
+ qcom,msm-dai-q6-sb-5-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16395>;
+ };
+
qcom,msm-dai-q6-bt-sco-rx {
compatible = "qcom,msm-dai-q6-dev";
qcom,msm-dai-q6-dev-id = <12288>;
@@ -1186,31 +1198,18 @@
reg-names = "ssusb", "hsusb", "qscratch_ram1_reg";
interrupts = <0 132 0 0 135 0>;
interrupt-names = "ssusb", "hsusb";
- qcom,usb-active-bam = <0>;
- qcom,usb-total-bam-num = <2>;
qcom,usb-bam-num-pipes = <16>;
qcom,usb-base-address = <0xf9200000>;
qcom,ignore-core-reset-ack;
qcom,disable-clk-gating;
- qcom,pipe1 {
- label = "usb-to-peri-qdss-dwc3";
- qcom,usb-bam-type = <0>;
+ qcom,pipe0 {
+ label = "ssusb-qdss-in-0";
qcom,usb-bam-mem-type = <1>;
- qcom,src-bam-physical-address = <0>;
- qcom,src-bam-pipe-index = <0>;
- qcom,dst-bam-physical-address = <0>;
- qcom,dst-bam-pipe-index = <0>;
- qcom,data-fifo-offset = <0>;
- qcom,data-fifo-size = <0>;
- qcom,descriptor-fifo-offset = <0>;
- qcom,descriptor-fifo-size = <0>;
- };
-
- qcom,pipe2 {
- label = "peri-to-usb-qdss-dwc3";
- qcom,usb-bam-type = <0>;
- qcom,usb-bam-mem-type = <1>;
+ qcom,bam-type = <0>;
+ qcom,dir = <1>;
+ qcom,pipe-num = <0>;
+ qcom,peer-bam = <1>;
qcom,src-bam-physical-address = <0xfc37C000>;
qcom,src-bam-pipe-index = <0>;
qcom,dst-bam-physical-address = <0xf9304000>;
@@ -1222,24 +1221,13 @@
qcom,reset-bam-on-connect;
};
- qcom,pipe3 {
- label = "usb-to-peri-qdss-hsusb";
- qcom,usb-bam-type = <1>;
+ qcom,pipe1 {
+ label = "hsusb-qdss-in-0";
qcom,usb-bam-mem-type = <1>;
- qcom,src-bam-physical-address = <0>;
- qcom,src-bam-pipe-index = <0>;
- qcom,dst-bam-physical-address = <0>;
- qcom,dst-bam-pipe-index = <0>;
- qcom,data-fifo-offset = <0>;
- qcom,data-fifo-size = <0>;
- qcom,descriptor-fifo-offset = <0>;
- qcom,descriptor-fifo-size = <0>;
- };
-
- qcom,pipe4 {
- label = "peri-to-usb-qdss-hsusb";
- qcom,usb-bam-type = <1>;
- qcom,usb-bam-mem-type = <1>;
+ qcom,bam-type = <1>;
+ qcom,dir = <1>;
+ qcom,pipe-num = <0>;
+ qcom,peer-bam = <1>;
qcom,src-bam-physical-address = <0xfc37c000>;
qcom,src-bam-pipe-index = <0>;
qcom,dst-bam-physical-address = <0xf9a44000>;
@@ -1266,10 +1254,6 @@
interrupts = <0 29 1>;
};
- qcom,msm-wdog-debug@fc401000 {
- compatible = "qcom,msm-wdog-debug";
- reg = <0xfc401000 0x1000>;
- };
qcom,msm-mem-hole {
compatible = "qcom,msm-mem-hole";
qcom,memblock-remove = <0x7f00000 0x8000000>; /* Address and Size of Hole */
@@ -1374,8 +1358,8 @@
sfpb_spinlock: qcom,ipc-spinlock@fd484000 {
compatible = "qcom,ipc-spinlock-sfpb";
- reg = <0xfd484000 0x1000>;
- qcom,num-locks = <32>;
+ reg = <0xfd484000 0x400>;
+ qcom,num-locks = <8>;
};
ldrex_spinlock: qcom,ipc-spinlock@fa00000 {
diff --git a/arch/arm/boot/dts/msm9625-display.dtsi b/arch/arm/boot/dts/msm9625-display.dtsi
new file mode 100644
index 0000000..a160bae
--- /dev/null
+++ b/arch/arm/boot/dts/msm9625-display.dtsi
@@ -0,0 +1,20 @@
+/* Copyright (c) 2013, 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.
+ */
+
+/ {
+ qcom,msm_qpic@f9ac0000 {
+ compatible = "qcom,mdss_qpic";
+ reg = <0xf9ac0000 0x24000>;
+ reg-names = "qpic_base";
+ interrupts = <0 251 0>;
+ };
+};
diff --git a/arch/arm/boot/dts/msm9625-pm.dtsi b/arch/arm/boot/dts/msm9625-pm.dtsi
index e881977..51a3faa 100644
--- a/arch/arm/boot/dts/msm9625-pm.dtsi
+++ b/arch/arm/boot/dts/msm9625-pm.dtsi
@@ -38,7 +38,6 @@
qcom,lpm-resources@0 {
reg = <0x0>;
qcom,name = "vdd-dig";
- qcom,resource-type = <0>;
qcom,type = <0x616F646C>; /* "ldoa" */
qcom,id = <0x0A>;
qcom,key = <0x6e726f63>; /* "corn" */
@@ -48,7 +47,6 @@
qcom,lpm-resources@1 {
reg = <0x1>;
qcom,name = "vdd-mem";
- qcom,resource-type = <0>;
qcom,type = <0x616F646C>; /* "ldoa" */
qcom,id = <0x0C>;
qcom,key = <0x7675>; /* "uv" */
@@ -58,11 +56,10 @@
qcom,lpm-resources@2 {
reg = <0x2>;
qcom,name = "pxo";
- qcom,resource-type = <0>;
qcom,type = <0x306b6c63>; /* "clk0" */
qcom,id = <0x00>;
qcom,key = <0x62616e45>; /* "Enab" */
- qcom,init-value = <1>; /* On */
+ qcom,init-value = "xo_on";
};
};
@@ -75,9 +72,9 @@
qcom,lpm-level@0 {
reg = <0x0>;
- qcom,mode = <0>; /* MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT */
- qcom,xo = <1>; /* ON */
- qcom,l2 = <3>; /* ACTIVE */
+ qcom,mode = "wfi";
+ qcom,xo = "xo_on";
+ qcom,l2 = "l2_cache_active";
qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
@@ -92,9 +89,9 @@
qcom,lpm-level@1 {
reg = <0x1>;
- qcom,mode = <2>; /* MSM_PM_SLEEP_MODE_STANDALONE_POWER_COLLAPSE */
- qcom,xo = <1>; /* ON */
- qcom,l2 = <3>; /* ACTIVE */
+ qcom,mode = "standalone_pc";
+ qcom,xo = "xo_on";
+ qcom,l2 = "l2_cache_active";
qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
@@ -109,9 +106,9 @@
qcom,lpm-level@2 {
reg = <0x2>;
- qcom,mode = <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
- qcom,xo = <1>; /* ON */
- qcom,l2 = <1>; /* GDHS */
+ qcom,mode = "pc";
+ qcom,xo = "xo_on";
+ qcom,l2 = "l2_cache_gdhs";
qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
@@ -126,9 +123,9 @@
qcom,lpm-level@3 {
reg = <0x3>;
- qcom,mode = <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
- qcom,xo = <1>; /* ON */
- qcom,l2 = <0>; /* GDHS */
+ qcom,mode = "pc";
+ qcom,xo = "xo_on";
+ qcom,l2 = "l2_cache_pc";
qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
qcom,vdd-mem-lower-bound = <950000>; /* SVS SOC */
qcom,vdd-dig-upper-bound = <4>; /* NORMAL */
@@ -143,9 +140,9 @@
qcom,lpm-level@4 {
reg = <0x4>;
- qcom,mode= <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
- qcom,xo = <0>; /* OFF */
- qcom,l2 = <0>; /* OFF */
+ qcom,mode = "pc";
+ qcom,xo = "xo_off";
+ qcom,l2 = "l2_cache_pc";
qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
@@ -159,9 +156,9 @@
qcom,lpm-level@5 {
reg = <0x5>;
- qcom,mode= <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
- qcom,xo = <0>; /* OFF */
- qcom,l2 = <0>; /* OFF */
+ qcom,mode = "pc";
+ qcom,xo = "xo_off";
+ qcom,l2 = "l2_cache_pc";
qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
qcom,vdd-mem-lower-bound = <950000>; /* SVS SOC */
qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
@@ -175,9 +172,9 @@
qcom,lpm-level@6 {
reg = <0x6>;
- qcom,mode= <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
- qcom,xo = <0>; /* OFF */
- qcom,l2 = <0>; /* OFF */
+ qcom,mode = "pc";
+ qcom,xo = "xo_off";
+ qcom,l2 = "l2_cache_pc";
qcom,vdd-mem-upper-bound = <950000>; /* SVS SOC */
qcom,vdd-mem-lower-bound = <675000>; /* RETENTION */
qcom,vdd-dig-upper-bound = <3>; /* SVS SOC */
@@ -191,7 +188,7 @@
qcom,pm-boot {
compatible = "qcom,pm-boot";
- qcom,mode = <0>; /* MSM_PM_BOOT_CONFIG_TZ */
+ qcom,mode = "tz";
};
qcom,mpm@fc4281d0 {
@@ -277,7 +274,7 @@
qcom,pm-8x60 {
compatible = "qcom,pm-8x60";
- qcom,pc-mode = <2>; /*MSM_PC_TZ_L2_EXT */
+ qcom,pc-mode = "tz_l2_ext";
qcom,use-sync-timer;
};
diff --git a/arch/arm/boot/dts/msm9625-smp2p.dtsi b/arch/arm/boot/dts/msm9625-smp2p.dtsi
index 425bf00..02c95e4 100644
--- a/arch/arm/boot/dts/msm9625-smp2p.dtsi
+++ b/arch/arm/boot/dts/msm9625-smp2p.dtsi
@@ -12,8 +12,7 @@
/ {
qcom,smp2p-modem {
compatible = "qcom,smp2p";
- reg = <0xfa006000 0x1000>, <0x8 0x0>;
- reg-names = "irq-reg-base", "irq-reg-offset";
+ reg = <0xf9011008 0x4>;
qcom,remote-pid = <1>;
qcom,irq-bitmask = <0x4000>;
interrupts = <0 27 1>;
@@ -21,8 +20,7 @@
qcom,smp2p-adsp {
compatible = "qcom,smp2p";
- reg = <0xfa006000 0x1000>, <0x8 0x0>;
- reg-names = "irq-reg-base", "irq-reg-offset";
+ reg = <0xf9011008 0x4>;
qcom,remote-pid = <2>;
qcom,irq-bitmask = <0x400>;
interrupts = <0 158 1>;
diff --git a/arch/arm/boot/dts/msm9625-v2-cdp.dts b/arch/arm/boot/dts/msm9625-v2-cdp.dts
index 244556d..919c6d5 100644
--- a/arch/arm/boot/dts/msm9625-v2-cdp.dts
+++ b/arch/arm/boot/dts/msm9625-v2-cdp.dts
@@ -13,6 +13,8 @@
/dts-v1/;
/include/ "msm9625-v2.dtsi"
+/include/ "msm9625-display.dtsi"
+/include/ "qpic-panel-ili-qvga.dtsi"
/ {
model = "Qualcomm MSM 9625V2 CDP";
@@ -42,7 +44,7 @@
wlan0: qca,wlan {
cell-index = <0>;
- compatible = "qca,ar6004-sdio";
+ compatible = "qca,ar6004-hsic";
qca,chip-pwd-l-gpios = <&msmgpio 62 0>;
qca,pm-enable-gpios = <&pm8019_gpios 3 0x0>;
qca,ar6004-vdd-io-supply = <&pm8019_l11>;
diff --git a/arch/arm/boot/dts/msm9625-v2-mtp.dts b/arch/arm/boot/dts/msm9625-v2-mtp.dts
index bf0f539..7949080 100644
--- a/arch/arm/boot/dts/msm9625-v2-mtp.dts
+++ b/arch/arm/boot/dts/msm9625-v2-mtp.dts
@@ -42,7 +42,7 @@
wlan0: qca,wlan {
cell-index = <0>;
- compatible = "qca,ar6004-sdio";
+ compatible = "qca,ar6004-hsic";
qca,chip-pwd-l-gpios = <&msmgpio 62 0>;
qca,pm-enable-gpios = <&pm8019_gpios 3 0x0>;
qca,ar6004-vdd-io-supply = <&pm8019_l11>;
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index 78786f6..9172029 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -123,24 +123,28 @@
qcom,msm-bus,vectors-KBps =
<85 512 0 0>,
<85 512 40000 640000>;
+ qcom,pool-64-bit-align;
+ qcom,enable-hbm;
};
qcom,usbbam@f9a44000 {
compatible = "qcom,usb-bam-msm";
- reg = <0xf9a44000 0x11000>;
- reg-names = "hsusb";
- interrupts = <0 135 0>;
- interrupt-names = "hsusb";
- qcom,usb-active-bam = <1>;
- qcom,usb-total-bam-num = <3>;
+ reg = <0xf9a44000 0x11000>,
+ <0xf9a04000 0x11000>;
+ reg-names = "hsusb", "hsic";
+ interrupts = <0 135 0 0 255 0>;
+ interrupt-names = "hsusb", "hsic";
qcom,usb-bam-num-pipes = <16>;
qcom,ignore-core-reset-ack;
qcom,disable-clk-gating;
qcom,pipe0 {
- label = "usb-to-ipa";
- qcom,usb-bam-type = <1>;
+ label = "hsusb-ipa-out-0";
qcom,usb-bam-mem-type = <0>;
+ qcom,bam-type = <1>;
+ qcom,dir = <0>;
+ qcom,pipe-num = <0>;
+ qcom,peer-bam = <2>;
qcom,src-bam-physical-address = <0xf9a44000>;
qcom,src-bam-pipe-index = <1>;
qcom,data-fifo-offset = <0x2200>;
@@ -149,9 +153,12 @@
qcom,descriptor-fifo-size = <0x100>;
};
qcom,pipe1 {
- label = "ipa-to-usb";
- qcom,usb-bam-type = <1>;
+ label = "hsusb-ipa-in-0";
qcom,usb-bam-mem-type = <0>;
+ qcom,bam-type = <1>;
+ qcom,dir = <1>;
+ qcom,pipe-num = <0>;
+ qcom,peer-bam = <2>;
qcom,dst-bam-physical-address = <0xf9a44000>;
qcom,dst-bam-pipe-index = <0>;
qcom,data-fifo-offset = <0x300>;
@@ -160,22 +167,12 @@
qcom,descriptor-fifo-size = <0x300>;
};
qcom,pipe2 {
- label = "usb-to-qdss-hsusb";
- qcom,usb-bam-type = <1>;
+ label = "hsusb-qdss-in-0";
qcom,usb-bam-mem-type = <0>;
- qcom,src-bam-physical-address = <0xf9a44000>;
- qcom,src-bam-pipe-index = <0>;
- qcom,dst-bam-physical-address = <0xfc37c000>;
- qcom,dst-bam-pipe-index = <0>;
- qcom,data-fifo-offset = <0>;
- qcom,data-fifo-size = <0>;
- qcom,descriptor-fifo-offset = <0>;
- qcom,descriptor-fifo-size = <0>;
- };
- qcom,pipe3 {
- label = "qdss-to-usb-hsusb";
- qcom,usb-bam-type = <1>;
- qcom,usb-bam-mem-type = <0>;
+ qcom,bam-type = <1>;
+ qcom,dir = <1>;
+ qcom,pipe-num = <0>;
+ qcom,peer-bam = <1>;
qcom,src-bam-physical-address = <0xfc37c000>;
qcom,src-bam-pipe-index = <0>;
qcom,dst-bam-physical-address = <0xf9a44000>;
@@ -185,6 +182,66 @@
qcom,descriptor-fifo-offset = <0x4000>;
qcom,descriptor-fifo-size = <0x400>;
};
+ qcom,pipe3 {
+ label = "hsic-ipa-in-0";
+ qcom,usb-bam-mem-type = <2>;
+ qcom,bam-type = <2>;
+ qcom,dir = <1>;
+ qcom,pipe-num = <0>;
+ qcom,peer-bam = <2>;
+ qcom,dst-bam-physical-address = <0xf9a04000>;
+ qcom,dst-bam-pipe-index = <3>;
+ qcom,data-fifo-size = <0xD480>;
+ qcom,descriptor-fifo-size = <0x1A80>;
+ };
+ qcom,pipe4 {
+ label = "hsic-ipa-in-1";
+ qcom,bam-type = <2>;
+ qcom,dir = <1>;
+ qcom,pipe-num = <1>;
+ qcom,peer-bam = <2>;
+ qcom,usb-bam-mem-type = <2>;
+ qcom,dst-bam-physical-address = <0xf9a04000>;
+ qcom,dst-bam-pipe-index = <4>;
+ qcom,data-fifo-size = <0xD480>;
+ qcom,descriptor-fifo-size = <0x1A80>;
+ };
+ qcom,pipe5 {
+ label = "hsic-ipa-in-2";
+ qcom,usb-bam-mem-type = <2>;
+ qcom,bam-type = <2>;
+ qcom,dir = <1>;
+ qcom,pipe-num = <2>;
+ qcom,peer-bam = <2>;
+ qcom,dst-bam-physical-address = <0xf9a04000>;
+ qcom,dst-bam-pipe-index = <5>;
+ qcom,data-fifo-size = <0xD480>;
+ qcom,descriptor-fifo-size = <0x1A80>;
+ };
+ qcom,pipe6 {
+ label = "hsic-ipa-in-3";
+ qcom,usb-bam-mem-type = <2>;
+ qcom,bam-type = <2>;
+ qcom,dir = <1>;
+ qcom,pipe-num = <3>;
+ qcom,peer-bam = <2>;
+ qcom,dst-bam-physical-address = <0xf9a04000>;
+ qcom,dst-bam-pipe-index = <6>;
+ qcom,data-fifo-size = <0xD480>;
+ qcom,descriptor-fifo-size = <0x1A80>;
+ };
+ qcom,pipe7 {
+ label = "hsic-ipa-out-0";
+ qcom,usb-bam-mem-type = <2>;
+ qcom,bam-type = <2>;
+ qcom,dir = <0>;
+ qcom,pipe-num = <0>;
+ qcom,peer-bam = <2>;
+ qcom,src-bam-physical-address = <0xf9a04000>;
+ qcom,src-bam-pipe-index = <7>;
+ qcom,data-fifo-size = <0xD480>;
+ qcom,descriptor-fifo-size = <0x1A80>;
+ };
};
qcom,nand@f9ac0000 {
@@ -727,8 +784,8 @@
sfpb_spinlock: qcom,ipc-spinlock@fd484000 {
compatible = "qcom,ipc-spinlock-sfpb";
- reg = <0xfd484000 0x1000>;
- qcom,num-locks = <32>;
+ reg = <0xfd484000 0x400>;
+ qcom,num-locks = <8>;
};
ldrex_spinlock: qcom,ipc-spinlock@fa00000 {
diff --git a/arch/arm/boot/dts/msmzinc-ion.dtsi b/arch/arm/boot/dts/msmzinc-ion.dtsi
new file mode 100644
index 0000000..4bf078a
--- /dev/null
+++ b/arch/arm/boot/dts/msmzinc-ion.dtsi
@@ -0,0 +1,27 @@
+/* Copyright (c) 2013, 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.
+ */
+
+/ {
+ qcom,ion {
+ compatible = "qcom,msm-ion";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,ion-heap@30 { /* SYSTEM HEAP */
+ reg = <30>;
+ };
+
+ qcom,ion-heap@25 { /* IOMMU HEAP */
+ reg = <25>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/msmzinc-sim.dts b/arch/arm/boot/dts/msmzinc-sim.dts
new file mode 100644
index 0000000..48d7ef1
--- /dev/null
+++ b/arch/arm/boot/dts/msmzinc-sim.dts
@@ -0,0 +1,29 @@
+/* Copyright (c) 2013, 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/ "msmzinc.dtsi"
+
+/ {
+ model = "Qualcomm MSM ZINC Simulator";
+ compatible = "qcom,msmzinc-sim", "qcom,msmzinc";
+ qcom,msm-id = <178 0 0>;
+
+ aliases {
+ serial0 = &uart0;
+ };
+
+ uart0: serial@f991f000 {
+ status = "ok";
+ };
+};
diff --git a/arch/arm/boot/dts/msmzinc.dtsi b/arch/arm/boot/dts/msmzinc.dtsi
new file mode 100644
index 0000000..642597d
--- /dev/null
+++ b/arch/arm/boot/dts/msmzinc.dtsi
@@ -0,0 +1,86 @@
+/* Copyright (c) 2013, 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/ "skeleton.dtsi"
+/include/ "msmzinc-ion.dtsi"
+
+/ {
+ model = "Qualcomm MSM ZINC";
+ compatible = "qcom,msmzinc";
+ interrupt-parent = <&intc>;
+
+ intc: interrupt-controller@f9000000 {
+ compatible = "qcom,msm-qgic2";
+ interrupt-controller;
+ #interrupt-cells = <3>;
+ reg = <0xF9000000 0x1000>,
+ <0xF9002000 0x1000>;
+ };
+
+ msmgpio: gpio@fd510000 {
+ compatible = "qcom,msm-gpio";
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ reg = <0xfd510000 0x4000>;
+ ngpio = <146>;
+ interrupts = <0 208 0>;
+ qcom,direct-connect-irqs = <8>;
+ };
+
+ timer {
+ compatible = "arm,armv7-timer";
+ interrupts = <1 2 0 1 3 0>;
+ clock-frequency = <19200000>;
+ };
+
+ serial@f991f000 {
+ compatible = "qcom,msm-lsuart-v14";
+ reg = <0xf991f000 0x1000>;
+ interrupts = <0 109 0>;
+ status = "disabled";
+ };
+
+ qcom,cache_erp {
+ compatible = "qcom,cache_erp";
+ interrupts = <1 9 0>, <0 2 0>;
+ interrupt-names = "l1_irq", "l2_irq";
+ };
+
+ qcom,cache_dump {
+ compatible = "qcom,cache_dump";
+ qcom,l1-dump-size = <0x100000>;
+ qcom,l2-dump-size = <0x500000>;
+ qcom,memory-reservation-type = "EBI1";
+ qcom,memory-reservation-size = <0x600000>; /* 6M EBI1 buffer */
+ };
+
+ rpm_bus: qcom,rpm-smd {
+ compatible = "qcom,rpm-smd";
+ rpm-channel-name = "rpm_requests";
+ rpm-channel-type = <15>; /* SMD_APPS_RPM */
+ rpm-standalone;
+ };
+
+ qcom,msm-imem@fe805000 {
+ compatible = "qcom,msm-imem";
+ reg = <0xfe805000 0x1000>; /* Address and size of IMEM */
+ };
+
+ qcom,msm-rtb {
+ compatible = "qcom,msm-rtb";
+ qcom,memory-reservation-type = "EBI1";
+ qcom,memory-reservation-size = <0x100000>; /* 1M EBI1 buffer */
+ };
+
+};
diff --git a/arch/arm/boot/dts/qpic-panel-ili-qvga.dtsi b/arch/arm/boot/dts/qpic-panel-ili-qvga.dtsi
new file mode 100644
index 0000000..a0c906e
--- /dev/null
+++ b/arch/arm/boot/dts/qpic-panel-ili-qvga.dtsi
@@ -0,0 +1,27 @@
+/* Copyright (c) 2013, 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.
+ */
+
+/ {
+ qcom,mdss_lcdc_ili9341_qvga {
+ compatible = "qcom,mdss-qpic-panel";
+ label = "ili qvga lcdc panel";
+ vdd-supply = <&pm8019_l11>;
+ avdd-supply = <&pm8019_l14>;
+ qcom,cs-gpio = <&msmgpio 21 0>;
+ qcom,te-gpio = <&msmgpio 22 0>;
+ qcom,rst-gpio = <&msmgpio 23 0>;
+ qcom,ad8-gpio = <&msmgpio 20 0>;
+ qcom,mdss-pan-res = <240 320>;
+ qcom,mdss-pan-bpp = <18>;
+ qcom,refresh_rate = <60>;
+ };
+};
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index 084880f..097e830 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -105,6 +105,74 @@
CONFIG_IPV6_MULTIPLE_TABLES=y
CONFIG_IPV6_SUBTREES=y
CONFIG_NETFILTER=y
+CONFIG_NETFILTER_NETLINK_LOG=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_H323=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SANE=y
+CONFIG_NF_CONNTRACK_SIP=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NF_CT_NETLINK=y
+CONFIG_NETFILTER_TPROXY=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_LOG=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_MATCH_COMMENT=y
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_HELPER=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+CONFIG_NETFILTER_XT_MATCH_LENGTH=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
+CONFIG_NETFILTER_XT_MATCH_STRING=y
+CONFIG_NETFILTER_XT_MATCH_TIME=y
+CONFIG_NETFILTER_XT_MATCH_U32=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_RAW=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_NF_CONNTRACK_IPV6=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_TARGET_REJECT=y
+CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_RAW=y
CONFIG_BRIDGE_NF_EBTABLES=y
CONFIG_BRIDGE_EBT_BROUTE=y
CONFIG_BRIDGE=y
@@ -114,6 +182,18 @@
CONFIG_NET_CLS_FW=y
CONFIG_SYNC=y
CONFIG_SW_SYNC=y
+CONFIG_CMA=y
+CONFIG_BT=y
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=y
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=y
+CONFIG_BT_HCISMD=y
+CONFIG_MSM_BT_POWER=y
+CONFIG_CFG80211=y
+CONFIG_NL80211_TESTMODE=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
CONFIG_MD=y
@@ -164,6 +244,8 @@
CONFIG_REGULATOR=y
CONFIG_REGULATOR_STUB=y
CONFIG_REGULATOR_QPNP=y
+CONFIG_RADIO_IRIS=y
+CONFIG_RADIO_IRIS_TRANSPORT=m
CONFIG_ION=y
CONFIG_ION_MSM=y
CONFIG_MSM_KGSL=y
@@ -256,6 +338,7 @@
CONFIG_THERMAL=y
CONFIG_THERMAL_TSENS8974=y
CONFIG_THERMAL_MONITOR=y
+CONFIG_THERMAL_QPNP_ADC_TM=y
CONFIG_MSM_RTB=y
CONFIG_MSM_RTB_SEPARATE_CPUS=y
CONFIG_CORESIGHT=y
@@ -264,9 +347,11 @@
CONFIG_CORESIGHT_FUNNEL=y
CONFIG_CORESIGHT_REPLICATOR=y
CONFIG_CORESIGHT_STM=y
+CONFIG_CORESIGHT_ETM=y
CONFIG_CORESIGHT_EVENT=m
CONFIG_ENABLE_DEFAULT_TRACERS=y
CONFIG_PM_WAKELOCKS=y
CONFIG_PM_WAKELOCKS_LIMIT=0
CONFIG_PM_AUTOSLEEP=y
# CONFIG_PM_WAKELOCKS_GC is not set
+CONFIG_MSM_TZ_LOG=y
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index ea10007..663e937 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -329,6 +329,7 @@
CONFIG_MSM_CSIPHY=y
CONFIG_MSM_CSID=y
CONFIG_MSM_ISPIF=y
+CONFIG_IMX135=y
CONFIG_S5K3L1YX=y
CONFIG_MSMB_CAMERA=y
CONFIG_MSMB_JPEG=y
@@ -474,3 +475,4 @@
CONFIG_PM_WAKELOCKS_LIMIT=0
CONFIG_PM_AUTOSLEEP=y
# CONFIG_PM_WAKELOCKS_GC is not set
+CONFIG_MSM_BOOT_STATS=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index 077c7a6..2de81d4d1 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -336,6 +336,7 @@
CONFIG_MSM_CSID=y
CONFIG_MSM_ISPIF=y
CONFIG_S5K3L1YX=y
+CONFIG_IMX135=y
CONFIG_MSMB_CAMERA=y
CONFIG_MSMB_JPEG=y
CONFIG_MSM_VIDC_V4L2=y
@@ -499,3 +500,4 @@
CONFIG_PM_WAKELOCKS_LIMIT=0
CONFIG_PM_AUTOSLEEP=y
# CONFIG_PM_WAKELOCKS_GC is not set
+CONFIG_MSM_BOOT_STATS=y
diff --git a/arch/arm/configs/msm9625-perf_defconfig b/arch/arm/configs/msm9625-perf_defconfig
index f525eee..c2fb1487 100644
--- a/arch/arm/configs/msm9625-perf_defconfig
+++ b/arch/arm/configs/msm9625-perf_defconfig
@@ -161,6 +161,8 @@
CONFIG_MTD_BLOCK=y
# CONFIG_MTD_MSM_NAND is not set
CONFIG_MTD_MSM_QPIC_NAND=y
+CONFIG_SYNC=y
+CONFIG_SW_SYNC=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
# CONFIG_ANDROID_PMEM is not set
@@ -218,6 +220,10 @@
CONFIG_REGULATOR_QPNP=y
CONFIG_ION=y
CONFIG_ION_MSM=y
+CONFIG_FB=y
+CONFIG_FB_MSM=y
+CONFIG_FB_MSM_QPIC=y
+CONFIG_FB_MSM_QPIC_PANEL_DETECT=y
CONFIG_SOUND=y
CONFIG_SND=y
CONFIG_SND_SOC=y
@@ -323,7 +329,6 @@
CONFIG_SCSI_SCAN_ASYNC=y
CONFIG_MSM_RTB=y
CONFIG_MSM_MEMORY_DUMP=y
-CONFIG_PM_WAKELOCKS=y
-CONFIG_PM_WAKELOCKS_LIMIT=0
CONFIG_PM_AUTOSLEEP=y
# CONFIG_PM_WAKELOCKS_GC is not set
+CONFIG_MSM_BOOT_STATS=y
diff --git a/arch/arm/configs/msm9625_defconfig b/arch/arm/configs/msm9625_defconfig
index f3a7b5c..828eaa9 100644
--- a/arch/arm/configs/msm9625_defconfig
+++ b/arch/arm/configs/msm9625_defconfig
@@ -161,6 +161,8 @@
CONFIG_MTD_BLOCK=y
# CONFIG_MTD_MSM_NAND is not set
CONFIG_MTD_MSM_QPIC_NAND=y
+CONFIG_SYNC=y
+CONFIG_SW_SYNC=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
# CONFIG_ANDROID_PMEM is not set
@@ -219,6 +221,10 @@
CONFIG_REGULATOR_QPNP=y
CONFIG_ION=y
CONFIG_ION_MSM=y
+CONFIG_FB=y
+CONFIG_FB_MSM=y
+CONFIG_FB_MSM_QPIC=y
+CONFIG_FB_MSM_QPIC_PANEL_DETECT=y
CONFIG_SOUND=y
CONFIG_SND=y
CONFIG_SND_SOC=y
@@ -324,7 +330,6 @@
CONFIG_SCSI_SCAN_ASYNC=y
CONFIG_MSM_RTB=y
CONFIG_MSM_MEMORY_DUMP=y
-CONFIG_PM_WAKELOCKS=y
-CONFIG_PM_WAKELOCKS_LIMIT=0
CONFIG_PM_AUTOSLEEP=y
# CONFIG_PM_WAKELOCKS_GC is not set
+CONFIG_MSM_BOOT_STATS=y
diff --git a/arch/arm/configs/msmzinc_defconfig b/arch/arm/configs/msmzinc_defconfig
new file mode 100644
index 0000000..678b086
--- /dev/null
+++ b/arch/arm/configs/msmzinc_defconfig
@@ -0,0 +1,384 @@
+# CONFIG_ARM_PATCH_PHYS_VIRT is not set
+CONFIG_EXPERIMENTAL=y
+CONFIG_SYSVIPC=y
+CONFIG_RCU_FAST_NO_HZ=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_DEBUG=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_PID_NS is not set
+CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_RD_BZIP2=y
+CONFIG_RD_LZMA=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_PANIC_TIMEOUT=5
+CONFIG_KALLSYMS_ALL=y
+CONFIG_ASHMEM=y
+CONFIG_EMBEDDED=y
+CONFIG_PROFILING=y
+CONFIG_KPROBES=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_EFI_PARTITION=y
+CONFIG_IOSCHED_TEST=y
+CONFIG_ARCH_MSM=y
+CONFIG_ARCH_MSMZINC=y
+CONFIG_MSM_KRAIT_TBB_ABORT_HANDLER=y
+CONFIG_MSM_RPM_SMD=y
+# CONFIG_MSM_STACKED_MEMORY is not set
+CONFIG_CPU_HAS_L2_PMU=y
+# CONFIG_MSM_FIQ_SUPPORT is not set
+# CONFIG_MSM_PROC_COMM is not set
+CONFIG_MSM_SMD=y
+CONFIG_MSM_SMD_PKG4=y
+CONFIG_MSM_IPC_LOGGING=y
+CONFIG_MSM_IPC_ROUTER=y
+CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
+CONFIG_MSM_IPC_ROUTER_SECURITY=y
+# CONFIG_MSM_HW3D is not set
+CONFIG_MSM_RPM_REGULATOR_SMD=y
+CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_MSM_SYSMON_COMM=y
+CONFIG_MSM_DIRECT_SCLK_ACCESS=y
+CONFIG_MSM_WATCHDOG_V2=y
+CONFIG_MSM_MEMORY_DUMP=y
+CONFIG_MSM_DLOAD_MODE=y
+CONFIG_MSM_RUN_QUEUE_STATS=y
+CONFIG_MSM_SPM_V2=y
+CONFIG_MSM_L2_SPM=y
+CONFIG_MSM_MULTIMEDIA_USE_ION=y
+CONFIG_MSM_OCMEM=y
+CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
+CONFIG_MSM_OCMEM_DEBUG=y
+CONFIG_MSM_OCMEM_NONSECURE=y
+CONFIG_SENSORS_ADSP=y
+CONFIG_MSM_RTB=y
+CONFIG_MSM_RTB_SEPARATE_CPUS=y
+CONFIG_MSM_CACHE_ERP=y
+CONFIG_MSM_L1_ERR_PANIC=y
+CONFIG_MSM_L1_RECOV_ERR_PANIC=y
+CONFIG_MSM_L1_ERR_LOG=y
+CONFIG_MSM_L2_ERP_PRINT_ACCESS_ERRORS=y
+CONFIG_MSM_L2_ERP_PORT_PANIC=y
+CONFIG_MSM_L2_ERP_1BIT_PANIC=y
+CONFIG_MSM_L2_ERP_2BIT_PANIC=y
+CONFIG_MSM_CACHE_DUMP=y
+CONFIG_MSM_CACHE_DUMP_ON_PANIC=y
+CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
+CONFIG_ARM_LPAE=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_SMP=y
+# CONFIG_SMP_ON_UP is not set
+CONFIG_SCHED_MC=y
+CONFIG_ARM_ARCH_TIMER=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_HIGHMEM=y
+CONFIG_VMALLOC_RESERVE=0x19000000
+CONFIG_CC_STACKPROTECTOR=y
+CONFIG_CP_ACCESS=y
+CONFIG_USE_OF=y
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPU_IDLE=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_WAKELOCK=y
+CONFIG_PM_RUNTIME=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+CONFIG_IPV6=y
+CONFIG_IPV6_PRIVACY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_NETFILTER=y
+CONFIG_NETFILTER_NETLINK_LOG=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_H323=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SANE=y
+CONFIG_NF_CONNTRACK_SIP=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NF_CT_NETLINK=y
+CONFIG_NETFILTER_TPROXY=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_LOG=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_MATCH_COMMENT=y
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_HELPER=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+CONFIG_NETFILTER_XT_MATCH_LENGTH=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
+CONFIG_NETFILTER_XT_MATCH_STRING=y
+CONFIG_NETFILTER_XT_MATCH_TIME=y
+CONFIG_NETFILTER_XT_MATCH_U32=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_RAW=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_NF_CONNTRACK_IPV6=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_TARGET_REJECT=y
+CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_RAW=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_SCH_PRIO=y
+CONFIG_NET_CLS_FW=y
+CONFIG_NET_CLS_U32=y
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_FLOW=y
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_CMP=y
+CONFIG_NET_EMATCH_NBYTE=y
+CONFIG_NET_EMATCH_U32=y
+CONFIG_NET_EMATCH_META=y
+CONFIG_NET_EMATCH_TEXT=y
+CONFIG_NET_CLS_ACT=y
+CONFIG_CFG80211=y
+CONFIG_RFKILL=y
+CONFIG_GENLOCK=y
+CONFIG_GENLOCK_MISCDEVICE=y
+CONFIG_SYNC=y
+CONFIG_SW_SYNC=y
+CONFIG_CMA=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_HAPTIC_ISA1200=y
+CONFIG_USB_HSIC_SMSC_HUB=y
+CONFIG_TI_DRV2667=y
+CONFIG_SCSI=y
+CONFIG_SCSI_TGT=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SCH=y
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_CRYPT=y
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+CONFIG_TUN=y
+CONFIG_KS8851=m
+# CONFIG_MSM_RMNET is not set
+CONFIG_SLIP=y
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_MODE_SLIP6=y
+CONFIG_USB_USBNET=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_EVBUG=m
+CONFIG_KEYBOARD_GPIO=y
+CONFIG_INPUT_JOYSTICK=y
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ATMEL_MXT=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_SERIAL_MSM_HSL=y
+CONFIG_SERIAL_MSM_HSL_CONSOLE=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_MSM=y
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_QUP=y
+CONFIG_SPI=y
+CONFIG_SPI_SPIDEV=m
+CONFIG_SPMI=y
+CONFIG_SPMI_MSM_PMIC_ARB=y
+CONFIG_MSM_QPNP_INT=y
+CONFIG_DEBUG_GPIO=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_QPNP_PIN=y
+CONFIG_GPIO_QPNP_PIN_DEBUG=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_SMB350_CHARGER=y
+CONFIG_BATTERY_BQ28400=y
+CONFIG_QPNP_CHARGER=y
+CONFIG_BATTERY_BCL=y
+CONFIG_SENSORS_EPM_ADC=y
+CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
+CONFIG_SENSORS_QPNP_ADC_CURRENT=y
+CONFIG_THERMAL=y
+CONFIG_THERMAL_TSENS8974=y
+CONFIG_THERMAL_MONITOR=y
+CONFIG_THERMAL_QPNP=y
+CONFIG_THERMAL_QPNP_ADC_TM=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_STUB=y
+CONFIG_REGULATOR_QPNP=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
+CONFIG_ION=y
+CONFIG_ION_MSM=y
+CONFIG_MSM_KGSL=y
+CONFIG_FB=y
+CONFIG_FB_MSM=y
+# CONFIG_FB_MSM_BACKLIGHT is not set
+CONFIG_FB_MSM_MDSS=y
+CONFIG_FB_MSM_MDSS_WRITEBACK=y
+CONFIG_FB_MSM_MDSS_HDMI_PANEL=y
+CONFIG_FB_MSM_MDSS_HDMI_MHL_SII8334=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_LCD_CLASS_DEVICE is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+# CONFIG_BACKLIGHT_GENERIC is not set
+CONFIG_USB=y
+CONFIG_USB_SUSPEND=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_MSM=y
+CONFIG_USB_EHCI_MSM_HSIC=y
+CONFIG_USB_ACM=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_STORAGE_DATAFAB=y
+CONFIG_USB_STORAGE_FREECOM=y
+CONFIG_USB_STORAGE_ISD200=y
+CONFIG_USB_STORAGE_USBAT=y
+CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_USB_STORAGE_SDDR55=y
+CONFIG_USB_STORAGE_JUMPSHOT=y
+CONFIG_USB_STORAGE_ALAUDA=y
+CONFIG_USB_STORAGE_ONETOUCH=y
+CONFIG_USB_STORAGE_KARMA=y
+CONFIG_USB_STORAGE_CYPRESS_ATACB=y
+CONFIG_USB_STORAGE_ENE_UB6250=y
+CONFIG_LEDS_QPNP=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_BACKLIGHT=y
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
+CONFIG_SWITCH=y
+CONFIG_RTC_CLASS=y
+# CONFIG_RTC_DRV_MSM is not set
+CONFIG_RTC_DRV_QPNP=y
+CONFIG_STAGING=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_ANDROID_LOGGER=y
+CONFIG_ANDROID_TIMED_GPIO=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_MSM_SSBI=y
+CONFIG_SPS=y
+CONFIG_SPS_SUPPORT_BAMDMA=y
+CONFIG_SPS_SUPPORT_NDP_BAM=y
+CONFIG_QPNP_PWM=y
+CONFIG_QPNP_POWER_ON=y
+CONFIG_QPNP_CLKDIV=y
+CONFIG_MSM_IOMMU=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT4_FS=y
+CONFIG_FUSE_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_PSTORE=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_LOCKUP_DETECTOR=y
+# CONFIG_DETECT_HUNG_TASK is not set
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
+CONFIG_DEBUG_KMEMLEAK=y
+CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_MUTEXES=y
+CONFIG_DEBUG_ATOMIC_SLEEP=y
+CONFIG_DEBUG_STACK_USAGE=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_DEBUG_LIST=y
+CONFIG_FAULT_INJECTION=y
+CONFIG_FAIL_PAGE_ALLOC=y
+CONFIG_FAULT_INJECTION_DEBUG_FS=y
+CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y
+CONFIG_DEBUG_PAGEALLOC=y
+CONFIG_CPU_FREQ_SWITCH_PROFILER=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_LL=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_PID_IN_CONTEXTIDR=y
+CONFIG_KEYS=y
+CONFIG_CRYPTO_MD4=y
+CONFIG_CRYPTO_SHA256=y
+CONFIG_CRYPTO_ARC4=y
+CONFIG_CRYPTO_TWOFISH=y
+CONFIG_CRYPTO_DEV_QCRYPTO=m
+CONFIG_CRYPTO_DEV_QCE=m
+CONFIG_CRYPTO_DEV_QCEDEV=m
+CONFIG_CRC_CCITT=y
diff --git a/arch/arm/kernel/machine_kexec.c b/arch/arm/kernel/machine_kexec.c
index dfcdb9f..c355aeb 100644
--- a/arch/arm/kernel/machine_kexec.c
+++ b/arch/arm/kernel/machine_kexec.c
@@ -110,6 +110,7 @@
unsigned long reboot_code_buffer_phys;
void *reboot_code_buffer;
+ arch_kexec();
page_list = image->head & PAGE_MASK;
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index ce557b1..f7d993f 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -286,6 +286,24 @@
select MSM_LPM_TEST
select MSM_RPM_LOG
+config ARCH_MSMZINC
+ bool "MSMZINC"
+ select ARCH_MSM_KRAITMP
+ select GPIO_MSM_V3
+ select ARM_GIC
+ select CPU_V7
+ select MSM_SCM if SMP
+ select MSM_GPIOMUX
+ select MULTI_IRQ_HANDLER
+ select MSM_NATIVE_RESTART
+ select MSM_RESTART_V2
+ select MSM_PM8X60 if PM
+ select MAY_HAVE_SPARSE_IRQ
+ select SPARSE_IRQ
+ select REGULATOR
+ select ARM_HAS_SG_CHAIN
+ select ARCH_DMA_ADDR_T_64BIT if ARM_LPAE
+
config ARCH_MPQ8092
bool "MPQ8092"
select ARCH_MSM_KRAITMP
@@ -445,6 +463,7 @@
select ARM_HAS_SG_CHAIN
select REGULATOR
select MSM_RPM_REGULATOR_SMD
+ select MSM_JTAG_MM if CORESIGHT_ETM
endmenu
choice
@@ -1043,6 +1062,7 @@
default "0x80200000" if ARCH_MSM8960
default "0x80200000" if ARCH_MSM8930
default "0x00000000" if ARCH_MSM8974
+ default "0x00000000" if ARCH_MSMZINC
default "0x00000000" if ARCH_MPQ8092
default "0x00000000" if ARCH_MSM8226
default "0x00000000" if ARCH_MSM8610
@@ -1193,6 +1213,14 @@
help
Say Y here if you want the debug print routines to direct
their output to the serial port on MPQ8092 devices.
+
+ config DEBUG_MSMZINC_UART
+ bool "Kernel low-level debugging messages via MSMZINC UART"
+ depends on ARCH_MSMZINC
+ select MSM_HAS_DEBUG_UART_HS_V14
+ help
+ Say Y here if you want the debug print routines to direct
+ their output to the serial port on MSMZINC devices.
endchoice
choice
@@ -2817,12 +2845,12 @@
does not have a direct access to the PMIC.
config MSM_ENABLE_WDOG_DEBUG_CONTROL
- bool "MSM Watchdog driver to disable debug Image"
+ bool "Enable control of watchdog debug and boot partition select"
help
- This driver supports the configuration of the GCC_WDOG_DEBUG register
- used to control debug image.
- This support is currently required for MSM8974 to disable debug image
- on PS HOLD reset
+ Enables support for controlling watchdog debug and boot partition
+ select. This is currently used to bypass debug image for PS_HOLD reset
+ by disabling watchdog debug and boot partition select. This allows
+ for a clean MSM reset for reboot scenarios.
config MSM_FIQ
bool "Enable FIQ for debugging"
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index fb7e4e3..161ee3d 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -118,6 +118,7 @@
ifndef CONFIG_ARCH_MSM9625
ifndef CONFIG_ARCH_MPQ8092
ifndef CONFIG_ARCH_MSM8610
+ifndef CONFIG_ARCH_MSMZINC
obj-y += nand_partitions.o
endif
endif
@@ -127,6 +128,7 @@
endif
endif
endif
+endif
obj-$(CONFIG_MSM_SDIO_TTY) += sdio_tty.o
obj-$(CONFIG_MSM_SMD_TTY) += smd_tty.o
obj-$(CONFIG_MSM_SMD_QMI) += smd_qmi.o
@@ -290,6 +292,7 @@
obj-$(CONFIG_MACH_MPQ8064_DTV) += board-8064-all.o board-8064-regulator.o
obj-$(CONFIG_ARCH_MSM9615) += board-9615.o devices-9615.o board-9615-regulator.o board-9615-gpiomux.o board-9615-storage.o board-9615-display.o
obj-$(CONFIG_ARCH_MSM9615) += clock-local.o clock-9615.o acpuclock-9615.o clock-rpm.o clock-pll.o
+obj-$(CONFIG_ARCH_MSMZINC) += board-zinc.o board-zinc-gpiomux.o
obj-$(CONFIG_ARCH_MSM8974) += board-8974.o board-8974-gpiomux.o
obj-$(CONFIG_ARCH_MSM8974) += acpuclock-8974.o
obj-$(CONFIG_ARCH_MSM8974) += clock-local2.o clock-pll.o clock-8974.o clock-rpm.o clock-voter.o clock-mdss-8974.o
@@ -365,6 +368,7 @@
obj-$(CONFIG_ARCH_MPQ8092) += gpiomux-v2.o gpiomux.o
obj-$(CONFIG_ARCH_MSM8226) += gpiomux-v2.o gpiomux.o
obj-$(CONFIG_ARCH_MSM8610) += gpiomux-v2.o gpiomux.o
+obj-$(CONFIG_ARCH_MSMZINC) += gpiomux-v2.o gpiomux.o
obj-$(CONFIG_MSM_SLEEP_STATS_DEVICE) += idle_stats_device.o
obj-$(CONFIG_MSM_DCVS) += msm_dcvs_scm.o msm_dcvs.o msm_mpdecision.o
diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot
index 02d0b46..e3b8d73 100644
--- a/arch/arm/mach-msm/Makefile.boot
+++ b/arch/arm/mach-msm/Makefile.boot
@@ -58,6 +58,11 @@
dtb-$(CONFIG_ARCH_MSM8974) += msm8974-v2-liquid.dtb
dtb-$(CONFIG_ARCH_MSM8974) += msm8974-v2-mtp.dtb
+# MSMZINC
+ zreladdr-$(CONFIG_ARCH_MSMZINC) := 0x00008000
+ dtb-$(CONFIG_ARCH_MSMZINC) += msmzinc-sim.dtb
+
+
# MSM9615
zreladdr-$(CONFIG_ARCH_MSM9615) := 0x40808000
diff --git a/arch/arm/mach-msm/acpuclock-8226.c b/arch/arm/mach-msm/acpuclock-8226.c
index 8ba1b39..fcbd74d 100644
--- a/arch/arm/mach-msm/acpuclock-8226.c
+++ b/arch/arm/mach-msm/acpuclock-8226.c
@@ -98,13 +98,13 @@
drv_data.apcs_rcg_config = drv_data.apcs_rcg_cmd + 4;
- drv_data.vdd_cpu = regulator_get(&pdev->dev, "a7_cpu");
+ drv_data.vdd_cpu = devm_regulator_get(&pdev->dev, "a7_cpu");
if (IS_ERR(drv_data.vdd_cpu)) {
dev_err(&pdev->dev, "regulator for %s get failed\n", "a7_cpu");
return PTR_ERR(drv_data.vdd_cpu);
}
- drv_data.vdd_mem = regulator_get(&pdev->dev, "a7_mem");
+ drv_data.vdd_mem = devm_regulator_get(&pdev->dev, "a7_mem");
if (IS_ERR(drv_data.vdd_mem)) {
dev_err(&pdev->dev, "regulator for %s get failed\n", "a7_mem");
return PTR_ERR(drv_data.vdd_mem);
diff --git a/arch/arm/mach-msm/acpuclock-9625.c b/arch/arm/mach-msm/acpuclock-9625.c
index b439088..34952fb 100644
--- a/arch/arm/mach-msm/acpuclock-9625.c
+++ b/arch/arm/mach-msm/acpuclock-9625.c
@@ -105,13 +105,13 @@
if (!drv_data.apcs_cpu_pwr_ctl)
return -ENOMEM;
- drv_data.vdd_cpu = regulator_get(&pdev->dev, "a5_cpu");
+ drv_data.vdd_cpu = devm_regulator_get(&pdev->dev, "a5_cpu");
if (IS_ERR(drv_data.vdd_cpu)) {
dev_err(&pdev->dev, "regulator for %s get failed\n", "a5_cpu");
return PTR_ERR(drv_data.vdd_cpu);
}
- drv_data.vdd_mem = regulator_get(&pdev->dev, "a5_mem");
+ drv_data.vdd_mem = devm_regulator_get(&pdev->dev, "a5_mem");
if (IS_ERR(drv_data.vdd_mem)) {
dev_err(&pdev->dev, "regulator for %s get failed\n", "a5_mem");
return PTR_ERR(drv_data.vdd_mem);
diff --git a/arch/arm/mach-msm/acpuclock-cortex.c b/arch/arm/mach-msm/acpuclock-cortex.c
index 9104f98..88bf919 100644
--- a/arch/arm/mach-msm/acpuclock-cortex.c
+++ b/arch/arm/mach-msm/acpuclock-cortex.c
@@ -40,7 +40,7 @@
#define POLL_INTERVAL_US 1
#define APCS_RCG_UPDATE_TIMEOUT_US 20
-static struct acpuclk_drv_data *acpuclk_init_data;
+static struct acpuclk_drv_data *priv;
static uint32_t bus_perf_client;
/* Update the bus bandwidth request. */
@@ -48,7 +48,7 @@
{
int ret;
- if (bw >= acpuclk_init_data->bus_scale->num_usecases) {
+ if (bw >= priv->bus_scale->num_usecases) {
pr_err("invalid bandwidth request (%d)\n", bw);
return;
}
@@ -67,15 +67,13 @@
int rc = 0;
/* Increase vdd_mem before vdd_cpu. vdd_mem should be >= vdd_cpu. */
- rc = regulator_set_voltage(acpuclk_init_data->vdd_mem, vdd_mem,
- acpuclk_init_data->vdd_max_mem);
+ rc = regulator_set_voltage(priv->vdd_mem, vdd_mem, priv->vdd_max_mem);
if (rc) {
pr_err("vdd_mem increase failed (%d)\n", rc);
return rc;
}
- rc = regulator_set_voltage(acpuclk_init_data->vdd_cpu, vdd_cpu,
- acpuclk_init_data->vdd_max_cpu);
+ rc = regulator_set_voltage(priv->vdd_cpu, vdd_cpu, priv->vdd_max_cpu);
if (rc)
pr_err("vdd_cpu increase failed (%d)\n", rc);
@@ -88,16 +86,14 @@
int ret;
/* Update CPU voltage. */
- ret = regulator_set_voltage(acpuclk_init_data->vdd_cpu, vdd_cpu,
- acpuclk_init_data->vdd_max_cpu);
+ ret = regulator_set_voltage(priv->vdd_cpu, vdd_cpu, priv->vdd_max_cpu);
if (ret) {
pr_err("vdd_cpu decrease failed (%d)\n", ret);
return;
}
/* Decrease vdd_mem after vdd_cpu. vdd_mem should be >= vdd_cpu. */
- ret = regulator_set_voltage(acpuclk_init_data->vdd_mem, vdd_mem,
- acpuclk_init_data->vdd_max_mem);
+ ret = regulator_set_voltage(priv->vdd_mem, vdd_mem, priv->vdd_max_mem);
if (ret)
pr_err("vdd_mem decrease failed (%d)\n", ret);
}
@@ -142,14 +138,14 @@
{
int rc = 0;
unsigned int tgt_freq_hz = tgt_s->khz * 1000;
- struct clkctl_acpu_speed *strt_s = acpuclk_init_data->current_speed;
- struct clkctl_acpu_speed *cxo_s = &acpuclk_init_data->freq_tbl[0];
- struct clk *strt = acpuclk_init_data->src_clocks[strt_s->src].clk;
- struct clk *tgt = acpuclk_init_data->src_clocks[tgt_s->src].clk;
+ struct clkctl_acpu_speed *strt_s = priv->current_speed;
+ struct clkctl_acpu_speed *cxo_s = &priv->freq_tbl[0];
+ struct clk *strt = priv->src_clocks[strt_s->src].clk;
+ struct clk *tgt = priv->src_clocks[tgt_s->src].clk;
if (strt_s->src == ACPUPLL && tgt_s->src == ACPUPLL) {
/* Switch to another always on src */
- select_clk_source_div(acpuclk_init_data, cxo_s);
+ select_clk_source_div(priv, cxo_s);
/* Re-program acpu pll */
if (atomic)
@@ -167,7 +163,7 @@
BUG_ON(clk_prepare_enable(tgt));
/* Switch back to acpu pll */
- select_clk_source_div(acpuclk_init_data, tgt_s);
+ select_clk_source_div(priv, tgt_s);
} else if (strt_s->src != ACPUPLL && tgt_s->src == ACPUPLL) {
rc = clk_set_rate(tgt, tgt_freq_hz);
@@ -177,16 +173,16 @@
}
if (atomic)
- clk_enable(tgt);
+ rc = clk_enable(tgt);
else
- clk_prepare_enable(tgt);
+ rc = clk_prepare_enable(tgt);
if (rc) {
pr_err("ACPU PLL enable failed\n");
return rc;
}
- select_clk_source_div(acpuclk_init_data, tgt_s);
+ select_clk_source_div(priv, tgt_s);
if (atomic)
clk_disable(strt);
@@ -195,17 +191,17 @@
} else {
if (atomic)
- clk_enable(tgt);
+ rc = clk_enable(tgt);
else
- clk_prepare_enable(tgt);
+ rc = clk_prepare_enable(tgt);
if (rc) {
pr_err("%s enable failed\n",
- acpuclk_init_data->src_clocks[tgt_s->src].name);
+ priv->src_clocks[tgt_s->src].name);
return rc;
}
- select_clk_source_div(acpuclk_init_data, tgt_s);
+ select_clk_source_div(priv, tgt_s);
if (atomic)
clk_disable(strt);
@@ -224,16 +220,16 @@
int rc = 0;
if (reason == SETRATE_CPUFREQ)
- mutex_lock(&acpuclk_init_data->lock);
+ mutex_lock(&priv->lock);
- strt_s = acpuclk_init_data->current_speed;
+ strt_s = priv->current_speed;
/* Return early if rate didn't change */
if (rate == strt_s->khz)
goto out;
/* Find target frequency */
- for (tgt_s = acpuclk_init_data->freq_tbl; tgt_s->khz != 0; tgt_s++)
+ for (tgt_s = priv->freq_tbl; tgt_s->khz != 0; tgt_s++)
if (tgt_s->khz == rate)
break;
if (tgt_s->khz == 0) {
@@ -261,7 +257,7 @@
if (rc)
goto out;
- acpuclk_init_data->current_speed = tgt_s;
+ priv->current_speed = tgt_s;
pr_debug("CPU speed change complete\n");
/* Nothing else to do for SWFI or power-collapse. */
@@ -277,13 +273,13 @@
out:
if (reason == SETRATE_CPUFREQ)
- mutex_unlock(&acpuclk_init_data->lock);
+ mutex_unlock(&priv->lock);
return rc;
}
static unsigned long acpuclk_cortex_get_rate(int cpu)
{
- return acpuclk_init_data->current_speed->khz;
+ return priv->current_speed->khz;
}
#ifdef CONFIG_CPU_FREQ_MSM
@@ -293,18 +289,17 @@
{
int i, freq_cnt = 0;
- /* Construct the freq_table tables from acpuclk_init_data->freq_tbl. */
- for (i = 0; acpuclk_init_data->freq_tbl[i].khz != 0
+ /* Construct the freq_table tables from priv->freq_tbl. */
+ for (i = 0; priv->freq_tbl[i].khz != 0
&& freq_cnt < ARRAY_SIZE(freq_table); i++) {
- if (!acpuclk_init_data->freq_tbl[i].use_for_scaling)
+ if (!priv->freq_tbl[i].use_for_scaling)
continue;
freq_table[freq_cnt].index = freq_cnt;
- freq_table[freq_cnt].frequency =
- acpuclk_init_data->freq_tbl[i].khz;
+ freq_table[freq_cnt].frequency = priv->freq_tbl[i].khz;
freq_cnt++;
}
/* freq_table not big enough to store all usable freqs. */
- BUG_ON(acpuclk_init_data->freq_tbl[i].khz != 0);
+ BUG_ON(priv->freq_tbl[i].khz != 0);
freq_table[freq_cnt].index = freq_cnt;
freq_table[freq_cnt].frequency = CPUFREQ_TABLE_END;
@@ -332,43 +327,40 @@
unsigned long max_cpu_khz = 0;
int i, rc;
- acpuclk_init_data = data;
- mutex_init(&acpuclk_init_data->lock);
+ priv = data;
+ mutex_init(&priv->lock);
- bus_perf_client = msm_bus_scale_register_client(
- acpuclk_init_data->bus_scale);
+ bus_perf_client = msm_bus_scale_register_client(priv->bus_scale);
if (!bus_perf_client) {
pr_err("Unable to register bus client\n");
BUG();
}
for (i = 0; i < NUM_SRC; i++) {
- if (!acpuclk_init_data->src_clocks[i].name)
+ if (!priv->src_clocks[i].name)
continue;
- acpuclk_init_data->src_clocks[i].clk =
- clk_get(&pdev->dev,
- acpuclk_init_data->src_clocks[i].name);
- BUG_ON(IS_ERR(acpuclk_init_data->src_clocks[i].clk));
+ priv->src_clocks[i].clk =
+ devm_clk_get(&pdev->dev, priv->src_clocks[i].name);
+ BUG_ON(IS_ERR(priv->src_clocks[i].clk));
}
/* Improve boot time by ramping up CPU immediately */
- for (i = 0; acpuclk_init_data->freq_tbl[i].khz != 0; i++)
- if (acpuclk_init_data->freq_tbl[i].use_for_scaling)
- max_cpu_khz = acpuclk_init_data->freq_tbl[i].khz;
+ for (i = 0; priv->freq_tbl[i].khz != 0; i++)
+ if (priv->freq_tbl[i].use_for_scaling)
+ max_cpu_khz = priv->freq_tbl[i].khz;
/* Initialize regulators */
- rc = increase_vdd(acpuclk_init_data->vdd_max_cpu,
- acpuclk_init_data->vdd_max_mem);
+ rc = increase_vdd(priv->vdd_max_cpu, priv->vdd_max_mem);
if (rc)
goto err_vdd;
- rc = regulator_enable(acpuclk_init_data->vdd_mem);
+ rc = regulator_enable(priv->vdd_mem);
if (rc) {
dev_err(&pdev->dev, "regulator_enable for mem failed\n");
goto err_vdd;
}
- rc = regulator_enable(acpuclk_init_data->vdd_cpu);
+ rc = regulator_enable(priv->vdd_cpu);
if (rc) {
dev_err(&pdev->dev, "regulator_enable for cpu failed\n");
goto err_vdd_cpu;
@@ -388,15 +380,7 @@
return 0;
err_vdd_cpu:
- regulator_disable(acpuclk_init_data->vdd_mem);
+ regulator_disable(priv->vdd_mem);
err_vdd:
- regulator_put(acpuclk_init_data->vdd_mem);
- regulator_put(acpuclk_init_data->vdd_cpu);
-
- for (i = 0; i < NUM_SRC; i++) {
- if (!acpuclk_init_data->src_clocks[i].name)
- continue;
- clk_put(acpuclk_init_data->src_clocks[i].clk);
- }
return rc;
}
diff --git a/arch/arm/mach-msm/acpuclock-krait-debug.c b/arch/arm/mach-msm/acpuclock-krait-debug.c
index a29735e..f11b9fc 100644
--- a/arch/arm/mach-msm/acpuclock-krait-debug.c
+++ b/arch/arm/mach-msm/acpuclock-krait-debug.c
@@ -249,6 +249,56 @@
}
DEFINE_SIMPLE_ATTRIBUTE(boost_fops, boost_get, NULL, "%lld\n");
+static int acpu_table_show(struct seq_file *m, void *unused)
+{
+ const struct acpu_level *level;
+
+ seq_printf(m, "CPU_KHz PLL_L_Val L2_KHz VDD_Dig VDD_Mem ");
+ seq_printf(m, "BW_Mbps VDD_Core UA_Core AVS\n");
+
+ for (level = drv->acpu_freq_tbl; level->speed.khz != 0; level++) {
+
+ const struct l2_level *l2 =
+ &drv->l2_freq_tbl[level->l2_level];
+ u32 bw = drv->bus_scale->usecase[l2->bw_level].vectors[0].ib;
+
+ if (!level->use_for_scaling)
+ continue;
+
+ /* CPU speed information */
+ seq_printf(m, "%7lu %9u ",
+ level->speed.khz,
+ level->speed.pll_l_val);
+
+ /* L2 level information */
+ seq_printf(m, "%7lu %7d %7d %7u ",
+ l2->speed.khz,
+ l2->vdd_dig,
+ l2->vdd_mem,
+ bw / 1000000);
+
+ /* Core voltage information */
+ seq_printf(m, "%8d %7d %3d\n",
+ level->vdd_core,
+ level->ua_core,
+ level->avsdscr_setting);
+ }
+
+ return 0;
+}
+
+static int acpu_table_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, acpu_table_show, inode->i_private);
+}
+
+static const struct file_operations acpu_table_fops = {
+ .open = acpu_table_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
static void __cpuinit add_scalable_dir(int sc_id)
{
char sc_name[8];
@@ -326,6 +376,8 @@
&speed_bin_fops);
debugfs_create_file("pvs_bin", S_IRUGO, base_dir, NULL, &pvs_bin_fops);
debugfs_create_file("boost_uv", S_IRUGO, base_dir, NULL, &boost_fops);
+ debugfs_create_file("acpu_table", S_IRUGO, base_dir, NULL,
+ &acpu_table_fops);
for_each_online_cpu(cpu)
add_scalable_dir(cpu);
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index 833b213..20c461d 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -1577,8 +1577,6 @@
{
DMUX_LOG_KERR("%s: modem timeout: BAM DMUX disabled\n", __func__);
in_global_reset = 1;
- if (get_restart_level() <= RESET_SOC)
- DMUX_LOG_KERR("%s: ssrestart not enabled\n", __func__);
return 1;
}
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index c8bdb5d..48abd35 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -2388,12 +2388,6 @@
}
}
-static void __init fsm8064_ep_pcie_init(void)
-{
- msm_device_pcie.dev.platform_data = &ep_pcie_platform_data;
- platform_device_register(&msm_device_pcie);
-}
-
static struct platform_device mpq8064_device_ext_3p3v_vreg = {
.name = "reg-fixed-voltage",
.dev = {
@@ -2401,6 +2395,12 @@
},
};
+static void __init fsm8064_ep_pcie_init(void)
+{
+ msm_device_pcie.dev.platform_data = &ep_pcie_platform_data;
+ platform_device_register(&msm_device_pcie);
+}
+
static struct platform_device apq8064_device_ext_5v_vreg __devinitdata = {
.name = GPIO_REGULATOR_DEV_NAME,
.id = PM8921_MPP_PM_TO_SYS(7),
diff --git a/arch/arm/mach-msm/board-8226-gpiomux.c b/arch/arm/mach-msm/board-8226-gpiomux.c
index 41263f8..2b70e7c 100644
--- a/arch/arm/mach-msm/board-8226-gpiomux.c
+++ b/arch/arm/mach-msm/board-8226-gpiomux.c
@@ -17,7 +17,7 @@
#include <mach/gpio.h>
#include <mach/gpiomux.h>
-#define KS8851_IRQ_GPIO 75
+#define KS8851_IRQ_GPIO 115
#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
static struct gpiomux_setting gpio_eth_config = {
@@ -84,6 +84,24 @@
.pull = GPIOMUX_PULL_DOWN,
};
+static struct gpiomux_setting gpio_spi_cs_eth_config = {
+ .func = GPIOMUX_FUNC_4,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting wcnss_5wire_suspend_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting wcnss_5wire_active_cfg = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
static struct gpiomux_setting gpio_i2c_config = {
.func = GPIOMUX_FUNC_3,
.drv = GPIOMUX_DRV_2MA,
@@ -186,6 +204,12 @@
[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
},
},
+ {
+ .gpio = 22, /* BLSP1 QUP1 SPI_CS_ETH */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_spi_cs_eth_config,
+ },
+ },
};
static struct msm_gpiomux_config msm_synaptics_configs[] __initdata = {
@@ -227,6 +251,43 @@
},
};
+static struct msm_gpiomux_config wcnss_5wire_interface[] = {
+ {
+ .gpio = 40,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5wire_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 41,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5wire_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 42,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5wire_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 43,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5wire_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 44,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5wire_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg,
+ },
+ },
+};
void __init msm8226_init_gpiomux(void)
{
int rc;
@@ -244,6 +305,8 @@
ARRAY_SIZE(msm_keypad_configs));
msm_gpiomux_install(msm_blsp_configs, ARRAY_SIZE(msm_blsp_configs));
+ msm_gpiomux_install(wcnss_5wire_interface,
+ ARRAY_SIZE(wcnss_5wire_interface));
msm_gpiomux_install(&sd_card_det, 1);
msm_gpiomux_install(msm_synaptics_configs,
diff --git a/arch/arm/mach-msm/board-8610.c b/arch/arm/mach-msm/board-8610.c
index b4f202d..5f5366f 100644
--- a/arch/arm/mach-msm/board-8610.c
+++ b/arch/arm/mach-msm/board-8610.c
@@ -36,6 +36,7 @@
#ifdef CONFIG_ION_MSM
#include <mach/ion.h>
#endif
+#include <linux/regulator/qpnp-regulator.h>
#include <mach/msm_memtypes.h>
#include <mach/socinfo.h>
#include <mach/board.h>
@@ -48,6 +49,7 @@
#include "platsmp.h"
#include "spm.h"
#include "lpm_resources.h"
+#include "modem_notifier.h"
static struct memtype_reserve msm8610_reserve_table[] __initdata = {
[MEMTYPE_SMI] = {
@@ -93,9 +95,12 @@
void __init msm8610_add_drivers(void)
{
+ msm_init_modem_notifier_list();
+ msm_smd_init();
msm_rpm_driver_init();
msm_lpmrs_module_init();
msm_spm_device_init();
+ qpnp_regulator_init();
msm_thermal_device_init();
if (machine_is_msm8610_rumi())
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index 78e3ca6..7ef6fed 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -652,29 +652,6 @@
#endif
}
-static void ion_adjust_secure_allocation(void)
-{
- int i;
-
- for (i = 0; i < msm8960_ion_pdata.nr; i++) {
- struct ion_platform_heap *heap =
- &(msm8960_ion_pdata.heaps[i]);
-
-
- if (heap->extra_data) {
- switch ((int) heap->type) {
- case ION_HEAP_TYPE_CP:
- if (cpu_is_msm8960()) {
- ((struct ion_cp_heap_pdata *)
- heap->extra_data)->allow_nonsecure_alloc
- = 1;
- }
-
- }
- }
- }
-}
-
static void __init reserve_mdp_memory(void)
{
msm8960_mdp_writeback(msm8960_reserve_table);
@@ -3394,7 +3371,6 @@
mdm_sglte_device.dev.platform_data = &sglte_platform_data;
platform_device_register(&mdm_sglte_device);
}
- ion_adjust_secure_allocation();
}
MACHINE_START(MSM8960_CDP, "QCT MSM8960 CDP")
diff --git a/arch/arm/mach-msm/board-8974-gpiomux.c b/arch/arm/mach-msm/board-8974-gpiomux.c
index d8a9c3e..688c6f7 100644
--- a/arch/arm/mach-msm/board-8974-gpiomux.c
+++ b/arch/arm/mach-msm/board-8974-gpiomux.c
@@ -203,7 +203,6 @@
.func = GPIOMUX_FUNC_GPIO,
.drv = GPIOMUX_DRV_2MA,
.pull = GPIOMUX_PULL_DOWN,
- .dir = GPIOMUX_OUT_LOW,
};
static struct gpiomux_setting hsic_act_cfg = {
@@ -219,6 +218,19 @@
.dir = GPIOMUX_IN,
};
+static struct gpiomux_setting hsic_resume_act_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
+ .dir = GPIOMUX_OUT_LOW,
+};
+
+static struct gpiomux_setting hsic_resume_susp_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
static struct msm_gpiomux_config msm_hsic_configs[] = {
{
.gpio = 144, /*HSIC_STROBE */
@@ -234,6 +246,13 @@
[GPIOMUX_SUSPENDED] = &hsic_sus_cfg,
},
},
+ {
+ .gpio = 80,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &hsic_resume_act_cfg,
+ [GPIOMUX_SUSPENDED] = &hsic_resume_susp_cfg,
+ },
+ },
};
static struct msm_gpiomux_config msm_hsic_hub_configs[] = {
diff --git a/arch/arm/mach-msm/board-9615.c b/arch/arm/mach-msm/board-9615.c
index f609bbc..50f4fd7 100644
--- a/arch/arm/mach-msm/board-9615.c
+++ b/arch/arm/mach-msm/board-9615.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, 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
@@ -625,8 +625,13 @@
#define USB_BAM_PHY_BASE 0x12502000
#define HSIC_BAM_PHY_BASE 0x12542000
#define A2_BAM_PHY_BASE 0x124C2000
-static struct usb_bam_pipe_connect msm_usb_bam_connections[MAX_BAMS][8][2] = {
- [HSUSB_BAM][0][USB_TO_PEER_PERIPHERAL] = {
+static struct usb_bam_pipe_connect msm_usb_bam_connections[] = {
+ {
+ .name = "hsusb-a2-out-0",
+ .bam_type = HSUSB_BAM,
+ .peer_bam = A2_P_BAM,
+ .dir = USB_TO_PEER_PERIPHERAL,
+ .pipe_num = 0,
.src_phy_addr = USB_BAM_PHY_BASE,
.src_pipe_index = 11,
.dst_phy_addr = A2_BAM_PHY_BASE,
@@ -636,7 +641,12 @@
.desc_fifo_base_offset = 0x1700,
.desc_fifo_size = 0x300,
},
- [HSUSB_BAM][0][PEER_PERIPHERAL_TO_USB] = {
+ {
+ .name = "hsusb-a2-in-0",
+ .bam_type = HSUSB_BAM,
+ .peer_bam = A2_P_BAM,
+ .dir = PEER_PERIPHERAL_TO_USB,
+ .pipe_num = 0,
.src_phy_addr = A2_BAM_PHY_BASE,
.src_pipe_index = 1,
.dst_phy_addr = USB_BAM_PHY_BASE,
@@ -646,7 +656,12 @@
.desc_fifo_base_offset = 0x1000,
.desc_fifo_size = 0x100,
},
- [HSUSB_BAM][1][USB_TO_PEER_PERIPHERAL] = {
+ {
+ .name = "hsusb-a2-out-1",
+ .bam_type = HSUSB_BAM,
+ .peer_bam = A2_P_BAM,
+ .dir = USB_TO_PEER_PERIPHERAL,
+ .pipe_num = 1,
.src_phy_addr = USB_BAM_PHY_BASE,
.src_pipe_index = 13,
.dst_phy_addr = A2_BAM_PHY_BASE,
@@ -656,7 +671,12 @@
.desc_fifo_base_offset = 0x2700,
.desc_fifo_size = 0x300,
},
- [HSUSB_BAM][1][PEER_PERIPHERAL_TO_USB] = {
+ {
+ .name = "hsusb-a2-in-1",
+ .bam_type = HSUSB_BAM,
+ .peer_bam = A2_P_BAM,
+ .dir = PEER_PERIPHERAL_TO_USB,
+ .pipe_num = 1,
.src_phy_addr = A2_BAM_PHY_BASE,
.src_pipe_index = 3,
.dst_phy_addr = USB_BAM_PHY_BASE,
@@ -666,7 +686,12 @@
.desc_fifo_base_offset = 0x2000,
.desc_fifo_size = 0x100,
},
- [HSUSB_BAM][2][USB_TO_PEER_PERIPHERAL] = {
+ {
+ .name = "hsusb-a2-out-2",
+ .bam_type = HSUSB_BAM,
+ .peer_bam = A2_P_BAM,
+ .dir = USB_TO_PEER_PERIPHERAL,
+ .pipe_num = 2,
.src_phy_addr = USB_BAM_PHY_BASE,
.src_pipe_index = 15,
.dst_phy_addr = A2_BAM_PHY_BASE,
@@ -676,7 +701,12 @@
.desc_fifo_base_offset = 0x3700,
.desc_fifo_size = 0x300,
},
- [HSUSB_BAM][2][PEER_PERIPHERAL_TO_USB] = {
+ {
+ .name = "hsusb-a2-in-2",
+ .bam_type = HSUSB_BAM,
+ .peer_bam = A2_P_BAM,
+ .dir = PEER_PERIPHERAL_TO_USB,
+ .pipe_num = 2,
.src_phy_addr = A2_BAM_PHY_BASE,
.src_pipe_index = 5,
.dst_phy_addr = USB_BAM_PHY_BASE,
@@ -686,7 +716,12 @@
.desc_fifo_base_offset = 0x3000,
.desc_fifo_size = 0x100,
},
- [HSIC_BAM][0][USB_TO_PEER_PERIPHERAL] = {
+ {
+ .name = "hsic-a2-out-0",
+ .bam_type = HSIC_BAM,
+ .peer_bam = A2_P_BAM,
+ .dir = USB_TO_PEER_PERIPHERAL,
+ .pipe_num = 0,
.src_phy_addr = HSIC_BAM_PHY_BASE,
.src_pipe_index = 1,
.dst_phy_addr = A2_BAM_PHY_BASE,
@@ -696,7 +731,12 @@
.desc_fifo_base_offset = 0x1700,
.desc_fifo_size = 0x300,
},
- [HSIC_BAM][0][PEER_PERIPHERAL_TO_USB] = {
+ {
+ .name = "hsic-a2-in-0",
+ .bam_type = HSIC_BAM,
+ .peer_bam = A2_P_BAM,
+ .dir = PEER_PERIPHERAL_TO_USB,
+ .pipe_num = 0,
.src_phy_addr = A2_BAM_PHY_BASE,
.src_pipe_index = 1,
.dst_phy_addr = HSIC_BAM_PHY_BASE,
@@ -706,7 +746,12 @@
.desc_fifo_base_offset = 0x1000,
.desc_fifo_size = 0x100,
},
- [HSIC_BAM][1][USB_TO_PEER_PERIPHERAL] = {
+ {
+ .name = "hsic-a2-out-1",
+ .bam_type = HSIC_BAM,
+ .peer_bam = A2_P_BAM,
+ .dir = USB_TO_PEER_PERIPHERAL,
+ .pipe_num = 1,
.src_phy_addr = HSIC_BAM_PHY_BASE,
.src_pipe_index = 3,
.dst_phy_addr = A2_BAM_PHY_BASE,
@@ -716,7 +761,12 @@
.desc_fifo_base_offset = 0x2700,
.desc_fifo_size = 0x300,
},
- [HSIC_BAM][1][PEER_PERIPHERAL_TO_USB] = {
+ {
+ .name = "hsic-a2-in-1",
+ .bam_type = HSIC_BAM,
+ .peer_bam = A2_P_BAM,
+ .dir = PEER_PERIPHERAL_TO_USB,
+ .pipe_num = 1,
.src_phy_addr = A2_BAM_PHY_BASE,
.src_pipe_index = 3,
.dst_phy_addr = HSIC_BAM_PHY_BASE,
@@ -726,7 +776,12 @@
.desc_fifo_base_offset = 0x2000,
.desc_fifo_size = 0x100,
},
- [HSIC_BAM][2][USB_TO_PEER_PERIPHERAL] = {
+ {
+ .name = "hsic-a2-out-2",
+ .bam_type = HSIC_BAM,
+ .peer_bam = A2_P_BAM,
+ .dir = USB_TO_PEER_PERIPHERAL,
+ .pipe_num = 2,
.src_phy_addr = HSIC_BAM_PHY_BASE,
.src_pipe_index = 5,
.dst_phy_addr = A2_BAM_PHY_BASE,
@@ -736,7 +791,12 @@
.desc_fifo_base_offset = 0x3700,
.desc_fifo_size = 0x300,
},
- [HSIC_BAM][2][PEER_PERIPHERAL_TO_USB] = {
+ {
+ .name = "hsic-a2-in-2",
+ .bam_type = HSIC_BAM,
+ .peer_bam = A2_P_BAM,
+ .dir = PEER_PERIPHERAL_TO_USB,
+ .pipe_num = 2,
.src_phy_addr = A2_BAM_PHY_BASE,
.src_pipe_index = 5,
.dst_phy_addr = HSIC_BAM_PHY_BASE,
@@ -749,12 +809,9 @@
};
static struct msm_usb_bam_platform_data msm_usb_bam_pdata = {
- .connections = &msm_usb_bam_connections[0][0][0],
-#ifndef CONFIG_USB_CI13XXX_MSM_HSIC
- .usb_active_bam = HSUSB_BAM,
-#else
- .usb_active_bam = HSIC_BAM,
-#endif
+ .connections = &msm_usb_bam_connections[0],
+ .max_connections = sizeof(msm_usb_bam_connections) /
+ sizeof(struct usb_bam_pipe_connect),
.usb_bam_num_pipes = 16,
};
diff --git a/arch/arm/mach-msm/board-9625-gpiomux.c b/arch/arm/mach-msm/board-9625-gpiomux.c
index 1b76441..75aaaec 100644
--- a/arch/arm/mach-msm/board-9625-gpiomux.c
+++ b/arch/arm/mach-msm/board-9625-gpiomux.c
@@ -276,6 +276,57 @@
},
};
+static struct gpiomux_setting qpic_lcdc_a_d = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_10MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting qpic_lcdc_cs = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_10MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting qpic_lcdc_rs = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_10MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting qpic_lcdc_te = {
+ .func = GPIOMUX_FUNC_7,
+ .drv = GPIOMUX_DRV_10MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct msm_gpiomux_config msm9625_qpic_lcdc_configs[] __initdata = {
+ {
+ .gpio = 20, /* a_d */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &qpic_lcdc_a_d,
+ },
+ },
+ {
+ .gpio = 21, /* cs */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &qpic_lcdc_cs,
+ },
+ },
+ {
+ .gpio = 22, /* te */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &qpic_lcdc_te,
+ },
+ },
+ {
+ .gpio = 23, /* rs */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &qpic_lcdc_rs,
+ },
+ },
+};
+
void __init msm9625_init_gpiomux(void)
{
int rc;
@@ -296,4 +347,7 @@
ARRAY_SIZE(mdm9625_cdc_reset_config));
msm_gpiomux_install(sdc2_card_det_config,
ARRAY_SIZE(sdc2_card_det_config));
+ msm_gpiomux_install(msm9625_qpic_lcdc_configs,
+ ARRAY_SIZE(msm9625_qpic_lcdc_configs));
+
}
diff --git a/arch/arm/mach-msm/board-zinc-gpiomux.c b/arch/arm/mach-msm/board-zinc-gpiomux.c
new file mode 100644
index 0000000..ac4daa8
--- /dev/null
+++ b/arch/arm/mach-msm/board-zinc-gpiomux.c
@@ -0,0 +1,29 @@
+/* Copyright (c) 2013, 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/gpio.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <mach/board.h>
+#include <mach/gpiomux.h>
+
+void __init msmzinc_init_gpiomux(void)
+{
+ int rc;
+
+ rc = msm_gpiomux_init_dt();
+ if (rc) {
+ pr_err("%s failed %d\n", __func__, rc);
+ return;
+ }
+}
diff --git a/arch/arm/mach-msm/board-zinc.c b/arch/arm/mach-msm/board-zinc.c
new file mode 100644
index 0000000..fa19e39
--- /dev/null
+++ b/arch/arm/mach-msm/board-zinc.c
@@ -0,0 +1,127 @@
+/* Copyright (c) 2013, 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/err.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/memory.h>
+#include <asm/hardware/gic.h>
+#include <asm/mach/map.h>
+#include <asm/mach/arch.h>
+#include <mach/board.h>
+#include <mach/gpiomux.h>
+#include <mach/msm_iomap.h>
+#include <mach/msm_memtypes.h>
+#include <mach/msm_smd.h>
+#include <mach/restart.h>
+#include <mach/socinfo.h>
+#include <mach/clk-provider.h>
+#include "board-dt.h"
+#include "clock.h"
+#include "devices.h"
+#include "platsmp.h"
+
+static struct memtype_reserve msmzinc_reserve_table[] __initdata = {
+ [MEMTYPE_SMI] = {
+ },
+ [MEMTYPE_EBI0] = {
+ .flags = MEMTYPE_FLAGS_1M_ALIGN,
+ },
+ [MEMTYPE_EBI1] = {
+ .flags = MEMTYPE_FLAGS_1M_ALIGN,
+ },
+};
+
+static int msmzinc_paddr_to_memtype(unsigned int paddr)
+{
+ return MEMTYPE_EBI1;
+}
+
+static struct reserve_info msmzinc_reserve_info __initdata = {
+ .memtype_reserve_table = msmzinc_reserve_table,
+ .paddr_to_memtype = msmzinc_paddr_to_memtype,
+};
+
+void __init msmzinc_reserve(void)
+{
+ reserve_info = &msmzinc_reserve_info;
+ of_scan_flat_dt(dt_scan_for_memory_reserve, msmzinc_reserve_table);
+ msm_reserve();
+}
+
+static void __init msmzinc_early_memory(void)
+{
+ reserve_info = &msmzinc_reserve_info;
+ of_scan_flat_dt(dt_scan_for_memory_hole, msmzinc_reserve_table);
+}
+
+static struct clk_lookup msm_clocks_dummy[] = {
+ CLK_DUMMY("core_clk", BLSP1_UART_CLK, "f991f000.serial", OFF),
+ CLK_DUMMY("iface_clk", BLSP1_UART_CLK, "f991f000.serial", OFF),
+};
+
+static struct clock_init_data msm_dummy_clock_init_data __initdata = {
+ .table = msm_clocks_dummy,
+ .size = ARRAY_SIZE(msm_clocks_dummy),
+};
+
+/*
+ * Used to satisfy dependencies for devices that need to be
+ * run early or in a particular order. Most likely your device doesn't fall
+ * into this category, and thus the driver should not be added here. The
+ * EPROBE_DEFER can satisfy most dependency problems.
+ */
+void __init msmzinc_add_drivers(void)
+{
+ msm_smd_init();
+ msm_clock_init(&msm_dummy_clock_init_data);
+}
+
+static void __init msmzinc_map_io(void)
+{
+ msm_map_zinc_io();
+}
+
+void __init msmzinc_init(void)
+{
+ if (socinfo_init() < 0)
+ pr_err("%s: socinfo_init() failed\n", __func__);
+
+ msmzinc_init_gpiomux();
+ of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+ msmzinc_add_drivers();
+}
+
+void __init msmzinc_init_very_early(void)
+{
+ msmzinc_early_memory();
+}
+
+static const char *msmzinc_dt_match[] __initconst = {
+ "qcom,msmzinc",
+ NULL
+};
+
+DT_MACHINE_START(MSMZINC_DT, "Qualcomm MSM ZINC (Flattened Device Tree)")
+ .map_io = msmzinc_map_io,
+ .init_irq = msm_dt_init_irq,
+ .init_machine = msmzinc_init,
+ .handle_irq = gic_handle_irq,
+ .timer = &msm_dt_timer,
+ .dt_compat = msmzinc_dt_match,
+ .reserve = msmzinc_reserve,
+ .init_very_early = msmzinc_init_very_early,
+ .restart = msm_restart,
+ .smp = &msm8974_smp_ops,
+MACHINE_END
diff --git a/arch/arm/mach-msm/clock-8226.c b/arch/arm/mach-msm/clock-8226.c
index 813b210..8e2b7c9 100644
--- a/arch/arm/mach-msm/clock-8226.c
+++ b/arch/arm/mach-msm/clock-8226.c
@@ -1919,6 +1919,8 @@
};
static struct clk_freq_tbl ftbl_camss_mclk0_1_clk[] = {
+ F_MMSS( 19200000, xo, 1, 0, 0),
+ F_MMSS( 24000000, gpll0, 5, 1, 5),
F_MMSS( 66670000, gpll0, 9, 0, 0),
F_END
};
@@ -3062,7 +3064,8 @@
CLK_LOOKUP("a7sspll", a7sspll.c, "f9011050.qcom,acpuclk"),
/* WCNSS CLOCKS */
- CLK_LOOKUP("xo", xo.c, "fb000000.qcom,wcnss-wlan"),
+ CLK_LOOKUP("xo", xo.c, "fb000000.qcom,wcnss-wlan"),
+ CLK_LOOKUP("rf_clk", cxo_a2.c, "fb000000.qcom,wcnss-wlan"),
/* BUS DRIVER */
CLK_LOOKUP("bus_clk", cnoc_msmbus_clk.c, "msm_config_noc"),
@@ -3094,6 +3097,24 @@
CLK_LOOKUP("core_clk", qdss_clk.c, "fc33d000.etm"),
CLK_LOOKUP("core_clk", qdss_clk.c, "fc33e000.etm"),
CLK_LOOKUP("core_clk", qdss_clk.c, "fc33f000.etm"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc33c000.jtagmm"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc33d000.jtagmm"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc33e000.jtagmm"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc33f000.jtagmm"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc308000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc309000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc30a000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc30b000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc30c000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc30d000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc30e000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc30f000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc310000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc340000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc341000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc342000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc343000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc344000.cti"),
CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc322000.tmc"),
CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc318000.tpiu"),
@@ -3109,6 +3130,24 @@
CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc33d000.etm"),
CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc33e000.etm"),
CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc33f000.etm"),
+ CLK_LOOKUP("core_a_clk", qdss_clk.c, "fc33c000.jtagmm"),
+ CLK_LOOKUP("core_a_clk", qdss_clk.c, "fc33d000.jtagmm"),
+ CLK_LOOKUP("core_a_clk", qdss_clk.c, "fc33e000.jtagmm"),
+ CLK_LOOKUP("core_a_clk", qdss_clk.c, "fc33f000.jtagmm"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc308000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc309000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc30a000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc30b000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc30c000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc30d000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc30e000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc30f000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc310000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc340000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc341000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc342000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc343000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc344000.cti"),
/* HSUSB-OTG Clocks */
CLK_LOOKUP("xo", xo.c, "f9a55000.usb"),
@@ -3143,6 +3182,11 @@
CLK_LOOKUP("bus_clk", gcc_ce1_axi_clk.c, "qseecom"),
CLK_LOOKUP("core_clk_src", ce1_clk_src.c, "qseecom"),
+ CLK_LOOKUP("core_clk", gcc_ce1_clk.c, "scm"),
+ CLK_LOOKUP("iface_clk", gcc_ce1_ahb_clk.c, "scm"),
+ CLK_LOOKUP("bus_clk", gcc_ce1_axi_clk.c, "scm"),
+ CLK_LOOKUP("core_clk_src", ce1_clk_src.c, "scm"),
+
/* SDCC */
CLK_LOOKUP("iface_clk", gcc_sdcc1_ahb_clk.c, "f9824000.qcom,sdcc"),
CLK_LOOKUP("core_clk", gcc_sdcc1_apps_clk.c, "f9824000.qcom,sdcc"),
@@ -3350,6 +3394,15 @@
CLK_LOOKUP("", mmss_mmssnoc_bto_ahb_clk.c, ""),
CLK_LOOKUP("", mmss_mmssnoc_axi_clk.c, ""),
CLK_LOOKUP("", mmss_s0_axi_clk.c, ""),
+
+ /* Audio clocks */
+ CLK_LOOKUP("osr_clk", div_clk1.c, "msm-dai-q6-dev.224"),
+ CLK_LOOKUP("osr_clk", div_clk1.c, "msm-dai-q6-dev.4106"),
+ CLK_LOOKUP("osr_clk", div_clk1.c, "msm-dai-q6-dev.16384"),
+ CLK_LOOKUP("osr_clk", div_clk1.c, "msm-dai-q6-dev.16386"),
+ CLK_LOOKUP("osr_clk", div_clk1.c, "msm-dai-q6-dev.16390"),
+ CLK_LOOKUP("osr_clk", div_clk1.c, "msm-dai-q6-dev.16391"),
+
};
static struct clk_lookup msm_clocks_8226_rumi[] = {
@@ -3387,6 +3440,12 @@
static void __init msm8226_clock_post_init(void)
{
+ /*
+ * Hold an active set vote for CXO; this is because CXO is expected
+ * to remain on whenever CPUs aren't power collapsed.
+ */
+ clk_prepare_enable(&xo_a_clk.c);
+
/* Set rates for single-rate clocks. */
clk_set_rate(&usb_hs_system_clk_src.c,
usb_hs_system_clk_src.freq_tbl[0].freq_hz);
@@ -3472,11 +3531,8 @@
*/
clk_set_rate(&mmssnoc_ahb_a_clk.c, 40000000);
- /*
- * Hold an active set vote for CXO; this is because CXO is expected
- * to remain on whenever CPUs aren't power collapsed.
- */
- clk_prepare_enable(&xo_a_clk.c);
+ /* Set an initial rate (fmax at nominal) on the MMSSNOC AXI clock */
+ clk_set_rate(&axi_clk_src.c, 200000000);
enable_rpm_scaling();
diff --git a/arch/arm/mach-msm/clock-8610.c b/arch/arm/mach-msm/clock-8610.c
index 5690730..0aee878 100644
--- a/arch/arm/mach-msm/clock-8610.c
+++ b/arch/arm/mach-msm/clock-8610.c
@@ -3047,35 +3047,65 @@
CLK_LOOKUP("mem_a_clk", bimc_msmbus_a_clk.c, "msm_bimc"),
CLK_LOOKUP("mem_clk", bimc_acpu_a_clk.c, ""),
- CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-tmc-etr"),
- CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-tpiu"),
- CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-replicator"),
- CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-tmc-etf"),
- CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-funnel-merg"),
- CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-funnel-in0"),
- CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-funnel-in1"),
- CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-funnel-kpss"),
- CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-funnel-mmss"),
- CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-stm"),
- CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-etm0"),
- CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-etm1"),
- CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-etm2"),
- CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-etm3"),
+ /* CoreSight clocks */
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc326000.tmc"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc320000.tpiu"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc324000.replicator"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc325000.tmc"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc323000.funnel"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc321000.funnel"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc322000.funnel"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc355000.funnel"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc302000.stm"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc34c000.etm"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc34d000.etm"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc34e000.etm"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc34f000.etm"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc301000.csr"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc310000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc311000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc312000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc313000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc314000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc315000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc316000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc317000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc318000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc351000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc352000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc353000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc354000.cti"),
- CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-tmc-etr"),
- CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-tpiu"),
- CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-replicator"),
- CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-tmc-etf"),
- CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-funnel-merg"),
- CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-funnel-in0"),
- CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-funnel-in1"),
- CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-funnel-kpss"),
- CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-funnel-mmss"),
- CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-stm"),
- CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-etm0"),
- CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-etm1"),
- CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-etm2"),
- CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-etm3"),
+
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc326000.tmc"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc320000.tpiu"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc324000.replicator"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc325000.tmc"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc323000.funnel"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc321000.funnel"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc322000.funnel"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc355000.funnel"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc302000.stm"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc34c000.etm"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc34d000.etm"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc34e000.etm"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc34f000.etm"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc301000.csr"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc310000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc311000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc312000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc313000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc314000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc315000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc316000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc317000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc318000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc351000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc352000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc353000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc354000.cti"),
+
+
CLK_LOOKUP("core_clk_src", blsp1_qup1_spi_apps_clk_src.c, ""),
CLK_LOOKUP("core_clk_src", blsp1_qup2_spi_apps_clk_src.c, ""),
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index 78e3259..c5594e2 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -4815,6 +4815,11 @@
CLK_LOOKUP("bus_clk", gcc_ce1_axi_clk.c, "qseecom"),
CLK_LOOKUP("core_clk_src", ce1_clk_src.c, "qseecom"),
+ CLK_LOOKUP("core_clk", gcc_ce1_clk.c, "scm"),
+ CLK_LOOKUP("iface_clk", gcc_ce1_ahb_clk.c, "scm"),
+ CLK_LOOKUP("bus_clk", gcc_ce1_axi_clk.c, "scm"),
+ CLK_LOOKUP("core_clk_src", ce1_clk_src.c, "scm"),
+
CLK_LOOKUP("core_clk", gcc_gp1_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_gp2_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_gp3_clk.c, ""),
@@ -4851,6 +4856,7 @@
CLK_LOOKUP("phy_clk", gcc_usb_hsic_clk.c, "msm_hsic_host"),
CLK_LOOKUP("cal_clk", gcc_usb_hsic_io_cal_clk.c, "msm_hsic_host"),
CLK_LOOKUP("core_clk", gcc_usb_hsic_system_clk.c, "msm_hsic_host"),
+ CLK_LOOKUP("osr_clk", div_clk1.c, "msm-dai-q6-dev.16384"),
CLK_LOOKUP("ref_clk", div_clk2.c, "msm_smsc_hub"),
CLK_LOOKUP("iface_clk", gcc_usb_hs_ahb_clk.c, "msm_ehci_host"),
CLK_LOOKUP("core_clk", gcc_usb_hs_system_clk.c, "msm_ehci_host"),
diff --git a/arch/arm/mach-msm/clock-mdss-8974.c b/arch/arm/mach-msm/clock-mdss-8974.c
index 91e96b7..8e7f1fa 100644
--- a/arch/arm/mach-msm/clock-mdss-8974.c
+++ b/arch/arm/mach-msm/clock-mdss-8974.c
@@ -192,11 +192,12 @@
static int mdss_dsi_pll_pixel_set_rate(struct clk *c, unsigned long rate)
{
- if (pll_initialized)
+ if (pll_initialized) {
+ pll_pclk_rate = (rate * 3) / 2;
+ pr_debug("%s: pll_pclk_rate=%d\n", __func__, pll_pclk_rate);
return 0;
- else {
- pr_err("%s: Configure Byte clk first\n",
- __func__);
+ } else {
+ pr_err("%s: Configure Byte clk first\n", __func__);
return -EINVAL;
}
}
@@ -256,11 +257,9 @@
REG_W(0x20, mdss_dsi_base + 0x029c); /* EFUSE CFG */
dsi_pll_rate = rate;
+ pll_byte_clk_rate = rate;
- pll_byte_clk_rate = 53000000;
- pll_pclk_rate = 105000000;
-
- pr_debug("%s: **** PLL initialized success\n", __func__);
+ pr_debug("%s: PLL initialized. bcl=%d\n", __func__, pll_byte_clk_rate);
pll_initialized = 1;
return 0;
diff --git a/arch/arm/mach-msm/clock-pll.c b/arch/arm/mach-msm/clock-pll.c
index c82058b..d2be1f9 100644
--- a/arch/arm/mach-msm/clock-pll.c
+++ b/arch/arm/mach-msm/clock-pll.c
@@ -529,6 +529,18 @@
BUG();
}
+ if (!pll_clk_is_enabled(c))
+ return HANDOFF_DISABLED_CLK;
+
+ /*
+ * Do not call pll_clk_enable() since that function can assume
+ * the PLL is not in use when it's called.
+ */
+ remote_spin_lock(&pll_lock);
+ pll_control->pll[PLL_BASE + pll->id].votes |= BIT(1);
+ pll_control->pll[PLL_BASE + pll->id].on = 1;
+ remote_spin_unlock(&pll_lock);
+
return HANDOFF_ENABLED_CLK;
}
@@ -572,10 +584,22 @@
spin_unlock_irqrestore(&soft_vote_lock, flags);
}
+static enum handoff pll_acpu_vote_clk_handoff(struct clk *c)
+{
+ if (pll_vote_clk_handoff(c) == HANDOFF_DISABLED_CLK)
+ return HANDOFF_DISABLED_CLK;
+
+ if (pll_acpu_vote_clk_enable(c))
+ return HANDOFF_DISABLED_CLK;
+
+ return HANDOFF_ENABLED_CLK;
+}
+
struct clk_ops clk_ops_pll_acpu_vote = {
.enable = pll_acpu_vote_clk_enable,
.disable = pll_acpu_vote_clk_disable,
.is_enabled = pll_vote_clk_is_enabled,
+ .handoff = pll_acpu_vote_clk_handoff,
};
static void __init __set_fsm_mode(void __iomem *mode_reg,
diff --git a/arch/arm/mach-msm/cpufreq.c b/arch/arm/mach-msm/cpufreq.c
index 46af77d..d02ab66 100644
--- a/arch/arm/mach-msm/cpufreq.c
+++ b/arch/arm/mach-msm/cpufreq.c
@@ -32,6 +32,17 @@
#include "acpuclock.h"
+struct cpufreq_work_struct {
+ struct work_struct work;
+ struct cpufreq_policy *policy;
+ struct completion complete;
+ int frequency;
+ int status;
+};
+
+static DEFINE_PER_CPU(struct cpufreq_work_struct, cpufreq_work);
+static struct workqueue_struct *msm_cpufreq_wq;
+
struct cpufreq_suspend_t {
struct mutex suspend_mutex;
int device_suspended;
@@ -99,6 +110,15 @@
return ret;
}
+static void set_cpu_work(struct work_struct *work)
+{
+ struct cpufreq_work_struct *cpu_work =
+ container_of(work, struct cpufreq_work_struct, work);
+
+ cpu_work->status = set_cpu_freq(cpu_work->policy, cpu_work->frequency);
+ complete(&cpu_work->complete);
+}
+
static int msm_cpufreq_target(struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation)
@@ -107,11 +127,17 @@
int index;
struct cpufreq_frequency_table *table;
+ struct cpufreq_work_struct *cpu_work = NULL;
+ cpumask_var_t mask;
+
if (!cpu_active(policy->cpu)) {
pr_info("cpufreq: cpu %d is not active.\n", policy->cpu);
return -ENODEV;
}
+ if (!alloc_cpumask_var(&mask, GFP_KERNEL))
+ return -ENOMEM;
+
mutex_lock(&per_cpu(cpufreq_suspend, policy->cpu).suspend_mutex);
if (per_cpu(cpufreq_suspend, policy->cpu).device_suspended) {
@@ -133,9 +159,27 @@
policy->cpu, target_freq, relation,
policy->min, policy->max, table[index].frequency);
- ret = set_cpu_freq(policy, table[index].frequency);
+ cpu_work = &per_cpu(cpufreq_work, policy->cpu);
+ cpu_work->policy = policy;
+ cpu_work->frequency = table[index].frequency;
+ cpu_work->status = -ENODEV;
+
+ cpumask_clear(mask);
+ cpumask_set_cpu(policy->cpu, mask);
+ if (cpumask_equal(mask, ¤t->cpus_allowed)) {
+ ret = set_cpu_freq(cpu_work->policy, cpu_work->frequency);
+ goto done;
+ } else {
+ cancel_work_sync(&cpu_work->work);
+ INIT_COMPLETION(cpu_work->complete);
+ queue_work_on(policy->cpu, msm_cpufreq_wq, &cpu_work->work);
+ wait_for_completion(&cpu_work->complete);
+ }
+
+ ret = cpu_work->status;
done:
+ free_cpumask_var(mask);
mutex_unlock(&per_cpu(cpufreq_suspend, policy->cpu).suspend_mutex);
return ret;
}
@@ -218,6 +262,7 @@
int cur_freq;
int index;
struct cpufreq_frequency_table *table;
+ struct cpufreq_work_struct *cpu_work = NULL;
table = cpufreq_frequency_get_table(policy->cpu);
if (table == NULL)
@@ -247,7 +292,7 @@
CPUFREQ_RELATION_H, &index) &&
cpufreq_frequency_table_target(policy, table, cur_freq,
CPUFREQ_RELATION_L, &index)) {
- pr_info("%s: cpu%d at invalid freq: %d\n", __func__,
+ pr_info("cpufreq: cpu%d at invalid freq: %d\n",
policy->cpu, cur_freq);
return -EINVAL;
}
@@ -268,6 +313,10 @@
policy->cpuinfo.transition_latency =
acpuclk_get_switch_time() * NSEC_PER_USEC;
+ cpu_work = &per_cpu(cpufreq_work, policy->cpu);
+ INIT_WORK(&cpu_work->work, set_cpu_work);
+ init_completion(&cpu_work->complete);
+
return 0;
}
@@ -355,6 +404,7 @@
per_cpu(cpufreq_suspend, cpu).device_suspended = 0;
}
+ msm_cpufreq_wq = create_workqueue("msm-cpufreq");
register_hotcpu_notifier(&msm_cpufreq_cpu_notifier);
return cpufreq_register_driver(&msm_cpufreq_driver);
diff --git a/arch/arm/mach-msm/hotplug.c b/arch/arm/mach-msm/hotplug.c
index 5cd5057..0e97c27 100644
--- a/arch/arm/mach-msm/hotplug.c
+++ b/arch/arm/mach-msm/hotplug.c
@@ -70,6 +70,11 @@
int platform_cpu_kill(unsigned int cpu)
{
+ int ret;
+
+ ret = msm_pm_wait_cpu_shutdown(cpu);
+ if (ret)
+ return 0;
return 1;
}
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index 327212e..3fa2d5e 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -598,6 +598,7 @@
void msm_map_msm7x30_io(void);
void msm_map_fsm9xxx_io(void);
void msm_map_8974_io(void);
+void msm_map_zinc_io(void);
void msm_map_msm8625_io(void);
void msm_map_msm9625_io(void);
void msm_init_irq(void);
@@ -606,6 +607,7 @@
void msm_8974_reserve(void);
void msm_8974_very_early(void);
void msm_8974_init_gpiomux(void);
+void msmzinc_init_gpiomux(void);
void msm9625_init_gpiomux(void);
void msm_map_mpq8092_io(void);
void mpq8092_init_gpiomux(void);
diff --git a/arch/arm/mach-msm/include/mach/iommu_domains.h b/arch/arm/mach-msm/include/mach/iommu_domains.h
index a104a42..d908a65 100644
--- a/arch/arm/mach-msm/include/mach/iommu_domains.h
+++ b/arch/arm/mach-msm/include/mach/iommu_domains.h
@@ -94,7 +94,7 @@
extern int msm_iommu_map_extra(struct iommu_domain *domain,
unsigned long start_iova,
- unsigned long phys_addr,
+ phys_addr_t phys_addr,
unsigned long size,
unsigned long page_size,
int cached);
@@ -104,7 +104,7 @@
unsigned long size,
unsigned long page_size);
-extern int msm_iommu_map_contig_buffer(unsigned long phys,
+extern int msm_iommu_map_contig_buffer(phys_addr_t phys,
unsigned int domain_no,
unsigned int partition_no,
unsigned long size,
@@ -148,7 +148,7 @@
static inline int msm_iommu_map_extra(struct iommu_domain *domain,
unsigned long start_iova,
- unsigned long phys_addr,
+ phys_addr_t phys_addr,
unsigned long size,
unsigned long page_size,
int cached)
@@ -163,7 +163,7 @@
{
}
-static inline int msm_iommu_map_contig_buffer(unsigned long phys,
+static inline int msm_iommu_map_contig_buffer(phys_addr_t phys,
unsigned int domain_no,
unsigned int partition_no,
unsigned long size,
diff --git a/arch/arm/mach-msm/include/mach/ipa.h b/arch/arm/mach-msm/include/mach/ipa.h
index 2010abb..cc03c48 100644
--- a/arch/arm/mach-msm/include/mach/ipa.h
+++ b/arch/arm/mach-msm/include/mach/ipa.h
@@ -652,6 +652,8 @@
int teth_bridge_connect(struct teth_bridge_connect_params *connect_params);
+int teth_bridge_set_aggr_params(struct teth_aggr_params *aggr_params);
+
#else /* CONFIG_IPA */
static inline int a2_mux_open_channel(enum a2_mux_logical_channel_id lcid,
@@ -1073,6 +1075,12 @@
return -EPERM;
}
+static inline int teth_bridge_set_aggr_params(struct teth_aggr_params
+ *aggr_params)
+{
+ return -EPERM;
+}
+
#endif /* CONFIG_IPA*/
#endif /* _IPA_H_ */
diff --git a/arch/arm/mach-msm/include/mach/memory.h b/arch/arm/mach-msm/include/mach/memory.h
index 8c53ea5..56c4afd 100644
--- a/arch/arm/mach-msm/include/mach/memory.h
+++ b/arch/arm/mach-msm/include/mach/memory.h
@@ -1,7 +1,7 @@
/* arch/arm/mach-msm/include/mach/memory.h
*
* Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -93,21 +93,27 @@
#endif
#define MAX_HOLE_ADDRESS (PHYS_OFFSET + 0x10000000)
-extern unsigned long memory_hole_offset;
-extern unsigned long memory_hole_start;
-extern unsigned long memory_hole_end;
+extern phys_addr_t memory_hole_offset;
+extern phys_addr_t memory_hole_start;
+extern phys_addr_t memory_hole_end;
+extern unsigned long memory_hole_align;
+extern unsigned long virtual_hole_start;
+extern unsigned long virtual_hole_end;
#ifdef CONFIG_DONT_MAP_HOLE_AFTER_MEMBANK0
void find_memory_hole(void);
#define MEM_HOLE_END_PHYS_OFFSET (memory_hole_end)
-#define MEM_HOLE_PAGE_OFFSET (PAGE_OFFSET + memory_hole_offset)
+#define MEM_HOLE_PAGE_OFFSET (PAGE_OFFSET + memory_hole_offset + \
+ memory_hole_align)
#define __phys_to_virt(phys) \
+ (unsigned long)\
((MEM_HOLE_END_PHYS_OFFSET && ((phys) >= MEM_HOLE_END_PHYS_OFFSET)) ? \
(phys) - MEM_HOLE_END_PHYS_OFFSET + MEM_HOLE_PAGE_OFFSET : \
(phys) - PHYS_OFFSET + PAGE_OFFSET)
#define __virt_to_phys(virt) \
+ (unsigned long)\
((MEM_HOLE_END_PHYS_OFFSET && ((virt) >= MEM_HOLE_PAGE_OFFSET)) ? \
(virt) - MEM_HOLE_PAGE_OFFSET + MEM_HOLE_END_PHYS_OFFSET : \
(virt) - PAGE_OFFSET + PHYS_OFFSET)
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-zinc.h b/arch/arm/mach-msm/include/mach/msm_iomap-zinc.h
new file mode 100644
index 0000000..8283622
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-zinc.h
@@ -0,0 +1,42 @@
+/* Copyright (c) 2013, 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 __ASM_ARCH_MSM_IOMAP_zinc_H
+#define __ASM_ARCH_MSM_IOMAP_zinc_H
+
+/* Physical base address and size of peripherals.
+ * Ordered by the virtual base addresses they will be mapped at.
+ *
+ * If you add or remove entries here, you'll want to edit the
+ * io desc array in arch/arm/mach-msm/io.c to reflect your
+ * changes.
+ *
+ */
+
+#define MSMZINC_SHARED_RAM_PHYS 0x0FA00000
+
+#define MSMZINC_QGIC_DIST_PHYS 0xF9000000
+#define MSMZINC_QGIC_DIST_SIZE SZ_4K
+
+#define MSMZINC_QGIC_CPU_PHYS 0xF9002000
+#define MSMZINC_QGIC_CPU_SIZE SZ_4K
+
+#define MSMZINC_TLMM_PHYS 0xFD510000
+#define MSMZINC_TLMM_SIZE SZ_16K
+
+#ifdef CONFIG_DEBUG_MSMZINC_UART
+#define MSM_DEBUG_UART_BASE IOMEM(0xFA71E000)
+#define MSM_DEBUG_UART_PHYS 0xF991E000
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap.h b/arch/arm/mach-msm/include/mach/msm_iomap.h
index ebb096e..9cf9517 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap.h
@@ -54,7 +54,8 @@
defined(CONFIG_ARCH_MSM7X25) || defined(CONFIG_ARCH_MSM7X01A) || \
defined(CONFIG_ARCH_MSM8625) || defined(CONFIG_ARCH_MSM7X30) || \
defined(CONFIG_ARCH_MSM9625) || defined(CONFIG_ARCH_MPQ8092) || \
- defined(CONFIG_ARCH_MSM8226) || defined(CONFIG_ARCH_MSM8610)
+ defined(CONFIG_ARCH_MSM8226) || defined(CONFIG_ARCH_MSM8610) || \
+ defined(CONFIG_ARCH_MSMZINC)
/* Unified iomap */
@@ -129,6 +130,7 @@
#include "msm_iomap-8064.h"
#include "msm_iomap-9615.h"
#include "msm_iomap-8974.h"
+#include "msm_iomap-zinc.h"
#include "msm_iomap-9625.h"
#include "msm_iomap-8092.h"
#include "msm_iomap-8226.h"
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v2/apr.h b/arch/arm/mach-msm/include/mach/qdsp6v2/apr.h
index 59908e6..c21f6e5 100644
--- a/arch/arm/mach-msm/include/mach/qdsp6v2/apr.h
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/apr.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013, 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
@@ -82,6 +82,7 @@
#define APR_SVC_ADSP_CVS 0x0A
#define APR_SVC_ADSP_CVP 0x0B
#define APR_SVC_USM 0x0C
+#define APR_SVC_LSM 0x0D
#define APR_SVC_VIDC 0x16
#define APR_SVC_MAX 0x17
diff --git a/arch/arm/mach-msm/include/mach/scm.h b/arch/arm/mach-msm/include/mach/scm.h
index 8a06fe3..0cc7bbf 100644
--- a/arch/arm/mach-msm/include/mach/scm.h
+++ b/arch/arm/mach-msm/include/mach/scm.h
@@ -21,7 +21,7 @@
#define SCM_SVC_SSD 0x7
#define SCM_SVC_FUSE 0x8
#define SCM_SVC_PWR 0x9
-#define SCM_SVC_CP 0xC
+#define SCM_SVC_MP 0xC
#define SCM_SVC_DCVS 0xD
#define SCM_SVC_TZSCHEDULER 0xFC
diff --git a/arch/arm/mach-msm/include/mach/subsystem_restart.h b/arch/arm/mach-msm/include/mach/subsystem_restart.h
index 1f6ca66..67f643e 100644
--- a/arch/arm/mach-msm/include/mach/subsystem_restart.h
+++ b/arch/arm/mach-msm/include/mach/subsystem_restart.h
@@ -21,9 +21,8 @@
struct subsys_device;
enum {
- RESET_SOC = 1,
+ RESET_SOC = 0,
RESET_SUBSYS_COUPLED,
- RESET_SUBSYS_INDEPENDENT,
RESET_LEVEL_MAX
};
@@ -60,7 +59,7 @@
#if defined(CONFIG_MSM_SUBSYSTEM_RESTART)
-extern int get_restart_level(void);
+extern int subsys_get_restart_level(struct subsys_device *dev);
extern int subsystem_restart_dev(struct subsys_device *dev);
extern int subsystem_restart(const char *name);
extern int subsystem_crashed(const char *name);
@@ -75,7 +74,7 @@
#else
-static inline int get_restart_level(void)
+static inline int subsys_get_restart_level(struct subsys_device *dev)
{
return 0;
}
diff --git a/arch/arm/mach-msm/include/mach/usb_bam.h b/arch/arm/mach-msm/include/mach/usb_bam.h
index b3fb8af..5a77d99 100644
--- a/arch/arm/mach-msm/include/mach/usb_bam.h
+++ b/arch/arm/mach-msm/include/mach/usb_bam.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2013, 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
@@ -14,22 +14,36 @@
#define _USB_BAM_H_
#include "sps.h"
#include <mach/ipa.h>
+#include <linux/usb/msm_hsusb.h>
-/**
- * SPS Pipes direction.
- *
- * USB_TO_PEER_PERIPHERAL USB (as Producer) to other
- * peer peripheral.
- * PEER_PERIPHERAL_TO_USB Other Peripheral to
- * USB (as consumer).
- */
+enum usb_bam {
+ SSUSB_BAM = 0,
+ HSUSB_BAM,
+ HSIC_BAM,
+ MAX_BAMS,
+};
+
+enum peer_bam {
+ A2_P_BAM = 0,
+ QDSS_P_BAM,
+ IPA_P_BAM,
+ MAX_PEER_BAMS,
+};
+
enum usb_bam_pipe_dir {
USB_TO_PEER_PERIPHERAL,
PEER_PERIPHERAL_TO_USB,
};
+enum usb_pipe_mem_type {
+ SPS_PIPE_MEM = 0, /* Default, SPS dedicated pipe memory */
+ USB_PRIVATE_MEM, /* USB's private memory */
+ SYSTEM_MEM, /* System RAM, requires allocation */
+};
+
struct usb_bam_connect_ipa_params {
- u8 idx;
+ u8 src_idx;
+ u8 dst_idx;
u32 *src_pipe;
u32 *dst_pipe;
enum usb_bam_pipe_dir dir;
@@ -44,29 +58,100 @@
unsigned long data);
};
+/**
+* struct usb_bam_event_info: suspend/resume event information.
+* @event: holds event data.
+* @callback: suspend/resume callback.
+* @param: port num (for suspend) or NULL (for resume).
+* @event_w: holds work queue parameters.
+*/
+struct usb_bam_event_info {
+ struct sps_register_event event;
+ int (*callback)(void *);
+ void *param;
+ struct work_struct event_w;
+};
+
+/**
+* struct usb_bam_pipe_connect: pipe connection information
+* between USB/HSIC BAM and another BAM. USB/HSIC BAM can be
+* either src BAM or dst BAM
+* @name: pipe description.
+* @mem_type: type of memory used for BAM FIFOs
+* @src_phy_addr: src bam physical address.
+* @src_pipe_index: src bam pipe index.
+* @dst_phy_addr: dst bam physical address.
+* @dst_pipe_index: dst bam pipe index.
+* @data_fifo_base_offset: data fifo offset.
+* @data_fifo_size: data fifo size.
+* @desc_fifo_base_offset: descriptor fifo offset.
+* @desc_fifo_size: descriptor fifo size.
+* @data_mem_buf: data fifo buffer.
+* @desc_mem_buf: descriptor fifo buffer.
+* @wake_event: event for wakeup.
+* @enabled: true if pipe is enabled.
+*/
+struct usb_bam_pipe_connect {
+ const char *name;
+ u32 pipe_num;
+ enum usb_pipe_mem_type mem_type;
+ enum usb_bam_pipe_dir dir;
+ enum usb_bam bam_type;
+ enum peer_bam peer_bam;
+ u32 src_phy_addr;
+ u32 src_pipe_index;
+ u32 dst_phy_addr;
+ u32 dst_pipe_index;
+ u32 data_fifo_base_offset;
+ u32 data_fifo_size;
+ u32 desc_fifo_base_offset;
+ u32 desc_fifo_size;
+ struct sps_mem_buffer data_mem_buf;
+ struct sps_mem_buffer desc_mem_buf;
+ struct usb_bam_event_info wake_event;
+ bool enabled;
+};
+
+/**
+ * struct msm_usb_bam_platform_data: pipe connection information
+ * between USB/HSIC BAM and another BAM. USB/HSIC BAM can be
+ * either src BAM or dst BAM
+ * @connections: holds all pipe connections data.
+ * @usb_bam_num_pipes: max number of pipes to use.
+ * @active_conn_num: number of active pipe connections.
+ * @usb_base_address: BAM physical address.
+ * @ignore_core_reset_ack: BAM can ignore ACK from USB core during PIPE RESET
+ * @disable_clk_gating: Disable clock gating
+ */
+struct msm_usb_bam_platform_data {
+ struct usb_bam_pipe_connect *connections;
+ u8 max_connections;
+ int usb_bam_num_pipes;
+ u32 usb_base_address;
+ bool ignore_core_reset_ack;
+ bool reset_on_connect[MAX_BAMS];
+ bool disable_clk_gating;
+};
+
#ifdef CONFIG_USB_BAM
/**
- * Connect USB-to-Periperal SPS connection.
+ * Connect USB-to-Peripheral SPS connection.
*
- * This function returns the allocated pipes number.
+ * This function returns the allocated pipe number.
*
* @idx - Connection index.
*
- * @src_pipe_idx - allocated pipe index - USB as a
- * source (output)
- *
- * @dst_pipe_idx - allocated pipe index - USB as a
- * destination (output)
+ * @bam_pipe_idx - allocated pipe index.
*
* @return 0 on success, negative value on error
*
*/
-int usb_bam_connect(u8 idx, u32 *src_pipe_idx, u32 *dst_pipe_idx);
+int usb_bam_connect(u8 idx, u32 *bam_pipe_idx);
/**
* Connect USB-to-IPA SPS connection.
*
- * This function returns the allocated pipes number adn clnt handles.
+ * This function returns the allocated pipes number and clnt handles.
*
* @ipa_params - in/out parameters
*
@@ -78,14 +163,12 @@
/**
* Disconnect USB-to-IPA SPS connection.
*
- * @idx - Connection index.
- *
* @ipa_params - in/out parameters
*
* @return 0 on success, negative value on error
*
*/
-int usb_bam_disconnect_ipa(u8 idx,
+int usb_bam_disconnect_ipa(
struct usb_bam_connect_ipa_params *ipa_params);
/**
@@ -99,13 +182,11 @@
*
*/
int usb_bam_register_wake_cb(u8 idx,
- int (*callback)(void *), void* param);
+ int (*callback)(void *), void *param);
/**
* Register a callback for peer BAM reset.
*
- * @idx - Connection index.
- *
* @callback - the callback function that will be called in USB
* driver upon a peer bam reset
*
@@ -114,8 +195,7 @@
* @return 0 on success, negative value on error
*
*/
-int usb_bam_register_peer_reset_cb(u8 idx,
- int (*callback)(void *), void *param);
+int usb_bam_register_peer_reset_cb(int (*callback)(void *), void *param);
/**
* Disconnect USB-to-Periperal SPS connection.
@@ -129,9 +209,7 @@
/**
* Returns usb bam connection parameters.
*
- * @conn_idx - Connection index.
- *
- * @usb_bam_pipe_dir - Usb pipe direction to/from peripheral.
+ * @idx - Connection index.
*
* @usb_bam_handle - Usb bam handle.
*
@@ -143,16 +221,17 @@
*
* @data_fifo - Data fifo parameters.
*
+ * @return pipe index on success, negative value on error.
*/
-void get_bam2bam_connection_info(u8 conn_idx, enum usb_bam_pipe_dir pipe_dir,
+int get_bam2bam_connection_info(u8 idx,
u32 *usb_bam_handle, u32 *usb_bam_pipe_idx, u32 *peer_pipe_idx,
struct sps_mem_buffer *desc_fifo, struct sps_mem_buffer *data_fifo);
/**
- * Resets the entire USB BAM.
+ * Resets the USB BAM that has A2 pipes
*
*/
-int usb_bam_reset(void);
+int usb_bam_a2_reset(void);
/**
* Indicates if the client of the USB BAM is ready to start
@@ -162,9 +241,41 @@
*
*/
int usb_bam_client_ready(bool ready);
+/**
+* Returns qdss index from the connections array.
+*
+* @num - The qdss pipe number.
+*
+* @return pipe index on success, negative value on error
+*/
+int usb_bam_get_qdss_idx(u8 num);
+
+/**
+* Saves qdss core number.
+*
+* @qdss_core - The qdss core name.
+*/
+void usb_bam_set_qdss_core(const char *qdss_core);
+
+/**
+* Indicates if the client of the USB BAM is ready to start
+* sending/receiving transfers.
+*
+* @name - Core name (ssusb/hsusb/hsic).
+*
+* @client - Usb pipe peer (a2, ipa, qdss...)
+*
+* @dir - In (from peer to usb) or out (from usb to peer)
+*
+* @num - Pipe number.
+*
+* @return 0 on success, negative value on error
+*/
+int usb_bam_get_connection_idx(const char *name, enum peer_bam client,
+ enum usb_bam_pipe_dir dir, u32 num);
#else
-static inline int usb_bam_connect(u8 idx, u32 *src_pipe_idx, u32 *dst_pipe_idx)
+static inline int usb_bam_connect(u8 idx, u32 *bam_pipe_idx)
{
return -ENODEV;
}
@@ -175,7 +286,7 @@
return -ENODEV;
}
-static inline int usb_bam_disconnect_ipa(u8 idx,
+static inline int usb_bam_disconnect_ipa(
struct usb_bam_connect_ipa_params *ipa_params)
{
return -ENODEV;
@@ -187,8 +298,8 @@
return -ENODEV;
}
-static inline int usb_bam_register_peer_reset_cb(u8 idx,
- int (*callback)(void *), void *param)
+static inline int usb_bam_register_peer_reset_cb(
+ int (*callback)(void *), void *param)
{
return -ENODEV;
}
@@ -198,15 +309,14 @@
return -ENODEV;
}
-static inline void get_bam2bam_connection_info(u8 conn_idx,
- enum usb_bam_pipe_dir pipe_dir, u32 *usb_bam_handle,
- u32 *usb_bam_pipe_idx, u32 *peer_pipe_idx,
+static inline int get_bam2bam_connection_info(u8 idx,
+ u32 *usb_bam_handle, u32 *usb_bam_pipe_idx, u32 *peer_pipe_idx,
struct sps_mem_buffer *desc_fifo, struct sps_mem_buffer *data_fifo)
{
- return;
+ return -ENODEV;
}
-static inline int usb_bam_reset(void)
+static inline int usb_bam_a2_reset(void)
{
return -ENODEV;
}
@@ -216,5 +326,20 @@
return -ENODEV;
}
+static inline int usb_bam_get_qdss_idx(u8 num)
+{
+ return -ENODEV;
+}
+
+static inline void usb_bam_set_qdss_core(const char *qdss_core)
+{
+ return;
+}
+
+static inline int usb_bam_get_connection_idx(const char *name,
+ enum peer_bam client, enum usb_bam_pipe_dir dir, u32 num)
+{
+ return -ENODEV;
+}
#endif
#endif /* _USB_BAM_H_ */
diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c
index fd096ec..c71a79a 100644
--- a/arch/arm/mach-msm/io.c
+++ b/arch/arm/mach-msm/io.c
@@ -323,6 +323,29 @@
}
#endif /* CONFIG_ARCH_MSM8974 */
+#ifdef CONFIG_ARCH_MSMZINC
+static struct map_desc msm_zinc_io_desc[] __initdata = {
+ MSM_CHIP_DEVICE(QGIC_DIST, MSMZINC),
+ MSM_CHIP_DEVICE(QGIC_CPU, MSMZINC),
+ MSM_CHIP_DEVICE(TLMM, MSMZINC),
+ {
+ .virtual = (unsigned long) MSM_SHARED_RAM_BASE,
+ .length = MSM_SHARED_RAM_SIZE,
+ .type = MT_DEVICE,
+ },
+#ifdef CONFIG_DEBUG_MSMZINC_UART
+ MSM_DEVICE(DEBUG_UART),
+#endif
+};
+
+void __init msm_map_zinc_io(void)
+{
+ msm_shared_ram_phys = MSMZINC_SHARED_RAM_PHYS;
+ msm_map_io(msm_zinc_io_desc, ARRAY_SIZE(msm_zinc_io_desc));
+ of_scan_flat_dt(msm_scan_dt_map_imem, NULL);
+}
+#endif /* CONFIG_ARCH_MSMZINC */
+
#ifdef CONFIG_ARCH_MSM7X30
static struct map_desc msm7x30_io_desc[] __initdata = {
MSM_CHIP_DEVICE(VIC, MSM7X30),
diff --git a/arch/arm/mach-msm/iommu_domains.c b/arch/arm/mach-msm/iommu_domains.c
index f24dc87..5228abc 100644
--- a/arch/arm/mach-msm/iommu_domains.c
+++ b/arch/arm/mach-msm/iommu_domains.c
@@ -55,7 +55,7 @@
int msm_iommu_map_extra(struct iommu_domain *domain,
unsigned long start_iova,
- unsigned long phy_addr,
+ phys_addr_t phy_addr,
unsigned long size,
unsigned long page_size,
int prot)
@@ -135,7 +135,7 @@
static int msm_iommu_map_iova_phys(struct iommu_domain *domain,
unsigned long iova,
- unsigned long phys,
+ phys_addr_t phys,
unsigned long size,
int cached)
{
@@ -167,7 +167,7 @@
}
-int msm_iommu_map_contig_buffer(unsigned long phys,
+int msm_iommu_map_contig_buffer(phys_addr_t phys,
unsigned int domain_no,
unsigned int partition_no,
unsigned long size,
diff --git a/arch/arm/mach-msm/jtag-mm.c b/arch/arm/mach-msm/jtag-mm.c
index af05995..8a67614 100644
--- a/arch/arm/mach-msm/jtag-mm.c
+++ b/arch/arm/mach-msm/jtag-mm.c
@@ -124,6 +124,8 @@
#define DBGBCRn(n) (0x140 + (n * 4))
#define DBGWVRn(n) (0x180 + (n * 4))
#define DBGWCRn(n) (0x1C0 + (n * 4))
+#define DBGOSLAR (0x300)
+#define DBGOSLSR (0x304)
#define DBGPRCR (0x310)
#define DBGITMISCOUT (0xEF8)
#define DBGITMISCIN (0xEFC)
@@ -131,6 +133,7 @@
#define DBGCLAIMCLR (0xFA4)
#define DBGDSCR_MASK (0x6C30FC3C)
+#define OSLOCK_MAGIC (0xC5ACCE55)
#define MAX_DBG_STATE_SIZE (90)
#define MAX_ETM_STATE_SIZE (78)
@@ -140,6 +143,7 @@
#define ARCH_V3_5 (0x25)
#define ARM_DEBUG_ARCH_V7B (0x3)
+#define ARM_DEBUG_ARCH_V7p1 (0x5)
#define etm_write(etm, val, off) \
__raw_writel(val, etm->base + off)
@@ -221,12 +225,40 @@
uint8_t nr_ctxid_cmp;
struct etm_cpu_ctx *cpu_ctx[NR_CPUS];
bool save_restore_enabled[NR_CPUS];
+ bool os_lock_present;
};
static struct etm_ctx etm;
static struct clk *clock[NR_CPUS];
+static void etm_os_lock(struct etm_cpu_ctx *etmdata)
+{
+ uint32_t count;
+
+ if (etm.os_lock_present) {
+ etm_write(etmdata, OSLOCK_MAGIC, ETMOSLAR);
+ /* Ensure OS lock is set before proceeding */
+ mb();
+ for (count = TIMEOUT_US; BVAL(etm_read(etmdata, ETMSR), 1) != 1
+ && count > 0; count--)
+ udelay(1);
+ if (count == 0)
+ pr_err_ratelimited(
+ "timeout while setting prog bit, ETMSR: %#x\n",
+ etm_read(etmdata, ETMSR));
+ }
+}
+
+static void etm_os_unlock(struct etm_cpu_ctx *etmdata)
+{
+ if (etm.os_lock_present) {
+ /* Ensure all writes are complete before clearing OS lock */
+ mb();
+ etm_write(etmdata, 0x0, ETMOSLAR);
+ }
+}
+
static void etm_set_pwrdwn(struct etm_cpu_ctx *etmdata)
{
uint32_t etmcr;
@@ -273,6 +305,8 @@
switch (etm.arch) {
case ETM_ARCH_V3_5:
+ etm_os_lock(etmdata);
+
etmdata->state[i++] = etm_read(etmdata, ETMTRIGGER);
etmdata->state[i++] = etm_read(etmdata, ETMASICCTLR);
etmdata->state[i++] = etm_read(etmdata, ETMSR);
@@ -346,6 +380,8 @@
switch (etm.arch) {
case ETM_ARCH_V3_5:
+ etm_os_lock(etmdata);
+
etm_clr_pwrdwn(etmdata);
etm_write(etmdata, etmdata->state[i++], ETMTRIGGER);
etm_write(etmdata, etmdata->state[i++], ETMASICCTLR);
@@ -406,6 +442,8 @@
* bit
*/
etm_write(etmdata, etmdata->state[i++], ETMCR);
+
+ etm_os_unlock(etmdata);
break;
default:
pr_err_ratelimited("unsupported etm arch %d in %s\n", etm.arch,
@@ -422,22 +460,46 @@
i = 0;
DBG_UNLOCK(dbgdata);
- dbgdata->state[i++] = dbg_read(dbgdata, DBGWFAR);
- dbgdata->state[i++] = dbg_read(dbgdata, DBGVCR);
- for (j = 0; j < dbg.nr_bp; j++) {
- dbgdata->state[i++] = dbg_read(dbgdata, DBGBVRn(j));
- dbgdata->state[i++] = dbg_read(dbgdata, DBGBCRn(j));
+ switch (dbg.arch) {
+ case ARM_DEBUG_ARCH_V7B:
+ dbgdata->state[i++] = dbg_read(dbgdata, DBGWFAR);
+ dbgdata->state[i++] = dbg_read(dbgdata, DBGVCR);
+ for (j = 0; j < dbg.nr_bp; j++) {
+ dbgdata->state[i++] = dbg_read(dbgdata, DBGBVRn(j));
+ dbgdata->state[i++] = dbg_read(dbgdata, DBGBCRn(j));
+ }
+ for (j = 0; j < dbg.nr_wp; j++) {
+ dbgdata->state[i++] = dbg_read(dbgdata, DBGWVRn(j));
+ dbgdata->state[i++] = dbg_read(dbgdata, DBGWCRn(j));
+ }
+ dbgdata->state[i++] = dbg_read(dbgdata, DBGPRCR);
+ dbgdata->state[i++] = dbg_read(dbgdata, DBGDTRTXext);
+ dbgdata->state[i++] = dbg_read(dbgdata, DBGDTRRXext);
+ dbgdata->state[i++] = dbg_read(dbgdata, DBGDSCRext);
+ break;
+ case ARM_DEBUG_ARCH_V7p1:
+ /* Set OS Lock */
+ dbg_write(dbgdata, OSLOCK_MAGIC, DBGOSLAR);
+ /* Ensure OS lock is set before proceeding */
+ mb();
+
+ dbgdata->state[i++] = dbg_read(dbgdata, DBGWFAR);
+ dbgdata->state[i++] = dbg_read(dbgdata, DBGVCR);
+ for (j = 0; j < dbg.nr_bp; j++) {
+ dbgdata->state[i++] = dbg_read(dbgdata, DBGBVRn(j));
+ dbgdata->state[i++] = dbg_read(dbgdata, DBGBCRn(j));
+ }
+ for (j = 0; j < dbg.nr_wp; j++) {
+ dbgdata->state[i++] = dbg_read(dbgdata, DBGWVRn(j));
+ dbgdata->state[i++] = dbg_read(dbgdata, DBGWCRn(j));
+ }
+ dbgdata->state[i++] = dbg_read(dbgdata, DBGPRCR);
+ dbgdata->state[i++] = dbg_read(dbgdata, DBGCLAIMCLR);
+ dbgdata->state[i++] = dbg_read(dbgdata, DBGDTRTXext);
+ dbgdata->state[i++] = dbg_read(dbgdata, DBGDTRRXext);
+ dbgdata->state[i++] = dbg_read(dbgdata, DBGDSCRext);
+ break;
}
- for (j = 0; j < dbg.nr_wp; j++) {
- dbgdata->state[i++] = dbg_read(dbgdata, DBGWVRn(j));
- dbgdata->state[i++] = dbg_read(dbgdata, DBGWCRn(j));
- }
- dbgdata->state[i++] = dbg_read(dbgdata, DBGPRCR);
- dbgdata->state[i++] = dbg_read(dbgdata, DBGCLAIMSET);
- dbgdata->state[i++] = dbg_read(dbgdata, DBGCLAIMCLR);
- dbgdata->state[i++] = dbg_read(dbgdata, DBGDTRTXext);
- dbgdata->state[i++] = dbg_read(dbgdata, DBGDTRRXext);
- dbgdata->state[i++] = dbg_read(dbgdata, DBGDSCRext);
DBG_LOCK(dbgdata);
}
@@ -449,23 +511,55 @@
i = 0;
DBG_UNLOCK(dbgdata);
- dbg_write(dbgdata, dbgdata->state[i++], DBGWFAR);
- dbg_write(dbgdata, dbgdata->state[i++], DBGVCR);
- for (j = 0; j < dbg.nr_bp; j++) {
- dbg_write(dbgdata, dbgdata->state[i++], DBGBVRn(j));
- dbg_write(dbgdata, dbgdata->state[i++], DBGBCRn(j));
- }
- for (j = 0; j < dbg.nr_wp; j++) {
- dbg_write(dbgdata, dbgdata->state[i++], DBGWVRn(j));
- dbg_write(dbgdata, dbgdata->state[i++], DBGWCRn(j));
- }
- dbg_write(dbgdata, dbgdata->state[i++], DBGPRCR);
- dbg_write(dbgdata, dbgdata->state[i++], DBGCLAIMSET);
- dbg_write(dbgdata, dbgdata->state[i++], DBGCLAIMCLR);
- dbg_write(dbgdata, dbgdata->state[i++], DBGDTRTXext);
- dbg_write(dbgdata, dbgdata->state[i++], DBGDTRRXext);
- dbg_write(dbgdata, dbgdata->state[i++] & DBGDSCR_MASK,
+ switch (dbg.arch) {
+ case ARM_DEBUG_ARCH_V7B:
+ dbg_write(dbgdata, dbgdata->state[i++], DBGWFAR);
+ dbg_write(dbgdata, dbgdata->state[i++], DBGVCR);
+ for (j = 0; j < dbg.nr_bp; j++) {
+ dbg_write(dbgdata, dbgdata->state[i++], DBGBVRn(j));
+ dbg_write(dbgdata, dbgdata->state[i++], DBGBCRn(j));
+ }
+ for (j = 0; j < dbg.nr_wp; j++) {
+ dbg_write(dbgdata, dbgdata->state[i++], DBGWVRn(j));
+ dbg_write(dbgdata, dbgdata->state[i++], DBGWCRn(j));
+ }
+ dbg_write(dbgdata, dbgdata->state[i++], DBGPRCR);
+ dbg_write(dbgdata, dbgdata->state[i++], DBGDTRTXext);
+ dbg_write(dbgdata, dbgdata->state[i++], DBGDTRRXext);
+ dbg_write(dbgdata, dbgdata->state[i++] & DBGDSCR_MASK,
DBGDSCRext);
+ break;
+ case ARM_DEBUG_ARCH_V7p1:
+ /* Set OS lock. Lock will already be set after power collapse
+ * but this write is included to ensure it is set.
+ */
+ dbg_write(dbgdata, OSLOCK_MAGIC, DBGOSLAR);
+ /* Ensure OS lock is set before proceeding */
+ mb();
+
+ dbg_write(dbgdata, dbgdata->state[i++], DBGWFAR);
+ dbg_write(dbgdata, dbgdata->state[i++], DBGVCR);
+ for (j = 0; j < dbg.nr_bp; j++) {
+ dbg_write(dbgdata, dbgdata->state[i++], DBGBVRn(j));
+ dbg_write(dbgdata, dbgdata->state[i++], DBGBCRn(j));
+ }
+ for (j = 0; j < dbg.nr_wp; j++) {
+ dbg_write(dbgdata, dbgdata->state[i++], DBGWVRn(j));
+ dbg_write(dbgdata, dbgdata->state[i++], DBGWCRn(j));
+ }
+ dbg_write(dbgdata, dbgdata->state[i++], DBGPRCR);
+ dbg_write(dbgdata, dbgdata->state[i++], DBGCLAIMSET);
+ dbg_write(dbgdata, dbgdata->state[i++], DBGDTRTXext);
+ dbg_write(dbgdata, dbgdata->state[i++], DBGDTRRXext);
+ dbg_write(dbgdata, dbgdata->state[i++] & DBGDSCR_MASK,
+ DBGDSCRext);
+ /* Ensure all writes are completing before clearing OS lock */
+ mb();
+ dbg_write(dbgdata, 0x0, DBGOSLAR);
+ /* Ensure OS lock is cleared before proceeding */
+ mb();
+ break;
+ }
DBG_LOCK(dbgdata);
}
@@ -529,6 +623,17 @@
return true;
}
+static void __devinit etm_os_lock_init(struct etm_cpu_ctx *etmdata)
+{
+ uint32_t etmoslsr;
+
+ etmoslsr = etm_read(etmdata, ETMOSLSR);
+ if (!BVAL(etmoslsr, 0) && !BVAL(etmoslsr, 3))
+ etm.os_lock_present = false;
+ else
+ etm.os_lock_present = true;
+}
+
static void __devinit etm_init_arch_data(void *info)
{
uint32_t etmidr;
@@ -541,6 +646,8 @@
*/
ETM_UNLOCK(etmdata);
+ etm_os_lock_init(etmdata);
+
etm_clr_pwrdwn(etmdata);
/* Set prog bit. It will be set from reset but this is included to
* ensure it is set
@@ -578,7 +685,7 @@
etm.cpu_ctx[cpu] = etmdata;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "etm-base");
etmdata->base = devm_ioremap(dev, res->start, resource_size(res));
if (!etmdata->base)
@@ -590,8 +697,11 @@
if (!etmdata->state)
return -ENOMEM;
- smp_call_function_single(0, etm_init_arch_data, etmdata, 1);
-
+ if (cpu == 0) {
+ if (smp_call_function_single(cpu, etm_init_arch_data,
+ etmdata, 1))
+ dev_err(dev, "Jtagmm: ETM arch init failed\n");
+ }
if (etm_arch_supported(etm.arch)) {
if (scm_get_feat_version(TZ_DBG_ETM_FEAT_ID) < TZ_DBG_ETM_VER)
etm.save_restore_enabled[cpu] = true;
@@ -606,6 +716,7 @@
{
switch (arch) {
case ARM_DEBUG_ARCH_V7B:
+ case ARM_DEBUG_ARCH_V7p1:
break;
default:
return false;
@@ -642,7 +753,7 @@
dbg.cpu_ctx[cpu] = dbgdata;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "debug-base");
dbgdata->base = devm_ioremap(dev, res->start, resource_size(res));
if (!dbgdata->base)
@@ -654,8 +765,11 @@
if (!dbgdata->state)
return -ENOMEM;
- smp_call_function_single(0, dbg_init_arch_data, dbgdata, 1);
-
+ if (cpu == 0) {
+ if (smp_call_function_single(cpu, dbg_init_arch_data,
+ dbgdata, 1))
+ dev_err(dev, "Jtagmm: Dbg arch init failed\n");
+ }
if (dbg_arch_supported(dbg.arch)) {
if (scm_get_feat_version(TZ_DBG_ETM_FEAT_ID) < TZ_DBG_ETM_VER)
dbg.save_restore_enabled[cpu] = true;
diff --git a/arch/arm/mach-msm/krait-regulator.c b/arch/arm/mach-msm/krait-regulator.c
index 8fe69d9..953f941d 100644
--- a/arch/arm/mach-msm/krait-regulator.c
+++ b/arch/arm/mach-msm/krait-regulator.c
@@ -28,6 +28,7 @@
#include <linux/regulator/of_regulator.h>
#include <linux/regulator/krait-regulator.h>
#include <linux/debugfs.h>
+#include <linux/syscore_ops.h>
#include <mach/msm_iomap.h>
#include "spm.h"
@@ -292,27 +293,6 @@
return 0;
}
-int krait_power_mdd_enable(int cpu_num, bool on)
-{
- /*
- * Expected to be called when the cpu goes to retention mode as a part
- * of idle power collapse. IT is guaranteed that cpu won't be put in
- * retention while being hotplugged out
- */
- struct krait_power_vreg *kvreg = per_cpu(krait_vregs, cpu_num);
-
- if (!on && kvreg->mode == LDO_MODE) {
- pr_debug("%s using LDO - cannot turn off MDD\n", kvreg->name);
- return -EINVAL;
- }
-
- if (on && kvreg->mode == LDO_MODE)
- return 0;
-
- __krait_power_mdd_enable(kvreg, on);
- return 0;
-}
-
static int switch_to_using_hs(struct krait_power_vreg *kvreg)
{
if (kvreg->mode == HS_MODE)
@@ -342,8 +322,6 @@
krait_masked_write(kvreg, APC_PWR_GATE_CTL,
LDO_PWR_DWN_MASK, LDO_PWR_DWN_MASK);
- /* turn off MDD since LDO is not used */
- __krait_power_mdd_enable(kvreg, false);
kvreg->mode = HS_MODE;
pr_debug("%s using BHS\n", kvreg->name);
return 0;
@@ -362,9 +340,6 @@
if (kvreg->mode == LDO_MODE)
switch_to_using_hs(kvreg);
- /* turn on MDD since LDO is being turned on */
- __krait_power_mdd_enable(kvreg, true);
-
set_krait_ldo_uv(kvreg, kvreg->uV - kvreg->ldo_delta_uV);
/*
@@ -792,8 +767,7 @@
int rc;
mutex_lock(&pvreg->krait_power_vregs_lock);
- if (kvreg->mode == LDO_MODE)
- __krait_power_mdd_enable(kvreg, true);
+ __krait_power_mdd_enable(kvreg, true);
kvreg->online = true;
rc = _get_optimum_mode(rdev, kvreg->uV, kvreg->uV, kvreg->load_uA);
if (rc < 0)
@@ -823,8 +797,7 @@
goto dis_err;
rc = _set_voltage(rdev, kvreg->uV, kvreg->uV);
- if (kvreg->mode == LDO_MODE)
- __krait_power_mdd_enable(kvreg, false);
+ __krait_power_mdd_enable(kvreg, false);
dis_err:
mutex_unlock(&pvreg->krait_power_vregs_lock);
return rc;
@@ -889,6 +862,8 @@
/* setup the bandgap that configures the reference to the LDO */
writel_relaxed(0x00000190, kvreg->mdd_base + MDD_CONFIG_CTL);
+ /* Enable MDD */
+ writel_relaxed(0x00000002, kvreg->mdd_base + MDD_MODE);
mb();
}
@@ -1112,6 +1087,26 @@
{}
};
+static int boot_cpu_mdd_off(void)
+{
+ struct krait_power_vreg *kvreg = per_cpu(krait_vregs, 0);
+
+ __krait_power_mdd_enable(kvreg, false);
+ return 0;
+}
+
+static void boot_cpu_mdd_on(void)
+{
+ struct krait_power_vreg *kvreg = per_cpu(krait_vregs, 0);
+
+ __krait_power_mdd_enable(kvreg, true);
+}
+
+static struct syscore_ops boot_cpu_mdd_ops = {
+ .suspend = boot_cpu_mdd_off,
+ .resume = boot_cpu_mdd_on,
+};
+
static int __devinit krait_pdn_probe(struct platform_device *pdev)
{
int rc;
@@ -1172,6 +1167,7 @@
dent = debugfs_create_dir(KRAIT_REGULATOR_DRIVER_NAME, NULL);
debugfs_create_file("retention_uV",
0644, dent, the_gang, &retention_fops);
+ register_syscore_ops(&boot_cpu_mdd_ops);
return 0;
}
diff --git a/arch/arm/mach-msm/lpm_levels.c b/arch/arm/mach-msm/lpm_levels.c
index 8194721..aa33f2c 100644
--- a/arch/arm/mach-msm/lpm_levels.c
+++ b/arch/arm/mach-msm/lpm_levels.c
@@ -28,6 +28,8 @@
MSM_LPM_LVL_DBG_IDLE_LIMITS = BIT(1),
};
+#define MAX_STR_LEN 30
+
static int msm_lpm_lvl_dbg_msk;
module_param_named(
@@ -41,6 +43,48 @@
static DEFINE_PER_CPU(int , lpm_permitted_level);
static DEFINE_PER_CPU(struct atomic_notifier_head, lpm_notify_head);
+static int msm_pm_get_sleep_mode_value(struct device_node *node,
+ const char *key, uint32_t *sleep_mode_val)
+{
+ int i;
+ struct lpm_lookup_table {
+ uint32_t modes;
+ const char *mode_name;
+ };
+ struct lpm_lookup_table pm_sm_lookup[] = {
+ {MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT,
+ "wfi"},
+ {MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT,
+ "ramp_down_and_wfi"},
+ {MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE,
+ "standalone_pc"},
+ {MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
+ "pc"},
+ {MSM_PM_SLEEP_MODE_RETENTION,
+ "retention"},
+ {MSM_PM_SLEEP_MODE_POWER_COLLAPSE_SUSPEND,
+ "pc_suspend"},
+ {MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN,
+ "pc_no_xo_shutdown"}
+ };
+ int ret;
+ const char *mode_name;
+
+ ret = of_property_read_string(node, key, &mode_name);
+ if (!ret) {
+ ret = -EINVAL;
+ for (i = 0; i < ARRAY_SIZE(pm_sm_lookup); i++) {
+ if (!strncmp(mode_name, pm_sm_lookup[i].mode_name,
+ MAX_STR_LEN)) {
+ *sleep_mode_val = pm_sm_lookup[i].modes;
+ ret = 0;
+ break;
+ }
+ }
+ }
+ return ret;
+}
+
static void msm_lpm_level_update(void)
{
unsigned int lpm_level;
@@ -343,19 +387,19 @@
level->available = false;
key = "qcom,mode";
- ret = of_property_read_u32(node, key, &val);
+ ret = msm_pm_get_sleep_mode_value(node, key, &val);
if (ret)
goto fail;
level->sleep_mode = val;
key = "qcom,xo";
- ret = of_property_read_u32(node, key, &val);
+ ret = msm_lpm_get_xo_value(node, key, &val);
if (ret)
goto fail;
level->rs_limits.pxo = val;
key = "qcom,l2";
- ret = of_property_read_u32(node, key, &val);
+ ret = msm_lpm_get_l2_cache_value(node, key, &val);
if (ret)
goto fail;
level->rs_limits.l2_cache = val;
diff --git a/arch/arm/mach-msm/lpm_resources.c b/arch/arm/mach-msm/lpm_resources.c
index 60184b4..f0e5ebd 100644
--- a/arch/arm/mach-msm/lpm_resources.c
+++ b/arch/arm/mach-msm/lpm_resources.c
@@ -51,29 +51,39 @@
#define MAX_RS_SIZE (4)
#define IS_RPM_CTL(rs) \
(!strncmp(rs->name, "rpm_ctl", MAX_RS_NAME))
+#define MAX_STR_LEN 30
static bool msm_lpm_beyond_limits_vdd_dig(struct msm_rpmrs_limits *limits);
static void msm_lpm_aggregate_vdd_dig(struct msm_rpmrs_limits *limits);
static void msm_lpm_flush_vdd_dig(int notify_rpm);
static void msm_lpm_notify_vdd_dig(struct msm_rpm_notifier_data
*rpm_notifier_cb);
+static int msm_lpm_init_value_vdd_dig(struct device_node *node,
+ char *key, uint32_t *default_value);
static bool msm_lpm_beyond_limits_vdd_mem(struct msm_rpmrs_limits *limits);
static void msm_lpm_aggregate_vdd_mem(struct msm_rpmrs_limits *limits);
static void msm_lpm_flush_vdd_mem(int notify_rpm);
static void msm_lpm_notify_vdd_mem(struct msm_rpm_notifier_data
*rpm_notifier_cb);
+static int msm_lpm_init_value_vdd_mem(struct device_node *node,
+ char *key, uint32_t *default_value);
+
static bool msm_lpm_beyond_limits_pxo(struct msm_rpmrs_limits *limits);
static void msm_lpm_aggregate_pxo(struct msm_rpmrs_limits *limits);
static void msm_lpm_flush_pxo(int notify_rpm);
static void msm_lpm_notify_pxo(struct msm_rpm_notifier_data
*rpm_notifier_cb);
+static int msm_lpm_init_value_pxo(struct device_node *node,
+ char *key, uint32_t *default_value);
static bool msm_lpm_beyond_limits_l2(struct msm_rpmrs_limits *limits);
static void msm_lpm_flush_l2(int notify_rpm);
static void msm_lpm_aggregate_l2(struct msm_rpmrs_limits *limits);
+static int msm_lpm_init_value_l2(struct device_node *node,
+ char *key, uint32_t *default_value);
static void msm_lpm_flush_rpm_ctl(int notify_rpm);
@@ -127,8 +137,14 @@
void (*flush)(int notify_rpm);
void (*notify)(struct msm_rpm_notifier_data *rpm_notifier_cb);
struct kobj_attribute ko_attr;
+ int (*init_value)(struct device_node *node,
+ char *key, uint32_t *default_value);
};
+struct lpm_lookup_table {
+ uint32_t modes;
+ const char *mode_name;
+};
static struct msm_lpm_resource msm_lpm_l2 = {
.name = "l2",
@@ -138,6 +154,7 @@
.notify = NULL,
.valid = false,
.ko_attr = RPMRS_ATTR(l2),
+ .init_value = msm_lpm_init_value_l2,
};
static struct msm_lpm_resource msm_lpm_vdd_dig = {
@@ -148,6 +165,7 @@
.notify = msm_lpm_notify_vdd_dig,
.valid = false,
.ko_attr = RPMRS_ATTR(vdd_dig),
+ .init_value = msm_lpm_init_value_vdd_dig,
};
static struct msm_lpm_resource msm_lpm_vdd_mem = {
@@ -158,6 +176,7 @@
.notify = msm_lpm_notify_vdd_mem,
.valid = false,
.ko_attr = RPMRS_ATTR(vdd_mem),
+ .init_value = msm_lpm_init_value_vdd_mem,
};
static struct msm_lpm_resource msm_lpm_pxo = {
@@ -168,6 +187,7 @@
.notify = msm_lpm_notify_pxo,
.valid = false,
.ko_attr = RPMRS_ATTR(pxo),
+ .init_value = msm_lpm_init_value_pxo,
};
static struct msm_lpm_resource *msm_lpm_resources[] = {
@@ -444,6 +464,12 @@
__func__, lpm);
}
+static int msm_lpm_init_value_l2(struct device_node *node,
+ char *key, uint32_t *default_value)
+{
+ return msm_lpm_get_l2_cache_value(node, key, default_value);
+}
+
static void msm_lpm_flush_l2(int notify_rpm)
{
struct msm_lpm_resource *rs = &msm_lpm_l2;
@@ -451,6 +477,34 @@
msm_lpm_set_l2_mode(rs->sleep_value, notify_rpm);
}
+int msm_lpm_get_l2_cache_value(struct device_node *node,
+ char *key, uint32_t *l2_val)
+{
+ int i;
+ struct lpm_lookup_table l2_mode_lookup[] = {
+ {MSM_LPM_L2_CACHE_HSFS_OPEN, "l2_cache_pc"},
+ {MSM_LPM_L2_CACHE_GDHS, "l2_cache_gdhs"},
+ {MSM_LPM_L2_CACHE_RETENTION, "l2_cache_retention"},
+ {MSM_LPM_L2_CACHE_ACTIVE, "l2_cache_active"}
+ };
+ const char *l2_str;
+ int ret;
+
+ ret = of_property_read_string(node, key, &l2_str);
+ if (!ret) {
+ ret = -EINVAL;
+ for (i = 0; i < ARRAY_SIZE(l2_mode_lookup); i++) {
+ if (!strncmp(l2_str, l2_mode_lookup[i].mode_name,
+ MAX_STR_LEN)) {
+ *l2_val = l2_mode_lookup[i].modes;
+ ret = 0;
+ break;
+ }
+ }
+ }
+ return ret;
+}
+
/* RPM CTL */
static void msm_lpm_flush_rpm_ctl(int notify_rpm)
{
@@ -484,6 +538,12 @@
return ret;
}
+static int msm_lpm_init_value_vdd_dig(struct device_node *node,
+ char *key, uint32_t *default_value)
+{
+ return of_property_read_u32(node, key, default_value);
+}
+
static void msm_lpm_aggregate_vdd_dig(struct msm_rpmrs_limits *limits)
{
struct msm_lpm_resource *rs = &msm_lpm_vdd_dig;
@@ -570,6 +630,12 @@
msm_lpm_notify_common(rpm_notifier_cb, rs);
}
+static int msm_lpm_init_value_vdd_mem(struct device_node *node,
+ char *key, uint32_t *default_value)
+{
+ return of_property_read_u32(node, key, default_value);
+}
+
/*PXO*/
static bool msm_lpm_beyond_limits_pxo(struct msm_rpmrs_limits *limits)
{
@@ -628,11 +694,43 @@
msm_lpm_notify_common(rpm_notifier_cb, rs);
}
+static int msm_lpm_init_value_pxo(struct device_node *node,
+ char *key, uint32_t *default_value)
+{
+ return msm_lpm_get_xo_value(node, key, default_value);
+}
+
static inline bool msm_lpm_use_mpm(struct msm_rpmrs_limits *limits)
{
return (limits->pxo == MSM_LPM_PXO_OFF);
}
+int msm_lpm_get_xo_value(struct device_node *node,
+ char *key, uint32_t *xo_val)
+{
+ int i;
+ struct lpm_lookup_table pxo_mode_lookup[] = {
+ {MSM_LPM_PXO_OFF, "xo_off"},
+ {MSM_LPM_PXO_ON, "xo_on"}
+ };
+ const char *xo_str;
+ int ret;
+
+ ret = of_property_read_string(node, key, &xo_str);
+ if (!ret) {
+ ret = -EINVAL;
+ for (i = 0; i < ARRAY_SIZE(pxo_mode_lookup); i++) {
+ if (!strncmp(xo_str, pxo_mode_lookup[i].mode_name,
+ MAX_STR_LEN)) {
+ *xo_val = pxo_mode_lookup[i].modes;
+ ret = 0;
+ break;
+ }
+ }
+ }
+ return ret;
+}
+
/* LPM levels interface */
bool msm_lpm_level_beyond_limit(struct msm_rpmrs_limits *limits)
{
@@ -797,7 +895,7 @@
struct msm_lpm_resource *rs = NULL;
const char *val;
int i;
- uint32_t resource_type;
+ bool local_resource;
key = "qcom,name";
ret = of_property_read_string(node, key, &val);
@@ -822,8 +920,7 @@
}
key = "qcom,init-value";
- ret = of_property_read_u32(node, key,
- &rs->rs_data.default_value);
+ ret = rs->init_value(node, key, &rs->rs_data.default_value);
if (ret) {
pr_err("%s():Failed to read %s\n", __func__, key);
goto fail;
@@ -831,18 +928,13 @@
rs->rs_data.value = rs->rs_data.default_value;
- key = "qcom,resource-type";
- ret = of_property_read_u32(node, key, &resource_type);
- if (ret) {
- pr_err("Failed to read resource-type\n");
- goto fail;
- }
+ key = "qcom,local-resource-type";
+ local_resource = of_property_read_bool(node, key);
- switch (resource_type) {
- case MSM_LPM_RPM_RS_TYPE:
+ if (!local_resource) {
key = "qcom,type";
ret = of_property_read_u32(node, key,
- &rs->rs_data.type);
+ &rs->rs_data.type);
if (ret) {
pr_err("Failed to read type\n");
goto fail;
@@ -873,15 +965,9 @@
goto fail;
}
/* fall through */
-
- case MSM_LPM_LOCAL_RS_TYPE:
- rs->valid = true;
- break;
- default:
- pr_err("%s: Invalid resource type %d", __func__,
- resource_type);
- goto fail;
}
+
+ rs->valid = true;
}
msm_rpm_register_notifier(&msm_lpm_rpm_nblk);
msm_lpm_init_rpm_ctl();
diff --git a/arch/arm/mach-msm/lpm_resources.h b/arch/arm/mach-msm/lpm_resources.h
index 1a2d72d..105cfe6 100644
--- a/arch/arm/mach-msm/lpm_resources.h
+++ b/arch/arm/mach-msm/lpm_resources.h
@@ -17,15 +17,15 @@
#include "test-lpm.h"
enum {
- MSM_LPM_PXO_OFF = 0,
- MSM_LPM_PXO_ON = 1,
+ MSM_LPM_PXO_OFF,
+ MSM_LPM_PXO_ON
};
enum {
- MSM_LPM_L2_CACHE_HSFS_OPEN = 0,
- MSM_LPM_L2_CACHE_GDHS = 1,
- MSM_LPM_L2_CACHE_RETENTION = 2,
- MSM_LPM_L2_CACHE_ACTIVE = 3,
+ MSM_LPM_L2_CACHE_HSFS_OPEN,
+ MSM_LPM_L2_CACHE_GDHS,
+ MSM_LPM_L2_CACHE_RETENTION,
+ MSM_LPM_L2_CACHE_ACTIVE,
};
struct msm_rpmrs_limits {
@@ -99,6 +99,24 @@
uint32_t msm_pm_get_vdd_dig(struct msm_rpmrs_limits *limits);
/**
+ * msm_lpm_get_xo_value() - get the enum value for xo
+ * @node pointer to the device node
+ * @key pxo property key
+ * @xo_val xo enum value
+ */
+int msm_lpm_get_xo_value(struct device_node *node,
+ char *key, uint32_t *xo_val);
+
+/**
+ * msm_lpm_get_l2_cache_value() - get the enum value for l2 cache
+ * @node pointer to the device node
+ * @key l2 cache property key
+ * @l2_val l2 mode enum value
+ */
+int msm_lpm_get_l2_cache_value(struct device_node *node,
+ char *key, uint32_t *l2_val);
+
+/**
* struct msm_lpm_sleep_data - abstraction to get sleep data
* @limits: pointer to the msm_rpmrs_limits structure
* @kernel_sleep: kernel sleep time as decided by the power calculation
diff --git a/arch/arm/mach-msm/mdm.c b/arch/arm/mach-msm/mdm.c
index fd8c878..7474215 100644
--- a/arch/arm/mach-msm/mdm.c
+++ b/arch/arm/mach-msm/mdm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013, 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
@@ -119,7 +119,7 @@
CHARM_DBG("%s: setting AP2MDM_ERRFATAL high for a non graceful reset\n",
__func__);
- if (get_restart_level() == RESET_SOC)
+ if (subsys_get_restart_level(charm_subsys) == RESET_SOC)
pm8xxx_stay_on();
charm_disable_irqs();
@@ -237,7 +237,7 @@
static void charm_fatal_fn(struct work_struct *work)
{
pr_info("Reseting the charm due to an errfatal\n");
- if (get_restart_level() == RESET_SOC)
+ if (subsys_get_restart_level(charm_subsys) == RESET_SOC)
pm8xxx_stay_on();
subsystem_restart_dev(charm_subsys);
}
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_arb.c b/arch/arm/mach-msm/msm_bus/msm_bus_arb.c
index 4336945..4adfe4d 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_arb.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_arb.c
@@ -562,7 +562,7 @@
int pnode, src, curr, ctx;
uint64_t req_clk, req_bw, curr_clk, curr_bw;
struct msm_bus_client *client = (struct msm_bus_client *)cl;
- if (IS_ERR(client)) {
+ if (IS_ERR_OR_NULL(client)) {
MSM_BUS_ERR("msm_bus_scale_client update req error %d\n",
(uint32_t)client);
return -ENXIO;
diff --git a/arch/arm/mach-msm/msm_rq_stats.c b/arch/arm/mach-msm/msm_rq_stats.c
index d1538dd..1589623 100644
--- a/arch/arm/mach-msm/msm_rq_stats.c
+++ b/arch/arm/mach-msm/msm_rq_stats.c
@@ -31,6 +31,7 @@
#include <linux/tick.h>
#include <asm/smp_plat.h>
#include "acpuclock.h"
+#include <linux/suspend.h>
#define MAX_LONG_SIZE 24
#define DEFAULT_RQ_POLL_JIFFIES 1
@@ -206,6 +207,34 @@
return NOTIFY_OK;
}
+static int system_suspend_handler(struct notifier_block *nb,
+ unsigned long val, void *data)
+{
+ switch (val) {
+ case PM_POST_HIBERNATION:
+ case PM_POST_SUSPEND:
+ rq_info.hotplug_disabled = 0;
+ case PM_HIBERNATION_PREPARE:
+ case PM_SUSPEND_PREPARE:
+ rq_info.hotplug_disabled = 1;
+ break;
+ default:
+ return NOTIFY_DONE;
+ }
+ return NOTIFY_OK;
+}
+
+
+static ssize_t hotplug_disable_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ unsigned int val = 0;
+ val = rq_info.hotplug_disabled;
+ return snprintf(buf, MAX_LONG_SIZE, "%d\n", val);
+}
+
+static struct kobj_attribute hotplug_disabled_attr = __ATTR_RO(hotplug_disable);
+
static void def_work_fn(struct work_struct *work)
{
int64_t diff;
@@ -310,6 +339,7 @@
&def_timer_ms_attr.attr,
&run_queue_avg_attr.attr,
&run_queue_poll_ms_attr.attr,
+ &hotplug_disabled_attr.attr,
NULL,
};
@@ -358,6 +388,7 @@
rq_info.def_timer_jiffies = DEFAULT_DEF_TIMER_JIFFIES;
rq_info.rq_poll_last_jiffy = 0;
rq_info.def_timer_last_jiffy = 0;
+ rq_info.hotplug_disabled = 0;
ret = init_rq_attribs();
rq_info.init = 1;
@@ -380,3 +411,16 @@
return ret;
}
late_initcall(msm_rq_stats_init);
+
+static int __init msm_rq_stats_early_init(void)
+{
+ /* Bail out if this is not an SMP Target */
+ if (!is_smp()) {
+ rq_info.init = 0;
+ return -ENOSYS;
+ }
+
+ pm_notifier(system_suspend_handler, 0);
+ return 0;
+}
+core_initcall(msm_rq_stats_early_init);
diff --git a/arch/arm/mach-msm/msm_rtb.c b/arch/arm/mach-msm/msm_rtb.c
index e797e2e..fdf39be 100644
--- a/arch/arm/mach-msm/msm_rtb.c
+++ b/arch/arm/mach-msm/msm_rtb.c
@@ -55,7 +55,7 @@
struct msm_rtb_state {
struct msm_rtb_layout *rtb;
- unsigned long phys;
+ phys_addr_t phys;
int nentries;
int size;
int enabled;
diff --git a/arch/arm/mach-msm/peripheral-loader.c b/arch/arm/mach-msm/peripheral-loader.c
index fc9a0fa..958edaf 100644
--- a/arch/arm/mach-msm/peripheral-loader.c
+++ b/arch/arm/mach-msm/peripheral-loader.c
@@ -208,16 +208,24 @@
return ret;
}
-static void pil_proxy_unvote(struct pil_desc *desc, unsigned long timeout)
+static void pil_proxy_unvote(struct pil_desc *desc, int immediate)
{
struct pil_priv *priv = desc->priv;
+ unsigned long timeout;
- if (proxy_timeout_ms >= 0)
+ if (proxy_timeout_ms == 0 && !immediate)
+ return;
+ else if (proxy_timeout_ms > 0)
timeout = proxy_timeout_ms;
+ else
+ timeout = desc->proxy_timeout;
- if (timeout && desc->ops->proxy_unvote) {
+ if (desc->ops->proxy_unvote) {
if (WARN_ON(!try_module_get(desc->owner)))
return;
+
+ if (immediate)
+ timeout = 0;
schedule_delayed_work(&priv->proxy, msecs_to_jiffies(timeout));
}
}
@@ -558,7 +566,6 @@
const struct elf32_hdr *ehdr;
struct pil_seg *seg;
const struct firmware *fw;
- unsigned long proxy_timeout = desc->proxy_timeout;
struct pil_priv *priv = desc->priv;
/* Reinitialize for new image */
@@ -633,12 +640,11 @@
ret = desc->ops->auth_and_reset(desc);
if (ret) {
pil_err(desc, "Failed to bring out of reset\n");
- proxy_timeout = 0; /* Remove proxy vote immediately on error */
goto err_boot;
}
pil_info(desc, "Brought out of reset\n");
err_boot:
- pil_proxy_unvote(desc, proxy_timeout);
+ pil_proxy_unvote(desc, ret);
release_fw:
release_firmware(fw);
out:
diff --git a/arch/arm/mach-msm/pil-dsps.c b/arch/arm/mach-msm/pil-dsps.c
index 0630e6a..65d60d6 100644
--- a/arch/arm/mach-msm/pil-dsps.c
+++ b/arch/arm/mach-msm/pil-dsps.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, 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
@@ -142,9 +142,6 @@
static void dsps_restart_handler(struct dsps_data *drv)
{
- pr_debug("%s: Restart lvl %d\n",
- __func__, get_restart_level());
-
if (atomic_add_return(1, &drv->crash_in_progress) > 1) {
pr_err("%s: DSPS already resetting. Count %d\n", __func__,
atomic_read(&drv->crash_in_progress));
diff --git a/arch/arm/mach-msm/pil-q6v5-lpass.c b/arch/arm/mach-msm/pil-q6v5-lpass.c
index dfbda74..ef13c34 100644
--- a/arch/arm/mach-msm/pil-q6v5-lpass.c
+++ b/arch/arm/mach-msm/pil-q6v5-lpass.c
@@ -114,6 +114,8 @@
pil_q6v5_shutdown(pil);
pil_lpass_disable_clks(drv);
+ writel_relaxed(1, drv->restart_reg);
+
drv->is_booted = false;
return 0;
@@ -125,6 +127,11 @@
unsigned long start_addr = pil_get_entry_addr(pil);
int ret;
+ /* Deassert reset to subsystem and wait for propagation */
+ writel_relaxed(0, drv->restart_reg);
+ mb();
+ udelay(2);
+
ret = pil_lpass_enable_clks(drv);
if (ret)
return ret;
@@ -385,6 +392,7 @@
struct lpass_data *drv;
struct q6v5_data *q6;
struct pil_desc *desc;
+ struct resource *res;
int ret;
drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
@@ -405,6 +413,11 @@
desc->owner = THIS_MODULE;
desc->proxy_timeout = PROXY_TIMEOUT_MS;
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "restart_reg");
+ q6->restart_reg = devm_request_and_ioremap(&pdev->dev, res);
+ if (!q6->restart_reg)
+ return -ENOMEM;
+
q6->core_clk = devm_clk_get(&pdev->dev, "core_clk");
if (IS_ERR(q6->core_clk))
return PTR_ERR(q6->core_clk);
diff --git a/arch/arm/mach-msm/platsmp.c b/arch/arm/mach-msm/platsmp.c
index e7b4cea..bc40130 100644
--- a/arch/arm/mach-msm/platsmp.c
+++ b/arch/arm/mach-msm/platsmp.c
@@ -284,7 +284,8 @@
if (per_cpu(cold_boot_done, cpu) == false) {
if (machine_is_msm8974_sim() || machine_is_mpq8092_sim())
release_secondary_sim(0xf9088000, cpu);
- else if (!machine_is_msm8974_rumi())
+ else if (!machine_is_msm8974_rumi() &&
+ !machine_is_msmzinc_sim())
msm8974_release_secondary(0xf9088000, cpu);
per_cpu(cold_boot_done, cpu) = true;
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index b52d284..717c057 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -25,7 +25,9 @@
#include <linux/smp.h>
#include <linux/suspend.h>
#include <linux/tick.h>
+#include <linux/delay.h>
#include <linux/platform_device.h>
+#include <linux/of_platform.h>
#include <linux/regulator/krait-regulator.h>
#include <mach/msm_iomap.h>
#include <mach/socinfo.h>
@@ -127,6 +129,41 @@
static bool msm_pm_retention_calls_tz;
static uint32_t msm_pm_max_sleep_time;
static bool msm_no_ramp_down_pc;
+static struct msm_pm_sleep_status_data *msm_pm_slp_sts;
+
+static int msm_pm_get_pc_mode(struct device_node *node,
+ const char *key, uint32_t *pc_mode_val)
+{
+ struct pc_mode_of {
+ uint32_t mode;
+ char *mode_name;
+ };
+ int i;
+ struct pc_mode_of pc_modes[] = {
+ {MSM_PM_PC_TZ_L2_INT, "tz_l2_int"},
+ {MSM_PM_PC_NOTZ_L2_EXT, "no_tz_l2_ext"},
+ {MSM_PM_PC_TZ_L2_EXT , "tz_l2_ext"} };
+ int ret;
+ const char *pc_mode_str;
+
+ ret = of_property_read_string(node, key, &pc_mode_str);
+ if (ret) {
+ pr_debug("%s: Cannot read %s,defaulting to 0", __func__, key);
+ pc_mode_val = MSM_PM_PC_TZ_L2_INT;
+ ret = 0;
+ } else {
+ ret = -EINVAL;
+ for (i = 0; i < ARRAY_SIZE(pc_modes); i++) {
+ if (!strncmp(pc_mode_str, pc_modes[i].mode_name,
+ strlen(pc_modes[i].mode_name))) {
+ *pc_mode_val = pc_modes[i].mode;
+ ret = 0;
+ break;
+ }
+ }
+ }
+ return ret;
+}
/*
* Write out the attribute.
@@ -360,12 +397,10 @@
ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING, false);
WARN_ON(ret);
- krait_power_mdd_enable(smp_processor_id(), false);
}
static void msm_pm_config_hw_before_retention(void)
{
- krait_power_mdd_enable(smp_processor_id(), true);
return;
}
@@ -619,7 +654,7 @@
int64_t time = 0;
if (msm_pm_use_sync_timer)
- return ktime_to_ns(ktime_get());
+ return sched_clock();
time = msm_timer_get_sclk_time(period);
if (!time)
@@ -631,7 +666,7 @@
static int64_t msm_pm_timer_exit_suspend(int64_t time, int64_t period)
{
if (msm_pm_use_sync_timer)
- return ktime_to_ns(ktime_get()) - time;
+ return sched_clock() - time;
if (time != 0) {
int64_t end_time = msm_timer_get_sclk_time(NULL);
@@ -921,6 +956,32 @@
return sleep_mode;
}
+int msm_pm_wait_cpu_shutdown(unsigned int cpu)
+{
+ int timeout = 10;
+
+ if (!msm_pm_slp_sts)
+ return 0;
+ if (!msm_pm_slp_sts[cpu].base_addr)
+ return 0;
+ while (timeout--) {
+ /*
+ * Check for the SPM of the core being hotplugged to set
+ * its sleep state.The SPM sleep state indicates that the
+ * core has been power collapsed.
+ */
+ int acc_sts = __raw_readl(msm_pm_slp_sts[cpu].base_addr);
+
+ if (acc_sts & msm_pm_slp_sts[cpu].mask)
+ return 0;
+ usleep(100);
+ }
+
+ pr_info("%s(): Timed out waiting for CPU %u SPM to enter sleep state",
+ __func__, cpu);
+ return -EBUSY;
+}
+
void msm_pm_cpu_enter_lowpower(unsigned int cpu)
{
int i;
@@ -967,10 +1028,15 @@
* up as they enter the deepest sleep mode, namely RPM assited power
* collapse
*/
- if (!enable)
+ if (!enable) {
+ preempt_disable();
smp_call_function_many(cpu_online_mask,
msm_pm_ack_retention_disable,
NULL, true);
+ preempt_enable();
+
+
+ }
}
EXPORT_SYMBOL(msm_pm_enable_retention);
@@ -1072,6 +1138,93 @@
.enter = msm_pm_enter,
.valid = suspend_valid_only_mem,
};
+static int __devinit msm_cpu_status_probe(struct platform_device *pdev)
+{
+ struct msm_pm_sleep_status_data *pdata;
+ char *key;
+ u32 cpu;
+
+ if (!pdev)
+ return -EFAULT;
+
+ msm_pm_slp_sts =
+ kzalloc(sizeof(*msm_pm_slp_sts) * num_possible_cpus(),
+ GFP_KERNEL);
+
+ if (!msm_pm_slp_sts)
+ return -ENOMEM;
+
+ if (pdev->dev.of_node) {
+ struct resource *res;
+ u32 offset;
+ int rc;
+ u32 mask;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ goto fail_free_mem;
+
+ key = "qcom,cpu-alias-addr";
+ rc = of_property_read_u32(pdev->dev.of_node, key, &offset);
+
+ if (rc)
+ goto fail_free_mem;
+
+ key = "qcom,sleep-status-mask";
+ rc = of_property_read_u32(pdev->dev.of_node, key,
+ &mask);
+ if (rc)
+ goto fail_free_mem;
+
+ for_each_possible_cpu(cpu) {
+ msm_pm_slp_sts[cpu].base_addr =
+ ioremap(res->start + cpu * offset,
+ resource_size(res));
+ msm_pm_slp_sts[cpu].mask = mask;
+
+ if (!msm_pm_slp_sts[cpu].base_addr)
+ goto failed_of_node;
+ }
+
+ } else {
+ pdata = pdev->dev.platform_data;
+ if (!pdev->dev.platform_data)
+ goto fail_free_mem;
+
+ for_each_possible_cpu(cpu) {
+ msm_pm_slp_sts[cpu].base_addr =
+ pdata->base_addr + cpu * pdata->cpu_offset;
+ msm_pm_slp_sts[cpu].mask = pdata->mask;
+ }
+ }
+
+ return 0;
+
+failed_of_node:
+ pr_info("%s(): Failed to key=%s\n", __func__, key);
+ for_each_possible_cpu(cpu) {
+ if (msm_pm_slp_sts[cpu].base_addr)
+ iounmap(msm_pm_slp_sts[cpu].base_addr);
+ }
+fail_free_mem:
+ kfree(msm_pm_slp_sts);
+ return -EINVAL;
+
+};
+
+static struct of_device_id msm_slp_sts_match_tbl[] = {
+ {.compatible = "qcom,cpu-sleep-status"},
+ {},
+};
+
+static struct platform_driver msm_cpu_status_driver = {
+ .probe = msm_cpu_status_probe,
+ .driver = {
+ .name = "cpu_slp_status",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_slp_sts_match_tbl,
+ },
+};
static int __devinit msm_pm_init(void)
{
@@ -1257,7 +1410,6 @@
{
char *key = NULL;
struct dentry *dent = NULL;
- uint32_t val = 0;
struct resource *res = NULL;
int i ;
struct msm_pm_init_data_type pdata_local;
@@ -1299,14 +1451,14 @@
} else {
key = "qcom,pc-mode";
- ret = of_property_read_u32(pdev->dev.of_node, key, &val);
+ ret = msm_pm_get_pc_mode(pdev->dev.of_node,
+ key,
+ &pdata_local.pc_mode);
if (ret) {
- pr_debug("%s: Cannot read %s,defaulting to 0",
+ pr_debug("%s: Error reading key %s",
__func__, key);
- val = MSM_PM_PC_TZ_L2_INT;
- ret = 0;
+ return -EINVAL;
}
- pdata_local.pc_mode = val;
key = "qcom,use-sync-timer";
pdata_local.use_sync_timer =
@@ -1342,6 +1494,9 @@
pm_8x60_probe_done:
msm_pm_init();
+ if (pdev->dev.of_node)
+ of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
+
return ret;
}
@@ -1361,6 +1516,16 @@
static int __init msm_pm_8x60_init(void)
{
+ int rc;
+
+ rc = platform_driver_register(&msm_cpu_status_driver);
+
+ if (rc) {
+ pr_err("%s(): failed to register driver %s\n", __func__,
+ msm_cpu_status_driver.driver.name);
+ return rc;
+ }
+
return platform_driver_register(&msm_pm_8x60_driver);
}
device_initcall(msm_pm_8x60_init);
diff --git a/arch/arm/mach-msm/pm-boot.c b/arch/arm/mach-msm/pm-boot.c
index c77b19c..3559510 100644
--- a/arch/arm/mach-msm/pm-boot.c
+++ b/arch/arm/mach-msm/pm-boot.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, 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
@@ -32,6 +32,42 @@
static void (*msm_pm_boot_before_pc)(unsigned int cpu, unsigned long entry);
static void (*msm_pm_boot_after_pc)(unsigned int cpu);
+
+static int msm_pm_get_boot_config_mode(struct device_node *dev,
+ const char *key, uint32_t *boot_config_mode)
+{
+ struct pm_lookup_table {
+ uint32_t boot_config_mode;
+ const char *boot_config_name;
+ };
+ const char *boot_config_str;
+ struct pm_lookup_table boot_config_lookup[] = {
+ {MSM_PM_BOOT_CONFIG_TZ, "tz"},
+ {MSM_PM_BOOT_CONFIG_RESET_VECTOR_PHYS, "reset_vector_phys"},
+ {MSM_PM_BOOT_CONFIG_RESET_VECTOR_VIRT, "reset_vector_virt"},
+ {MSM_PM_BOOT_CONFIG_REMAP_BOOT_ADDR, "remap_boot_addr"}
+ };
+ int ret;
+ int i;
+
+ ret = of_property_read_string(dev, key, &boot_config_str);
+ if (!ret) {
+ ret = -EINVAL;
+ for (i = 0; i < ARRAY_SIZE(boot_config_lookup); i++) {
+ if (!strncmp(boot_config_str,
+ boot_config_lookup[i].boot_config_name,
+ strlen(boot_config_lookup[i].boot_config_name))
+ ) {
+ *boot_config_mode =
+ boot_config_lookup[i].boot_config_mode;
+ ret = 0;
+ break;
+ }
+ }
+ }
+ return ret;
+}
+
static void msm_pm_write_boot_vector(unsigned int cpu, unsigned long address)
{
msm_pm_boot_vector[cpu] = address;
@@ -235,11 +271,9 @@
vaddr_val = 0;
key = "qcom,mode";
- ret = of_property_read_u32(pdev->dev.of_node, key, &val);
- if (ret) {
- pr_err("Unable to read boot mode Err(%d).\n", ret);
- return -ENODEV;
- }
+ ret = msm_pm_get_boot_config_mode(pdev->dev.of_node, key, &val);
+ if (ret)
+ goto fail;
pdata.mode = val;
key = "qcom,phy-addr";
diff --git a/arch/arm/mach-msm/pm-boot.h b/arch/arm/mach-msm/pm-boot.h
index 8ca3bb5..2d5110d 100644
--- a/arch/arm/mach-msm/pm-boot.h
+++ b/arch/arm/mach-msm/pm-boot.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, 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
@@ -18,10 +18,10 @@
/* end */
enum {
- MSM_PM_BOOT_CONFIG_TZ = 0,
- MSM_PM_BOOT_CONFIG_RESET_VECTOR_PHYS = 1,
- MSM_PM_BOOT_CONFIG_RESET_VECTOR_VIRT = 2,
- MSM_PM_BOOT_CONFIG_REMAP_BOOT_ADDR = 3,
+ MSM_PM_BOOT_CONFIG_TZ ,
+ MSM_PM_BOOT_CONFIG_RESET_VECTOR_PHYS,
+ MSM_PM_BOOT_CONFIG_RESET_VECTOR_VIRT,
+ MSM_PM_BOOT_CONFIG_REMAP_BOOT_ADDR ,
};
struct msm_pm_boot_platform_data {
diff --git a/arch/arm/mach-msm/pm.h b/arch/arm/mach-msm/pm.h
index c77304d..8a043d8 100644
--- a/arch/arm/mach-msm/pm.h
+++ b/arch/arm/mach-msm/pm.h
@@ -95,11 +95,11 @@
};
enum msm_pm_pc_mode_type {
- MSM_PM_PC_TZ_L2_INT = 0, /*Power collapse terminates in TZ;
+ MSM_PM_PC_TZ_L2_INT, /*Power collapse terminates in TZ;
integrated L2 cache controller */
- MSM_PM_PC_NOTZ_L2_EXT = 1, /* Power collapse doesn't terminate in
+ MSM_PM_PC_NOTZ_L2_EXT, /* Power collapse doesn't terminate in
TZ; external L2 cache controller */
- MSM_PM_PC_TZ_L2_EXT = 2, /* Power collapse terminates in TZ;
+ MSM_PM_PC_TZ_L2_EXT, /* Power collapse terminates in TZ;
external L2 cache controller */
};
@@ -135,9 +135,11 @@
#ifdef CONFIG_MSM_PM8X60
void msm_pm_set_rpm_wakeup_irq(unsigned int irq);
void msm_pm_set_sleep_ops(struct msm_pm_sleep_ops *ops);
+int msm_pm_wait_cpu_shutdown(unsigned int cpu);
#else
static inline void msm_pm_set_rpm_wakeup_irq(unsigned int irq) {}
static inline void msm_pm_set_sleep_ops(struct msm_pm_sleep_ops *ops) {}
+static inline int msm_pm_wait_cpu_shutdown(unsigned int cpu) { return 0; }
#endif
#ifdef CONFIG_HOTPLUG_CPU
int msm_platform_secondary_init(unsigned int cpu);
diff --git a/arch/arm/mach-msm/qdsp6v2/apr.c b/arch/arm/mach-msm/qdsp6v2/apr.c
index 4c106c5..6e60db1 100644
--- a/arch/arm/mach-msm/qdsp6v2/apr.c
+++ b/arch/arm/mach-msm/qdsp6v2/apr.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013, 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
@@ -26,6 +26,7 @@
#include <linux/sysfs.h>
#include <linux/device.h>
#include <linux/slab.h>
+#include <sound/apr_audio-v2.h>
#include <asm/mach-types.h>
#include <mach/subsystem_restart.h>
#include <mach/msm_smd.h>
@@ -114,6 +115,11 @@
.name = "VIDC",
.idx = 9,
.id = APR_SVC_VIDC,
+ },
+ {
+ .name = "LSM",
+ .idx = 9,
+ .id = APR_SVC_LSM,
.client_id = APR_CLIENT_AUDIO,
},
};
@@ -280,7 +286,6 @@
return -ENETRESET;
}
-
spin_lock_irqsave(&svc->w_lock, flags);
dest_id = svc->dest_id;
client_id = svc->client_id;
@@ -391,7 +396,8 @@
svc == APR_SVC_ADM || svc == APR_SVC_ADSP_CORE ||
svc == APR_SVC_USM ||
svc == APR_SVC_TEST_CLIENT || svc == APR_SVC_ADSP_MVM ||
- svc == APR_SVC_ADSP_CVS || svc == APR_SVC_ADSP_CVP)
+ svc == APR_SVC_ADSP_CVS || svc == APR_SVC_ADSP_CVP ||
+ svc == APR_SVC_LSM)
clnt = APR_CLIENT_AUDIO;
else if (svc == APR_SVC_VIDC)
clnt = APR_CLIENT_AUDIO;
diff --git a/arch/arm/mach-msm/ramdump.h b/arch/arm/mach-msm/ramdump.h
index e43ca12..3a960a1 100644
--- a/arch/arm/mach-msm/ramdump.h
+++ b/arch/arm/mach-msm/ramdump.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, 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
@@ -20,6 +20,7 @@
unsigned long size;
};
+#ifdef CONFIG_MSM_SUBSYSTEM_RESTART
void *create_ramdump_device(const char *dev_name, struct device *parent);
void destroy_ramdump_device(void *dev);
int do_ramdump(void *handle, struct ramdump_segment *segments,
@@ -27,4 +28,28 @@
int do_elf_ramdump(void *handle, struct ramdump_segment *segments,
int nsegments);
+#else
+static inline void *create_ramdump_device(const char *dev_name,
+ struct device *parent)
+{
+ return NULL;
+}
+
+static inline void destroy_ramdump_device(void *dev)
+{
+}
+
+static inline int do_ramdump(void *handle, struct ramdump_segment *segments,
+ int nsegments)
+{
+ return -ENODEV;
+}
+
+static inline int do_elf_ramdump(void *handle, struct ramdump_segment *segments,
+ int nsegments)
+{
+ return -ENODEV;
+}
+#endif /* CONFIG_MSM_SUBSYSTEM_RESTART */
+
#endif
diff --git a/arch/arm/mach-msm/restart.c b/arch/arm/mach-msm/restart.c
index a67af45..d95f979 100644
--- a/arch/arm/mach-msm/restart.c
+++ b/arch/arm/mach-msm/restart.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013, 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
@@ -253,7 +253,7 @@
__raw_writel(0x31F3, msm_tmr0_base + WDT0_BITE_TIME);
__raw_writel(1, msm_tmr0_base + WDT0_EN);
} else {
- /* Needed for 8974: Reset GCC_WDOG_DEBUG register */
+ /* Needed to bypass debug image on some chips */
msm_disable_wdog_debug();
__raw_writel(0, MSM_MPM2_PSHOLD_BASE);
}
diff --git a/arch/arm/mach-msm/scm-pas.c b/arch/arm/mach-msm/scm-pas.c
index f73055e..b7271bb 100644
--- a/arch/arm/mach-msm/scm-pas.c
+++ b/arch/arm/mach-msm/scm-pas.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013, 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
@@ -29,6 +29,23 @@
#define PAS_SHUTDOWN_CMD 6
#define PAS_IS_SUPPORTED_CMD 7
+enum scm_clock_ids {
+ BUS_CLK = 0,
+ CORE_CLK,
+ IFACE_CLK,
+ CORE_CLK_SRC,
+ NUM_CLKS
+};
+
+static const char * const scm_clock_names[NUM_CLKS] = {
+ [BUS_CLK] = "bus_clk",
+ [CORE_CLK] = "core_clk",
+ [IFACE_CLK] = "iface_clk",
+ [CORE_CLK_SRC] = "core_clk_src",
+};
+
+static struct clk *scm_clocks[NUM_CLKS];
+
int pas_init_image(enum pas_id id, const u8 *metadata, size_t size)
{
int ret;
@@ -108,14 +125,13 @@
};
static uint32_t scm_perf_client;
-static struct clk *scm_bus_clk;
static DEFINE_MUTEX(scm_pas_bw_mutex);
static int scm_pas_bw_count;
static int scm_pas_enable_bw(void)
{
- int ret = 0;
+ int ret = 0, i;
if (!scm_perf_client)
return -EINVAL;
@@ -123,30 +139,40 @@
mutex_lock(&scm_pas_bw_mutex);
if (!scm_pas_bw_count) {
ret = msm_bus_scale_client_update_request(scm_perf_client, 1);
- if (ret) {
- pr_err("bandwidth request failed (%d)\n", ret);
- } else if (scm_bus_clk) {
- ret = clk_prepare_enable(scm_bus_clk);
- if (ret)
- pr_err("clock enable failed\n");
- }
- }
- if (ret)
- msm_bus_scale_client_update_request(scm_perf_client, 0);
- else
+ if (ret)
+ goto err_bus;
scm_pas_bw_count++;
+ }
+ for (i = 0; i < NUM_CLKS; i++)
+ if (clk_prepare_enable(scm_clocks[i]))
+ goto err_clk;
+
+ mutex_unlock(&scm_pas_bw_mutex);
+ return ret;
+
+err_clk:
+ pr_err("clk prepare_enable failed (%s)\n", scm_clock_names[i]);
+ for (i--; i >= 0; i--)
+ clk_disable_unprepare(scm_clocks[i]);
+
+err_bus:
+ pr_err("bandwidth request failed (%d)\n", ret);
+ msm_bus_scale_client_update_request(scm_perf_client, 0);
+
mutex_unlock(&scm_pas_bw_mutex);
return ret;
}
static void scm_pas_disable_bw(void)
{
+ int i;
mutex_lock(&scm_pas_bw_mutex);
if (scm_pas_bw_count-- == 1) {
msm_bus_scale_client_update_request(scm_perf_client, 0);
- if (scm_bus_clk)
- clk_disable_unprepare(scm_bus_clk);
}
+ for (i = NUM_CLKS - 1; i >= 0; i--)
+ clk_disable_unprepare(scm_clocks[i]);
+
mutex_unlock(&scm_pas_bw_mutex);
}
@@ -214,17 +240,25 @@
static int __init scm_pas_init(void)
{
- if (cpu_is_msm8974()) {
+ int i, rate;
+ for (i = 0; i < NUM_CLKS; i++) {
+ scm_clocks[i] = clk_get_sys("scm", scm_clock_names[i]);
+ if (IS_ERR(scm_clocks[i]))
+ scm_clocks[i] = NULL;
+ }
+
+ /* Fail silently if this clock is not supported */
+ rate = clk_round_rate(scm_clocks[CORE_CLK_SRC], 1);
+ clk_set_rate(scm_clocks[CORE_CLK_SRC], rate);
+
+ if (cpu_is_msm8974() || cpu_is_msm8226()) {
scm_pas_bw_tbl[0].vectors[0].src = MSM_BUS_MASTER_CRYPTO_CORE0;
scm_pas_bw_tbl[1].vectors[0].src = MSM_BUS_MASTER_CRYPTO_CORE0;
} else {
- scm_bus_clk = clk_get_sys("scm", "bus_clk");
- if (!IS_ERR(scm_bus_clk)) {
- clk_set_rate(scm_bus_clk, 64000000);
- } else {
- scm_bus_clk = NULL;
+ if (!IS_ERR(scm_clocks[BUS_CLK]))
+ clk_set_rate(scm_clocks[BUS_CLK], 64000000);
+ else
pr_warn("unable to get bus clock\n");
- }
}
scm_perf_client = msm_bus_scale_register_client(&scm_pas_bus_pdata);
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index cffb211..40ef20e 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -49,6 +49,7 @@
#include "smd_private.h"
#include "modem_notifier.h"
+#include "ramdump.h"
#if defined(CONFIG_ARCH_QSD8X50) || defined(CONFIG_ARCH_MSM8X60) \
|| defined(CONFIG_ARCH_MSM8960) || defined(CONFIG_ARCH_FSM9XXX) \
@@ -178,7 +179,10 @@
};
static uint32_t num_smem_areas;
static struct smem_area *smem_areas;
+static struct ramdump_segment *smem_ramdump_segments;
+static void *smem_ramdump_dev;
static void *smem_range_check(phys_addr_t base, unsigned offset);
+static void *smd_dev;
struct interrupt_stat interrupt_stats[NUM_SMD_SUBSYSTEMS];
@@ -977,10 +981,6 @@
SMx_POWER_INFO("%s: starting reset\n", __func__);
- /* release any held spinlocks */
- remote_spin_release(&remote_spinlock, restart_pid);
- remote_spin_release_all(restart_pid);
-
shared = smem_find(ID_CH_ALLOC_TBL, sizeof(*shared) * 64);
if (!shared) {
pr_err("%s: allocation table not initialized\n", __func__);
@@ -3720,6 +3720,7 @@
struct device_node *node;
int ret;
const char *compatible;
+ struct ramdump_segment *ramdump_segments_tmp;
int subnode_num = 0;
resource_size_t irq_out_size;
@@ -3757,13 +3758,33 @@
}
}
+ /* initialize SSR ramdump regions */
+ key = "smem";
+ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, key);
+ if (!r) {
+ pr_err("%s: missing '%s'\n", __func__, key);
+ return -ENODEV;
+ }
+ ramdump_segments_tmp = kmalloc_array(num_smem_areas + 1,
+ sizeof(struct ramdump_segment), GFP_KERNEL);
+
+ if (!ramdump_segments_tmp) {
+ pr_err("%s: ramdump segment kmalloc failed\n", __func__);
+ ret = -ENOMEM;
+ goto free_smem_areas;
+ }
+ ramdump_segments_tmp[0].address = r->start;
+ ramdump_segments_tmp[0].size = resource_size(r);
+
if (num_smem_areas) {
+
smem_areas = kmalloc(sizeof(struct smem_area) * num_smem_areas,
GFP_KERNEL);
+
if (!smem_areas) {
pr_err("%s: smem areas kmalloc failed\n", __func__);
- num_smem_areas = 0;
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto free_smem_areas;
}
count = 1;
while (1) {
@@ -3775,6 +3796,16 @@
break;
aux_mem_base = r->start;
aux_mem_size = resource_size(r);
+
+ /*
+ * Add to ram-dumps segments.
+ * ramdump_segments_tmp[0] is the main SMEM region,
+ * so auxiliary segments are indexed by count
+ * instead of count - 1.
+ */
+ ramdump_segments_tmp[count].address = aux_mem_base;
+ ramdump_segments_tmp[count].size = aux_mem_size;
+
SMD_DBG("%s: %s = %pa %pa", __func__, temp_string,
&aux_mem_base, &aux_mem_size);
smem_areas[count - 1].phys_addr = aux_mem_base;
@@ -3822,6 +3853,7 @@
++subnode_num;
}
+ smem_ramdump_segments = ramdump_segments_tmp;
return 0;
rollback_subnodes:
@@ -3838,6 +3870,7 @@
}
free_smem_areas:
num_smem_areas = 0;
+ kfree(ramdump_segments_tmp);
kfree(smem_areas);
smem_areas = NULL;
return ret;
@@ -3869,6 +3902,7 @@
__func__);
return ret;
}
+ smd_dev = &pdev->dev;
} else if (pdev->dev.platform_data) {
ret = smd_core_platform_init(pdev);
if (ret) {
@@ -3928,6 +3962,26 @@
__func__, notifier->processor,
notifier->name);
+ remote_spin_release(&remote_spinlock, notifier->processor);
+ remote_spin_release_all(notifier->processor);
+
+ if (smem_ramdump_dev) {
+ int ret;
+
+ SMD_INFO("%s: saving ramdump\n", __func__);
+ /*
+ * XPU protection does not currently allow the
+ * auxiliary memory regions to be dumped. If this
+ * changes, then num_smem_areas + 1 should be passed
+ * into do_elf_ramdump() to dump all regions.
+ */
+ ret = do_elf_ramdump(smem_ramdump_dev,
+ smem_ramdump_segments, 1);
+ if (ret < 0)
+ pr_err("%s: unable to dump smem %d\n", __func__,
+ ret);
+ }
+
smd_channel_reset(notifier->processor);
}
@@ -3940,12 +3994,20 @@
void *handle;
struct restart_notifier_block *nb;
+ smem_ramdump_dev = create_ramdump_device("smem-smd", smd_dev);
+ if (IS_ERR_OR_NULL(smem_ramdump_dev)) {
+ pr_err("%s: Unable to create smem ramdump device.\n",
+ __func__);
+ smem_ramdump_dev = NULL;
+ }
+
for (i = 0; i < ARRAY_SIZE(restart_notifiers); i++) {
nb = &restart_notifiers[i];
handle = subsys_notif_register_notifier(nb->name, &nb->nb);
SMD_DBG("%s: registering notif for '%s', handle=%p\n",
__func__, nb->name, handle);
}
+
return 0;
}
late_initcall(modem_restart_late_init);
diff --git a/arch/arm/mach-msm/smd_pkt.c b/arch/arm/mach-msm/smd_pkt.c
index eb7aa8a..7eb9ead 100644
--- a/arch/arm/mach-msm/smd_pkt.c
+++ b/arch/arm/mach-msm/smd_pkt.c
@@ -645,8 +645,9 @@
struct smd_pkt_dev *smd_pkt_devp = priv;
if (smd_pkt_devp->ch == 0) {
- pr_err("%s on a closed smd_pkt_dev id:%d\n",
- __func__, smd_pkt_devp->i);
+ if (event != SMD_EVENT_CLOSE)
+ pr_err("%s on a closed smd_pkt_dev id:%d\n",
+ __func__, smd_pkt_devp->i);
return;
}
diff --git a/arch/arm/mach-msm/smp2p.c b/arch/arm/mach-msm/smp2p.c
index 8066005..7bdcce9 100644
--- a/arch/arm/mach-msm/smp2p.c
+++ b/arch/arm/mach-msm/smp2p.c
@@ -1599,8 +1599,8 @@
*/
static int __devinit msm_smp2p_probe(struct platform_device *pdev)
{
- struct resource *irq_out_base;
- struct resource *irq_offset;
+ struct resource *r;
+ void *irq_out_ptr;
char *key;
uint32_t edge;
int ret;
@@ -1617,15 +1617,18 @@
goto fail;
}
- key = "irq-reg-base";
- irq_out_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, key);
- if (!irq_out_base)
- goto missing_key;
-
- key = "irq-reg-offset";
- irq_offset = platform_get_resource_byname(pdev, IORESOURCE_MEM, key);
- if (!irq_offset)
- goto missing_key;
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!r) {
+ SMP2P_ERR("%s: failed gathering irq-reg resource for edge %d\n"
+ , __func__, edge);
+ goto fail;
+ }
+ irq_out_ptr = ioremap_nocache(r->start, resource_size(r));
+ if (!irq_out_ptr) {
+ SMP2P_ERR("%s: failed remap from phys to virt for edge %d\n",
+ __func__, edge);
+ return -ENOMEM;
+ }
key = "qcom,irq-bitmask";
ret = of_property_read_u32(node, key, &irq_bitmask);
@@ -1656,9 +1659,7 @@
*/
smp2p_int_cfgs[edge].in_int_id = irq_line;
smp2p_int_cfgs[edge].out_int_mask = irq_bitmask;
- smp2p_int_cfgs[edge].out_int_ptr =
- (uint32_t *)((uint32_t)irq_out_base->start +
- (uint32_t)irq_offset->start);
+ smp2p_int_cfgs[edge].out_int_ptr = irq_out_ptr;
smp2p_int_cfgs[edge].is_configured = true;
return 0;
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index efbd8c6..57c85e1 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -44,6 +44,7 @@
HW_PLATFORM_LIQUID = 9,
/* Dragonboard platform id is assigned as 10 in CDT */
HW_PLATFORM_DRAGON = 10,
+ HW_PLATFORM_QRD = 11,
HW_PLATFORM_HRD = 13,
HW_PLATFORM_DTV = 14,
HW_PLATFORM_INVALID
@@ -59,6 +60,7 @@
[HW_PLATFORM_MTP] = "MTP",
[HW_PLATFORM_LIQUID] = "Liquid",
[HW_PLATFORM_DRAGON] = "Dragon",
+ [HW_PLATFORM_QRD] = "QRD",
[HW_PLATFORM_HRD] = "HRD",
[HW_PLATFORM_DTV] = "DTV",
};
@@ -249,6 +251,7 @@
[105] = MSM_CPU_9615,
[106] = MSM_CPU_9615,
[107] = MSM_CPU_9615,
+ [171] = MSM_CPU_9615,
/* 8064 IDs */
[109] = MSM_CPU_8064,
diff --git a/arch/arm/mach-msm/subsystem_restart.c b/arch/arm/mach-msm/subsystem_restart.c
index 29481d3..5fe7a29 100644
--- a/arch/arm/mach-msm/subsystem_restart.c
+++ b/arch/arm/mach-msm/subsystem_restart.c
@@ -72,6 +72,11 @@
[SUBSYS_ONLINE] = "ONLINE",
};
+static const char * const restart_levels[] = {
+ [RESET_SOC] = "SYSTEM",
+ [RESET_SUBSYS_COUPLED] = "RELATED",
+};
+
/**
* struct subsys_tracking - track state of a subsystem or restart order
* @p_state: private state of subsystem/order
@@ -123,6 +128,7 @@
* @owner: module that provides @desc
* @count: reference count of subsystem_get()/subsystem_put()
* @id: ida
+ * @restart_level: restart level (0 - panic, 1 - related, 2 - independent, etc.)
* @restart_order: order of other devices this devices restarts with
* @dentry: debugfs directory for this device
* @do_ramdump_on_put: ramdump on subsystem_put() if true
@@ -140,6 +146,7 @@
struct module *owner;
int count;
int id;
+ int restart_level;
struct subsys_soc_restart_order *restart_order;
#ifdef CONFIG_DEBUG_FS
struct dentry *dentry;
@@ -167,6 +174,38 @@
return snprintf(buf, PAGE_SIZE, "%s\n", subsys_states[state]);
}
+static ssize_t
+restart_level_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ int level = to_subsys(dev)->restart_level;
+ return snprintf(buf, PAGE_SIZE, "%s\n", restart_levels[level]);
+}
+
+static ssize_t restart_level_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct subsys_device *subsys = to_subsys(dev);
+ int i;
+ const char *p;
+
+ p = memchr(buf, '\n', count);
+ if (p)
+ count = p - buf;
+
+ for (i = 0; i < ARRAY_SIZE(restart_levels); i++)
+ if (!strncasecmp(buf, restart_levels[i], count)) {
+ subsys->restart_level = i;
+ return count;
+ }
+ return -EPERM;
+}
+
+int subsys_get_restart_level(struct subsys_device *dev)
+{
+ return dev->restart_level;
+}
+EXPORT_SYMBOL(subsys_get_restart_level);
+
static void subsys_set_state(struct subsys_device *subsys,
enum subsys_state state)
{
@@ -199,6 +238,7 @@
static struct device_attribute subsys_attrs[] = {
__ATTR_RO(name),
__ATTR_RO(state),
+ __ATTR(restart_level, 0644, restart_level_show, restart_level_store),
__ATTR_NULL,
};
@@ -259,48 +299,6 @@
static struct subsys_soc_restart_order **restart_orders;
static int n_restart_orders;
-static int restart_level = RESET_SOC;
-
-int get_restart_level()
-{
- return restart_level;
-}
-EXPORT_SYMBOL(get_restart_level);
-
-static int restart_level_set(const char *val, struct kernel_param *kp)
-{
- int ret;
- int old_val = restart_level;
-
- if (cpu_is_msm9615()) {
- pr_err("Only Phase 1 subsystem restart is supported\n");
- return -EINVAL;
- }
-
- ret = param_set_int(val, kp);
- if (ret)
- return ret;
-
- switch (restart_level) {
- case RESET_SUBSYS_INDEPENDENT:
- if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE) {
- pr_info("Phase 3 is currently unsupported. Using phase 2 instead.\n");
- restart_level = RESET_SUBSYS_COUPLED;
- }
- case RESET_SUBSYS_COUPLED:
- case RESET_SOC:
- pr_info("Phase %d behavior activated.\n", restart_level);
- break;
- default:
- restart_level = old_val;
- return -EINVAL;
- }
- return 0;
-}
-
-module_param_call(restart_level, restart_level_set, param_get_int,
- &restart_level, 0644);
-
static struct subsys_soc_restart_order *
update_restart_order(struct subsys_device *dev)
{
@@ -484,7 +482,7 @@
{
struct subsys_soc_restart_order *order = subsys->restart_order;
- if (restart_level != RESET_SUBSYS_INDEPENDENT && order)
+ if (order)
return &order->track;
else
return &subsys->track;
@@ -603,7 +601,7 @@
* This is because the subsystem list inside the relevant
* restart order is not being traversed.
*/
- if (restart_level != RESET_SUBSYS_INDEPENDENT && order) {
+ if (order) {
list = order->subsys_ptrs;
count = order->count;
track = &order->track;
@@ -662,7 +660,8 @@
struct subsys_tracking *track;
unsigned long flags;
- pr_debug("Restarting %s [level=%d]!\n", desc->name, restart_level);
+ pr_debug("Restarting %s [level=%s]!\n", desc->name,
+ restart_levels[dev->restart_level]);
track = subsys_get_track(dev);
/*
@@ -708,13 +707,12 @@
return -EBUSY;
}
- pr_info("Restart sequence requested for %s, restart_level = %d.\n",
- name, restart_level);
+ pr_info("Restart sequence requested for %s, restart_level = %s.\n",
+ name, restart_levels[dev->restart_level]);
- switch (restart_level) {
+ switch (dev->restart_level) {
case RESET_SUBSYS_COUPLED:
- case RESET_SUBSYS_INDEPENDENT:
__subsystem_restart_dev(dev);
break;
case RESET_SOC:
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c
index f410e7f..3144113 100644
--- a/arch/arm/mach-msm/timer.c
+++ b/arch/arm/mach-msm/timer.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -1082,9 +1082,11 @@
__raw_writel(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL);
gpt->status_mask = BIT(10);
dgt->status_mask = BIT(2);
- gpt->freq = 32765;
- gpt_hz = 32765;
- sclk_hz = 32765;
+ if (!soc_class_is_apq8064()) {
+ gpt->freq = 32765;
+ gpt_hz = 32765;
+ sclk_hz = 32765;
+ }
if (!soc_class_is_msm8930() && !cpu_is_msm8960ab()) {
gpt->flags |= MSM_CLOCK_FLAGS_UNSTABLE_COUNT;
dgt->flags |= MSM_CLOCK_FLAGS_UNSTABLE_COUNT;
diff --git a/arch/arm/mach-msm/wdog_debug.c b/arch/arm/mach-msm/wdog_debug.c
index 8b39d26..cccca26 100644
--- a/arch/arm/mach-msm/wdog_debug.c
+++ b/arch/arm/mach-msm/wdog_debug.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, 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
@@ -10,144 +10,31 @@
* GNU General Public License for more details.
*/
-#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/io.h>
-#include <linux/delay.h>
-#include <linux/mutex.h>
-#include <linux/sched.h>
-#include <linux/of.h>
-#include <linux/platform_device.h>
+#include <linux/module.h>
#include <mach/scm.h>
-#include <linux/slab.h>
-#define MODULE_NAME "wdog_debug"
-#define WDOG_DEBUG_EN 17
-#define GCC_WDOG_DEBUG_OFFSET 0x780
-
-struct msm_wdog_debug_data {
- unsigned int __iomem phys_base;
- size_t size;
- void __iomem *base;
- struct device *dev;
-};
-
-static struct msm_wdog_debug_data *wdog_data;
-
-void msm_disable_wdog_debug(void)
-{
- unsigned long int value;
-
- if (wdog_data == NULL)
- return;
- value = readl_relaxed(wdog_data->base + GCC_WDOG_DEBUG_OFFSET);
- value &= ~BIT(WDOG_DEBUG_EN);
- writel_relaxed(value, wdog_data->base + GCC_WDOG_DEBUG_OFFSET);
-
- /* Ensure the WDOG_DEBUG_EN status has changed */
- while (readl_relaxed(wdog_data->base + GCC_WDOG_DEBUG_OFFSET) &
- BIT(WDOG_DEBUG_EN))
- ;
-}
-EXPORT_SYMBOL(msm_disable_wdog_debug);
+#define SCM_WDOG_DEBUG_BOOT_PART 0x9
+#define BOOT_PART_EN_VAL 0x5D1
void msm_enable_wdog_debug(void)
{
- unsigned long int value;
+ int ret;
- if (wdog_data == NULL)
- return;
- value = readl_relaxed(wdog_data->base + GCC_WDOG_DEBUG_OFFSET);
- value |= BIT(WDOG_DEBUG_EN);
- writel_relaxed(value, wdog_data->base + GCC_WDOG_DEBUG_OFFSET);
+ ret = scm_call_atomic2(SCM_SVC_BOOT,
+ SCM_WDOG_DEBUG_BOOT_PART, 0, BOOT_PART_EN_VAL);
+ if (ret)
+ pr_err("failed to enable wdog debug\n");
}
EXPORT_SYMBOL(msm_enable_wdog_debug);
-static int __devexit msm_wdog_debug_remove(struct platform_device *pdev)
-{
- kfree(wdog_data);
- wdog_data = NULL;
- pr_info("MSM wdog_debug Exit - Deactivated\n");
- return 0;
-}
-
-static int __devinit msm_wdog_debug_dt_to_pdata(struct platform_device *pdev,
- struct msm_wdog_debug_data *pdata)
-{
- struct resource *wdog_resource;
-
- wdog_resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!wdog_resource) {
- dev_err(&pdev->dev, \
- "%s cannot allocate resource for wdog_debug\n", \
- __func__);
- return -ENXIO;
- }
- pdata->size = resource_size(wdog_resource);
- pdata->phys_base = wdog_resource->start;
- if (unlikely(!(devm_request_region(&pdev->dev, pdata->phys_base,
- pdata->size, "msm-wdog-debug")))) {
- dev_err(&pdev->dev, "%s cannot reserve wdog_debug region\n",
- __func__);
- return -ENXIO;
- }
- pdata->base = devm_ioremap(&pdev->dev, pdata->phys_base,
- pdata->size);
- if (!pdata->base) {
- dev_err(&pdev->dev, "%s cannot map wdog register space\n",
- __func__);
- return -ENXIO;
- }
-
- return 0;
-}
-
-static int __devinit msm_wdog_debug_probe(struct platform_device *pdev)
+void msm_disable_wdog_debug(void)
{
int ret;
- if (!pdev->dev.of_node)
- return -ENODEV;
- wdog_data = kzalloc(sizeof(struct msm_wdog_debug_data), GFP_KERNEL);
- if (!wdog_data)
- return -ENOMEM;
- ret = msm_wdog_debug_dt_to_pdata(pdev, wdog_data);
+
+ ret = scm_call_atomic2(SCM_SVC_BOOT,
+ SCM_WDOG_DEBUG_BOOT_PART, 1, 0);
if (ret)
- goto err;
- wdog_data->dev = &pdev->dev;
- platform_set_drvdata(pdev, wdog_data);
- return 0;
-err:
- kzfree(wdog_data);
- wdog_data = NULL;
- return ret;
+ pr_err("failed to disable wdog debug\n");
}
-
-static struct of_device_id msm_wdog_debug_match_table[] = {
- { .compatible = "qcom,msm-wdog-debug" },
- {}
-};
-
-static struct platform_driver msm_wdog_debug_driver = {
- .probe = msm_wdog_debug_probe,
- .remove = msm_wdog_debug_remove,
- .driver = {
- .name = MODULE_NAME,
- .owner = THIS_MODULE,
- .of_match_table = msm_wdog_debug_match_table,
- },
-};
-
-static int __devinit wdog_debug_init(void)
-{
- return platform_driver_register(&msm_wdog_debug_driver);
-}
-module_init(wdog_debug_init);
-
-static void __exit wdog_debug_exit(void)
-{
- platform_driver_unregister(&msm_wdog_debug_driver);
-}
-module_exit(wdog_debug_exit);
-
-MODULE_DESCRIPTION("MSM Driver to disable debug Image");
-MODULE_LICENSE("GPL v2");
+EXPORT_SYMBOL(msm_disable_wdog_debug);
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index 2ec87b8..892b007 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -425,9 +425,9 @@
writel_relaxed(1, l2x0_base + L2X0_CTRL);
}
- outer_cache.inv_range = l2x0_inv_range;
- outer_cache.clean_range = l2x0_clean_range;
- outer_cache.flush_range = l2x0_flush_range;
+ outer_cache.inv_range = l2x0_inv_range;
+ outer_cache.clean_range = l2x0_clean_range;
+ outer_cache.flush_range = l2x0_flush_range;
outer_cache.sync = l2x0_cache_sync;
outer_cache.flush_all = l2x0_flush_all;
outer_cache.inv_all = l2x0_inv_all;
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 38da432..66567bb 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -375,19 +375,24 @@
return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
}
-unsigned long memory_hole_offset;
+phys_addr_t memory_hole_offset;
EXPORT_SYMBOL(memory_hole_offset);
-unsigned long memory_hole_start;
+phys_addr_t memory_hole_start;
EXPORT_SYMBOL(memory_hole_start);
-unsigned long memory_hole_end;
+phys_addr_t memory_hole_end;
EXPORT_SYMBOL(memory_hole_end);
+unsigned long memory_hole_align;
+EXPORT_SYMBOL(memory_hole_align);
+unsigned long virtual_hole_start;
+unsigned long virtual_hole_end;
#ifdef CONFIG_DONT_MAP_HOLE_AFTER_MEMBANK0
void find_memory_hole(void)
{
int i;
- unsigned long hole_start;
- unsigned long hole_size;
+ phys_addr_t hole_start;
+ phys_addr_t hole_size;
+ unsigned long hole_end_virt;
/*
* Find the start and end of the hole, using meminfo
@@ -420,7 +425,33 @@
}
}
}
+
memory_hole_offset = memory_hole_start - PHYS_OFFSET;
+ if (!IS_ALIGNED(memory_hole_start, SECTION_SIZE)) {
+ pr_err("memory_hole_start %pa is not aligned to %lx\n",
+ &memory_hole_start, SECTION_SIZE);
+ BUG();
+ }
+ if (!IS_ALIGNED(memory_hole_end, SECTION_SIZE)) {
+ pr_err("memory_hole_end %pa is not aligned to %lx\n",
+ &memory_hole_end, SECTION_SIZE);
+ BUG();
+ }
+
+ hole_end_virt = __phys_to_virt(memory_hole_end);
+
+ if ((!IS_ALIGNED(hole_end_virt, PMD_SIZE) &&
+ IS_ALIGNED(memory_hole_end, PMD_SIZE)) ||
+ (IS_ALIGNED(hole_end_virt, PMD_SIZE) &&
+ !IS_ALIGNED(memory_hole_end, PMD_SIZE))) {
+ memory_hole_align = !IS_ALIGNED(hole_end_virt, PMD_SIZE) ?
+ hole_end_virt & ~PMD_MASK :
+ memory_hole_end & ~PMD_MASK;
+ virtual_hole_start = hole_end_virt;
+ virtual_hole_end = hole_end_virt + memory_hole_align;
+ pr_info("Physical memory hole is not aligned. There will be a virtual memory hole from %lx to %lx\n",
+ virtual_hole_start, virtual_hole_end);
+ }
}
#endif
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index 0e31910..266be05 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -625,39 +625,60 @@
} while (pte++, addr += PAGE_SIZE, addr != end);
}
-static void __init alloc_init_section(pud_t *pud, unsigned long addr,
+static void __init map_init_section(pmd_t *pmd, unsigned long addr,
+ unsigned long end, phys_addr_t phys,
+ const struct mem_type *type)
+{
+#ifndef CONFIG_ARM_LPAE
+ /*
+ * In classic MMU format, puds and pmds are folded in to
+ * the pgds. pmd_offset gives the PGD entry. PGDs refer to a
+ * group of L1 entries making up one logical pointer to
+ * an L2 table (2MB), where as PMDs refer to the individual
+ * L1 entries (1MB). Hence increment to get the correct
+ * offset for odd 1MB sections.
+ * (See arch/arm/include/asm/pgtable-2level.h)
+ */
+ if (addr & SECTION_SIZE)
+ pmd++;
+#endif
+ do {
+ *pmd = __pmd(phys | type->prot_sect);
+ phys += SECTION_SIZE;
+ } while (pmd++, addr += SECTION_SIZE, addr != end);
+
+ flush_pmd_entry(pmd);
+}
+
+static void __init alloc_init_pmd(pud_t *pud, unsigned long addr,
unsigned long end, phys_addr_t phys,
const struct mem_type *type)
{
pmd_t *pmd = pmd_offset(pud, addr);
+ unsigned long next;
- /*
- * Try a section mapping - end, addr and phys must all be aligned
- * to a section boundary. Note that PMDs refer to the individual
- * L1 entries, whereas PGDs refer to a group of L1 entries making
- * up one logical pointer to an L2 table.
- */
- if (type->prot_sect && ((addr | end | phys) & ~SECTION_MASK) == 0) {
- pmd_t *p = pmd;
-
-#ifndef CONFIG_ARM_LPAE
- if (addr & SECTION_SIZE)
- pmd++;
-#endif
-
- do {
- *pmd = __pmd(phys | type->prot_sect);
- phys += SECTION_SIZE;
- } while (pmd++, addr += SECTION_SIZE, addr != end);
-
- flush_pmd_entry(p);
- } else {
+ do {
/*
- * No need to loop; pte's aren't interested in the
- * individual L1 entries.
+ * With LPAE, we must loop over to map
+ * all the pmds for the given range.
*/
- alloc_init_pte(pmd, addr, end, __phys_to_pfn(phys), type);
- }
+ next = pmd_addr_end(addr, end);
+
+ /*
+ * Try a section mapping - addr, next and phys must all be
+ * aligned to a section boundary.
+ */
+ if (type->prot_sect &&
+ ((addr | next | phys) & ~SECTION_MASK) == 0) {
+ map_init_section(pmd, addr, next, phys, type);
+ } else {
+ alloc_init_pte(pmd, addr, next,
+ __phys_to_pfn(phys), type);
+ }
+
+ phys += next - addr;
+
+ } while (pmd++, addr = next, addr != end);
}
static void __init alloc_init_pud(pgd_t *pgd, unsigned long addr,
@@ -668,7 +689,7 @@
do {
next = pud_addr_end(addr, end);
- alloc_init_section(pud, addr, next, phys, type);
+ alloc_init_pmd(pud, addr, next, phys, type);
phys += next - addr;
} while (pud++, addr = next, addr != end);
}
diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c
index 3a8bbc5..ed91480 100644
--- a/drivers/base/dma-contiguous.c
+++ b/drivers/base/dma-contiguous.c
@@ -213,8 +213,7 @@
__be32 *prop;
char *name;
- if (strncmp(uname, "region@", 7) != 0 || depth != 2 ||
- !of_get_flat_dt_prop(node, "linux,contiguous-region", NULL))
+ if (!of_get_flat_dt_prop(node, "linux,contiguous-region", NULL))
return 0;
prop = of_get_flat_dt_prop(node, "reg", &len);
diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c
index ac993ea..50b2831 100644
--- a/drivers/base/power/opp.c
+++ b/drivers/base/power/opp.c
@@ -22,6 +22,8 @@
#include <linux/rculist.h>
#include <linux/rcupdate.h>
#include <linux/opp.h>
+#include <linux/of.h>
+#include <linux/export.h>
/*
* Internal data structure organization with the OPP layer library is as
@@ -64,6 +66,7 @@
unsigned long u_volt;
struct device_opp *dev_opp;
+ struct rcu_head head;
};
/**
@@ -159,6 +162,7 @@
return v;
}
+EXPORT_SYMBOL(opp_get_voltage);
/**
* opp_get_freq() - Gets the frequency corresponding to an available opp
@@ -188,6 +192,7 @@
return f;
}
+EXPORT_SYMBOL(opp_get_freq);
/**
* opp_get_opp_count() - Get number of opps available in the opp list
@@ -220,6 +225,7 @@
return count;
}
+EXPORT_SYMBOL(opp_get_opp_count);
/**
* opp_find_freq_exact() - search for an exact frequency
@@ -229,7 +235,10 @@
*
* Searches for exact match in the opp list and returns pointer to the matching
* opp if found, else returns ERR_PTR in case of error and should be handled
- * using IS_ERR.
+ * using IS_ERR. Error return values can be:
+ * EINVAL: for bad pointer
+ * ERANGE: no match found for search
+ * ENODEV: if device not found in list of registered devices
*
* Note: available is a modifier for the search. if available=true, then the
* match is for exact matching frequency and is available in the stored OPP
@@ -248,7 +257,7 @@
bool available)
{
struct device_opp *dev_opp;
- struct opp *temp_opp, *opp = ERR_PTR(-ENODEV);
+ struct opp *temp_opp, *opp = ERR_PTR(-ERANGE);
dev_opp = find_device_opp(dev);
if (IS_ERR(dev_opp)) {
@@ -267,6 +276,7 @@
return opp;
}
+EXPORT_SYMBOL(opp_find_freq_exact);
/**
* opp_find_freq_ceil() - Search for an rounded ceil freq
@@ -277,7 +287,11 @@
* for a device.
*
* Returns matching *opp and refreshes *freq accordingly, else returns
- * ERR_PTR in case of error and should be handled using IS_ERR.
+ * ERR_PTR in case of error and should be handled using IS_ERR. Error return
+ * values can be:
+ * EINVAL: for bad pointer
+ * ERANGE: no match found for search
+ * ENODEV: if device not found in list of registered devices
*
* Locking: This function must be called under rcu_read_lock(). opp is a rcu
* protected pointer. The reason for the same is that the opp pointer which is
@@ -288,7 +302,7 @@
struct opp *opp_find_freq_ceil(struct device *dev, unsigned long *freq)
{
struct device_opp *dev_opp;
- struct opp *temp_opp, *opp = ERR_PTR(-ENODEV);
+ struct opp *temp_opp, *opp = ERR_PTR(-ERANGE);
if (!dev || !freq) {
dev_err(dev, "%s: Invalid argument freq=%p\n", __func__, freq);
@@ -297,7 +311,7 @@
dev_opp = find_device_opp(dev);
if (IS_ERR(dev_opp))
- return opp;
+ return ERR_CAST(dev_opp);
list_for_each_entry_rcu(temp_opp, &dev_opp->opp_list, node) {
if (temp_opp->available && temp_opp->rate >= *freq) {
@@ -309,6 +323,7 @@
return opp;
}
+EXPORT_SYMBOL(opp_find_freq_ceil);
/**
* opp_find_freq_floor() - Search for a rounded floor freq
@@ -319,7 +334,11 @@
* for a device.
*
* Returns matching *opp and refreshes *freq accordingly, else returns
- * ERR_PTR in case of error and should be handled using IS_ERR.
+ * ERR_PTR in case of error and should be handled using IS_ERR. Error return
+ * values can be:
+ * EINVAL: for bad pointer
+ * ERANGE: no match found for search
+ * ENODEV: if device not found in list of registered devices
*
* Locking: This function must be called under rcu_read_lock(). opp is a rcu
* protected pointer. The reason for the same is that the opp pointer which is
@@ -330,7 +349,7 @@
struct opp *opp_find_freq_floor(struct device *dev, unsigned long *freq)
{
struct device_opp *dev_opp;
- struct opp *temp_opp, *opp = ERR_PTR(-ENODEV);
+ struct opp *temp_opp, *opp = ERR_PTR(-ERANGE);
if (!dev || !freq) {
dev_err(dev, "%s: Invalid argument freq=%p\n", __func__, freq);
@@ -339,7 +358,7 @@
dev_opp = find_device_opp(dev);
if (IS_ERR(dev_opp))
- return opp;
+ return ERR_CAST(dev_opp);
list_for_each_entry_rcu(temp_opp, &dev_opp->opp_list, node) {
if (temp_opp->available) {
@@ -355,6 +374,7 @@
return opp;
}
+EXPORT_SYMBOL(opp_find_freq_floor);
/**
* opp_add() - Add an OPP table from a table definitions
@@ -511,7 +531,7 @@
list_replace_rcu(&opp->node, &new_opp->node);
mutex_unlock(&dev_opp_list_lock);
- synchronize_rcu();
+ kfree_rcu(opp, head);
/* Notify the change of the OPP availability */
if (availability_req)
@@ -521,13 +541,10 @@
srcu_notifier_call_chain(&dev_opp->head, OPP_EVENT_DISABLE,
new_opp);
- /* clean up old opp */
- new_opp = opp;
- goto out;
+ return 0;
unlock:
mutex_unlock(&dev_opp_list_lock);
-out:
kfree(new_opp);
return r;
}
@@ -551,6 +568,7 @@
{
return opp_set_availability(dev, freq, true);
}
+EXPORT_SYMBOL(opp_enable);
/**
* opp_disable() - Disable a specific OPP
@@ -572,6 +590,7 @@
{
return opp_set_availability(dev, freq, false);
}
+EXPORT_SYMBOL(opp_disable);
#ifdef CONFIG_CPU_FREQ
/**
@@ -674,3 +693,49 @@
return &dev_opp->head;
}
+
+#ifdef CONFIG_OF
+/**
+ * of_init_opp_table() - Initialize opp table from device tree
+ * @dev: device pointer used to lookup device OPPs.
+ *
+ * Register the initial OPP table with the OPP library for given device.
+ */
+int of_init_opp_table(struct device *dev)
+{
+ const struct property *prop;
+ const __be32 *val;
+ int nr;
+
+ prop = of_find_property(dev->of_node, "operating-points", NULL);
+ if (!prop)
+ return -ENODEV;
+ if (!prop->value)
+ return -ENODATA;
+
+ /*
+ * Each OPP is a set of tuples consisting of frequency and
+ * voltage like <freq-kHz vol-uV>.
+ */
+ nr = prop->length / sizeof(u32);
+ if (nr % 2) {
+ dev_err(dev, "%s: Invalid OPP list\n", __func__);
+ return -EINVAL;
+ }
+
+ val = prop->value;
+ while (nr) {
+ unsigned long freq = be32_to_cpup(val++) * 1000;
+ unsigned long volt = be32_to_cpup(val++);
+
+ if (opp_add(dev, freq, volt)) {
+ dev_warn(dev, "%s: Failed to add OPP %ld\n",
+ __func__, freq);
+ continue;
+ }
+ nr -= 2;
+ }
+
+ return 0;
+}
+#endif
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c
index 73fe5d6..d78327f 100644
--- a/drivers/char/adsprpc.c
+++ b/drivers/char/adsprpc.c
@@ -89,7 +89,7 @@
int n = -1, err = 0;
VERIFY(err, 0 != access_ok(access ? VERIFY_WRITE : VERIFY_READ,
- (void __user *)start, len));
+ (void __user *)start, len));
if (err)
goto bail;
VERIFY(err, 0 != (vma = find_vma(current->mm, start)));
@@ -138,6 +138,15 @@
struct hlist_head htbl[RPC_HASH_SZ];
};
+struct fastrpc_mmap {
+ struct hlist_node hn;
+ struct ion_handle *handle;
+ void *virt;
+ uint32_t vaddrin;
+ uint32_t vaddrout;
+ int size;
+};
+
struct fastrpc_buf {
struct ion_handle *handle;
void *virt;
@@ -146,6 +155,11 @@
int used;
};
+struct file_data {
+ spinlock_t hlock;
+ struct hlist_head hlst;
+};
+
struct fastrpc_device {
uint32_t tgid;
struct hlist_node hn;
@@ -168,18 +182,31 @@
}
}
+static void free_map(struct fastrpc_mmap *map)
+{
+ struct fastrpc_apps *me = &gfa;
+ if (map->handle) {
+ if (map->virt) {
+ ion_unmap_kernel(me->iclient, map->handle);
+ map->virt = 0;
+ }
+ ion_free(me->iclient, map->handle);
+ }
+ map->handle = 0;
+}
+
static int alloc_mem(struct fastrpc_buf *buf)
{
struct ion_client *clnt = gfa.iclient;
struct sg_table *sg;
int err = 0;
-
+ buf->handle = 0;
+ buf->virt = 0;
buf->handle = ion_alloc(clnt, buf->size, SZ_4K,
ION_HEAP(ION_AUDIO_HEAP_ID), 0);
VERIFY(err, 0 == IS_ERR_OR_NULL(buf->handle));
if (err)
goto bail;
- buf->virt = 0;
VERIFY(err, 0 != (buf->virt = ion_map_kernel(clnt, buf->handle)));
if (err)
goto bail;
@@ -211,7 +238,6 @@
static void context_list_dtor(struct smq_context_list *me)
{
kfree(me->ls);
- me->ls = 0;
}
static void context_list_alloc_ctx(struct smq_context_list *me,
@@ -277,7 +303,6 @@
if (rlen < 0) {
rlen = ((uint32_t)pages - (uint32_t)obuf->virt) - obuf->size;
obuf->size += buf_page_size(rlen);
- obuf->handle = 0;
VERIFY(err, 0 == alloc_mem(obuf));
if (err)
goto bail;
@@ -314,7 +339,6 @@
if (obuf->handle != ibuf->handle)
free_mem(obuf);
obuf->size += buf_page_size(sizeof(*pages));
- obuf->handle = 0;
VERIFY(err, 0 == alloc_mem(obuf));
if (err)
goto bail;
@@ -430,10 +454,15 @@
outbufs = REMOTE_SCALARS_OUTBUFS(sc);
for (i = inbufs; i < inbufs + outbufs; ++i) {
if (rpra[i].buf.pv != pra[i].buf.pv) {
- VERIFY(err, 0 == copy_to_user(pra[i].buf.pv,
+ if (!kernel) {
+ VERIFY(err, 0 == copy_to_user(pra[i].buf.pv,
rpra[i].buf.pv, rpra[i].buf.len));
- if (err)
- goto bail;
+ if (err)
+ goto bail;
+ } else {
+ memmove(pra[i].buf.pv, rpra[i].buf.pv,
+ rpra[i].buf.len);
+ }
}
}
size = sizeof(*rpra) * REMOTE_SCALARS_OUTHANDLES(sc);
@@ -471,15 +500,17 @@
dmac_inv_range(rpra, (char *)rpra + used);
}
-static int fastrpc_invoke_send(struct fastrpc_apps *me, uint32_t handle,
+static int fastrpc_invoke_send(struct fastrpc_apps *me,
+ uint32_t kernel, uint32_t handle,
uint32_t sc, struct smq_invoke_ctx *ctx,
struct fastrpc_buf *buf)
{
struct smq_msg msg;
int err = 0, len;
-
msg.pid = current->tgid;
msg.tid = current->pid;
+ if (kernel)
+ msg.pid = 0;
msg.invoke.header.ctx = ctx;
msg.invoke.header.handle = handle;
msg.invoke.header.sc = sc;
@@ -595,12 +626,15 @@
VERIFY(err, 0 != (fd = kzalloc(sizeof(*fd), GFP_KERNEL)));
if (err)
goto bail;
+
+ INIT_HLIST_NODE(&fd->hn);
+
fd->buf.size = PAGE_SIZE;
VERIFY(err, 0 == alloc_mem(&fd->buf));
if (err)
goto bail;
fd->tgid = current->tgid;
- INIT_HLIST_NODE(&fd->hn);
+
*dev = fd;
bail:
if (err)
@@ -611,27 +645,28 @@
static int get_dev(struct fastrpc_apps *me, struct fastrpc_device **rdev)
{
struct hlist_head *head;
- struct fastrpc_device *dev = 0;
- struct hlist_node *n;
+ struct fastrpc_device *dev = 0, *devfree = 0;
+ struct hlist_node *pos, *n;
uint32_t h = hash_32(current->tgid, RPC_HASH_BITS);
int err = 0;
spin_lock(&me->hlock);
head = &me->htbl[h];
- hlist_for_each_entry(dev, n, head, hn) {
+ hlist_for_each_entry_safe(dev, pos, n, head, hn) {
if (dev->tgid == current->tgid) {
hlist_del(&dev->hn);
+ devfree = dev;
break;
}
}
spin_unlock(&me->hlock);
- VERIFY(err, dev != 0);
+ VERIFY(err, devfree != 0);
if (err)
goto bail;
- *rdev = dev;
+ *rdev = devfree;
bail:
if (err) {
- free_dev(dev);
+ free_dev(devfree);
err = alloc_dev(rdev);
}
return err;
@@ -680,8 +715,8 @@
}
context_list_alloc_ctx(&me->clst, &ctx);
- VERIFY(err, 0 == fastrpc_invoke_send(me, invoke->handle, sc, ctx,
- &obuf));
+ VERIFY(err, 0 == fastrpc_invoke_send(me, kernel, invoke->handle, sc,
+ ctx, &obuf));
if (err)
goto bail;
inv_args(sc, rpra, obuf.used);
@@ -729,7 +764,7 @@
ioctl.handle = 1;
ioctl.sc = REMOTE_SCALARS_MAKE(0, 1, 0);
ioctl.pra = ra;
- VERIFY(err, 0 == fastrpc_internal_invoke(me, 1, &ioctl, ra));
+ VERIFY(err, 0 == (err = fastrpc_internal_invoke(me, 1, &ioctl, ra)));
return err;
}
@@ -747,7 +782,155 @@
ioctl.handle = 1;
ioctl.sc = REMOTE_SCALARS_MAKE(1, 1, 0);
ioctl.pra = ra;
- VERIFY(err, 0 == fastrpc_internal_invoke(me, 1, &ioctl, ra));
+ VERIFY(err, 0 == (err = fastrpc_internal_invoke(me, 1, &ioctl, ra)));
+ return err;
+}
+
+static int fastrpc_mmap_on_dsp(struct fastrpc_apps *me,
+ struct fastrpc_ioctl_mmap *mmap,
+ struct smq_phy_page *pages,
+ int num)
+{
+ struct fastrpc_ioctl_invoke ioctl;
+ remote_arg_t ra[3];
+ int err = 0;
+ struct {
+ int pid;
+ uint32_t flags;
+ uint32_t vaddrin;
+ int num;
+ } inargs;
+
+ struct {
+ uint32_t vaddrout;
+ } routargs;
+ inargs.pid = current->tgid;
+ inargs.vaddrin = mmap->vaddrin;
+ inargs.flags = mmap->flags;
+ inargs.num = num;
+ ra[0].buf.pv = &inargs;
+ ra[0].buf.len = sizeof(inargs);
+
+ ra[1].buf.pv = pages;
+ ra[1].buf.len = num * sizeof(*pages);
+
+ ra[2].buf.pv = &routargs;
+ ra[2].buf.len = sizeof(routargs);
+
+ ioctl.handle = 1;
+ ioctl.sc = REMOTE_SCALARS_MAKE(2, 2, 1);
+ ioctl.pra = ra;
+ VERIFY(err, 0 == (err = fastrpc_internal_invoke(me, 1, &ioctl, ra)));
+ mmap->vaddrout = routargs.vaddrout;
+ if (err)
+ goto bail;
+bail:
+ return err;
+}
+
+static int fastrpc_munmap_on_dsp(struct fastrpc_apps *me,
+ struct fastrpc_ioctl_munmap *munmap)
+{
+ struct fastrpc_ioctl_invoke ioctl;
+ remote_arg_t ra[1];
+ int err = 0;
+ struct {
+ int pid;
+ uint32_t vaddrout;
+ int size;
+ } inargs;
+
+ inargs.pid = current->tgid;
+ inargs.size = munmap->size;
+ inargs.vaddrout = munmap->vaddrout;
+ ra[0].buf.pv = &inargs;
+ ra[0].buf.len = sizeof(inargs);
+
+ ioctl.handle = 1;
+ ioctl.sc = REMOTE_SCALARS_MAKE(3, 1, 0);
+ ioctl.pra = ra;
+ VERIFY(err, 0 == (err = fastrpc_internal_invoke(me, 1, &ioctl, ra)));
+ return err;
+}
+
+static int fastrpc_internal_munmap(struct fastrpc_apps *me,
+ struct file_data *fdata,
+ struct fastrpc_ioctl_munmap *munmap)
+{
+ int err = 0;
+ struct fastrpc_mmap *map = 0, *mapfree = 0;
+ struct hlist_node *pos, *n;
+ VERIFY(err, 0 == (err = fastrpc_munmap_on_dsp(me, munmap)));
+ if (err)
+ goto bail;
+ spin_lock(&fdata->hlock);
+ hlist_for_each_entry_safe(map, pos, n, &fdata->hlst, hn) {
+ if (map->vaddrout == munmap->vaddrout &&
+ map->size == munmap->size) {
+ hlist_del(&map->hn);
+ mapfree = map;
+ map = 0;
+ break;
+ }
+ }
+ spin_unlock(&fdata->hlock);
+bail:
+ if (mapfree) {
+ free_map(mapfree);
+ kfree(mapfree);
+ }
+ return err;
+}
+
+
+static int fastrpc_internal_mmap(struct fastrpc_apps *me,
+ struct file_data *fdata,
+ struct fastrpc_ioctl_mmap *mmap)
+{
+ struct ion_client *clnt = gfa.iclient;
+ struct fastrpc_mmap *map = 0;
+ struct smq_phy_page *pages = 0;
+ void *buf;
+ int len;
+ int num;
+ int err = 0;
+
+ VERIFY(err, 0 != (map = kzalloc(sizeof(*map), GFP_KERNEL)));
+ if (err)
+ goto bail;
+ map->handle = ion_import_dma_buf(clnt, mmap->fd);
+ VERIFY(err, 0 == IS_ERR_OR_NULL(map->handle));
+ if (err)
+ goto bail;
+ VERIFY(err, 0 != (map->virt = ion_map_kernel(clnt, map->handle)));
+ if (err)
+ goto bail;
+ buf = (void *)mmap->vaddrin;
+ len = mmap->size;
+ num = buf_num_pages(buf, len);
+ VERIFY(err, 0 != (pages = kzalloc(num * sizeof(*pages), GFP_KERNEL)));
+ if (err)
+ goto bail;
+ VERIFY(err, 0 < (num = buf_get_pages(buf, len, num, 1, pages, num)));
+ if (err)
+ goto bail;
+
+ VERIFY(err, 0 == fastrpc_mmap_on_dsp(me, mmap, pages, num));
+ if (err)
+ goto bail;
+ map->vaddrin = mmap->vaddrin;
+ map->vaddrout = mmap->vaddrout;
+ map->size = mmap->size;
+ INIT_HLIST_NODE(&map->hn);
+ spin_lock(&fdata->hlock);
+ hlist_add_head(&map->hn, &fdata->hlst);
+ spin_unlock(&fdata->hlock);
+ bail:
+ if (err && map) {
+ free_map(map);
+ kfree(map);
+ }
+ kfree(pages);
return err;
}
@@ -756,22 +939,23 @@
struct fastrpc_apps *me = &gfa;
uint32_t h = hash_32(current->tgid, RPC_HASH_BITS);
struct hlist_head *head;
- struct hlist_node *pos;
- struct fastrpc_device *dev;
+ struct hlist_node *pos, *n;
+ struct fastrpc_device *dev, *devfree;
rnext:
- dev = 0;
+ devfree = dev = 0;
spin_lock(&me->hlock);
head = &me->htbl[h];
- hlist_for_each_entry(dev, pos, head, hn) {
+ hlist_for_each_entry_safe(dev, pos, n, head, hn) {
if (dev->tgid == current->tgid) {
hlist_del(&dev->hn);
+ devfree = dev;
break;
}
}
spin_unlock(&me->hlock);
- if (dev) {
- free_dev(dev);
+ if (devfree) {
+ free_dev(devfree);
goto rnext;
}
return;
@@ -779,22 +963,48 @@
static int fastrpc_device_release(struct inode *inode, struct file *file)
{
+ struct file_data *fdata = (struct file_data *)file->private_data;
(void)fastrpc_release_current_dsp_process();
cleanup_current_dev();
+ if (fdata) {
+ struct fastrpc_mmap *map;
+ struct hlist_node *n, *pos;
+ file->private_data = 0;
+ hlist_for_each_entry_safe(map, pos, n, &fdata->hlst, hn) {
+ hlist_del(&map->hn);
+ free_map(map);
+ kfree(map);
+ }
+ kfree(fdata);
+ }
return 0;
}
static int fastrpc_device_open(struct inode *inode, struct file *filp)
{
int err = 0;
-
+ filp->private_data = 0;
if (0 != try_module_get(THIS_MODULE)) {
+ struct file_data *fdata = 0;
/* This call will cause a dev to be created
* which will addref this module
*/
+ VERIFY(err, 0 != (fdata = kzalloc(sizeof(*fdata), GFP_KERNEL)));
+ if (err)
+ goto bail;
+
+ spin_lock_init(&fdata->hlock);
+ INIT_HLIST_HEAD(&fdata->hlst);
+
VERIFY(err, 0 == fastrpc_create_current_dsp_process());
if (err)
+ goto bail;
+ filp->private_data = fdata;
+bail:
+ if (err) {
cleanup_current_dev();
+ kfree(fdata);
+ }
module_put(THIS_MODULE);
}
return err;
@@ -806,8 +1016,11 @@
{
struct fastrpc_apps *me = &gfa;
struct fastrpc_ioctl_invoke invoke;
+ struct fastrpc_ioctl_mmap mmap;
+ struct fastrpc_ioctl_munmap munmap;
remote_arg_t *pra = 0;
void *param = (char *)ioctl_param;
+ struct file_data *fdata = (struct file_data *)file->private_data;
int bufs, err = 0;
switch (ioctl_num) {
@@ -832,6 +1045,29 @@
if (err)
goto bail;
break;
+ case FASTRPC_IOCTL_MMAP:
+ VERIFY(err, 0 == copy_from_user(&mmap, param,
+ sizeof(mmap)));
+ if (err)
+ goto bail;
+ VERIFY(err, 0 == (err = fastrpc_internal_mmap(me, fdata,
+ &mmap)));
+ if (err)
+ goto bail;
+ VERIFY(err, 0 == copy_to_user(param, &mmap, sizeof(mmap)));
+ if (err)
+ goto bail;
+ break;
+ case FASTRPC_IOCTL_MUNMAP:
+ VERIFY(err, 0 == copy_from_user(&munmap, param,
+ sizeof(munmap)));
+ if (err)
+ goto bail;
+ VERIFY(err, 0 == (err = fastrpc_internal_munmap(me, fdata,
+ &munmap)));
+ if (err)
+ goto bail;
+ break;
default:
err = -ENOTTY;
break;
diff --git a/drivers/char/adsprpc_shared.h b/drivers/char/adsprpc_shared.h
index 8932d3c..f2804ad 100644
--- a/drivers/char/adsprpc_shared.h
+++ b/drivers/char/adsprpc_shared.h
@@ -16,7 +16,9 @@
#include <linux/types.h>
-#define FASTRPC_IOCTL_INVOKE _IOWR('R', 1, struct fastrpc_ioctl_invoke)
+#define FASTRPC_IOCTL_INVOKE _IOWR('R', 1, struct fastrpc_ioctl_invoke)
+#define FASTRPC_IOCTL_MMAP _IOWR('R', 2, struct fastrpc_ioctl_mmap)
+#define FASTRPC_IOCTL_MUNMAP _IOWR('R', 3, struct fastrpc_ioctl_munmap)
#define FASTRPC_SMD_GUID "fastrpcsmd-apps-dsp"
#define DEVICE_NAME "adsprpc-smd"
@@ -92,6 +94,20 @@
remote_arg_t *pra; /* remote arguments list */
};
+struct fastrpc_ioctl_munmap {
+ uint32_t vaddrout; /* address to unmap */
+ int size; /* size */
+};
+
+
+struct fastrpc_ioctl_mmap {
+ int fd; /* ion fd */
+ uint32_t flags; /* flags for dsp to map with */
+ uint32_t vaddrin; /* optional virtual address */
+ int size; /* size */
+ uint32_t vaddrout; /* dsps virtual address */
+};
+
struct smq_null_invoke {
struct smq_invoke_ctx *ctx; /* invoke caller context */
uint32_t handle; /* handle to invoke */
diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c
index 6ae5d03..6d28042 100644
--- a/drivers/char/diag/diag_dci.c
+++ b/drivers/char/diag/diag_dci.c
@@ -37,6 +37,7 @@
unsigned char dci_cumulative_event_mask[DCI_EVENT_MASK_SIZE];
struct mutex dci_log_mask_mutex;
struct mutex dci_event_mask_mutex;
+struct mutex dci_health_mutex;
#define DCI_CHK_CAPACITY(entry, new_data_len) \
((entry->data_len + new_data_len > entry->total_capacity) ? 1 : 0) \
@@ -211,6 +212,7 @@
entry = &(driver->dci_client_tbl[i]);
event_mask_ptr = entry->dci_event_mask +
byte_index;
+ mutex_lock(&dci_health_mutex);
if (*event_mask_ptr & byte_mask) {
/* copy to client buffer */
if (DCI_CHK_CAPACITY(entry,
@@ -218,7 +220,9 @@
pr_err("diag: DCI event drop\n");
driver->dci_client_tbl[i].
dropped_events++;
- return;
+ mutex_unlock(
+ &dci_health_mutex);
+ break;
}
driver->dci_client_tbl[i].
received_events++;
@@ -230,6 +234,7 @@
, total_event_len);
entry->data_len += 4 + total_event_len;
}
+ mutex_unlock(&dci_health_mutex);
}
}
temp_len += 2 + timestamp_len + payload_len_field + payload_len;
@@ -264,6 +269,7 @@
if (!log_mask_ptr)
return;
log_mask_ptr = log_mask_ptr + byte_offset;
+ mutex_lock(&dci_health_mutex);
if (*log_mask_ptr & byte_mask) {
pr_debug("\t log code %x needed by client %d",
log_code, entry->client->tgid);
@@ -273,6 +279,8 @@
pr_err("diag: DCI log drop\n");
driver->dci_client_tbl[i].
dropped_logs++;
+ mutex_unlock(
+ &dci_health_mutex);
return;
}
driver->dci_client_tbl[i].received_logs++;
@@ -282,6 +290,7 @@
buf + 4, *(uint16_t *)(buf + 2));
entry->data_len += 4 + *(uint16_t *)(buf + 2);
}
+ mutex_unlock(&dci_health_mutex);
}
}
}
@@ -1028,6 +1037,8 @@
mutex_init(&driver->dci_mutex);
mutex_init(&dci_log_mask_mutex);
mutex_init(&dci_event_mask_mutex);
+ mutex_init(&dci_health_mutex);
+
for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++) {
success = diag_smd_constructor(&driver->smd_dci[i],
i, SMD_DCI_TYPE);
@@ -1082,5 +1093,118 @@
kfree(driver->req_tracking_tbl);
kfree(driver->dci_client_tbl);
kfree(driver->apps_dci_buf);
+ mutex_destroy(&driver->dci_mutex);
+ mutex_destroy(&dci_log_mask_mutex);
+ mutex_destroy(&dci_event_mask_mutex);
+ mutex_destroy(&dci_health_mutex);
destroy_workqueue(driver->diag_dci_wq);
}
+
+int diag_dci_clear_log_mask()
+{
+ int i, j, k, err = DIAG_DCI_NO_ERROR;
+ uint8_t *log_mask_ptr, *update_ptr;
+
+ i = diag_dci_find_client_index(current->tgid);
+ if (i == DCI_CLIENT_INDEX_INVALID)
+ return DIAG_DCI_TABLE_ERR;
+
+ mutex_lock(&dci_log_mask_mutex);
+ create_dci_log_mask_tbl(
+ driver->dci_client_tbl[i].dci_log_mask);
+ memset(dci_cumulative_log_mask,
+ 0x0, DCI_LOG_MASK_SIZE);
+ for (i = 0; i < MAX_DCI_CLIENTS; i++) {
+ update_ptr = dci_cumulative_log_mask;
+ if (driver->dci_client_tbl[i].client) {
+ log_mask_ptr =
+ driver->dci_client_tbl[i].dci_log_mask;
+ for (j = 0; j < 16; j++) {
+ *update_ptr = j;
+ *(update_ptr + 1) = 1;
+ update_ptr += 2;
+ log_mask_ptr += 2;
+ for (k = 0; k < 513; k++) {
+ *update_ptr |= *log_mask_ptr;
+ update_ptr++;
+ log_mask_ptr++;
+ }
+ }
+ }
+ }
+ mutex_unlock(&dci_log_mask_mutex);
+ err = diag_send_dci_log_mask(driver->smd_cntl[MODEM_DATA].ch);
+ return err;
+}
+
+int diag_dci_clear_event_mask()
+{
+ int i, j, err = DIAG_DCI_NO_ERROR;
+ uint8_t *event_mask_ptr, *update_ptr;
+
+ i = diag_dci_find_client_index(current->tgid);
+ if (i == DCI_CLIENT_INDEX_INVALID)
+ return DIAG_DCI_TABLE_ERR;
+
+ mutex_lock(&dci_event_mask_mutex);
+ memset(driver->dci_client_tbl[i].dci_event_mask,
+ 0x0, DCI_EVENT_MASK_SIZE);
+ memset(dci_cumulative_event_mask,
+ 0x0, DCI_EVENT_MASK_SIZE);
+ update_ptr = dci_cumulative_event_mask;
+ for (i = 0; i < MAX_DCI_CLIENTS; i++) {
+ event_mask_ptr =
+ driver->dci_client_tbl[i].dci_event_mask;
+ for (j = 0; j < DCI_EVENT_MASK_SIZE; j++)
+ *(update_ptr + j) |= *(event_mask_ptr + j);
+ }
+ mutex_unlock(&dci_event_mask_mutex);
+ err = diag_send_dci_event_mask(driver->smd_cntl[MODEM_DATA].ch);
+ return err;
+}
+
+int diag_dci_query_log_mask(uint16_t log_code)
+{
+ uint16_t item_num;
+ uint8_t equip_id, *log_mask_ptr, byte_mask;
+ int i, byte_index, offset;
+
+ equip_id = LOG_GET_EQUIP_ID(log_code);
+ item_num = LOG_GET_ITEM_NUM(log_code);
+ byte_index = item_num/8 + 2;
+ byte_mask = 0x01 << (item_num % 8);
+ offset = equip_id * 514;
+
+ i = diag_dci_find_client_index(current->tgid);
+ if (i != DCI_CLIENT_INDEX_INVALID) {
+ log_mask_ptr = driver->dci_client_tbl[i].dci_log_mask;
+ log_mask_ptr = log_mask_ptr + offset + byte_index;
+ return ((*log_mask_ptr & byte_mask) == byte_mask) ?
+ 1 : 0;
+ }
+ return 0;
+}
+
+
+int diag_dci_query_event_mask(uint16_t event_id)
+{
+ uint8_t *event_mask_ptr, byte_mask;
+ int i, byte_index, bit_index;
+ byte_index = event_id/8;
+ bit_index = event_id % 8;
+ byte_mask = 0x1 << bit_index;
+
+ i = diag_dci_find_client_index(current->tgid);
+ if (i != DCI_CLIENT_INDEX_INVALID) {
+ event_mask_ptr =
+ driver->dci_client_tbl[i].dci_event_mask;
+ event_mask_ptr = event_mask_ptr + byte_index;
+ if ((*event_mask_ptr & byte_mask) == byte_mask)
+ return 1;
+ else
+ return 0;
+ }
+ return 0;
+}
+
+
diff --git a/drivers/char/diag/diag_dci.h b/drivers/char/diag/diag_dci.h
index 9187516..260cdf3 100644
--- a/drivers/char/diag/diag_dci.h
+++ b/drivers/char/diag/diag_dci.h
@@ -37,6 +37,7 @@
extern unsigned int dci_max_reg;
extern unsigned int dci_max_clients;
+extern struct mutex dci_health_mutex;
struct dci_pkt_req_tracking_tbl {
int pid;
@@ -68,6 +69,13 @@
int reset_status;
};
+/* This is used for querying DCI Log
+ or Event Mask */
+struct diag_log_event_stats {
+ uint16_t code;
+ int is_set;
+};
+
enum {
DIAG_DCI_NO_ERROR = 1001, /* No error */
DIAG_DCI_NO_REG, /* Could not register */
@@ -96,10 +104,14 @@
void clear_client_dci_cumulative_log_mask(int client_index);
int diag_send_dci_log_mask(smd_channel_t *ch);
void extract_dci_log(unsigned char *buf);
+int diag_dci_clear_log_mask(void);
+int diag_dci_query_log_mask(uint16_t log_code);
/* DCI event streaming functions */
void update_dci_cumulative_event_mask(int offset, uint8_t byte_mask);
void clear_client_dci_cumulative_event_mask(int client_index);
int diag_send_dci_event_mask(smd_channel_t *ch);
void extract_dci_events(unsigned char *buf);
void create_dci_event_mask_tbl(unsigned char *tbl_buf);
+int diag_dci_clear_event_mask(void);
+int diag_dci_query_event_mask(uint16_t event_id);
#endif
diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c
index 0c93101..071dd69 100644
--- a/drivers/char/diag/diag_masks.c
+++ b/drivers/char/diag/diag_masks.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-2013, 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
@@ -734,8 +734,8 @@
(driver->log_on_demand_support)) {
driver->apps_rsp_buf[0] = 0x78;
/* Copy log code received */
- *(uint16_t *)(driver->apps_rsp_buf+1) =
- *(uint16_t *)buf;
+ *(uint16_t *)(driver->apps_rsp_buf + 1) =
+ *(uint16_t *)(buf + 1);
driver->apps_rsp_buf[3] = 0x1;/* Unknown */
encode_rsp_and_send(3);
}
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index df28dab..9d9df2a 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -30,7 +30,6 @@
#define IN_BUF_SIZE 16384
#define MAX_IN_BUF_SIZE 32768
#define MAX_SYNC_OBJ_NAME_SIZE 32
-#define UINT32_MAX UINT_MAX
/* Size of the buffer used for deframing a packet
reveived from the PC tool*/
#define HDLC_MAX 4096
@@ -86,8 +85,8 @@
#define SMD_DCI_TYPE 2
/* Maximum number of pkt reg supported at initialization*/
-extern unsigned int diag_max_reg;
-extern unsigned int diag_threshold_reg;
+extern int diag_max_reg;
+extern int diag_threshold_reg;
#define APPEND_DEBUG(ch) \
do { \
@@ -163,6 +162,8 @@
smd_channel_t *ch;
smd_channel_t *ch_save;
+ struct mutex smd_ch_mutex;
+
int in_busy_1;
int in_busy_2;
@@ -250,6 +251,7 @@
unsigned char *buf_event_mask_update;
unsigned char *buf_feature_mask_update;
int read_len_legacy;
+ struct mutex diag_hdlc_mutex;
unsigned char *hdlc_buf;
unsigned hdlc_count;
unsigned hdlc_escape;
@@ -292,6 +294,7 @@
struct diag_request *write_ptr_mdm;
#endif
#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
+ spinlock_t hsic_ready_spinlock;
/* common for all bridges */
struct work_struct diag_disconnect_work;
/* SGLTE variables */
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 3e3d8fd..65fc89f 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -66,8 +66,8 @@
static unsigned int max_clients = 15;
static unsigned int threshold_client_limit = 30;
/* This is the maximum number of pkt registrations supported at initialization*/
-unsigned int diag_max_reg = 600;
-unsigned int diag_threshold_reg = 750;
+int diag_max_reg = 600;
+int diag_threshold_reg = 750;
/* Timer variables */
static struct timer_list drain_timer;
@@ -516,149 +516,379 @@
*pnum_data = num_data;
return exit_stat;
}
+
+static void diag_update_data_ready(int index)
+{
+ int clear_bit = 1;
+ unsigned long hsic_lock_flags;
+ unsigned long ready_lock_flags;
+ int i;
+
+ /*
+ * Determine whether the data_ready USER_SPACE_DATA_TYPE bit
+ * should be updated/cleared or not. There is a race condition that
+ * can occur when in MEMORY_DEVICE_MODE with the hsic data.
+ * When new hsic data arrives we prepare the data so it can
+ * later be copied to userspace. We set the USER_SPACE_DATA_TYPE
+ * bit in data ready at that time. We later copy the hsic data
+ * to userspace and clear the USER_SPACE_DATA_TYPE bit in
+ * data ready. The race condition occurs if new data arrives (bit set)
+ * while we are processing the current data and sending
+ * it to userspace (bit clear). The clearing of the bit can
+ * overwrite the setting of the bit.
+ */
+
+ spin_lock_irqsave(&driver->hsic_ready_spinlock, ready_lock_flags);
+ for (i = 0; i < MAX_HSIC_CH; i++) {
+ if (diag_hsic[i].hsic_inited) {
+ spin_lock_irqsave(&diag_hsic[i].hsic_spinlock,
+ hsic_lock_flags);
+ if ((diag_hsic[i].num_hsic_buf_tbl_entries > 0) &&
+ diag_hsic[i].hsic_device_enabled &&
+ diag_hsic[i].hsic_ch) {
+ /* New data do not clear the bit */
+ clear_bit = 0;
+ }
+ spin_unlock_irqrestore(&diag_hsic[i].hsic_spinlock,
+ hsic_lock_flags);
+ if (!clear_bit)
+ break;
+ }
+ }
+
+ if (clear_bit)
+ driver->data_ready[index] ^= USER_SPACE_DATA_TYPE;
+
+ spin_unlock_irqrestore(&driver->hsic_ready_spinlock, ready_lock_flags);
+}
#else
inline uint16_t diag_get_remote_device_mask(void) { return 0; }
inline int diag_copy_remote(char __user *buf, size_t count, int *pret,
int *pnum_data) { return 0; }
+static void diag_update_data_ready(int index)
+{
+ driver->data_ready[index] ^= USER_SPACE_DATA_TYPE;
+}
#endif
-long diagchar_ioctl(struct file *filp,
- unsigned int iocmd, unsigned long ioarg)
+int diag_command_reg(unsigned long ioarg)
{
- int i, j, temp, success = -1, status, index = -1;
- unsigned int count_entries = 0, interim_count = 0;
+ int i = 0, success = -EINVAL, j;
void *temp_buf;
- uint16_t support_list = 0;
- struct diag_dci_client_tbl *dci_params;
- struct diag_dci_health_stats stats;
-
- if (iocmd == DIAG_IOCTL_COMMAND_REG) {
- struct bindpkt_params_per_process pkt_params;
- struct bindpkt_params *params;
- struct bindpkt_params *head_params;
- if (copy_from_user(&pkt_params, (void *)ioarg,
- sizeof(struct bindpkt_params_per_process))) {
- return -EFAULT;
- }
- if ((UINT32_MAX/sizeof(struct bindpkt_params)) <
- pkt_params.count) {
- pr_warning("diag: integer overflow while multiply\n");
- return -EFAULT;
- }
- params = kzalloc(pkt_params.count*sizeof(
- struct bindpkt_params), GFP_KERNEL);
- if (!params) {
- pr_err("diag: unable to alloc memory\n");
- return -ENOMEM;
- } else
- head_params = params;
-
- if (copy_from_user(params, pkt_params.params,
- pkt_params.count*sizeof(struct bindpkt_params))) {
- kfree(head_params);
- return -EFAULT;
- }
- mutex_lock(&driver->diagchar_mutex);
- for (i = 0; i < diag_max_reg; i++) {
- if (driver->table[i].process_id == 0) {
- diag_add_reg(i, params, &success,
- &count_entries);
- if (pkt_params.count > count_entries) {
- params++;
- } else {
- mutex_unlock(&driver->diagchar_mutex);
- kfree(head_params);
- return success;
- }
+ unsigned int count_entries = 0, interim_count = 0;
+ struct bindpkt_params_per_process pkt_params;
+ struct bindpkt_params *params;
+ struct bindpkt_params *head_params;
+ if (copy_from_user(&pkt_params, (void *)ioarg,
+ sizeof(struct bindpkt_params_per_process))) {
+ return -EFAULT;
+ }
+ if ((UINT_MAX/sizeof(struct bindpkt_params)) <
+ pkt_params.count) {
+ pr_warn("diag: integer overflow while multiply\n");
+ return -EFAULT;
+ }
+ head_params = kzalloc(pkt_params.count*sizeof(
+ struct bindpkt_params), GFP_KERNEL);
+ if (!head_params) {
+ pr_err("diag: unable to alloc memory\n");
+ return -ENOMEM;
+ } else
+ params = head_params;
+ if (copy_from_user(params, pkt_params.params,
+ pkt_params.count*sizeof(struct bindpkt_params))) {
+ kfree(head_params);
+ return -EFAULT;
+ }
+ mutex_lock(&driver->diagchar_mutex);
+ for (i = 0; i < diag_max_reg; i++) {
+ if (driver->table[i].process_id == 0) {
+ diag_add_reg(i, params, &success,
+ &count_entries);
+ if (pkt_params.count > count_entries) {
+ params++;
+ } else {
+ kfree(head_params);
+ mutex_unlock(&driver->diagchar_mutex);
+ return success;
}
}
- if (i < diag_threshold_reg) {
- /* Increase table size by amount required */
+ }
+ if (i < diag_threshold_reg) {
+ /* Increase table size by amount required */
+ if (pkt_params.count >= count_entries) {
+ interim_count = pkt_params.count -
+ count_entries;
+ } else {
+ pr_warn("diag: error in params count\n");
+ kfree(head_params);
+ mutex_unlock(&driver->diagchar_mutex);
+ return -EFAULT;
+ }
+ if (UINT_MAX - diag_max_reg >=
+ interim_count) {
+ diag_max_reg += interim_count;
+ } else {
+ pr_warn("diag: Integer overflow\n");
+ kfree(head_params);
+ mutex_unlock(&driver->diagchar_mutex);
+ return -EFAULT;
+ }
+ /* Make sure size doesnt go beyond threshold */
+ if (diag_max_reg > diag_threshold_reg) {
+ diag_max_reg = diag_threshold_reg;
+ pr_err("diag: best case memory allocation\n");
+ }
+ if (UINT_MAX/sizeof(struct diag_master_table) <
+ diag_max_reg) {
+ pr_warn("diag: integer overflow\n");
+ kfree(head_params);
+ mutex_unlock(&driver->diagchar_mutex);
+ return -EFAULT;
+ }
+ temp_buf = krealloc(driver->table,
+ diag_max_reg*sizeof(struct
+ diag_master_table), GFP_KERNEL);
+ if (!temp_buf) {
+ pr_err("diag: Insufficient memory for reg.\n");
+
if (pkt_params.count >= count_entries) {
interim_count = pkt_params.count -
count_entries;
} else {
- pr_warning("diag: error in params count\n");
+ pr_warn("diag: params count error\n");
kfree(head_params);
mutex_unlock(&driver->diagchar_mutex);
return -EFAULT;
}
- if (UINT32_MAX - diag_max_reg >=
- interim_count) {
- diag_max_reg += interim_count;
+ if (diag_max_reg >= interim_count) {
+ diag_max_reg -= interim_count;
} else {
- pr_warning("diag: Integer overflow\n");
+ pr_warn("diag: Integer underflow\n");
kfree(head_params);
mutex_unlock(&driver->diagchar_mutex);
return -EFAULT;
}
- /* Make sure size doesnt go beyond threshold */
- if (diag_max_reg > diag_threshold_reg) {
- diag_max_reg = diag_threshold_reg;
- pr_info("diag: best case memory allocation\n");
- }
- if (UINT32_MAX/sizeof(struct diag_master_table) <
- diag_max_reg) {
- pr_warning("diag: integer overflow\n");
- kfree(head_params);
- mutex_unlock(&driver->diagchar_mutex);
- return -EFAULT;
- }
- temp_buf = krealloc(driver->table,
- diag_max_reg*sizeof(struct
- diag_master_table), GFP_KERNEL);
- if (!temp_buf) {
- pr_alert("diag: Insufficient memory for reg.\n");
- mutex_unlock(&driver->diagchar_mutex);
-
- if (pkt_params.count >= count_entries) {
- interim_count = pkt_params.count -
- count_entries;
- } else {
- pr_warning("diag: params count error\n");
- mutex_unlock(&driver->diagchar_mutex);
- kfree(head_params);
- return -EFAULT;
- }
- if (diag_max_reg >= interim_count) {
- diag_max_reg -= interim_count;
- } else {
- pr_warning("diag: Integer underflow\n");
- mutex_unlock(&driver->diagchar_mutex);
- kfree(head_params);
- return -EFAULT;
- }
- kfree(head_params);
- return 0;
- } else {
- driver->table = temp_buf;
- }
- for (j = i; j < diag_max_reg; j++) {
- diag_add_reg(j, params, &success,
- &count_entries);
- if (pkt_params.count > count_entries) {
- params++;
- } else {
- mutex_unlock(&driver->diagchar_mutex);
- kfree(head_params);
- return success;
- }
- }
kfree(head_params);
mutex_unlock(&driver->diagchar_mutex);
+ return 0;
} else {
- mutex_unlock(&driver->diagchar_mutex);
- kfree(head_params);
- pr_err("Max size reached, Pkt Registration failed for"
- " Process %d", current->tgid);
+ driver->table = temp_buf;
}
- success = 0;
- } else if (iocmd == DIAG_IOCTL_GET_DELAYED_RSP_ID) {
- struct diagpkt_delay_params delay_params;
- uint16_t interim_rsp_id;
- int interim_size;
+ for (j = i; j < diag_max_reg; j++) {
+ diag_add_reg(j, params, &success,
+ &count_entries);
+ if (pkt_params.count > count_entries) {
+ params++;
+ } else {
+ kfree(head_params);
+ mutex_unlock(&driver->diagchar_mutex);
+ return success;
+ }
+ }
+ kfree(head_params);
+ mutex_unlock(&driver->diagchar_mutex);
+ } else {
+ kfree(head_params);
+ mutex_unlock(&driver->diagchar_mutex);
+ pr_err("Max size reached, Pkt Registration failed for Process %d",
+ current->tgid);
+ }
+ success = 0;
+ return success;
+}
+
+#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
+void diag_cmp_logging_modes_diagfwd_bridge(int old_mode, int new_mode)
+{
+ if (old_mode == MEMORY_DEVICE_MODE && new_mode
+ == NO_LOGGING_MODE) {
+ diagfwd_disconnect_bridge(0);
+ diag_clear_hsic_tbl();
+ } else if (old_mode == NO_LOGGING_MODE && new_mode
+ == MEMORY_DEVICE_MODE) {
+ diagfwd_connect_bridge(0);
+ } else if (old_mode == USB_MODE && new_mode
+ == NO_LOGGING_MODE) {
+ diagfwd_disconnect_bridge(0);
+ } else if (old_mode == NO_LOGGING_MODE && new_mode
+ == USB_MODE) {
+ diagfwd_connect_bridge(0);
+ } else if (old_mode == USB_MODE && new_mode
+ == MEMORY_DEVICE_MODE) {
+ diagfwd_cancel_hsic();
+ diagfwd_connect_bridge(0);
+ } else if (old_mode == MEMORY_DEVICE_MODE && new_mode
+ == USB_MODE) {
+ diag_clear_hsic_tbl();
+ diagfwd_cancel_hsic();
+ diagfwd_connect_bridge(0);
+ }
+}
+#else
+void diag_cmp_logging_modes_diagfwd_bridge(int old_mode, int new_mode)
+{
+
+}
+#endif
+
+#ifdef CONFIG_DIAG_SDIO_PIPE
+void diag_cmp_logging_modes_sdio_pipe(int old_mode, int new_mode)
+{
+ if (old_mode == MEMORY_DEVICE_MODE && new_mode
+ == NO_LOGGING_MODE) {
+ mutex_lock(&driver->diagchar_mutex);
+ driver->in_busy_sdio = 1;
+ mutex_unlock(&driver->diagchar_mutex);
+ } else if (old_mode == NO_LOGGING_MODE && new_mode
+ == MEMORY_DEVICE_MODE) {
+ mutex_lock(&driver->diagchar_mutex);
+ driver->in_busy_sdio = 0;
+ mutex_unlock(&driver->diagchar_mutex);
+ /* Poll SDIO channel to check for data */
+ if (driver->sdio_ch)
+ queue_work(driver->diag_sdio_wq,
+ &(driver->diag_read_sdio_work));
+ } else if (old_mode == USB_MODE && new_mode
+ == MEMORY_DEVICE_MODE) {
+ mutex_lock(&driver->diagchar_mutex);
+ driver->in_busy_sdio = 0;
+ mutex_unlock(&driver->diagchar_mutex);
+ /* Poll SDIO channel to check for data */
+ if (driver->sdio_ch)
+ queue_work(driver->diag_sdio_wq,
+ &(driver->diag_read_sdio_work));
+ }
+}
+#else
+void diag_cmp_logging_modes_sdio_pipe(int old_mode, int new_mode)
+{
+
+}
+#endif
+
+int diag_switch_logging(unsigned long ioarg)
+{
+ int i, temp, success = -EINVAL, status;
+ mutex_lock(&driver->diagchar_mutex);
+ temp = driver->logging_mode;
+ driver->logging_mode = (int)ioarg;
+ if (temp == driver->logging_mode) {
+ mutex_unlock(&driver->diagchar_mutex);
+ pr_err("diag: forbidden logging change requested\n");
+ return 0;
+ }
+
+ if (driver->logging_mode == MEMORY_DEVICE_MODE) {
+ diag_clear_hsic_tbl();
+ driver->mask_check = 1;
+ if (driver->socket_process) {
+ /*
+ * Notify the socket logging process that we
+ * are switching to MEMORY_DEVICE_MODE
+ */
+ status = send_sig(SIGCONT,
+ driver->socket_process, 0);
+ if (status) {
+ pr_err("diag: %s, Error notifying ",
+ __func__);
+ pr_err("socket process, status: %d\n",
+ status);
+ }
+ }
+ } else if (driver->logging_mode == SOCKET_MODE) {
+ driver->socket_process = current;
+ } else if (driver->logging_mode == CALLBACK_MODE) {
+ driver->callback_process = current;
+ }
+
+ if (driver->logging_mode == UART_MODE ||
+ driver->logging_mode == SOCKET_MODE ||
+ driver->logging_mode == CALLBACK_MODE) {
+ diag_clear_hsic_tbl();
+ driver->mask_check = 0;
+ driver->logging_mode = MEMORY_DEVICE_MODE;
+ }
+
+ driver->logging_process_id = current->tgid;
+ mutex_unlock(&driver->diagchar_mutex);
+
+ if (temp == MEMORY_DEVICE_MODE && driver->logging_mode
+ == NO_LOGGING_MODE) {
+ for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
+ driver->smd_data[i].in_busy_1 = 0;
+ driver->smd_data[i].in_busy_2 = 0;
+ }
+ diag_cmp_logging_modes_sdio_pipe(temp, driver->logging_mode);
+ diag_cmp_logging_modes_diagfwd_bridge(temp,
+ driver->logging_mode);
+ } else if (temp == NO_LOGGING_MODE && driver->logging_mode
+ == MEMORY_DEVICE_MODE) {
+ for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
+ driver->smd_data[i].in_busy_1 = 0;
+ driver->smd_data[i].in_busy_2 = 0;
+ /* Poll SMD channels to check for data*/
+ if (driver->smd_data[i].ch)
+ queue_work(driver->diag_wq,
+ &(driver->smd_data[i].
+ diag_read_smd_work));
+ }
+ diag_cmp_logging_modes_sdio_pipe(temp,
+ driver->logging_mode);
+ diag_cmp_logging_modes_diagfwd_bridge(temp,
+ driver->logging_mode);
+ } else if (temp == USB_MODE && driver->logging_mode
+ == NO_LOGGING_MODE) {
+ diagfwd_disconnect();
+ diag_cmp_logging_modes_diagfwd_bridge(temp,
+ driver->logging_mode);
+ } else if (temp == NO_LOGGING_MODE && driver->logging_mode
+ == USB_MODE) {
+ diagfwd_connect();
+ diag_cmp_logging_modes_diagfwd_bridge(temp,
+ driver->logging_mode);
+ } else if (temp == USB_MODE && driver->logging_mode
+ == MEMORY_DEVICE_MODE) {
+ diagfwd_disconnect();
+ for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
+ driver->smd_data[i].in_busy_1 = 0;
+ driver->smd_data[i].in_busy_2 = 0;
+ /* Poll SMD channels to check for data*/
+ if (driver->smd_data[i].ch)
+ queue_work(driver->diag_wq,
+ &(driver->smd_data[i].
+ diag_read_smd_work));
+ }
+ diag_cmp_logging_modes_sdio_pipe(temp, driver->logging_mode);
+ diag_cmp_logging_modes_diagfwd_bridge(temp,
+ driver->logging_mode);
+ } else if (temp == MEMORY_DEVICE_MODE &&
+ driver->logging_mode == USB_MODE) {
+ diagfwd_connect();
+ diag_cmp_logging_modes_diagfwd_bridge(temp,
+ driver->logging_mode);
+ }
+ success = 1;
+ return success;
+}
+
+long diagchar_ioctl(struct file *filp,
+ unsigned int iocmd, unsigned long ioarg)
+{
+ int i, result = -EINVAL, interim_size = 0, client_id = 0;
+ uint16_t support_list = 0, interim_rsp_id, remote_dev;
+ struct diag_dci_client_tbl *dci_params;
+ struct diag_dci_health_stats stats;
+ struct diag_log_event_stats le_stats;
+ struct diagpkt_delay_params delay_params;
+
+ switch (iocmd) {
+ case DIAG_IOCTL_COMMAND_REG:
+ result = diag_command_reg(ioarg);
+ break;
+ case DIAG_IOCTL_GET_DELAYED_RSP_ID:
if (copy_from_user(&delay_params, (void *)ioarg,
- sizeof(struct diagpkt_delay_params)))
+ sizeof(struct diagpkt_delay_params)))
return -EFAULT;
if ((delay_params.rsp_ptr) &&
(delay_params.size == sizeof(delayed_rsp_id)) &&
@@ -672,9 +902,10 @@
if (copy_to_user((void *)delay_params.num_bytes_ptr,
&interim_size, sizeof(int)))
return -EFAULT;
- success = 0;
+ result = 0;
}
- } else if (iocmd == DIAG_IOCTL_DCI_REG) {
+ break;
+ case DIAG_IOCTL_DCI_REG:
if (driver->dci_state == DIAG_DCI_NO_REG)
return DIAG_DCI_NO_REG;
if (driver->num_dci_client >= MAX_DCI_CLIENTS)
@@ -723,49 +954,47 @@
}
kfree(dci_params);
mutex_unlock(&driver->dci_mutex);
- return driver->dci_client_id;
- } else if (iocmd == DIAG_IOCTL_DCI_DEINIT) {
- success = -1;
- /*
- * Clear log/event masks and send updated
- * masks to peripherals
- */
+ result = driver->dci_client_id;
+ break;
+ case DIAG_IOCTL_DCI_DEINIT:
+ result = -EIO;
+ /* Delete this process from DCI table */
mutex_lock(&driver->dci_mutex);
- index = diag_dci_find_client_index(current->tgid);
- if (index != DCI_CLIENT_INDEX_INVALID) {
+ i = diag_dci_find_client_index(current->tgid);
+ if (i == DCI_CLIENT_INDEX_INVALID) {
+ result = DIAG_DCI_NOT_SUPPORTED;
+ } else {
/* clear respective cumulative log masks */
- clear_client_dci_cumulative_log_mask(index);
+ clear_client_dci_cumulative_log_mask(i);
/* send updated log mask to peripherals */
- success =
+ result =
diag_send_dci_log_mask(driver->smd_cntl[MODEM_DATA].ch);
- if (success != DIAG_DCI_NO_ERROR) {
+ if (result != DIAG_DCI_NO_ERROR) {
mutex_unlock(&driver->dci_mutex);
- return success;
+ return result;
}
/* clear respective cumulative event masks */
- clear_client_dci_cumulative_event_mask(index);
+ clear_client_dci_cumulative_event_mask(i);
/* send updated event mask to peripherals */
- success =
+ result =
diag_send_dci_event_mask(
driver->smd_cntl[MODEM_DATA].ch);
- if (success != DIAG_DCI_NO_ERROR) {
+ if (result != DIAG_DCI_NO_ERROR) {
mutex_unlock(&driver->dci_mutex);
- return success;
+ return result;
}
- }
- /* Delete this process from DCI table */
- for (i = 0; i < dci_max_reg; i++)
- if (driver->req_tracking_tbl[i].pid == current->tgid)
- driver->req_tracking_tbl[i].pid = 0;
- if (index != DCI_CLIENT_INDEX_INVALID) {
- driver->dci_client_tbl[index].client = NULL;
- success = index;
- }
- if (success >= 0)
+ result = i;
+ /* Delete this process from DCI table */
+ for (i = 0; i < dci_max_reg; i++)
+ if (driver->req_tracking_tbl[i].pid ==
+ current->tgid)
+ driver->req_tracking_tbl[i].pid = 0;
+ driver->dci_client_tbl[result].client = NULL;
driver->num_dci_client--;
+ }
mutex_unlock(&driver->dci_mutex);
- return success;
- } else if (iocmd == DIAG_IOCTL_DCI_SUPPORT) {
+ break;
+ case DIAG_IOCTL_DCI_SUPPORT:
for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++) {
if (driver->smd_dci[i].ch)
support_list |=
@@ -774,35 +1003,69 @@
if (copy_to_user((void *)ioarg, &support_list,
sizeof(uint16_t)))
return -EFAULT;
- return DIAG_DCI_NO_ERROR;
- } else if (iocmd == DIAG_IOCTL_DCI_HEALTH_STATS) {
+ result = DIAG_DCI_NO_ERROR;
+ break;
+ case DIAG_IOCTL_DCI_HEALTH_STATS:
if (copy_from_user(&stats, (void *)ioarg,
sizeof(struct diag_dci_health_stats)))
return -EFAULT;
- for (i = 0; i < MAX_DCI_CLIENTS; i++) {
+ mutex_lock(&dci_health_mutex);
+ i = diag_dci_find_client_index(current->tgid);
+ if (i != DCI_CLIENT_INDEX_INVALID) {
dci_params = &(driver->dci_client_tbl[i]);
- if (dci_params->client &&
- dci_params->client->tgid == current->tgid) {
- stats.dropped_logs = dci_params->dropped_logs;
- stats.dropped_events =
- dci_params->dropped_events;
- stats.received_logs = dci_params->received_logs;
- stats.received_events =
- dci_params->received_events;
- if (stats.reset_status) {
- dci_params->dropped_logs = 0;
- dci_params->dropped_events = 0;
- dci_params->received_logs = 0;
- dci_params->received_events = 0;
- }
- break;
+ stats.dropped_logs = dci_params->dropped_logs;
+ stats.dropped_events =
+ dci_params->dropped_events;
+ stats.received_logs =
+ dci_params->received_logs;
+ stats.received_events =
+ dci_params->received_events;
+ if (stats.reset_status) {
+ dci_params->dropped_logs = 0;
+ dci_params->dropped_events = 0;
+ dci_params->received_logs = 0;
+ dci_params->received_events = 0;
}
}
+ mutex_unlock(&dci_health_mutex);
if (copy_to_user((void *)ioarg, &stats,
sizeof(struct diag_dci_health_stats)))
return -EFAULT;
- return DIAG_DCI_NO_ERROR;
- } else if (iocmd == DIAG_IOCTL_LSM_DEINIT) {
+ result = DIAG_DCI_NO_ERROR;
+ break;
+ case DIAG_IOCTL_DCI_LOG_STATUS:
+ if (copy_from_user(&le_stats, (void *)ioarg,
+ sizeof(struct diag_log_event_stats)))
+ return -EFAULT;
+ le_stats.is_set = diag_dci_query_log_mask(le_stats.code);
+ if (copy_to_user((void *)ioarg, &le_stats,
+ sizeof(struct diag_log_event_stats)))
+ return -EFAULT;
+ result = DIAG_DCI_NO_ERROR;
+ break;
+ case DIAG_IOCTL_DCI_EVENT_STATUS:
+ if (copy_from_user(&le_stats, (void *)ioarg,
+ sizeof(struct diag_log_event_stats)))
+ return -EFAULT;
+ le_stats.is_set = diag_dci_query_event_mask(le_stats.code);
+ if (copy_to_user((void *)ioarg, &le_stats,
+ sizeof(struct diag_log_event_stats)))
+ return -EFAULT;
+ result = DIAG_DCI_NO_ERROR;
+ break;
+ case DIAG_IOCTL_DCI_CLEAR_LOGS:
+ if (copy_from_user((void *)&client_id, (void *)ioarg,
+ sizeof(int)))
+ return -EFAULT;
+ result = diag_dci_clear_log_mask();
+ break;
+ case DIAG_IOCTL_DCI_CLEAR_EVENTS:
+ if (copy_from_user(&client_id, (void *)ioarg,
+ sizeof(int)))
+ return -EFAULT;
+ result = diag_dci_clear_event_mask();
+ break;
+ case DIAG_IOCTL_LSM_DEINIT:
for (i = 0; i < driver->num_clients; i++)
if (driver->client_map[i].pid == current->tgid)
break;
@@ -810,138 +1073,20 @@
return -EINVAL;
driver->data_ready[i] |= DEINIT_TYPE;
wake_up_interruptible(&driver->wait_q);
- success = 1;
- } else if (iocmd == DIAG_IOCTL_SWITCH_LOGGING) {
- mutex_lock(&driver->diagchar_mutex);
- temp = driver->logging_mode;
- driver->logging_mode = (int)ioarg;
- if (temp == driver->logging_mode) {
- mutex_unlock(&driver->diagchar_mutex);
- pr_alert("diag: forbidden logging change requested\n");
- return 0;
- }
- if (driver->logging_mode == MEMORY_DEVICE_MODE) {
- diag_clear_hsic_tbl();
- driver->mask_check = 1;
- if (driver->socket_process) {
- /*
- * Notify the socket logging process that we
- * are switching to MEMORY_DEVICE_MODE
- */
- status = send_sig(SIGCONT,
- driver->socket_process, 0);
- if (status) {
- pr_err("diag: %s, Error notifying ",
- __func__);
- pr_err("socket process, status: %d\n",
- status);
- }
- }
- }
- if (driver->logging_mode == SOCKET_MODE)
- driver->socket_process = current;
- if (driver->logging_mode == CALLBACK_MODE)
- driver->callback_process = current;
- if (driver->logging_mode == UART_MODE ||
- driver->logging_mode == SOCKET_MODE ||
- driver->logging_mode == CALLBACK_MODE) {
- diag_clear_hsic_tbl();
- driver->mask_check = 0;
- driver->logging_mode = MEMORY_DEVICE_MODE;
- }
- driver->logging_process_id = current->tgid;
- mutex_unlock(&driver->diagchar_mutex);
- if (temp == MEMORY_DEVICE_MODE && driver->logging_mode
- == NO_LOGGING_MODE) {
- for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
- driver->smd_data[i].in_busy_1 = 0;
- driver->smd_data[i].in_busy_2 = 0;
- }
-#ifdef CONFIG_DIAG_SDIO_PIPE
- driver->in_busy_sdio = 1;
-#endif
-#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
- diagfwd_disconnect_bridge(0);
- diag_clear_hsic_tbl();
-#endif
- } else if (temp == NO_LOGGING_MODE && driver->logging_mode
- == MEMORY_DEVICE_MODE) {
- for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
- driver->smd_data[i].in_busy_1 = 0;
- driver->smd_data[i].in_busy_2 = 0;
- /* Poll SMD channels to check for data*/
- if (driver->smd_data[i].ch)
- queue_work(driver->diag_wq,
- &(driver->smd_data[i].
- diag_read_smd_work));
- }
-#ifdef CONFIG_DIAG_SDIO_PIPE
- driver->in_busy_sdio = 0;
- /* Poll SDIO channel to check for data */
- if (driver->sdio_ch)
- queue_work(driver->diag_sdio_wq,
- &(driver->diag_read_sdio_work));
-#endif
-#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
- diagfwd_connect_bridge(0);
-#endif
- }
-#ifdef CONFIG_DIAG_OVER_USB
- else if (temp == USB_MODE && driver->logging_mode
- == NO_LOGGING_MODE) {
- diagfwd_disconnect();
-#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
- diagfwd_disconnect_bridge(0);
-#endif
- } else if (temp == NO_LOGGING_MODE && driver->logging_mode
- == USB_MODE) {
- diagfwd_connect();
-#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
- diagfwd_connect_bridge(0);
-#endif
- } else if (temp == USB_MODE && driver->logging_mode
- == MEMORY_DEVICE_MODE) {
- diagfwd_disconnect();
- for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
- driver->smd_data[i].in_busy_1 = 0;
- driver->smd_data[i].in_busy_2 = 0;
- /* Poll SMD channels to check for data*/
- if (driver->smd_data[i].ch)
- queue_work(driver->diag_wq,
- &(driver->smd_data[i].
- diag_read_smd_work));
- }
-#ifdef CONFIG_DIAG_SDIO_PIPE
- driver->in_busy_sdio = 0;
- /* Poll SDIO channel to check for data */
- if (driver->sdio_ch)
- queue_work(driver->diag_sdio_wq,
- &(driver->diag_read_sdio_work));
-#endif
-#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
- diagfwd_cancel_hsic();
- diagfwd_connect_bridge(0);
-#endif
- } else if (temp == MEMORY_DEVICE_MODE &&
- driver->logging_mode == USB_MODE) {
- diagfwd_connect();
-#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
- diag_clear_hsic_tbl();
- diagfwd_cancel_hsic();
- diagfwd_connect_bridge(0);
-#endif
- }
-#endif /* DIAG over USB */
- success = 1;
- } else if (iocmd == DIAG_IOCTL_REMOTE_DEV) {
- uint16_t remote_dev = diag_get_remote_device_mask();
+ result = 1;
+ break;
+ case DIAG_IOCTL_SWITCH_LOGGING:
+ result = diag_switch_logging(ioarg);
+ break;
+ case DIAG_IOCTL_REMOTE_DEV:
+ remote_dev = diag_get_remote_device_mask();
if (copy_to_user((void *)ioarg, &remote_dev, sizeof(uint16_t)))
- success = -EFAULT;
+ result = -EFAULT;
else
- success = 1;
+ result = 1;
+ break;
}
-
- return success;
+ return result;
}
static int diagchar_read(struct file *file, char __user *buf, size_t count,
@@ -1068,7 +1213,7 @@
/* copy number of data fields */
COPY_USER_SPACE_OR_EXIT(buf+4, num_data, 4);
ret -= 4;
- driver->data_ready[index] ^= USER_SPACE_DATA_TYPE;
+ diag_update_data_ready(index);
for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
if (driver->smd_data[i].ch)
queue_work(driver->diag_wq,
@@ -1654,6 +1799,7 @@
diag_masks_init();
diagfwd_init();
#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
+ spin_lock_init(&driver->hsic_ready_spinlock);
diagfwd_bridge_init(HSIC);
diagfwd_bridge_init(HSIC_2);
/* register HSIC device */
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index 2aca8cf..79a73f3 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -351,12 +351,32 @@
diag_smd_send_req(smd_info);
}
+#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
+static void diag_mem_dev_mode_ready_update(int index, int hsic_updated)
+{
+ if (hsic_updated) {
+ unsigned long flags;
+ spin_lock_irqsave(&driver->hsic_ready_spinlock, flags);
+ driver->data_ready[index] |= USER_SPACE_DATA_TYPE;
+ spin_unlock_irqrestore(&driver->hsic_ready_spinlock, flags);
+ } else {
+ driver->data_ready[index] |= USER_SPACE_DATA_TYPE;
+ }
+}
+#else
+static void diag_mem_dev_mode_ready_update(int index, int hsic_updated)
+{
+ (void) hsic_updated;
+ driver->data_ready[index] |= USER_SPACE_DATA_TYPE;
+}
+#endif
int diag_device_write(void *buf, int data_type, struct diag_request *write_ptr)
{
int i, err = 0, index;
index = 0;
if (driver->logging_mode == MEMORY_DEVICE_MODE) {
+ int hsic_updated = 0;
if (data_type == APPS_DATA) {
for (i = 0; i < driver->poolsize_write_struct; i++)
if (driver->buf_tbl[i].length == 0) {
@@ -377,6 +397,7 @@
else if (data_type == HSIC_DATA || data_type == HSIC_2_DATA) {
unsigned long flags;
int foundIndex = -1;
+ hsic_updated = 1;
index = data_type - HSIC_DATA;
spin_lock_irqsave(&diag_hsic[index].hsic_spinlock,
flags);
@@ -409,7 +430,7 @@
driver->logging_process_id)
break;
if (i < driver->num_clients) {
- driver->data_ready[i] |= USER_SPACE_DATA_TYPE;
+ diag_mem_dev_mode_ready_update(i, hsic_updated);
pr_debug("diag: wake up logging process\n");
wake_up_interruptible(&driver->wait_q);
} else
@@ -590,8 +611,12 @@
diag_check_mode_reset(buf)) {
return;
}
+ mutex_lock(&driver->smd_data[index].
+ smd_ch_mutex);
smd_write(driver->smd_data[index].ch,
buf, len);
+ mutex_unlock(&driver->smd_data[index].
+ smd_ch_mutex);
} else {
pr_err("diag: In %s, smd channel %d not open\n",
__func__, index);
@@ -982,6 +1007,9 @@
{
struct diag_hdlc_decode_type hdlc;
int ret, type = 0;
+
+ mutex_lock(&driver->diag_hdlc_mutex);
+
pr_debug("diag: HDLC decode fn, len of data %d\n", len);
hdlc.dest_ptr = driver->hdlc_buf;
hdlc.dest_size = USB_MAX_OUT_BUF;
@@ -1002,14 +1030,17 @@
if (hdlc.dest_idx < 4) {
pr_err_ratelimited("diag: In %s, message is too short, len: %d, dest len: %d\n",
__func__, len, hdlc.dest_idx);
+ mutex_unlock(&driver->diag_hdlc_mutex);
return;
}
if (ret) {
type = diag_process_apps_pkt(driver->hdlc_buf,
hdlc.dest_idx - 3);
- if (type < 0)
+ if (type < 0) {
+ mutex_unlock(&driver->diag_hdlc_mutex);
return;
+ }
} else if (driver->debug_flag) {
printk(KERN_ERR "Packet dropped due to bad HDLC coding/CRC"
" errors or partial packet received, packet"
@@ -1028,10 +1059,15 @@
if (chk_apps_only()) {
diag_send_error_rsp(hdlc.dest_idx);
} else { /* APQ 8060, Let Q6 respond */
- if (driver->smd_data[LPASS_DATA].ch)
+ if (driver->smd_data[LPASS_DATA].ch) {
+ mutex_lock(&driver->smd_data[LPASS_DATA].
+ smd_ch_mutex);
smd_write(driver->smd_data[LPASS_DATA].ch,
driver->hdlc_buf,
hdlc.dest_idx - 3);
+ mutex_unlock(&driver->smd_data[LPASS_DATA].
+ smd_ch_mutex);
+ }
}
type = 0;
}
@@ -1046,8 +1082,10 @@
if ((driver->smd_data[MODEM_DATA].ch) && (ret) && (type) &&
(hdlc.dest_idx > 3)) {
APPEND_DEBUG('g');
+ mutex_lock(&driver->smd_data[MODEM_DATA].smd_ch_mutex);
smd_write(driver->smd_data[MODEM_DATA].ch,
driver->hdlc_buf, hdlc.dest_idx - 3);
+ mutex_unlock(&driver->smd_data[MODEM_DATA].smd_ch_mutex);
APPEND_DEBUG('h');
#ifdef DIAG_DEBUG
printk(KERN_INFO "writing data to SMD, pkt length %d\n", len);
@@ -1055,6 +1093,7 @@
1, DUMP_PREFIX_ADDRESS, data, len, 1);
#endif /* DIAG DEBUG */
}
+ mutex_unlock(&driver->diag_hdlc_mutex);
}
#ifdef CONFIG_DIAG_OVER_USB
@@ -1390,6 +1429,7 @@
{
smd_info->peripheral = peripheral;
smd_info->type = type;
+ mutex_init(&smd_info->smd_ch_mutex);
switch (peripheral) {
case MODEM_DATA:
@@ -1504,6 +1544,7 @@
diag_debug_buf_idx = 0;
driver->read_len_legacy = 0;
driver->use_device_tree = has_device_tree();
+ mutex_init(&driver->diag_hdlc_mutex);
mutex_init(&driver->diag_cntl_mutex);
success = diag_smd_constructor(&driver->smd_data[MODEM_DATA],
diff --git a/drivers/char/diag/diagfwd.h b/drivers/char/diag/diagfwd.h
index 5a67b0c..afbe4be 100644
--- a/drivers/char/diag/diagfwd.h
+++ b/drivers/char/diag/diagfwd.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-2013, 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
@@ -39,6 +39,10 @@
int diag_smd_constructor(struct diag_smd_info *smd_info, int peripheral,
int type);
void diag_smd_destructor(struct diag_smd_info *smd_info);
+int diag_switch_logging(unsigned long);
+int diag_command_reg(unsigned long);
+void diag_cmp_logging_modes_sdio_pipe(int old_mode, int new_mode);
+void diag_cmp_logging_modes_diagfwd_bridge(int old_mode, int new_mode);
/* State for diag forwarding */
#ifdef CONFIG_DIAG_OVER_USB
int diagfwd_connect(void);
diff --git a/drivers/char/misc.c b/drivers/char/misc.c
index 522136d..2cfafc3 100644
--- a/drivers/char/misc.c
+++ b/drivers/char/misc.c
@@ -59,7 +59,7 @@
/*
* Assigned numbers, used for dynamic minors
*/
-#define DYNAMIC_MINORS 64 /* like dynamic majors */
+#define DYNAMIC_MINORS 96 /* like dynamic majors */
static DECLARE_BITMAP(misc_minors, DYNAMIC_MINORS);
#ifdef CONFIG_PROC_FS
diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile
index c113cf1..f5ca5b6 100644
--- a/drivers/char/tpm/Makefile
+++ b/drivers/char/tpm/Makefile
@@ -1,6 +1,7 @@
#
# Makefile for the kernel tpm device drivers.
#
+
obj-$(CONFIG_TCG_TPM) += tpm.o
ifdef CONFIG_ACPI
obj-$(CONFIG_TCG_TPM) += tpm_bios.o
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
deleted file mode 100644
index 94bb440..0000000
--- a/drivers/char/tty_io.c
+++ /dev/null
@@ -1,3154 +0,0 @@
-/*
- * linux/drivers/char/tty_io.c
- *
- * Copyright (C) 1991, 1992 Linus Torvalds
- */
-
-/*
- * 'tty_io.c' gives an orthogonal feeling to tty's, be they consoles
- * or rs-channels. It also implements echoing, cooked mode etc.
- *
- * Kill-line thanks to John T Kohl, who also corrected VMIN = VTIME = 0.
- *
- * Modified by Theodore Ts'o, 9/14/92, to dynamically allocate the
- * tty_struct and tty_queue structures. Previously there was an array
- * of 256 tty_struct's which was statically allocated, and the
- * tty_queue structures were allocated at boot time. Both are now
- * dynamically allocated only when the tty is open.
- *
- * Also restructured routines so that there is more of a separation
- * between the high-level tty routines (tty_io.c and tty_ioctl.c) and
- * the low-level tty routines (serial.c, pty.c, console.c). This
- * makes for cleaner and more compact code. -TYT, 9/17/92
- *
- * Modified by Fred N. van Kempen, 01/29/93, to add line disciplines
- * which can be dynamically activated and de-activated by the line
- * discipline handling modules (like SLIP).
- *
- * NOTE: pay no attention to the line discipline code (yet); its
- * interface is still subject to change in this version...
- * -- TYT, 1/31/92
- *
- * Added functionality to the OPOST tty handling. No delays, but all
- * other bits should be there.
- * -- Nick Holloway <alfie@dcs.warwick.ac.uk>, 27th May 1993.
- *
- * Rewrote canonical mode and added more termios flags.
- * -- julian@uhunix.uhcc.hawaii.edu (J. Cowley), 13Jan94
- *
- * Reorganized FASYNC support so mouse code can share it.
- * -- ctm@ardi.com, 9Sep95
- *
- * New TIOCLINUX variants added.
- * -- mj@k332.feld.cvut.cz, 19-Nov-95
- *
- * Restrict vt switching via ioctl()
- * -- grif@cs.ucr.edu, 5-Dec-95
- *
- * Move console and virtual terminal code to more appropriate files,
- * implement CONFIG_VT and generalize console device interface.
- * -- Marko Kohtala <Marko.Kohtala@hut.fi>, March 97
- *
- * Rewrote tty_init_dev and tty_release_dev to eliminate races.
- * -- Bill Hawes <whawes@star.net>, June 97
- *
- * Added devfs support.
- * -- C. Scott Ananian <cananian@alumni.princeton.edu>, 13-Jan-1998
- *
- * Added support for a Unix98-style ptmx device.
- * -- C. Scott Ananian <cananian@alumni.princeton.edu>, 14-Jan-1998
- *
- * Reduced memory usage for older ARM systems
- * -- Russell King <rmk@arm.linux.org.uk>
- *
- * Move do_SAK() into process context. Less stack use in devfs functions.
- * alloc_tty_struct() always uses kmalloc()
- * -- Andrew Morton <andrewm@uow.edu.eu> 17Mar01
- */
-
-#include <linux/types.h>
-#include <linux/major.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/fcntl.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_driver.h>
-#include <linux/tty_flip.h>
-#include <linux/devpts_fs.h>
-#include <linux/file.h>
-#include <linux/fdtable.h>
-#include <linux/console.h>
-#include <linux/timer.h>
-#include <linux/ctype.h>
-#include <linux/kd.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/proc_fs.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/smp_lock.h>
-#include <linux/device.h>
-#include <linux/wait.h>
-#include <linux/bitops.h>
-#include <linux/delay.h>
-#include <linux/seq_file.h>
-
-#include <linux/uaccess.h>
-#include <asm/system.h>
-
-#include <linux/kbd_kern.h>
-#include <linux/vt_kern.h>
-#include <linux/selection.h>
-
-#include <linux/kmod.h>
-#include <linux/nsproxy.h>
-
-#undef TTY_DEBUG_HANGUP
-
-#define TTY_PARANOIA_CHECK 1
-#define CHECK_TTY_COUNT 1
-
-struct ktermios tty_std_termios = { /* for the benefit of tty drivers */
- .c_iflag = ICRNL | IXON,
- .c_oflag = OPOST | ONLCR,
- .c_cflag = B38400 | CS8 | CREAD | HUPCL,
- .c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK |
- ECHOCTL | ECHOKE | IEXTEN,
- .c_cc = INIT_C_CC,
- .c_ispeed = 38400,
- .c_ospeed = 38400
-};
-
-EXPORT_SYMBOL(tty_std_termios);
-
-/* This list gets poked at by procfs and various bits of boot up code. This
- could do with some rationalisation such as pulling the tty proc function
- into this file */
-
-LIST_HEAD(tty_drivers); /* linked list of tty drivers */
-
-/* Mutex to protect creating and releasing a tty. This is shared with
- vt.c for deeply disgusting hack reasons */
-DEFINE_MUTEX(tty_mutex);
-EXPORT_SYMBOL(tty_mutex);
-
-static ssize_t tty_read(struct file *, char __user *, size_t, loff_t *);
-static ssize_t tty_write(struct file *, const char __user *, size_t, loff_t *);
-ssize_t redirected_tty_write(struct file *, const char __user *,
- size_t, loff_t *);
-static unsigned int tty_poll(struct file *, poll_table *);
-static int tty_open(struct inode *, struct file *);
-long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
-#ifdef CONFIG_COMPAT
-static long tty_compat_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg);
-#else
-#define tty_compat_ioctl NULL
-#endif
-static int tty_fasync(int fd, struct file *filp, int on);
-static void release_tty(struct tty_struct *tty, int idx);
-static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty);
-static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty);
-
-/**
- * alloc_tty_struct - allocate a tty object
- *
- * Return a new empty tty structure. The data fields have not
- * been initialized in any way but has been zeroed
- *
- * Locking: none
- */
-
-struct tty_struct *alloc_tty_struct(void)
-{
- return kzalloc(sizeof(struct tty_struct), GFP_KERNEL);
-}
-
-/**
- * free_tty_struct - free a disused tty
- * @tty: tty struct to free
- *
- * Free the write buffers, tty queue and tty memory itself.
- *
- * Locking: none. Must be called after tty is definitely unused
- */
-
-void free_tty_struct(struct tty_struct *tty)
-{
- kfree(tty->write_buf);
- tty_buffer_free_all(tty);
- kfree(tty);
-}
-
-#define TTY_NUMBER(tty) ((tty)->index + (tty)->driver->name_base)
-
-/**
- * tty_name - return tty naming
- * @tty: tty structure
- * @buf: buffer for output
- *
- * Convert a tty structure into a name. The name reflects the kernel
- * naming policy and if udev is in use may not reflect user space
- *
- * Locking: none
- */
-
-char *tty_name(struct tty_struct *tty, char *buf)
-{
- if (!tty) /* Hmm. NULL pointer. That's fun. */
- strcpy(buf, "NULL tty");
- else
- strcpy(buf, tty->name);
- return buf;
-}
-
-EXPORT_SYMBOL(tty_name);
-
-int tty_paranoia_check(struct tty_struct *tty, struct inode *inode,
- const char *routine)
-{
-#ifdef TTY_PARANOIA_CHECK
- if (!tty) {
- printk(KERN_WARNING
- "null TTY for (%d:%d) in %s\n",
- imajor(inode), iminor(inode), routine);
- return 1;
- }
- if (tty->magic != TTY_MAGIC) {
- printk(KERN_WARNING
- "bad magic number for tty struct (%d:%d) in %s\n",
- imajor(inode), iminor(inode), routine);
- return 1;
- }
-#endif
- return 0;
-}
-
-static int check_tty_count(struct tty_struct *tty, const char *routine)
-{
-#ifdef CHECK_TTY_COUNT
- struct list_head *p;
- int count = 0;
-
- file_list_lock();
- list_for_each(p, &tty->tty_files) {
- count++;
- }
- file_list_unlock();
- if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
- tty->driver->subtype == PTY_TYPE_SLAVE &&
- tty->link && tty->link->count)
- count++;
- if (tty->count != count) {
- printk(KERN_WARNING "Warning: dev (%s) tty->count(%d) "
- "!= #fd's(%d) in %s\n",
- tty->name, tty->count, count, routine);
- return count;
- }
-#endif
- return 0;
-}
-
-/**
- * get_tty_driver - find device of a tty
- * @dev_t: device identifier
- * @index: returns the index of the tty
- *
- * This routine returns a tty driver structure, given a device number
- * and also passes back the index number.
- *
- * Locking: caller must hold tty_mutex
- */
-
-static struct tty_driver *get_tty_driver(dev_t device, int *index)
-{
- struct tty_driver *p;
-
- list_for_each_entry(p, &tty_drivers, tty_drivers) {
- dev_t base = MKDEV(p->major, p->minor_start);
- if (device < base || device >= base + p->num)
- continue;
- *index = device - base;
- return tty_driver_kref_get(p);
- }
- return NULL;
-}
-
-#ifdef CONFIG_CONSOLE_POLL
-
-/**
- * tty_find_polling_driver - find device of a polled tty
- * @name: name string to match
- * @line: pointer to resulting tty line nr
- *
- * This routine returns a tty driver structure, given a name
- * and the condition that the tty driver is capable of polled
- * operation.
- */
-struct tty_driver *tty_find_polling_driver(char *name, int *line)
-{
- struct tty_driver *p, *res = NULL;
- int tty_line = 0;
- int len;
- char *str, *stp;
-
- for (str = name; *str; str++)
- if ((*str >= '0' && *str <= '9') || *str == ',')
- break;
- if (!*str)
- return NULL;
-
- len = str - name;
- tty_line = simple_strtoul(str, &str, 10);
-
- mutex_lock(&tty_mutex);
- /* Search through the tty devices to look for a match */
- list_for_each_entry(p, &tty_drivers, tty_drivers) {
- if (strncmp(name, p->name, len) != 0)
- continue;
- stp = str;
- if (*stp == ',')
- stp++;
- if (*stp == '\0')
- stp = NULL;
-
- if (tty_line >= 0 && tty_line <= p->num && p->ops &&
- p->ops->poll_init && !p->ops->poll_init(p, tty_line, stp)) {
- res = tty_driver_kref_get(p);
- *line = tty_line;
- break;
- }
- }
- mutex_unlock(&tty_mutex);
-
- return res;
-}
-EXPORT_SYMBOL_GPL(tty_find_polling_driver);
-#endif
-
-/**
- * tty_check_change - check for POSIX terminal changes
- * @tty: tty to check
- *
- * If we try to write to, or set the state of, a terminal and we're
- * not in the foreground, send a SIGTTOU. If the signal is blocked or
- * ignored, go ahead and perform the operation. (POSIX 7.2)
- *
- * Locking: ctrl_lock
- */
-
-int tty_check_change(struct tty_struct *tty)
-{
- unsigned long flags;
- int ret = 0;
-
- if (current->signal->tty != tty)
- return 0;
-
- spin_lock_irqsave(&tty->ctrl_lock, flags);
-
- if (!tty->pgrp) {
- printk(KERN_WARNING "tty_check_change: tty->pgrp == NULL!\n");
- goto out_unlock;
- }
- if (task_pgrp(current) == tty->pgrp)
- goto out_unlock;
- spin_unlock_irqrestore(&tty->ctrl_lock, flags);
- if (is_ignored(SIGTTOU))
- goto out;
- if (is_current_pgrp_orphaned()) {
- ret = -EIO;
- goto out;
- }
- kill_pgrp(task_pgrp(current), SIGTTOU, 1);
- set_thread_flag(TIF_SIGPENDING);
- ret = -ERESTARTSYS;
-out:
- return ret;
-out_unlock:
- spin_unlock_irqrestore(&tty->ctrl_lock, flags);
- return ret;
-}
-
-EXPORT_SYMBOL(tty_check_change);
-
-static ssize_t hung_up_tty_read(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
-{
- return 0;
-}
-
-static ssize_t hung_up_tty_write(struct file *file, const char __user *buf,
- size_t count, loff_t *ppos)
-{
- return -EIO;
-}
-
-/* No kernel lock held - none needed ;) */
-static unsigned int hung_up_tty_poll(struct file *filp, poll_table *wait)
-{
- return POLLIN | POLLOUT | POLLERR | POLLHUP | POLLRDNORM | POLLWRNORM;
-}
-
-static long hung_up_tty_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- return cmd == TIOCSPGRP ? -ENOTTY : -EIO;
-}
-
-static long hung_up_tty_compat_ioctl(struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- return cmd == TIOCSPGRP ? -ENOTTY : -EIO;
-}
-
-static const struct file_operations tty_fops = {
- .llseek = no_llseek,
- .read = tty_read,
- .write = tty_write,
- .poll = tty_poll,
- .unlocked_ioctl = tty_ioctl,
- .compat_ioctl = tty_compat_ioctl,
- .open = tty_open,
- .release = tty_release,
- .fasync = tty_fasync,
-};
-
-static const struct file_operations console_fops = {
- .llseek = no_llseek,
- .read = tty_read,
- .write = redirected_tty_write,
- .poll = tty_poll,
- .unlocked_ioctl = tty_ioctl,
- .compat_ioctl = tty_compat_ioctl,
- .open = tty_open,
- .release = tty_release,
- .fasync = tty_fasync,
-};
-
-static const struct file_operations hung_up_tty_fops = {
- .llseek = no_llseek,
- .read = hung_up_tty_read,
- .write = hung_up_tty_write,
- .poll = hung_up_tty_poll,
- .unlocked_ioctl = hung_up_tty_ioctl,
- .compat_ioctl = hung_up_tty_compat_ioctl,
- .release = tty_release,
-};
-
-static DEFINE_SPINLOCK(redirect_lock);
-static struct file *redirect;
-
-/**
- * tty_wakeup - request more data
- * @tty: terminal
- *
- * Internal and external helper for wakeups of tty. This function
- * informs the line discipline if present that the driver is ready
- * to receive more output data.
- */
-
-void tty_wakeup(struct tty_struct *tty)
-{
- struct tty_ldisc *ld;
-
- if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) {
- ld = tty_ldisc_ref(tty);
- if (ld) {
- if (ld->ops->write_wakeup)
- ld->ops->write_wakeup(tty);
- tty_ldisc_deref(ld);
- }
- }
- wake_up_interruptible_poll(&tty->write_wait, POLLOUT);
-}
-
-EXPORT_SYMBOL_GPL(tty_wakeup);
-
-/**
- * do_tty_hangup - actual handler for hangup events
- * @work: tty device
- *
- * This can be called by the "eventd" kernel thread. That is process
- * synchronous but doesn't hold any locks, so we need to make sure we
- * have the appropriate locks for what we're doing.
- *
- * The hangup event clears any pending redirections onto the hung up
- * device. It ensures future writes will error and it does the needed
- * line discipline hangup and signal delivery. The tty object itself
- * remains intact.
- *
- * Locking:
- * BKL
- * redirect lock for undoing redirection
- * file list lock for manipulating list of ttys
- * tty_ldisc_lock from called functions
- * termios_mutex resetting termios data
- * tasklist_lock to walk task list for hangup event
- * ->siglock to protect ->signal/->sighand
- */
-static void do_tty_hangup(struct work_struct *work)
-{
- struct tty_struct *tty =
- container_of(work, struct tty_struct, hangup_work);
- struct file *cons_filp = NULL;
- struct file *filp, *f = NULL;
- struct task_struct *p;
- int closecount = 0, n;
- unsigned long flags;
- int refs = 0;
-
- if (!tty)
- return;
-
-
- spin_lock(&redirect_lock);
- if (redirect && redirect->private_data == tty) {
- f = redirect;
- redirect = NULL;
- }
- spin_unlock(&redirect_lock);
-
- /* inuse_filps is protected by the single kernel lock */
- lock_kernel();
- check_tty_count(tty, "do_tty_hangup");
-
- file_list_lock();
- /* This breaks for file handles being sent over AF_UNIX sockets ? */
- list_for_each_entry(filp, &tty->tty_files, f_u.fu_list) {
- if (filp->f_op->write == redirected_tty_write)
- cons_filp = filp;
- if (filp->f_op->write != tty_write)
- continue;
- closecount++;
- tty_fasync(-1, filp, 0); /* can't block */
- filp->f_op = &hung_up_tty_fops;
- }
- file_list_unlock();
-
- tty_ldisc_hangup(tty);
-
- read_lock(&tasklist_lock);
- if (tty->session) {
- do_each_pid_task(tty->session, PIDTYPE_SID, p) {
- spin_lock_irq(&p->sighand->siglock);
- if (p->signal->tty == tty) {
- p->signal->tty = NULL;
- /* We defer the dereferences outside fo
- the tasklist lock */
- refs++;
- }
- if (!p->signal->leader) {
- spin_unlock_irq(&p->sighand->siglock);
- continue;
- }
- __group_send_sig_info(SIGHUP, SEND_SIG_PRIV, p);
- __group_send_sig_info(SIGCONT, SEND_SIG_PRIV, p);
- put_pid(p->signal->tty_old_pgrp); /* A noop */
- spin_lock_irqsave(&tty->ctrl_lock, flags);
- if (tty->pgrp)
- p->signal->tty_old_pgrp = get_pid(tty->pgrp);
- spin_unlock_irqrestore(&tty->ctrl_lock, flags);
- spin_unlock_irq(&p->sighand->siglock);
- } while_each_pid_task(tty->session, PIDTYPE_SID, p);
- }
- read_unlock(&tasklist_lock);
-
- spin_lock_irqsave(&tty->ctrl_lock, flags);
- clear_bit(TTY_THROTTLED, &tty->flags);
- clear_bit(TTY_PUSH, &tty->flags);
- clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
- put_pid(tty->session);
- put_pid(tty->pgrp);
- tty->session = NULL;
- tty->pgrp = NULL;
- tty->ctrl_status = 0;
- set_bit(TTY_HUPPED, &tty->flags);
- spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-
- /* Account for the p->signal references we killed */
- while (refs--)
- tty_kref_put(tty);
-
- /*
- * If one of the devices matches a console pointer, we
- * cannot just call hangup() because that will cause
- * tty->count and state->count to go out of sync.
- * So we just call close() the right number of times.
- */
- if (cons_filp) {
- if (tty->ops->close)
- for (n = 0; n < closecount; n++)
- tty->ops->close(tty, cons_filp);
- } else if (tty->ops->hangup)
- (tty->ops->hangup)(tty);
- /*
- * We don't want to have driver/ldisc interactions beyond
- * the ones we did here. The driver layer expects no
- * calls after ->hangup() from the ldisc side. However we
- * can't yet guarantee all that.
- */
- set_bit(TTY_HUPPED, &tty->flags);
- tty_ldisc_enable(tty);
- unlock_kernel();
- if (f)
- fput(f);
-}
-
-/**
- * tty_hangup - trigger a hangup event
- * @tty: tty to hangup
- *
- * A carrier loss (virtual or otherwise) has occurred on this like
- * schedule a hangup sequence to run after this event.
- */
-
-void tty_hangup(struct tty_struct *tty)
-{
-#ifdef TTY_DEBUG_HANGUP
- char buf[64];
- printk(KERN_DEBUG "%s hangup...\n", tty_name(tty, buf));
-#endif
- schedule_work(&tty->hangup_work);
-}
-
-EXPORT_SYMBOL(tty_hangup);
-
-/**
- * tty_vhangup - process vhangup
- * @tty: tty to hangup
- *
- * The user has asked via system call for the terminal to be hung up.
- * We do this synchronously so that when the syscall returns the process
- * is complete. That guarantee is necessary for security reasons.
- */
-
-void tty_vhangup(struct tty_struct *tty)
-{
-#ifdef TTY_DEBUG_HANGUP
- char buf[64];
-
- printk(KERN_DEBUG "%s vhangup...\n", tty_name(tty, buf));
-#endif
- do_tty_hangup(&tty->hangup_work);
-}
-
-EXPORT_SYMBOL(tty_vhangup);
-
-/**
- * tty_vhangup_self - process vhangup for own ctty
- *
- * Perform a vhangup on the current controlling tty
- */
-
-void tty_vhangup_self(void)
-{
- struct tty_struct *tty;
-
- tty = get_current_tty();
- if (tty) {
- tty_vhangup(tty);
- tty_kref_put(tty);
- }
-}
-
-/**
- * tty_hung_up_p - was tty hung up
- * @filp: file pointer of tty
- *
- * Return true if the tty has been subject to a vhangup or a carrier
- * loss
- */
-
-int tty_hung_up_p(struct file *filp)
-{
- return (filp->f_op == &hung_up_tty_fops);
-}
-
-EXPORT_SYMBOL(tty_hung_up_p);
-
-static void session_clear_tty(struct pid *session)
-{
- struct task_struct *p;
- do_each_pid_task(session, PIDTYPE_SID, p) {
- proc_clear_tty(p);
- } while_each_pid_task(session, PIDTYPE_SID, p);
-}
-
-/**
- * disassociate_ctty - disconnect controlling tty
- * @on_exit: true if exiting so need to "hang up" the session
- *
- * This function is typically called only by the session leader, when
- * it wants to disassociate itself from its controlling tty.
- *
- * It performs the following functions:
- * (1) Sends a SIGHUP and SIGCONT to the foreground process group
- * (2) Clears the tty from being controlling the session
- * (3) Clears the controlling tty for all processes in the
- * session group.
- *
- * The argument on_exit is set to 1 if called when a process is
- * exiting; it is 0 if called by the ioctl TIOCNOTTY.
- *
- * Locking:
- * BKL is taken for hysterical raisins
- * tty_mutex is taken to protect tty
- * ->siglock is taken to protect ->signal/->sighand
- * tasklist_lock is taken to walk process list for sessions
- * ->siglock is taken to protect ->signal/->sighand
- */
-
-void disassociate_ctty(int on_exit)
-{
- struct tty_struct *tty;
- struct pid *tty_pgrp = NULL;
-
- if (!current->signal->leader)
- return;
-
- tty = get_current_tty();
- if (tty) {
- tty_pgrp = get_pid(tty->pgrp);
- lock_kernel();
- if (on_exit && tty->driver->type != TTY_DRIVER_TYPE_PTY)
- tty_vhangup(tty);
- unlock_kernel();
- tty_kref_put(tty);
- } else if (on_exit) {
- struct pid *old_pgrp;
- spin_lock_irq(¤t->sighand->siglock);
- old_pgrp = current->signal->tty_old_pgrp;
- current->signal->tty_old_pgrp = NULL;
- spin_unlock_irq(¤t->sighand->siglock);
- if (old_pgrp) {
- kill_pgrp(old_pgrp, SIGHUP, on_exit);
- kill_pgrp(old_pgrp, SIGCONT, on_exit);
- put_pid(old_pgrp);
- }
- return;
- }
- if (tty_pgrp) {
- kill_pgrp(tty_pgrp, SIGHUP, on_exit);
- if (!on_exit)
- kill_pgrp(tty_pgrp, SIGCONT, on_exit);
- put_pid(tty_pgrp);
- }
-
- spin_lock_irq(¤t->sighand->siglock);
- put_pid(current->signal->tty_old_pgrp);
- current->signal->tty_old_pgrp = NULL;
- spin_unlock_irq(¤t->sighand->siglock);
-
- tty = get_current_tty();
- if (tty) {
- unsigned long flags;
- spin_lock_irqsave(&tty->ctrl_lock, flags);
- put_pid(tty->session);
- put_pid(tty->pgrp);
- tty->session = NULL;
- tty->pgrp = NULL;
- spin_unlock_irqrestore(&tty->ctrl_lock, flags);
- tty_kref_put(tty);
- } else {
-#ifdef TTY_DEBUG_HANGUP
- printk(KERN_DEBUG "error attempted to write to tty [0x%p]"
- " = NULL", tty);
-#endif
- }
-
- /* Now clear signal->tty under the lock */
- read_lock(&tasklist_lock);
- session_clear_tty(task_session(current));
- read_unlock(&tasklist_lock);
-}
-
-/**
- *
- * no_tty - Ensure the current process does not have a controlling tty
- */
-void no_tty(void)
-{
- struct task_struct *tsk = current;
- lock_kernel();
- disassociate_ctty(0);
- unlock_kernel();
- proc_clear_tty(tsk);
-}
-
-
-/**
- * stop_tty - propagate flow control
- * @tty: tty to stop
- *
- * Perform flow control to the driver. For PTY/TTY pairs we
- * must also propagate the TIOCKPKT status. May be called
- * on an already stopped device and will not re-call the driver
- * method.
- *
- * This functionality is used by both the line disciplines for
- * halting incoming flow and by the driver. It may therefore be
- * called from any context, may be under the tty atomic_write_lock
- * but not always.
- *
- * Locking:
- * Uses the tty control lock internally
- */
-
-void stop_tty(struct tty_struct *tty)
-{
- unsigned long flags;
- spin_lock_irqsave(&tty->ctrl_lock, flags);
- if (tty->stopped) {
- spin_unlock_irqrestore(&tty->ctrl_lock, flags);
- return;
- }
- tty->stopped = 1;
- if (tty->link && tty->link->packet) {
- tty->ctrl_status &= ~TIOCPKT_START;
- tty->ctrl_status |= TIOCPKT_STOP;
- wake_up_interruptible_poll(&tty->link->read_wait, POLLIN);
- }
- spin_unlock_irqrestore(&tty->ctrl_lock, flags);
- if (tty->ops->stop)
- (tty->ops->stop)(tty);
-}
-
-EXPORT_SYMBOL(stop_tty);
-
-/**
- * start_tty - propagate flow control
- * @tty: tty to start
- *
- * Start a tty that has been stopped if at all possible. Perform
- * any necessary wakeups and propagate the TIOCPKT status. If this
- * is the tty was previous stopped and is being started then the
- * driver start method is invoked and the line discipline woken.
- *
- * Locking:
- * ctrl_lock
- */
-
-void start_tty(struct tty_struct *tty)
-{
- unsigned long flags;
- spin_lock_irqsave(&tty->ctrl_lock, flags);
- if (!tty->stopped || tty->flow_stopped) {
- spin_unlock_irqrestore(&tty->ctrl_lock, flags);
- return;
- }
- tty->stopped = 0;
- if (tty->link && tty->link->packet) {
- tty->ctrl_status &= ~TIOCPKT_STOP;
- tty->ctrl_status |= TIOCPKT_START;
- wake_up_interruptible_poll(&tty->link->read_wait, POLLIN);
- }
- spin_unlock_irqrestore(&tty->ctrl_lock, flags);
- if (tty->ops->start)
- (tty->ops->start)(tty);
- /* If we have a running line discipline it may need kicking */
- tty_wakeup(tty);
-}
-
-EXPORT_SYMBOL(start_tty);
-
-/**
- * tty_read - read method for tty device files
- * @file: pointer to tty file
- * @buf: user buffer
- * @count: size of user buffer
- * @ppos: unused
- *
- * Perform the read system call function on this terminal device. Checks
- * for hung up devices before calling the line discipline method.
- *
- * Locking:
- * Locks the line discipline internally while needed. Multiple
- * read calls may be outstanding in parallel.
- */
-
-static ssize_t tty_read(struct file *file, char __user *buf, size_t count,
- loff_t *ppos)
-{
- int i;
- struct tty_struct *tty;
- struct inode *inode;
- struct tty_ldisc *ld;
-
- tty = (struct tty_struct *)file->private_data;
- inode = file->f_path.dentry->d_inode;
- if (tty_paranoia_check(tty, inode, "tty_read"))
- return -EIO;
- if (!tty || (test_bit(TTY_IO_ERROR, &tty->flags)))
- return -EIO;
-
- /* We want to wait for the line discipline to sort out in this
- situation */
- ld = tty_ldisc_ref_wait(tty);
- if (ld->ops->read)
- i = (ld->ops->read)(tty, file, buf, count);
- else
- i = -EIO;
- tty_ldisc_deref(ld);
- if (i > 0)
- inode->i_atime = current_fs_time(inode->i_sb);
- return i;
-}
-
-void tty_write_unlock(struct tty_struct *tty)
-{
- mutex_unlock(&tty->atomic_write_lock);
- wake_up_interruptible_poll(&tty->write_wait, POLLOUT);
-}
-
-int tty_write_lock(struct tty_struct *tty, int ndelay)
-{
- if (!mutex_trylock(&tty->atomic_write_lock)) {
- if (ndelay)
- return -EAGAIN;
- if (mutex_lock_interruptible(&tty->atomic_write_lock))
- return -ERESTARTSYS;
- }
- return 0;
-}
-
-/*
- * Split writes up in sane blocksizes to avoid
- * denial-of-service type attacks
- */
-static inline ssize_t do_tty_write(
- ssize_t (*write)(struct tty_struct *, struct file *, const unsigned char *, size_t),
- struct tty_struct *tty,
- struct file *file,
- const char __user *buf,
- size_t count)
-{
- ssize_t ret, written = 0;
- unsigned int chunk;
-
- ret = tty_write_lock(tty, file->f_flags & O_NDELAY);
- if (ret < 0)
- return ret;
-
- /*
- * We chunk up writes into a temporary buffer. This
- * simplifies low-level drivers immensely, since they
- * don't have locking issues and user mode accesses.
- *
- * But if TTY_NO_WRITE_SPLIT is set, we should use a
- * big chunk-size..
- *
- * The default chunk-size is 2kB, because the NTTY
- * layer has problems with bigger chunks. It will
- * claim to be able to handle more characters than
- * it actually does.
- *
- * FIXME: This can probably go away now except that 64K chunks
- * are too likely to fail unless switched to vmalloc...
- */
- chunk = 2048;
- if (test_bit(TTY_NO_WRITE_SPLIT, &tty->flags))
- chunk = 65536;
- if (count < chunk)
- chunk = count;
-
- /* write_buf/write_cnt is protected by the atomic_write_lock mutex */
- if (tty->write_cnt < chunk) {
- unsigned char *buf_chunk;
-
- if (chunk < 1024)
- chunk = 1024;
-
- buf_chunk = kmalloc(chunk, GFP_KERNEL);
- if (!buf_chunk) {
- ret = -ENOMEM;
- goto out;
- }
- kfree(tty->write_buf);
- tty->write_cnt = chunk;
- tty->write_buf = buf_chunk;
- }
-
- /* Do the write .. */
- for (;;) {
- size_t size = count;
- if (size > chunk)
- size = chunk;
- ret = -EFAULT;
- if (copy_from_user(tty->write_buf, buf, size))
- break;
- ret = write(tty, file, tty->write_buf, size);
- if (ret <= 0)
- break;
- written += ret;
- buf += ret;
- count -= ret;
- if (!count)
- break;
- ret = -ERESTARTSYS;
- if (signal_pending(current))
- break;
- cond_resched();
- }
- if (written) {
- struct inode *inode = file->f_path.dentry->d_inode;
- inode->i_mtime = current_fs_time(inode->i_sb);
- ret = written;
- }
-out:
- tty_write_unlock(tty);
- return ret;
-}
-
-/**
- * tty_write_message - write a message to a certain tty, not just the console.
- * @tty: the destination tty_struct
- * @msg: the message to write
- *
- * This is used for messages that need to be redirected to a specific tty.
- * We don't put it into the syslog queue right now maybe in the future if
- * really needed.
- *
- * We must still hold the BKL and test the CLOSING flag for the moment.
- */
-
-void tty_write_message(struct tty_struct *tty, char *msg)
-{
- if (tty) {
- mutex_lock(&tty->atomic_write_lock);
- lock_kernel();
- if (tty->ops->write && !test_bit(TTY_CLOSING, &tty->flags)) {
- unlock_kernel();
- tty->ops->write(tty, msg, strlen(msg));
- } else
- unlock_kernel();
- tty_write_unlock(tty);
- }
- return;
-}
-
-
-/**
- * tty_write - write method for tty device file
- * @file: tty file pointer
- * @buf: user data to write
- * @count: bytes to write
- * @ppos: unused
- *
- * Write data to a tty device via the line discipline.
- *
- * Locking:
- * Locks the line discipline as required
- * Writes to the tty driver are serialized by the atomic_write_lock
- * and are then processed in chunks to the device. The line discipline
- * write method will not be invoked in parallel for each device.
- */
-
-static ssize_t tty_write(struct file *file, const char __user *buf,
- size_t count, loff_t *ppos)
-{
- struct tty_struct *tty;
- struct inode *inode = file->f_path.dentry->d_inode;
- ssize_t ret;
- struct tty_ldisc *ld;
-
- tty = (struct tty_struct *)file->private_data;
- if (tty_paranoia_check(tty, inode, "tty_write"))
- return -EIO;
- if (!tty || !tty->ops->write ||
- (test_bit(TTY_IO_ERROR, &tty->flags)))
- return -EIO;
- /* Short term debug to catch buggy drivers */
- if (tty->ops->write_room == NULL)
- printk(KERN_ERR "tty driver %s lacks a write_room method.\n",
- tty->driver->name);
- ld = tty_ldisc_ref_wait(tty);
- if (!ld->ops->write)
- ret = -EIO;
- else
- ret = do_tty_write(ld->ops->write, tty, file, buf, count);
- tty_ldisc_deref(ld);
- return ret;
-}
-
-ssize_t redirected_tty_write(struct file *file, const char __user *buf,
- size_t count, loff_t *ppos)
-{
- struct file *p = NULL;
-
- spin_lock(&redirect_lock);
- if (redirect) {
- get_file(redirect);
- p = redirect;
- }
- spin_unlock(&redirect_lock);
-
- if (p) {
- ssize_t res;
- res = vfs_write(p, buf, count, &p->f_pos);
- fput(p);
- return res;
- }
- return tty_write(file, buf, count, ppos);
-}
-
-static char ptychar[] = "pqrstuvwxyzabcde";
-
-/**
- * pty_line_name - generate name for a pty
- * @driver: the tty driver in use
- * @index: the minor number
- * @p: output buffer of at least 6 bytes
- *
- * Generate a name from a driver reference and write it to the output
- * buffer.
- *
- * Locking: None
- */
-static void pty_line_name(struct tty_driver *driver, int index, char *p)
-{
- int i = index + driver->name_base;
- /* ->name is initialized to "ttyp", but "tty" is expected */
- sprintf(p, "%s%c%x",
- driver->subtype == PTY_TYPE_SLAVE ? "tty" : driver->name,
- ptychar[i >> 4 & 0xf], i & 0xf);
-}
-
-/**
- * tty_line_name - generate name for a tty
- * @driver: the tty driver in use
- * @index: the minor number
- * @p: output buffer of at least 7 bytes
- *
- * Generate a name from a driver reference and write it to the output
- * buffer.
- *
- * Locking: None
- */
-static void tty_line_name(struct tty_driver *driver, int index, char *p)
-{
- sprintf(p, "%s%d", driver->name, index + driver->name_base);
-}
-
-/**
- * tty_driver_lookup_tty() - find an existing tty, if any
- * @driver: the driver for the tty
- * @idx: the minor number
- *
- * Return the tty, if found or ERR_PTR() otherwise.
- *
- * Locking: tty_mutex must be held. If tty is found, the mutex must
- * be held until the 'fast-open' is also done. Will change once we
- * have refcounting in the driver and per driver locking
- */
-static struct tty_struct *tty_driver_lookup_tty(struct tty_driver *driver,
- struct inode *inode, int idx)
-{
- struct tty_struct *tty;
-
- if (driver->ops->lookup)
- return driver->ops->lookup(driver, inode, idx);
-
- tty = driver->ttys[idx];
- return tty;
-}
-
-/**
- * tty_init_termios - helper for termios setup
- * @tty: the tty to set up
- *
- * Initialise the termios structures for this tty. Thus runs under
- * the tty_mutex currently so we can be relaxed about ordering.
- */
-
-int tty_init_termios(struct tty_struct *tty)
-{
- struct ktermios *tp;
- int idx = tty->index;
-
- tp = tty->driver->termios[idx];
- if (tp == NULL) {
- tp = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL);
- if (tp == NULL)
- return -ENOMEM;
- memcpy(tp, &tty->driver->init_termios,
- sizeof(struct ktermios));
- tty->driver->termios[idx] = tp;
- }
- tty->termios = tp;
- tty->termios_locked = tp + 1;
-
- /* Compatibility until drivers always set this */
- tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios);
- tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios);
- return 0;
-}
-EXPORT_SYMBOL_GPL(tty_init_termios);
-
-/**
- * tty_driver_install_tty() - install a tty entry in the driver
- * @driver: the driver for the tty
- * @tty: the tty
- *
- * Install a tty object into the driver tables. The tty->index field
- * will be set by the time this is called. This method is responsible
- * for ensuring any need additional structures are allocated and
- * configured.
- *
- * Locking: tty_mutex for now
- */
-static int tty_driver_install_tty(struct tty_driver *driver,
- struct tty_struct *tty)
-{
- int idx = tty->index;
- int ret;
-
- if (driver->ops->install) {
- lock_kernel();
- ret = driver->ops->install(driver, tty);
- unlock_kernel();
- return ret;
- }
-
- if (tty_init_termios(tty) == 0) {
- lock_kernel();
- tty_driver_kref_get(driver);
- tty->count++;
- driver->ttys[idx] = tty;
- unlock_kernel();
- return 0;
- }
- return -ENOMEM;
-}
-
-/**
- * tty_driver_remove_tty() - remove a tty from the driver tables
- * @driver: the driver for the tty
- * @idx: the minor number
- *
- * Remvoe a tty object from the driver tables. The tty->index field
- * will be set by the time this is called.
- *
- * Locking: tty_mutex for now
- */
-static void tty_driver_remove_tty(struct tty_driver *driver,
- struct tty_struct *tty)
-{
- if (driver->ops->remove)
- driver->ops->remove(driver, tty);
- else
- driver->ttys[tty->index] = NULL;
-}
-
-/*
- * tty_reopen() - fast re-open of an open tty
- * @tty - the tty to open
- *
- * Return 0 on success, -errno on error.
- *
- * Locking: tty_mutex must be held from the time the tty was found
- * till this open completes.
- */
-static int tty_reopen(struct tty_struct *tty)
-{
- struct tty_driver *driver = tty->driver;
-
- if (test_bit(TTY_CLOSING, &tty->flags))
- return -EIO;
-
- if (driver->type == TTY_DRIVER_TYPE_PTY &&
- driver->subtype == PTY_TYPE_MASTER) {
- /*
- * special case for PTY masters: only one open permitted,
- * and the slave side open count is incremented as well.
- */
- if (tty->count)
- return -EIO;
-
- tty->link->count++;
- }
- tty->count++;
- tty->driver = driver; /* N.B. why do this every time?? */
-
- mutex_lock(&tty->ldisc_mutex);
- WARN_ON(!test_bit(TTY_LDISC, &tty->flags));
- mutex_unlock(&tty->ldisc_mutex);
-
- return 0;
-}
-
-/**
- * tty_init_dev - initialise a tty device
- * @driver: tty driver we are opening a device on
- * @idx: device index
- * @ret_tty: returned tty structure
- * @first_ok: ok to open a new device (used by ptmx)
- *
- * Prepare a tty device. This may not be a "new" clean device but
- * could also be an active device. The pty drivers require special
- * handling because of this.
- *
- * Locking:
- * The function is called under the tty_mutex, which
- * protects us from the tty struct or driver itself going away.
- *
- * On exit the tty device has the line discipline attached and
- * a reference count of 1. If a pair was created for pty/tty use
- * and the other was a pty master then it too has a reference count of 1.
- *
- * WSH 06/09/97: Rewritten to remove races and properly clean up after a
- * failed open. The new code protects the open with a mutex, so it's
- * really quite straightforward. The mutex locking can probably be
- * relaxed for the (most common) case of reopening a tty.
- */
-
-struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,
- int first_ok)
-{
- struct tty_struct *tty;
- int retval;
-
- lock_kernel();
- /* Check if pty master is being opened multiple times */
- if (driver->subtype == PTY_TYPE_MASTER &&
- (driver->flags & TTY_DRIVER_DEVPTS_MEM) && !first_ok) {
- unlock_kernel();
- return ERR_PTR(-EIO);
- }
- unlock_kernel();
-
- /*
- * First time open is complex, especially for PTY devices.
- * This code guarantees that either everything succeeds and the
- * TTY is ready for operation, or else the table slots are vacated
- * and the allocated memory released. (Except that the termios
- * and locked termios may be retained.)
- */
-
- if (!try_module_get(driver->owner))
- return ERR_PTR(-ENODEV);
-
- tty = alloc_tty_struct();
- if (!tty)
- goto fail_no_mem;
- initialize_tty_struct(tty, driver, idx);
-
- retval = tty_driver_install_tty(driver, tty);
- if (retval < 0) {
- free_tty_struct(tty);
- module_put(driver->owner);
- return ERR_PTR(retval);
- }
-
- /*
- * Structures all installed ... call the ldisc open routines.
- * If we fail here just call release_tty to clean up. No need
- * to decrement the use counts, as release_tty doesn't care.
- */
- retval = tty_ldisc_setup(tty, tty->link);
- if (retval)
- goto release_mem_out;
- return tty;
-
-fail_no_mem:
- module_put(driver->owner);
- return ERR_PTR(-ENOMEM);
-
- /* call the tty release_tty routine to clean out this slot */
-release_mem_out:
- if (printk_ratelimit())
- printk(KERN_INFO "tty_init_dev: ldisc open failed, "
- "clearing slot %d\n", idx);
- lock_kernel();
- release_tty(tty, idx);
- unlock_kernel();
- return ERR_PTR(retval);
-}
-
-void tty_free_termios(struct tty_struct *tty)
-{
- struct ktermios *tp;
- int idx = tty->index;
- /* Kill this flag and push into drivers for locking etc */
- if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) {
- /* FIXME: Locking on ->termios array */
- tp = tty->termios;
- tty->driver->termios[idx] = NULL;
- kfree(tp);
- }
-}
-EXPORT_SYMBOL(tty_free_termios);
-
-void tty_shutdown(struct tty_struct *tty)
-{
- tty_driver_remove_tty(tty->driver, tty);
- tty_free_termios(tty);
-}
-EXPORT_SYMBOL(tty_shutdown);
-
-/**
- * release_one_tty - release tty structure memory
- * @kref: kref of tty we are obliterating
- *
- * Releases memory associated with a tty structure, and clears out the
- * driver table slots. This function is called when a device is no longer
- * in use. It also gets called when setup of a device fails.
- *
- * Locking:
- * tty_mutex - sometimes only
- * takes the file list lock internally when working on the list
- * of ttys that the driver keeps.
- *
- * This method gets called from a work queue so that the driver private
- * cleanup ops can sleep (needed for USB at least)
- */
-static void release_one_tty(struct work_struct *work)
-{
- struct tty_struct *tty =
- container_of(work, struct tty_struct, hangup_work);
- struct tty_driver *driver = tty->driver;
-
- if (tty->ops->cleanup)
- tty->ops->cleanup(tty);
-
- tty->magic = 0;
- tty_driver_kref_put(driver);
- module_put(driver->owner);
-
- file_list_lock();
- list_del_init(&tty->tty_files);
- file_list_unlock();
-
- put_pid(tty->pgrp);
- put_pid(tty->session);
- free_tty_struct(tty);
-}
-
-static void queue_release_one_tty(struct kref *kref)
-{
- struct tty_struct *tty = container_of(kref, struct tty_struct, kref);
-
- if (tty->ops->shutdown)
- tty->ops->shutdown(tty);
- else
- tty_shutdown(tty);
-
- /* The hangup queue is now free so we can reuse it rather than
- waste a chunk of memory for each port */
- INIT_WORK(&tty->hangup_work, release_one_tty);
- schedule_work(&tty->hangup_work);
-}
-
-/**
- * tty_kref_put - release a tty kref
- * @tty: tty device
- *
- * Release a reference to a tty device and if need be let the kref
- * layer destruct the object for us
- */
-
-void tty_kref_put(struct tty_struct *tty)
-{
- if (tty)
- kref_put(&tty->kref, queue_release_one_tty);
-}
-EXPORT_SYMBOL(tty_kref_put);
-
-/**
- * release_tty - release tty structure memory
- *
- * Release both @tty and a possible linked partner (think pty pair),
- * and decrement the refcount of the backing module.
- *
- * Locking:
- * tty_mutex - sometimes only
- * takes the file list lock internally when working on the list
- * of ttys that the driver keeps.
- * FIXME: should we require tty_mutex is held here ??
- *
- */
-static void release_tty(struct tty_struct *tty, int idx)
-{
- /* This should always be true but check for the moment */
- WARN_ON(tty->index != idx);
-
- if (tty->link)
- tty_kref_put(tty->link);
- tty_kref_put(tty);
-}
-
-/**
- * tty_release - vfs callback for close
- * @inode: inode of tty
- * @filp: file pointer for handle to tty
- *
- * Called the last time each file handle is closed that references
- * this tty. There may however be several such references.
- *
- * Locking:
- * Takes bkl. See tty_release_dev
- *
- * Even releasing the tty structures is a tricky business.. We have
- * to be very careful that the structures are all released at the
- * same time, as interrupts might otherwise get the wrong pointers.
- *
- * WSH 09/09/97: rewritten to avoid some nasty race conditions that could
- * lead to double frees or releasing memory still in use.
- */
-
-int tty_release(struct inode *inode, struct file *filp)
-{
- struct tty_struct *tty, *o_tty;
- int pty_master, tty_closing, o_tty_closing, do_sleep;
- int devpts;
- int idx;
- char buf[64];
-
- tty = (struct tty_struct *)filp->private_data;
- if (tty_paranoia_check(tty, inode, "tty_release_dev"))
- return 0;
-
- lock_kernel();
- check_tty_count(tty, "tty_release_dev");
-
- tty_fasync(-1, filp, 0);
-
- idx = tty->index;
- pty_master = (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
- tty->driver->subtype == PTY_TYPE_MASTER);
- devpts = (tty->driver->flags & TTY_DRIVER_DEVPTS_MEM) != 0;
- o_tty = tty->link;
-
-#ifdef TTY_PARANOIA_CHECK
- if (idx < 0 || idx >= tty->driver->num) {
- printk(KERN_DEBUG "tty_release_dev: bad idx when trying to "
- "free (%s)\n", tty->name);
- unlock_kernel();
- return 0;
- }
- if (!devpts) {
- if (tty != tty->driver->ttys[idx]) {
- unlock_kernel();
- printk(KERN_DEBUG "tty_release_dev: driver.table[%d] not tty "
- "for (%s)\n", idx, tty->name);
- return 0;
- }
- if (tty->termios != tty->driver->termios[idx]) {
- unlock_kernel();
- printk(KERN_DEBUG "tty_release_dev: driver.termios[%d] not termios "
- "for (%s)\n",
- idx, tty->name);
- return 0;
- }
- }
-#endif
-
-#ifdef TTY_DEBUG_HANGUP
- printk(KERN_DEBUG "tty_release_dev of %s (tty count=%d)...",
- tty_name(tty, buf), tty->count);
-#endif
-
-#ifdef TTY_PARANOIA_CHECK
- if (tty->driver->other &&
- !(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) {
- if (o_tty != tty->driver->other->ttys[idx]) {
- unlock_kernel();
- printk(KERN_DEBUG "tty_release_dev: other->table[%d] "
- "not o_tty for (%s)\n",
- idx, tty->name);
- return 0 ;
- }
- if (o_tty->termios != tty->driver->other->termios[idx]) {
- unlock_kernel();
- printk(KERN_DEBUG "tty_release_dev: other->termios[%d] "
- "not o_termios for (%s)\n",
- idx, tty->name);
- return 0;
- }
- if (o_tty->link != tty) {
- unlock_kernel();
- printk(KERN_DEBUG "tty_release_dev: bad pty pointers\n");
- return 0;
- }
- }
-#endif
- if (tty->ops->close)
- tty->ops->close(tty, filp);
-
- unlock_kernel();
- /*
- * Sanity check: if tty->count is going to zero, there shouldn't be
- * any waiters on tty->read_wait or tty->write_wait. We test the
- * wait queues and kick everyone out _before_ actually starting to
- * close. This ensures that we won't block while releasing the tty
- * structure.
- *
- * The test for the o_tty closing is necessary, since the master and
- * slave sides may close in any order. If the slave side closes out
- * first, its count will be one, since the master side holds an open.
- * Thus this test wouldn't be triggered at the time the slave closes,
- * so we do it now.
- *
- * Note that it's possible for the tty to be opened again while we're
- * flushing out waiters. By recalculating the closing flags before
- * each iteration we avoid any problems.
- */
- while (1) {
- /* Guard against races with tty->count changes elsewhere and
- opens on /dev/tty */
-
- mutex_lock(&tty_mutex);
- lock_kernel();
- tty_closing = tty->count <= 1;
- o_tty_closing = o_tty &&
- (o_tty->count <= (pty_master ? 1 : 0));
- do_sleep = 0;
-
- if (tty_closing) {
- if (waitqueue_active(&tty->read_wait)) {
- wake_up_poll(&tty->read_wait, POLLIN);
- do_sleep++;
- }
- if (waitqueue_active(&tty->write_wait)) {
- wake_up_poll(&tty->write_wait, POLLOUT);
- do_sleep++;
- }
- }
- if (o_tty_closing) {
- if (waitqueue_active(&o_tty->read_wait)) {
- wake_up_poll(&o_tty->read_wait, POLLIN);
- do_sleep++;
- }
- if (waitqueue_active(&o_tty->write_wait)) {
- wake_up_poll(&o_tty->write_wait, POLLOUT);
- do_sleep++;
- }
- }
- if (!do_sleep)
- break;
-
- printk(KERN_WARNING "tty_release_dev: %s: read/write wait queue "
- "active!\n", tty_name(tty, buf));
- unlock_kernel();
- mutex_unlock(&tty_mutex);
- schedule();
- }
-
- /*
- * The closing flags are now consistent with the open counts on
- * both sides, and we've completed the last operation that could
- * block, so it's safe to proceed with closing.
- */
- if (pty_master) {
- if (--o_tty->count < 0) {
- printk(KERN_WARNING "tty_release_dev: bad pty slave count "
- "(%d) for %s\n",
- o_tty->count, tty_name(o_tty, buf));
- o_tty->count = 0;
- }
- }
- if (--tty->count < 0) {
- printk(KERN_WARNING "tty_release_dev: bad tty->count (%d) for %s\n",
- tty->count, tty_name(tty, buf));
- tty->count = 0;
- }
-
- /*
- * We've decremented tty->count, so we need to remove this file
- * descriptor off the tty->tty_files list; this serves two
- * purposes:
- * - check_tty_count sees the correct number of file descriptors
- * associated with this tty.
- * - do_tty_hangup no longer sees this file descriptor as
- * something that needs to be handled for hangups.
- */
- file_kill(filp);
- filp->private_data = NULL;
-
- /*
- * Perform some housekeeping before deciding whether to return.
- *
- * Set the TTY_CLOSING flag if this was the last open. In the
- * case of a pty we may have to wait around for the other side
- * to close, and TTY_CLOSING makes sure we can't be reopened.
- */
- if (tty_closing)
- set_bit(TTY_CLOSING, &tty->flags);
- if (o_tty_closing)
- set_bit(TTY_CLOSING, &o_tty->flags);
-
- /*
- * If _either_ side is closing, make sure there aren't any
- * processes that still think tty or o_tty is their controlling
- * tty.
- */
- if (tty_closing || o_tty_closing) {
- read_lock(&tasklist_lock);
- session_clear_tty(tty->session);
- if (o_tty)
- session_clear_tty(o_tty->session);
- read_unlock(&tasklist_lock);
- }
-
- mutex_unlock(&tty_mutex);
-
- /* check whether both sides are closing ... */
- if (!tty_closing || (o_tty && !o_tty_closing)) {
- unlock_kernel();
- return 0;
- }
-
-#ifdef TTY_DEBUG_HANGUP
- printk(KERN_DEBUG "freeing tty structure...");
-#endif
- /*
- * Ask the line discipline code to release its structures
- */
- tty_ldisc_release(tty, o_tty);
- /*
- * The release_tty function takes care of the details of clearing
- * the slots and preserving the termios structure.
- */
- release_tty(tty, idx);
-
- /* Make this pty number available for reallocation */
- if (devpts)
- devpts_kill_index(inode, idx);
- unlock_kernel();
- return 0;
-}
-
-/**
- * tty_open - open a tty device
- * @inode: inode of device file
- * @filp: file pointer to tty
- *
- * tty_open and tty_release keep up the tty count that contains the
- * number of opens done on a tty. We cannot use the inode-count, as
- * different inodes might point to the same tty.
- *
- * Open-counting is needed for pty masters, as well as for keeping
- * track of serial lines: DTR is dropped when the last close happens.
- * (This is not done solely through tty->count, now. - Ted 1/27/92)
- *
- * The termios state of a pty is reset on first open so that
- * settings don't persist across reuse.
- *
- * Locking: tty_mutex protects tty, get_tty_driver and tty_init_dev work.
- * tty->count should protect the rest.
- * ->siglock protects ->signal/->sighand
- */
-
-static int tty_open(struct inode *inode, struct file *filp)
-{
- struct tty_struct *tty = NULL;
- int noctty, retval;
- struct tty_driver *driver;
- int index;
- dev_t device = inode->i_rdev;
- unsigned saved_flags = filp->f_flags;
-
- nonseekable_open(inode, filp);
-
-retry_open:
- noctty = filp->f_flags & O_NOCTTY;
- index = -1;
- retval = 0;
-
- mutex_lock(&tty_mutex);
- lock_kernel();
-
- if (device == MKDEV(TTYAUX_MAJOR, 0)) {
- tty = get_current_tty();
- if (!tty) {
- unlock_kernel();
- mutex_unlock(&tty_mutex);
- return -ENXIO;
- }
- driver = tty_driver_kref_get(tty->driver);
- index = tty->index;
- filp->f_flags |= O_NONBLOCK; /* Don't let /dev/tty block */
- /* noctty = 1; */
- /* FIXME: Should we take a driver reference ? */
- tty_kref_put(tty);
- goto got_driver;
- }
-#ifdef CONFIG_VT
- if (device == MKDEV(TTY_MAJOR, 0)) {
- extern struct tty_driver *console_driver;
- driver = tty_driver_kref_get(console_driver);
- index = fg_console;
- noctty = 1;
- goto got_driver;
- }
-#endif
- if (device == MKDEV(TTYAUX_MAJOR, 1)) {
- struct tty_driver *console_driver = console_device(&index);
- if (console_driver) {
- driver = tty_driver_kref_get(console_driver);
- if (driver) {
- /* Don't let /dev/console block */
- filp->f_flags |= O_NONBLOCK;
- noctty = 1;
- goto got_driver;
- }
- }
- unlock_kernel();
- mutex_unlock(&tty_mutex);
- return -ENODEV;
- }
-
- driver = get_tty_driver(device, &index);
- if (!driver) {
- unlock_kernel();
- mutex_unlock(&tty_mutex);
- return -ENODEV;
- }
-got_driver:
- if (!tty) {
- /* check whether we're reopening an existing tty */
- tty = tty_driver_lookup_tty(driver, inode, index);
-
- if (IS_ERR(tty)) {
- unlock_kernel();
- mutex_unlock(&tty_mutex);
- return PTR_ERR(tty);
- }
- }
-
- if (tty) {
- retval = tty_reopen(tty);
- if (retval)
- tty = ERR_PTR(retval);
- } else
- tty = tty_init_dev(driver, index, 0);
-
- mutex_unlock(&tty_mutex);
- tty_driver_kref_put(driver);
- if (IS_ERR(tty)) {
- unlock_kernel();
- return PTR_ERR(tty);
- }
-
- filp->private_data = tty;
- file_move(filp, &tty->tty_files);
- check_tty_count(tty, "tty_open");
- if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
- tty->driver->subtype == PTY_TYPE_MASTER)
- noctty = 1;
-#ifdef TTY_DEBUG_HANGUP
- printk(KERN_DEBUG "opening %s...", tty->name);
-#endif
- if (!retval) {
- if (tty->ops->open)
- retval = tty->ops->open(tty, filp);
- else
- retval = -ENODEV;
- }
- filp->f_flags = saved_flags;
-
- if (!retval && test_bit(TTY_EXCLUSIVE, &tty->flags) &&
- !capable(CAP_SYS_ADMIN))
- retval = -EBUSY;
-
- if (retval) {
-#ifdef TTY_DEBUG_HANGUP
- printk(KERN_DEBUG "error %d in opening %s...", retval,
- tty->name);
-#endif
- tty_release(inode, filp);
- if (retval != -ERESTARTSYS) {
- unlock_kernel();
- return retval;
- }
- if (signal_pending(current)) {
- unlock_kernel();
- return retval;
- }
- schedule();
- /*
- * Need to reset f_op in case a hangup happened.
- */
- if (filp->f_op == &hung_up_tty_fops)
- filp->f_op = &tty_fops;
- unlock_kernel();
- goto retry_open;
- }
- unlock_kernel();
-
-
- mutex_lock(&tty_mutex);
- lock_kernel();
- spin_lock_irq(¤t->sighand->siglock);
- if (!noctty &&
- current->signal->leader &&
- !current->signal->tty &&
- tty->session == NULL)
- __proc_set_tty(current, tty);
- spin_unlock_irq(¤t->sighand->siglock);
- unlock_kernel();
- mutex_unlock(&tty_mutex);
- return 0;
-}
-
-
-
-/**
- * tty_poll - check tty status
- * @filp: file being polled
- * @wait: poll wait structures to update
- *
- * Call the line discipline polling method to obtain the poll
- * status of the device.
- *
- * Locking: locks called line discipline but ldisc poll method
- * may be re-entered freely by other callers.
- */
-
-static unsigned int tty_poll(struct file *filp, poll_table *wait)
-{
- struct tty_struct *tty;
- struct tty_ldisc *ld;
- int ret = 0;
-
- tty = (struct tty_struct *)filp->private_data;
- if (tty_paranoia_check(tty, filp->f_path.dentry->d_inode, "tty_poll"))
- return 0;
-
- ld = tty_ldisc_ref_wait(tty);
- if (ld->ops->poll)
- ret = (ld->ops->poll)(tty, filp, wait);
- tty_ldisc_deref(ld);
- return ret;
-}
-
-static int tty_fasync(int fd, struct file *filp, int on)
-{
- struct tty_struct *tty;
- unsigned long flags;
- int retval = 0;
-
- lock_kernel();
- tty = (struct tty_struct *)filp->private_data;
- if (tty_paranoia_check(tty, filp->f_path.dentry->d_inode, "tty_fasync"))
- goto out;
-
- retval = fasync_helper(fd, filp, on, &tty->fasync);
- if (retval <= 0)
- goto out;
-
- if (on) {
- enum pid_type type;
- struct pid *pid;
- if (!waitqueue_active(&tty->read_wait))
- tty->minimum_to_wake = 1;
- spin_lock_irqsave(&tty->ctrl_lock, flags);
- if (tty->pgrp) {
- pid = tty->pgrp;
- type = PIDTYPE_PGID;
- } else {
- pid = task_pid(current);
- type = PIDTYPE_PID;
- }
- get_pid(pid);
- spin_unlock_irqrestore(&tty->ctrl_lock, flags);
- retval = __f_setown(filp, pid, type, 0);
- put_pid(pid);
- if (retval)
- goto out;
- } else {
- if (!tty->fasync && !waitqueue_active(&tty->read_wait))
- tty->minimum_to_wake = N_TTY_BUF_SIZE;
- }
- retval = 0;
-out:
- unlock_kernel();
- return retval;
-}
-
-/**
- * tiocsti - fake input character
- * @tty: tty to fake input into
- * @p: pointer to character
- *
- * Fake input to a tty device. Does the necessary locking and
- * input management.
- *
- * FIXME: does not honour flow control ??
- *
- * Locking:
- * Called functions take tty_ldisc_lock
- * current->signal->tty check is safe without locks
- *
- * FIXME: may race normal receive processing
- */
-
-static int tiocsti(struct tty_struct *tty, char __user *p)
-{
- char ch, mbz = 0;
- struct tty_ldisc *ld;
-
- if ((current->signal->tty != tty) && !capable(CAP_SYS_ADMIN))
- return -EPERM;
- if (get_user(ch, p))
- return -EFAULT;
- tty_audit_tiocsti(tty, ch);
- ld = tty_ldisc_ref_wait(tty);
- ld->ops->receive_buf(tty, &ch, &mbz, 1);
- tty_ldisc_deref(ld);
- return 0;
-}
-
-/**
- * tiocgwinsz - implement window query ioctl
- * @tty; tty
- * @arg: user buffer for result
- *
- * Copies the kernel idea of the window size into the user buffer.
- *
- * Locking: tty->termios_mutex is taken to ensure the winsize data
- * is consistent.
- */
-
-static int tiocgwinsz(struct tty_struct *tty, struct winsize __user *arg)
-{
- int err;
-
- mutex_lock(&tty->termios_mutex);
- err = copy_to_user(arg, &tty->winsize, sizeof(*arg));
- mutex_unlock(&tty->termios_mutex);
-
- return err ? -EFAULT: 0;
-}
-
-/**
- * tty_do_resize - resize event
- * @tty: tty being resized
- * @rows: rows (character)
- * @cols: cols (character)
- *
- * Update the termios variables and send the necessary signals to
- * peform a terminal resize correctly
- */
-
-int tty_do_resize(struct tty_struct *tty, struct winsize *ws)
-{
- struct pid *pgrp;
- unsigned long flags;
-
- /* Lock the tty */
- mutex_lock(&tty->termios_mutex);
- if (!memcmp(ws, &tty->winsize, sizeof(*ws)))
- goto done;
- /* Get the PID values and reference them so we can
- avoid holding the tty ctrl lock while sending signals */
- spin_lock_irqsave(&tty->ctrl_lock, flags);
- pgrp = get_pid(tty->pgrp);
- spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-
- if (pgrp)
- kill_pgrp(pgrp, SIGWINCH, 1);
- put_pid(pgrp);
-
- tty->winsize = *ws;
-done:
- mutex_unlock(&tty->termios_mutex);
- return 0;
-}
-
-/**
- * tiocswinsz - implement window size set ioctl
- * @tty; tty side of tty
- * @arg: user buffer for result
- *
- * Copies the user idea of the window size to the kernel. Traditionally
- * this is just advisory information but for the Linux console it
- * actually has driver level meaning and triggers a VC resize.
- *
- * Locking:
- * Driver dependant. The default do_resize method takes the
- * tty termios mutex and ctrl_lock. The console takes its own lock
- * then calls into the default method.
- */
-
-static int tiocswinsz(struct tty_struct *tty, struct winsize __user *arg)
-{
- struct winsize tmp_ws;
- if (copy_from_user(&tmp_ws, arg, sizeof(*arg)))
- return -EFAULT;
-
- if (tty->ops->resize)
- return tty->ops->resize(tty, &tmp_ws);
- else
- return tty_do_resize(tty, &tmp_ws);
-}
-
-/**
- * tioccons - allow admin to move logical console
- * @file: the file to become console
- *
- * Allow the adminstrator to move the redirected console device
- *
- * Locking: uses redirect_lock to guard the redirect information
- */
-
-static int tioccons(struct file *file)
-{
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- if (file->f_op->write == redirected_tty_write) {
- struct file *f;
- spin_lock(&redirect_lock);
- f = redirect;
- redirect = NULL;
- spin_unlock(&redirect_lock);
- if (f)
- fput(f);
- return 0;
- }
- spin_lock(&redirect_lock);
- if (redirect) {
- spin_unlock(&redirect_lock);
- return -EBUSY;
- }
- get_file(file);
- redirect = file;
- spin_unlock(&redirect_lock);
- return 0;
-}
-
-/**
- * fionbio - non blocking ioctl
- * @file: file to set blocking value
- * @p: user parameter
- *
- * Historical tty interfaces had a blocking control ioctl before
- * the generic functionality existed. This piece of history is preserved
- * in the expected tty API of posix OS's.
- *
- * Locking: none, the open file handle ensures it won't go away.
- */
-
-static int fionbio(struct file *file, int __user *p)
-{
- int nonblock;
-
- if (get_user(nonblock, p))
- return -EFAULT;
-
- spin_lock(&file->f_lock);
- if (nonblock)
- file->f_flags |= O_NONBLOCK;
- else
- file->f_flags &= ~O_NONBLOCK;
- spin_unlock(&file->f_lock);
- return 0;
-}
-
-/**
- * tiocsctty - set controlling tty
- * @tty: tty structure
- * @arg: user argument
- *
- * This ioctl is used to manage job control. It permits a session
- * leader to set this tty as the controlling tty for the session.
- *
- * Locking:
- * Takes tty_mutex() to protect tty instance
- * Takes tasklist_lock internally to walk sessions
- * Takes ->siglock() when updating signal->tty
- */
-
-static int tiocsctty(struct tty_struct *tty, int arg)
-{
- int ret = 0;
- if (current->signal->leader && (task_session(current) == tty->session))
- return ret;
-
- mutex_lock(&tty_mutex);
- /*
- * The process must be a session leader and
- * not have a controlling tty already.
- */
- if (!current->signal->leader || current->signal->tty) {
- ret = -EPERM;
- goto unlock;
- }
-
- if (tty->session) {
- /*
- * This tty is already the controlling
- * tty for another session group!
- */
- if (arg == 1 && capable(CAP_SYS_ADMIN)) {
- /*
- * Steal it away
- */
- read_lock(&tasklist_lock);
- session_clear_tty(tty->session);
- read_unlock(&tasklist_lock);
- } else {
- ret = -EPERM;
- goto unlock;
- }
- }
- proc_set_tty(current, tty);
-unlock:
- mutex_unlock(&tty_mutex);
- return ret;
-}
-
-/**
- * tty_get_pgrp - return a ref counted pgrp pid
- * @tty: tty to read
- *
- * Returns a refcounted instance of the pid struct for the process
- * group controlling the tty.
- */
-
-struct pid *tty_get_pgrp(struct tty_struct *tty)
-{
- unsigned long flags;
- struct pid *pgrp;
-
- spin_lock_irqsave(&tty->ctrl_lock, flags);
- pgrp = get_pid(tty->pgrp);
- spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-
- return pgrp;
-}
-EXPORT_SYMBOL_GPL(tty_get_pgrp);
-
-/**
- * tiocgpgrp - get process group
- * @tty: tty passed by user
- * @real_tty: tty side of the tty pased by the user if a pty else the tty
- * @p: returned pid
- *
- * Obtain the process group of the tty. If there is no process group
- * return an error.
- *
- * Locking: none. Reference to current->signal->tty is safe.
- */
-
-static int tiocgpgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p)
-{
- struct pid *pid;
- int ret;
- /*
- * (tty == real_tty) is a cheap way of
- * testing if the tty is NOT a master pty.
- */
- if (tty == real_tty && current->signal->tty != real_tty)
- return -ENOTTY;
- pid = tty_get_pgrp(real_tty);
- ret = put_user(pid_vnr(pid), p);
- put_pid(pid);
- return ret;
-}
-
-/**
- * tiocspgrp - attempt to set process group
- * @tty: tty passed by user
- * @real_tty: tty side device matching tty passed by user
- * @p: pid pointer
- *
- * Set the process group of the tty to the session passed. Only
- * permitted where the tty session is our session.
- *
- * Locking: RCU, ctrl lock
- */
-
-static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p)
-{
- struct pid *pgrp;
- pid_t pgrp_nr;
- int retval = tty_check_change(real_tty);
- unsigned long flags;
-
- if (retval == -EIO)
- return -ENOTTY;
- if (retval)
- return retval;
- if (!current->signal->tty ||
- (current->signal->tty != real_tty) ||
- (real_tty->session != task_session(current)))
- return -ENOTTY;
- if (get_user(pgrp_nr, p))
- return -EFAULT;
- if (pgrp_nr < 0)
- return -EINVAL;
- rcu_read_lock();
- pgrp = find_vpid(pgrp_nr);
- retval = -ESRCH;
- if (!pgrp)
- goto out_unlock;
- retval = -EPERM;
- if (session_of_pgrp(pgrp) != task_session(current))
- goto out_unlock;
- retval = 0;
- spin_lock_irqsave(&tty->ctrl_lock, flags);
- put_pid(real_tty->pgrp);
- real_tty->pgrp = get_pid(pgrp);
- spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-out_unlock:
- rcu_read_unlock();
- return retval;
-}
-
-/**
- * tiocgsid - get session id
- * @tty: tty passed by user
- * @real_tty: tty side of the tty pased by the user if a pty else the tty
- * @p: pointer to returned session id
- *
- * Obtain the session id of the tty. If there is no session
- * return an error.
- *
- * Locking: none. Reference to current->signal->tty is safe.
- */
-
-static int tiocgsid(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p)
-{
- /*
- * (tty == real_tty) is a cheap way of
- * testing if the tty is NOT a master pty.
- */
- if (tty == real_tty && current->signal->tty != real_tty)
- return -ENOTTY;
- if (!real_tty->session)
- return -ENOTTY;
- return put_user(pid_vnr(real_tty->session), p);
-}
-
-/**
- * tiocsetd - set line discipline
- * @tty: tty device
- * @p: pointer to user data
- *
- * Set the line discipline according to user request.
- *
- * Locking: see tty_set_ldisc, this function is just a helper
- */
-
-static int tiocsetd(struct tty_struct *tty, int __user *p)
-{
- int ldisc;
- int ret;
-
- if (get_user(ldisc, p))
- return -EFAULT;
-
- ret = tty_set_ldisc(tty, ldisc);
-
- return ret;
-}
-
-/**
- * send_break - performed time break
- * @tty: device to break on
- * @duration: timeout in mS
- *
- * Perform a timed break on hardware that lacks its own driver level
- * timed break functionality.
- *
- * Locking:
- * atomic_write_lock serializes
- *
- */
-
-static int send_break(struct tty_struct *tty, unsigned int duration)
-{
- int retval;
-
- if (tty->ops->break_ctl == NULL)
- return 0;
-
- if (tty->driver->flags & TTY_DRIVER_HARDWARE_BREAK)
- retval = tty->ops->break_ctl(tty, duration);
- else {
- /* Do the work ourselves */
- if (tty_write_lock(tty, 0) < 0)
- return -EINTR;
- retval = tty->ops->break_ctl(tty, -1);
- if (retval)
- goto out;
- if (!signal_pending(current))
- msleep_interruptible(duration);
- retval = tty->ops->break_ctl(tty, 0);
-out:
- tty_write_unlock(tty);
- if (signal_pending(current))
- retval = -EINTR;
- }
- return retval;
-}
-
-/**
- * tty_tiocmget - get modem status
- * @tty: tty device
- * @file: user file pointer
- * @p: pointer to result
- *
- * Obtain the modem status bits from the tty driver if the feature
- * is supported. Return -EINVAL if it is not available.
- *
- * Locking: none (up to the driver)
- */
-
-static int tty_tiocmget(struct tty_struct *tty, struct file *file, int __user *p)
-{
- int retval = -EINVAL;
-
- if (tty->ops->tiocmget) {
- retval = tty->ops->tiocmget(tty, file);
-
- if (retval >= 0)
- retval = put_user(retval, p);
- }
- return retval;
-}
-
-/**
- * tty_tiocmset - set modem status
- * @tty: tty device
- * @file: user file pointer
- * @cmd: command - clear bits, set bits or set all
- * @p: pointer to desired bits
- *
- * Set the modem status bits from the tty driver if the feature
- * is supported. Return -EINVAL if it is not available.
- *
- * Locking: none (up to the driver)
- */
-
-static int tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int cmd,
- unsigned __user *p)
-{
- int retval;
- unsigned int set, clear, val;
-
- if (tty->ops->tiocmset == NULL)
- return -EINVAL;
-
- retval = get_user(val, p);
- if (retval)
- return retval;
- set = clear = 0;
- switch (cmd) {
- case TIOCMBIS:
- set = val;
- break;
- case TIOCMBIC:
- clear = val;
- break;
- case TIOCMSET:
- set = val;
- clear = ~val;
- break;
- }
- set &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP|TIOCM_CD|
- TIOCM_RI|TIOCM_DSR|TIOCM_CTS;
- clear &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP|TIOCM_CD|
- TIOCM_RI|TIOCM_DSR|TIOCM_CTS;
- return tty->ops->tiocmset(tty, file, set, clear);
-}
-
-struct tty_struct *tty_pair_get_tty(struct tty_struct *tty)
-{
- if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
- tty->driver->subtype == PTY_TYPE_MASTER)
- tty = tty->link;
- return tty;
-}
-EXPORT_SYMBOL(tty_pair_get_tty);
-
-struct tty_struct *tty_pair_get_pty(struct tty_struct *tty)
-{
- if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
- tty->driver->subtype == PTY_TYPE_MASTER)
- return tty;
- return tty->link;
-}
-EXPORT_SYMBOL(tty_pair_get_pty);
-
-/*
- * Split this up, as gcc can choke on it otherwise..
- */
-long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
- struct tty_struct *tty, *real_tty;
- void __user *p = (void __user *)arg;
- int retval;
- struct tty_ldisc *ld;
- struct inode *inode = file->f_dentry->d_inode;
-
- tty = (struct tty_struct *)file->private_data;
- if (tty_paranoia_check(tty, inode, "tty_ioctl"))
- return -EINVAL;
-
- real_tty = tty_pair_get_tty(tty);
-
- /*
- * Factor out some common prep work
- */
- switch (cmd) {
- case TIOCSETD:
- case TIOCSBRK:
- case TIOCCBRK:
- case TCSBRK:
- case TCSBRKP:
- retval = tty_check_change(tty);
- if (retval)
- return retval;
- if (cmd != TIOCCBRK) {
- tty_wait_until_sent(tty, 0);
- if (signal_pending(current))
- return -EINTR;
- }
- break;
- }
-
- /*
- * Now do the stuff.
- */
- switch (cmd) {
- case TIOCSTI:
- return tiocsti(tty, p);
- case TIOCGWINSZ:
- return tiocgwinsz(real_tty, p);
- case TIOCSWINSZ:
- return tiocswinsz(real_tty, p);
- case TIOCCONS:
- return real_tty != tty ? -EINVAL : tioccons(file);
- case FIONBIO:
- return fionbio(file, p);
- case TIOCEXCL:
- set_bit(TTY_EXCLUSIVE, &tty->flags);
- return 0;
- case TIOCNXCL:
- clear_bit(TTY_EXCLUSIVE, &tty->flags);
- return 0;
- case TIOCNOTTY:
- if (current->signal->tty != tty)
- return -ENOTTY;
- no_tty();
- return 0;
- case TIOCSCTTY:
- return tiocsctty(tty, arg);
- case TIOCGPGRP:
- return tiocgpgrp(tty, real_tty, p);
- case TIOCSPGRP:
- return tiocspgrp(tty, real_tty, p);
- case TIOCGSID:
- return tiocgsid(tty, real_tty, p);
- case TIOCGETD:
- return put_user(tty->ldisc->ops->num, (int __user *)p);
- case TIOCSETD:
- return tiocsetd(tty, p);
- /*
- * Break handling
- */
- case TIOCSBRK: /* Turn break on, unconditionally */
- if (tty->ops->break_ctl)
- return tty->ops->break_ctl(tty, -1);
- return 0;
- case TIOCCBRK: /* Turn break off, unconditionally */
- if (tty->ops->break_ctl)
- return tty->ops->break_ctl(tty, 0);
- return 0;
- case TCSBRK: /* SVID version: non-zero arg --> no break */
- /* non-zero arg means wait for all output data
- * to be sent (performed above) but don't send break.
- * This is used by the tcdrain() termios function.
- */
- if (!arg)
- return send_break(tty, 250);
- return 0;
- case TCSBRKP: /* support for POSIX tcsendbreak() */
- return send_break(tty, arg ? arg*100 : 250);
-
- case TIOCMGET:
- return tty_tiocmget(tty, file, p);
- case TIOCMSET:
- case TIOCMBIC:
- case TIOCMBIS:
- return tty_tiocmset(tty, file, cmd, p);
- case TCFLSH:
- switch (arg) {
- case TCIFLUSH:
- case TCIOFLUSH:
- /* flush tty buffer and allow ldisc to process ioctl */
- tty_buffer_flush(tty);
- break;
- }
- break;
- }
- if (tty->ops->ioctl) {
- retval = (tty->ops->ioctl)(tty, file, cmd, arg);
- if (retval != -ENOIOCTLCMD)
- return retval;
- }
- ld = tty_ldisc_ref_wait(tty);
- retval = -EINVAL;
- if (ld->ops->ioctl) {
- retval = ld->ops->ioctl(tty, file, cmd, arg);
- if (retval == -ENOIOCTLCMD)
- retval = -EINVAL;
- }
- tty_ldisc_deref(ld);
- return retval;
-}
-
-#ifdef CONFIG_COMPAT
-static long tty_compat_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- struct inode *inode = file->f_dentry->d_inode;
- struct tty_struct *tty = file->private_data;
- struct tty_ldisc *ld;
- int retval = -ENOIOCTLCMD;
-
- if (tty_paranoia_check(tty, inode, "tty_ioctl"))
- return -EINVAL;
-
- if (tty->ops->compat_ioctl) {
- retval = (tty->ops->compat_ioctl)(tty, file, cmd, arg);
- if (retval != -ENOIOCTLCMD)
- return retval;
- }
-
- ld = tty_ldisc_ref_wait(tty);
- if (ld->ops->compat_ioctl)
- retval = ld->ops->compat_ioctl(tty, file, cmd, arg);
- tty_ldisc_deref(ld);
-
- return retval;
-}
-#endif
-
-/*
- * This implements the "Secure Attention Key" --- the idea is to
- * prevent trojan horses by killing all processes associated with this
- * tty when the user hits the "Secure Attention Key". Required for
- * super-paranoid applications --- see the Orange Book for more details.
- *
- * This code could be nicer; ideally it should send a HUP, wait a few
- * seconds, then send a INT, and then a KILL signal. But you then
- * have to coordinate with the init process, since all processes associated
- * with the current tty must be dead before the new getty is allowed
- * to spawn.
- *
- * Now, if it would be correct ;-/ The current code has a nasty hole -
- * it doesn't catch files in flight. We may send the descriptor to ourselves
- * via AF_UNIX socket, close it and later fetch from socket. FIXME.
- *
- * Nasty bug: do_SAK is being called in interrupt context. This can
- * deadlock. We punt it up to process context. AKPM - 16Mar2001
- */
-void __do_SAK(struct tty_struct *tty)
-{
-#ifdef TTY_SOFT_SAK
- tty_hangup(tty);
-#else
- struct task_struct *g, *p;
- struct pid *session;
- int i;
- struct file *filp;
- struct fdtable *fdt;
-
- if (!tty)
- return;
- session = tty->session;
-
- tty_ldisc_flush(tty);
-
- tty_driver_flush_buffer(tty);
-
- read_lock(&tasklist_lock);
- /* Kill the entire session */
- do_each_pid_task(session, PIDTYPE_SID, p) {
- printk(KERN_NOTICE "SAK: killed process %d"
- " (%s): task_session(p)==tty->session\n",
- task_pid_nr(p), p->comm);
- send_sig(SIGKILL, p, 1);
- } while_each_pid_task(session, PIDTYPE_SID, p);
- /* Now kill any processes that happen to have the
- * tty open.
- */
- do_each_thread(g, p) {
- if (p->signal->tty == tty) {
- printk(KERN_NOTICE "SAK: killed process %d"
- " (%s): task_session(p)==tty->session\n",
- task_pid_nr(p), p->comm);
- send_sig(SIGKILL, p, 1);
- continue;
- }
- task_lock(p);
- if (p->files) {
- /*
- * We don't take a ref to the file, so we must
- * hold ->file_lock instead.
- */
- spin_lock(&p->files->file_lock);
- fdt = files_fdtable(p->files);
- for (i = 0; i < fdt->max_fds; i++) {
- filp = fcheck_files(p->files, i);
- if (!filp)
- continue;
- if (filp->f_op->read == tty_read &&
- filp->private_data == tty) {
- printk(KERN_NOTICE "SAK: killed process %d"
- " (%s): fd#%d opened to the tty\n",
- task_pid_nr(p), p->comm, i);
- force_sig(SIGKILL, p);
- break;
- }
- }
- spin_unlock(&p->files->file_lock);
- }
- task_unlock(p);
- } while_each_thread(g, p);
- read_unlock(&tasklist_lock);
-#endif
-}
-
-static void do_SAK_work(struct work_struct *work)
-{
- struct tty_struct *tty =
- container_of(work, struct tty_struct, SAK_work);
- __do_SAK(tty);
-}
-
-/*
- * The tq handling here is a little racy - tty->SAK_work may already be queued.
- * Fortunately we don't need to worry, because if ->SAK_work is already queued,
- * the values which we write to it will be identical to the values which it
- * already has. --akpm
- */
-void do_SAK(struct tty_struct *tty)
-{
- if (!tty)
- return;
- schedule_work(&tty->SAK_work);
-}
-
-EXPORT_SYMBOL(do_SAK);
-
-/**
- * initialize_tty_struct
- * @tty: tty to initialize
- *
- * This subroutine initializes a tty structure that has been newly
- * allocated.
- *
- * Locking: none - tty in question must not be exposed at this point
- */
-
-void initialize_tty_struct(struct tty_struct *tty,
- struct tty_driver *driver, int idx)
-{
- memset(tty, 0, sizeof(struct tty_struct));
- kref_init(&tty->kref);
- tty->magic = TTY_MAGIC;
- tty_ldisc_init(tty);
- tty->session = NULL;
- tty->pgrp = NULL;
- tty->overrun_time = jiffies;
- tty->buf.head = tty->buf.tail = NULL;
- tty_buffer_init(tty);
- mutex_init(&tty->termios_mutex);
- mutex_init(&tty->ldisc_mutex);
- init_waitqueue_head(&tty->write_wait);
- init_waitqueue_head(&tty->read_wait);
- INIT_WORK(&tty->hangup_work, do_tty_hangup);
- mutex_init(&tty->atomic_read_lock);
- mutex_init(&tty->atomic_write_lock);
- mutex_init(&tty->output_lock);
- mutex_init(&tty->echo_lock);
- spin_lock_init(&tty->read_lock);
- spin_lock_init(&tty->ctrl_lock);
- INIT_LIST_HEAD(&tty->tty_files);
- INIT_WORK(&tty->SAK_work, do_SAK_work);
-
- tty->driver = driver;
- tty->ops = driver->ops;
- tty->index = idx;
- tty_line_name(driver, idx, tty->name);
-}
-
-/**
- * tty_put_char - write one character to a tty
- * @tty: tty
- * @ch: character
- *
- * Write one byte to the tty using the provided put_char method
- * if present. Returns the number of characters successfully output.
- *
- * Note: the specific put_char operation in the driver layer may go
- * away soon. Don't call it directly, use this method
- */
-
-int tty_put_char(struct tty_struct *tty, unsigned char ch)
-{
- if (tty->ops->put_char)
- return tty->ops->put_char(tty, ch);
- return tty->ops->write(tty, &ch, 1);
-}
-EXPORT_SYMBOL_GPL(tty_put_char);
-
-struct class *tty_class;
-
-/**
- * tty_register_device - register a tty device
- * @driver: the tty driver that describes the tty device
- * @index: the index in the tty driver for this tty device
- * @device: a struct device that is associated with this tty device.
- * This field is optional, if there is no known struct device
- * for this tty device it can be set to NULL safely.
- *
- * Returns a pointer to the struct device for this tty device
- * (or ERR_PTR(-EFOO) on error).
- *
- * This call is required to be made to register an individual tty device
- * if the tty driver's flags have the TTY_DRIVER_DYNAMIC_DEV bit set. If
- * that bit is not set, this function should not be called by a tty
- * driver.
- *
- * Locking: ??
- */
-
-struct device *tty_register_device(struct tty_driver *driver, unsigned index,
- struct device *device)
-{
- char name[64];
- dev_t dev = MKDEV(driver->major, driver->minor_start) + index;
-
- if (index >= driver->num) {
- printk(KERN_ERR "Attempt to register invalid tty line number "
- " (%d).\n", index);
- return ERR_PTR(-EINVAL);
- }
-
- if (driver->type == TTY_DRIVER_TYPE_PTY)
- pty_line_name(driver, index, name);
- else
- tty_line_name(driver, index, name);
-
- return device_create(tty_class, device, dev, NULL, name);
-}
-EXPORT_SYMBOL(tty_register_device);
-
-/**
- * tty_unregister_device - unregister a tty device
- * @driver: the tty driver that describes the tty device
- * @index: the index in the tty driver for this tty device
- *
- * If a tty device is registered with a call to tty_register_device() then
- * this function must be called when the tty device is gone.
- *
- * Locking: ??
- */
-
-void tty_unregister_device(struct tty_driver *driver, unsigned index)
-{
- device_destroy(tty_class,
- MKDEV(driver->major, driver->minor_start) + index);
-}
-EXPORT_SYMBOL(tty_unregister_device);
-
-struct tty_driver *alloc_tty_driver(int lines)
-{
- struct tty_driver *driver;
-
- driver = kzalloc(sizeof(struct tty_driver), GFP_KERNEL);
- if (driver) {
- kref_init(&driver->kref);
- driver->magic = TTY_DRIVER_MAGIC;
- driver->num = lines;
- /* later we'll move allocation of tables here */
- }
- return driver;
-}
-EXPORT_SYMBOL(alloc_tty_driver);
-
-static void destruct_tty_driver(struct kref *kref)
-{
- struct tty_driver *driver = container_of(kref, struct tty_driver, kref);
- int i;
- struct ktermios *tp;
- void *p;
-
- if (driver->flags & TTY_DRIVER_INSTALLED) {
- /*
- * Free the termios and termios_locked structures because
- * we don't want to get memory leaks when modular tty
- * drivers are removed from the kernel.
- */
- for (i = 0; i < driver->num; i++) {
- tp = driver->termios[i];
- if (tp) {
- driver->termios[i] = NULL;
- kfree(tp);
- }
- if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV))
- tty_unregister_device(driver, i);
- }
- p = driver->ttys;
- proc_tty_unregister_driver(driver);
- driver->ttys = NULL;
- driver->termios = NULL;
- kfree(p);
- cdev_del(&driver->cdev);
- }
- kfree(driver);
-}
-
-void tty_driver_kref_put(struct tty_driver *driver)
-{
- kref_put(&driver->kref, destruct_tty_driver);
-}
-EXPORT_SYMBOL(tty_driver_kref_put);
-
-void tty_set_operations(struct tty_driver *driver,
- const struct tty_operations *op)
-{
- driver->ops = op;
-};
-EXPORT_SYMBOL(tty_set_operations);
-
-void put_tty_driver(struct tty_driver *d)
-{
- tty_driver_kref_put(d);
-}
-EXPORT_SYMBOL(put_tty_driver);
-
-/*
- * Called by a tty driver to register itself.
- */
-int tty_register_driver(struct tty_driver *driver)
-{
- int error;
- int i;
- dev_t dev;
- void **p = NULL;
-
- if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM) && driver->num) {
- p = kzalloc(driver->num * 2 * sizeof(void *), GFP_KERNEL);
- if (!p)
- return -ENOMEM;
- }
-
- if (!driver->major) {
- error = alloc_chrdev_region(&dev, driver->minor_start,
- driver->num, driver->name);
- if (!error) {
- driver->major = MAJOR(dev);
- driver->minor_start = MINOR(dev);
- }
- } else {
- dev = MKDEV(driver->major, driver->minor_start);
- error = register_chrdev_region(dev, driver->num, driver->name);
- }
- if (error < 0) {
- kfree(p);
- return error;
- }
-
- if (p) {
- driver->ttys = (struct tty_struct **)p;
- driver->termios = (struct ktermios **)(p + driver->num);
- } else {
- driver->ttys = NULL;
- driver->termios = NULL;
- }
-
- cdev_init(&driver->cdev, &tty_fops);
- driver->cdev.owner = driver->owner;
- error = cdev_add(&driver->cdev, dev, driver->num);
- if (error) {
- unregister_chrdev_region(dev, driver->num);
- driver->ttys = NULL;
- driver->termios = NULL;
- kfree(p);
- return error;
- }
-
- mutex_lock(&tty_mutex);
- list_add(&driver->tty_drivers, &tty_drivers);
- mutex_unlock(&tty_mutex);
-
- if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV)) {
- for (i = 0; i < driver->num; i++)
- tty_register_device(driver, i, NULL);
- }
- proc_tty_register_driver(driver);
- driver->flags |= TTY_DRIVER_INSTALLED;
- return 0;
-}
-
-EXPORT_SYMBOL(tty_register_driver);
-
-/*
- * Called by a tty driver to unregister itself.
- */
-int tty_unregister_driver(struct tty_driver *driver)
-{
-#if 0
- /* FIXME */
- if (driver->refcount)
- return -EBUSY;
-#endif
- unregister_chrdev_region(MKDEV(driver->major, driver->minor_start),
- driver->num);
- mutex_lock(&tty_mutex);
- list_del(&driver->tty_drivers);
- mutex_unlock(&tty_mutex);
- return 0;
-}
-
-EXPORT_SYMBOL(tty_unregister_driver);
-
-dev_t tty_devnum(struct tty_struct *tty)
-{
- return MKDEV(tty->driver->major, tty->driver->minor_start) + tty->index;
-}
-EXPORT_SYMBOL(tty_devnum);
-
-void proc_clear_tty(struct task_struct *p)
-{
- unsigned long flags;
- struct tty_struct *tty;
- spin_lock_irqsave(&p->sighand->siglock, flags);
- tty = p->signal->tty;
- p->signal->tty = NULL;
- spin_unlock_irqrestore(&p->sighand->siglock, flags);
- tty_kref_put(tty);
-}
-
-/* Called under the sighand lock */
-
-static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
-{
- if (tty) {
- unsigned long flags;
- /* We should not have a session or pgrp to put here but.... */
- spin_lock_irqsave(&tty->ctrl_lock, flags);
- put_pid(tty->session);
- put_pid(tty->pgrp);
- tty->pgrp = get_pid(task_pgrp(tsk));
- spin_unlock_irqrestore(&tty->ctrl_lock, flags);
- tty->session = get_pid(task_session(tsk));
- if (tsk->signal->tty) {
- printk(KERN_DEBUG "tty not NULL!!\n");
- tty_kref_put(tsk->signal->tty);
- }
- }
- put_pid(tsk->signal->tty_old_pgrp);
- tsk->signal->tty = tty_kref_get(tty);
- tsk->signal->tty_old_pgrp = NULL;
-}
-
-static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
-{
- spin_lock_irq(&tsk->sighand->siglock);
- __proc_set_tty(tsk, tty);
- spin_unlock_irq(&tsk->sighand->siglock);
-}
-
-struct tty_struct *get_current_tty(void)
-{
- struct tty_struct *tty;
- unsigned long flags;
-
- spin_lock_irqsave(¤t->sighand->siglock, flags);
- tty = tty_kref_get(current->signal->tty);
- spin_unlock_irqrestore(¤t->sighand->siglock, flags);
- return tty;
-}
-EXPORT_SYMBOL_GPL(get_current_tty);
-
-void tty_default_fops(struct file_operations *fops)
-{
- *fops = tty_fops;
-}
-
-/*
- * Initialize the console device. This is called *early*, so
- * we can't necessarily depend on lots of kernel help here.
- * Just do some early initializations, and do the complex setup
- * later.
- */
-void __init console_init(void)
-{
- initcall_t *call;
-
- /* Setup the default TTY line discipline. */
- tty_ldisc_begin();
-
- /*
- * set up the console device so that later boot sequences can
- * inform about problems etc..
- */
- call = __con_initcall_start;
- while (call < __con_initcall_end) {
- (*call)();
- call++;
- }
-}
-
-static char *tty_devnode(struct device *dev, mode_t *mode)
-{
- if (!mode)
- return NULL;
- if (dev->devt == MKDEV(TTYAUX_MAJOR, 0) ||
- dev->devt == MKDEV(TTYAUX_MAJOR, 2))
- *mode = 0666;
- return NULL;
-}
-
-static int __init tty_class_init(void)
-{
- tty_class = class_create(THIS_MODULE, "tty");
- if (IS_ERR(tty_class))
- return PTR_ERR(tty_class);
- tty_class->devnode = tty_devnode;
- return 0;
-}
-
-postcore_initcall(tty_class_init);
-
-/* 3/2004 jmc: why do these devices exist? */
-
-static struct cdev tty_cdev, console_cdev;
-
-/*
- * Ok, now we can initialize the rest of the tty devices and can count
- * on memory allocations, interrupts etc..
- */
-int __init tty_init(void)
-{
- cdev_init(&tty_cdev, &tty_fops);
- if (cdev_add(&tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1) ||
- register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty") < 0)
- panic("Couldn't register /dev/tty driver\n");
- device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL,
- "tty");
-
- cdev_init(&console_cdev, &console_fops);
- if (cdev_add(&console_cdev, MKDEV(TTYAUX_MAJOR, 1), 1) ||
- register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0)
- panic("Couldn't register /dev/console driver\n");
- device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL,
- "console");
-
-#ifdef CONFIG_VT
- vty_init(&console_fops);
-#endif
- return 0;
-}
-
diff --git a/drivers/coresight/coresight-etm.c b/drivers/coresight/coresight-etm.c
index 2ae54ea..1033233 100644
--- a/drivers/coresight/coresight-etm.c
+++ b/drivers/coresight/coresight-etm.c
@@ -265,6 +265,16 @@
static struct etm_drvdata *etmdrvdata[NR_CPUS];
+static bool etm_os_lock_present(struct etm_drvdata *drvdata)
+{
+ uint32_t etmoslsr;
+
+ etmoslsr = etm_readl(drvdata, ETMOSLSR);
+ if (!BVAL(etmoslsr, 0) && !BVAL(etmoslsr, 3))
+ return false;
+ return true;
+}
+
/*
* Memory mapped writes to clear os lock are not supported on Krait v1, v2
* and OS lock must be unlocked before any memory mapped access, otherwise
@@ -272,10 +282,17 @@
*/
static void etm_os_unlock(void *info)
{
+ struct etm_drvdata *drvdata = (struct etm_drvdata *) info;
+
+ ETM_UNLOCK(drvdata);
if (cpu_is_krait()) {
etm_writel_cp14(0x0, ETMOSLAR);
isb();
+ } else if (etm_os_lock_present(drvdata)) {
+ etm_writel(drvdata, 0x0, ETMOSLAR);
+ mb();
}
+ ETM_LOCK(drvdata);
}
/*
@@ -2104,7 +2121,7 @@
get_online_cpus();
etmdrvdata[drvdata->cpu] = drvdata;
- if (!smp_call_function_single(drvdata->cpu, etm_os_unlock, NULL, 1))
+ if (!smp_call_function_single(drvdata->cpu, etm_os_unlock, drvdata, 1))
drvdata->os_unlock = true;
/*
* Use CPU0 to populate read-only configuration data for ETM0. For
diff --git a/drivers/coresight/coresight-tmc.c b/drivers/coresight/coresight-tmc.c
index 0afb5a2..86276b7 100644
--- a/drivers/coresight/coresight-tmc.c
+++ b/drivers/coresight/coresight-tmc.c
@@ -217,7 +217,7 @@
{
struct tmc_etr_bam_data *bamdata = drvdata->bamdata;
- get_bam2bam_connection_info(0, PEER_PERIPHERAL_TO_USB,
+ get_bam2bam_connection_info(usb_bam_get_qdss_idx(0),
&bamdata->dest,
&bamdata->dest_pipe_idx,
&bamdata->src_pipe_idx,
diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index 3157a86..ec38843 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -163,15 +163,6 @@
{
int mult = 1;
- /* for higher loadavg, we are more reluctant */
-
- /*
- * this doesn't work as intended - it is almost always 0, but can
- * sometimes, depending on workload, spike very high into the hundreds
- * even when the average cpu load is under 10%.
- */
- /* mult += 2 * get_loadavg(); */
-
/* for IO wait tasks (per cpu!) we add 5x each */
mult += 10 * nr_iowait_cpu(smp_processor_id());
diff --git a/drivers/crypto/msm/qce.c b/drivers/crypto/msm/qce.c
index 5c1cc5a..24cf30a 100644
--- a/drivers/crypto/msm/qce.c
+++ b/drivers/crypto/msm/qce.c
@@ -2366,6 +2366,7 @@
ce_support->aes_ccm = false;
ce_support->ota = pce_dev->ota;
ce_support->aligned_only = false;
+ ce_support->is_shared = false;
ce_support->bam = false;
return 0;
}
diff --git a/drivers/crypto/msm/qce.h b/drivers/crypto/msm/qce.h
index 8a31003..3ff84cf 100644
--- a/drivers/crypto/msm/qce.h
+++ b/drivers/crypto/msm/qce.h
@@ -113,6 +113,7 @@
bool ota;
bool aligned_only;
bool bam;
+ bool is_shared;
};
/* Sha operation parameters */
diff --git a/drivers/crypto/msm/qce40.c b/drivers/crypto/msm/qce40.c
index 84d41da..7b0964d 100644
--- a/drivers/crypto/msm/qce40.c
+++ b/drivers/crypto/msm/qce40.c
@@ -2634,6 +2634,7 @@
ce_support->aes_ccm = true;
ce_support->ota = false;
ce_support->aligned_only = false;
+ ce_support->is_shared = false;
ce_support->bam = false;
return 0;
}
diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c
index 1facf24..b484c8a 100644
--- a/drivers/crypto/msm/qce50.c
+++ b/drivers/crypto/msm/qce50.c
@@ -61,6 +61,7 @@
unsigned char *coh_vmem; /* Allocated coherent virtual memory */
dma_addr_t coh_pmem; /* Allocated coherent physical memory */
int memsize; /* Memory allocated */
+ int is_shared; /* CE HW is shared */
void __iomem *iobase; /* Virtual io base of CE HW */
unsigned int phy_iobase; /* Physical io base of CE HW */
@@ -353,6 +354,9 @@
pce = cmdlistinfo->auth_seg_size;
pce->data = sreq->size;
+ pce = cmdlistinfo->encr_seg_cfg;
+ pce->data = 0;
+
/* write auth seg size start*/
pce = cmdlistinfo->auth_seg_start;
pce->data = 0;
@@ -521,8 +525,12 @@
pce->data = totallen_in - creq->authsize;
pce = cmdlistinfo->auth_seg_start;
pce->data = 0;
+ } else {
+ if (creq->op != QCE_REQ_AEAD) {
+ pce = cmdlistinfo->auth_seg_cfg;
+ pce->data = 0;
+ }
}
-
switch (creq->mode) {
case QCE_MODE_ECB:
encr_cfg |= (CRYPTO_ENCR_MODE_ECB << CRYPTO_ENCR_MODE);
@@ -1289,7 +1297,7 @@
CRYPTO_RESULT_DUMP_SIZE,
&pce_dev->ce_sps.out_transfer);
_qce_set_flag(&pce_dev->ce_sps.out_transfer,
- SPS_IOVEC_FLAG_EOT|SPS_IOVEC_FLAG_INT);
+ SPS_IOVEC_FLAG_INT);
rc = sps_transfer(pce_dev->ce_sps.producer.pipe,
&pce_dev->ce_sps.out_transfer);
if (rc) {
@@ -1364,7 +1372,7 @@
CRYPTO_RESULT_DUMP_SIZE,
&pce_dev->ce_sps.out_transfer);
_qce_set_flag(&pce_dev->ce_sps.out_transfer,
- SPS_IOVEC_FLAG_EOT|SPS_IOVEC_FLAG_INT);
+ SPS_IOVEC_FLAG_INT);
rc = sps_transfer(pce_dev->ce_sps.producer.pipe,
&pce_dev->ce_sps.out_transfer);
if (rc) {
@@ -2612,6 +2620,9 @@
struct resource *resource;
int rc = 0;
+ pce_dev->is_shared = of_property_read_bool((&pdev->dev)->of_node,
+ "qcom,ce-hw-shared");
+
if (of_property_read_u32((&pdev->dev)->of_node,
"qcom,bam-pipe-pair",
&pce_dev->ce_sps.pipe_pair_index)) {
@@ -2895,6 +2906,7 @@
ce_support->aes_xts = true;
ce_support->ota = false;
ce_support->bam = true;
+ ce_support->is_shared = (pce_dev->is_shared == 1) ? true : false;
ce_support->aes_ccm = true;
if (pce_dev->ce_sps.minor_version)
ce_support->aligned_only = false;
diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig
index 464fa21..1c63b70 100644
--- a/drivers/devfreq/Kconfig
+++ b/drivers/devfreq/Kconfig
@@ -30,7 +30,7 @@
comment "DEVFREQ Governors"
config DEVFREQ_GOV_SIMPLE_ONDEMAND
- bool "Simple Ondemand"
+ tristate "Simple Ondemand"
help
Chooses frequency based on the recent load on the device. Works
similar as ONDEMAND governor of CPUFREQ does. A device with
@@ -39,7 +39,7 @@
values to the governor with data field at devfreq_add_device().
config DEVFREQ_GOV_PERFORMANCE
- bool "Performance"
+ tristate "Performance"
help
Sets the frequency at the maximum available frequency.
This governor always returns UINT_MAX as frequency so that
@@ -47,7 +47,7 @@
at any time.
config DEVFREQ_GOV_POWERSAVE
- bool "Powersave"
+ tristate "Powersave"
help
Sets the frequency at the minimum available frequency.
This governor always returns 0 as frequency so that
@@ -55,7 +55,7 @@
at any time.
config DEVFREQ_GOV_USERSPACE
- bool "Userspace"
+ tristate "Userspace"
help
Sets the frequency at the user specified one.
This governor returns the user configured frequency if there
diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index 70c31d4..89d779c 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -27,21 +27,17 @@
#include <linux/hrtimer.h>
#include "governor.h"
-struct class *devfreq_class;
+static struct class *devfreq_class;
/*
- * devfreq_work periodically monitors every registered device.
- * The minimum polling interval is one jiffy. The polling interval is
- * determined by the minimum polling period among all polling devfreq
- * devices. The resolution of polling interval is one jiffy.
+ * devfreq core provides delayed work based load monitoring helper
+ * functions. Governors can use these or can implement their own
+ * monitoring mechanism.
*/
-static bool polling;
static struct workqueue_struct *devfreq_wq;
-static struct delayed_work devfreq_work;
-/* wait removing if this is to be removed */
-static struct devfreq *wait_remove_device;
-
+/* The list of all device-devfreq governors */
+static LIST_HEAD(devfreq_governor_list);
/* The list of all device-devfreq */
static LIST_HEAD(devfreq_list);
static DEFINE_MUTEX(devfreq_list_lock);
@@ -73,6 +69,79 @@
}
/**
+ * devfreq_get_freq_level() - Lookup freq_table for the frequency
+ * @devfreq: the devfreq instance
+ * @freq: the target frequency
+ */
+static int devfreq_get_freq_level(struct devfreq *devfreq, unsigned long freq)
+{
+ int lev;
+
+ for (lev = 0; lev < devfreq->profile->max_state; lev++)
+ if (freq == devfreq->profile->freq_table[lev])
+ return lev;
+
+ return -EINVAL;
+}
+
+/**
+ * devfreq_update_status() - Update statistics of devfreq behavior
+ * @devfreq: the devfreq instance
+ * @freq: the update target frequency
+ */
+static int devfreq_update_status(struct devfreq *devfreq, unsigned long freq)
+{
+ int lev, prev_lev;
+ unsigned long cur_time;
+
+ lev = devfreq_get_freq_level(devfreq, freq);
+ if (lev < 0)
+ return lev;
+
+ cur_time = jiffies;
+ devfreq->time_in_state[lev] +=
+ cur_time - devfreq->last_stat_updated;
+ if (freq != devfreq->previous_freq) {
+ prev_lev = devfreq_get_freq_level(devfreq,
+ devfreq->previous_freq);
+ devfreq->trans_table[(prev_lev *
+ devfreq->profile->max_state) + lev]++;
+ devfreq->total_trans++;
+ }
+ devfreq->last_stat_updated = cur_time;
+
+ return 0;
+}
+
+/**
+ * find_devfreq_governor() - find devfreq governor from name
+ * @name: name of the governor
+ *
+ * Search the list of devfreq governors and return the matched
+ * governor's pointer. devfreq_list_lock should be held by the caller.
+ */
+static struct devfreq_governor *find_devfreq_governor(const char *name)
+{
+ struct devfreq_governor *tmp_governor;
+
+ if (unlikely(IS_ERR_OR_NULL(name))) {
+ pr_err("DEVFREQ: %s: Invalid parameters\n", __func__);
+ return ERR_PTR(-EINVAL);
+ }
+ WARN(!mutex_is_locked(&devfreq_list_lock),
+ "devfreq_list_lock must be locked.");
+
+ list_for_each_entry(tmp_governor, &devfreq_governor_list, node) {
+ if (!strncmp(tmp_governor->name, name, DEVFREQ_NAME_LEN))
+ return tmp_governor;
+ }
+
+ return ERR_PTR(-ENODEV);
+}
+
+/* Load monitoring helper functions for governors use */
+
+/**
* update_devfreq() - Reevaluate the device and configure frequency.
* @devfreq: the devfreq instance.
*
@@ -90,6 +159,9 @@
return -EINVAL;
}
+ if (!devfreq->governor)
+ return -EINVAL;
+
/* Reevaluate the proper frequency */
err = devfreq->governor->get_target_freq(devfreq, &freq);
if (err)
@@ -116,16 +188,173 @@
if (err)
return err;
+ if (devfreq->profile->freq_table)
+ if (devfreq_update_status(devfreq, freq))
+ dev_err(&devfreq->dev,
+ "Couldn't update frequency transition information.\n");
+
devfreq->previous_freq = freq;
return err;
}
+EXPORT_SYMBOL(update_devfreq);
+
+/**
+ * devfreq_monitor() - Periodically poll devfreq objects.
+ * @work: the work struct used to run devfreq_monitor periodically.
+ *
+ */
+static void devfreq_monitor(struct work_struct *work)
+{
+ int err;
+ struct devfreq *devfreq = container_of(work,
+ struct devfreq, work.work);
+
+ mutex_lock(&devfreq->lock);
+ err = update_devfreq(devfreq);
+ if (err)
+ dev_err(&devfreq->dev, "dvfs failed with (%d) error\n", err);
+
+ queue_delayed_work(devfreq_wq, &devfreq->work,
+ msecs_to_jiffies(devfreq->profile->polling_ms));
+ mutex_unlock(&devfreq->lock);
+}
+
+/**
+ * devfreq_monitor_start() - Start load monitoring of devfreq instance
+ * @devfreq: the devfreq instance.
+ *
+ * Helper function for starting devfreq device load monitoing. By
+ * default delayed work based monitoring is supported. Function
+ * to be called from governor in response to DEVFREQ_GOV_START
+ * event when device is added to devfreq framework.
+ */
+void devfreq_monitor_start(struct devfreq *devfreq)
+{
+ INIT_DELAYED_WORK_DEFERRABLE(&devfreq->work, devfreq_monitor);
+ if (devfreq->profile->polling_ms)
+ queue_delayed_work(devfreq_wq, &devfreq->work,
+ msecs_to_jiffies(devfreq->profile->polling_ms));
+}
+EXPORT_SYMBOL(devfreq_monitor_start);
+
+/**
+ * devfreq_monitor_stop() - Stop load monitoring of a devfreq instance
+ * @devfreq: the devfreq instance.
+ *
+ * Helper function to stop devfreq device load monitoing. Function
+ * to be called from governor in response to DEVFREQ_GOV_STOP
+ * event when device is removed from devfreq framework.
+ */
+void devfreq_monitor_stop(struct devfreq *devfreq)
+{
+ cancel_delayed_work_sync(&devfreq->work);
+}
+EXPORT_SYMBOL(devfreq_monitor_stop);
+
+/**
+ * devfreq_monitor_suspend() - Suspend load monitoring of a devfreq instance
+ * @devfreq: the devfreq instance.
+ *
+ * Helper function to suspend devfreq device load monitoing. Function
+ * to be called from governor in response to DEVFREQ_GOV_SUSPEND
+ * event or when polling interval is set to zero.
+ *
+ * Note: Though this function is same as devfreq_monitor_stop(),
+ * intentionally kept separate to provide hooks for collecting
+ * transition statistics.
+ */
+void devfreq_monitor_suspend(struct devfreq *devfreq)
+{
+ mutex_lock(&devfreq->lock);
+ if (devfreq->stop_polling) {
+ mutex_unlock(&devfreq->lock);
+ return;
+ }
+
+ devfreq->stop_polling = true;
+ mutex_unlock(&devfreq->lock);
+ cancel_delayed_work_sync(&devfreq->work);
+}
+EXPORT_SYMBOL(devfreq_monitor_suspend);
+
+/**
+ * devfreq_monitor_resume() - Resume load monitoring of a devfreq instance
+ * @devfreq: the devfreq instance.
+ *
+ * Helper function to resume devfreq device load monitoing. Function
+ * to be called from governor in response to DEVFREQ_GOV_RESUME
+ * event or when polling interval is set to non-zero.
+ */
+void devfreq_monitor_resume(struct devfreq *devfreq)
+{
+ mutex_lock(&devfreq->lock);
+ if (!devfreq->stop_polling)
+ goto out;
+
+ if (!delayed_work_pending(&devfreq->work) &&
+ devfreq->profile->polling_ms)
+ queue_delayed_work(devfreq_wq, &devfreq->work,
+ msecs_to_jiffies(devfreq->profile->polling_ms));
+ devfreq->stop_polling = false;
+
+out:
+ mutex_unlock(&devfreq->lock);
+}
+EXPORT_SYMBOL(devfreq_monitor_resume);
+
+/**
+ * devfreq_interval_update() - Update device devfreq monitoring interval
+ * @devfreq: the devfreq instance.
+ * @delay: new polling interval to be set.
+ *
+ * Helper function to set new load monitoring polling interval. Function
+ * to be called from governor in response to DEVFREQ_GOV_INTERVAL event.
+ */
+void devfreq_interval_update(struct devfreq *devfreq, unsigned int *delay)
+{
+ unsigned int cur_delay = devfreq->profile->polling_ms;
+ unsigned int new_delay = *delay;
+
+ mutex_lock(&devfreq->lock);
+ devfreq->profile->polling_ms = new_delay;
+
+ if (devfreq->stop_polling)
+ goto out;
+
+ /* if new delay is zero, stop polling */
+ if (!new_delay) {
+ mutex_unlock(&devfreq->lock);
+ cancel_delayed_work_sync(&devfreq->work);
+ return;
+ }
+
+ /* if current delay is zero, start polling with new delay */
+ if (!cur_delay) {
+ queue_delayed_work(devfreq_wq, &devfreq->work,
+ msecs_to_jiffies(devfreq->profile->polling_ms));
+ goto out;
+ }
+
+ /* if current delay is greater than new delay, restart polling */
+ if (cur_delay > new_delay) {
+ mutex_unlock(&devfreq->lock);
+ cancel_delayed_work_sync(&devfreq->work);
+ mutex_lock(&devfreq->lock);
+ if (!devfreq->stop_polling)
+ queue_delayed_work(devfreq_wq, &devfreq->work,
+ msecs_to_jiffies(devfreq->profile->polling_ms));
+ }
+out:
+ mutex_unlock(&devfreq->lock);
+}
+EXPORT_SYMBOL(devfreq_interval_update);
/**
* devfreq_notifier_call() - Notify that the device frequency requirements
* has been changed out of devfreq framework.
- * @nb the notifier_block (supposed to be devfreq->nb)
- * @type not used
- * @devp not used
+ * @nb: the notifier_block (supposed to be devfreq->nb)
+ * @type: not used
+ * @devp: not used
*
* Called by a notifier that uses devfreq->nb.
*/
@@ -143,59 +372,34 @@
}
/**
- * _remove_devfreq() - Remove devfreq from the device.
+ * _remove_devfreq() - Remove devfreq from the list and release its resources.
* @devfreq: the devfreq struct
* @skip: skip calling device_unregister().
- *
- * Note that the caller should lock devfreq->lock before calling
- * this. _remove_devfreq() will unlock it and free devfreq
- * internally. devfreq_list_lock should be locked by the caller
- * as well (not relased at return)
- *
- * Lock usage:
- * devfreq->lock: locked before call.
- * unlocked at return (and freed)
- * devfreq_list_lock: locked before call.
- * kept locked at return.
- * if devfreq is centrally polled.
- *
- * Freed memory:
- * devfreq
*/
static void _remove_devfreq(struct devfreq *devfreq, bool skip)
{
- if (!mutex_is_locked(&devfreq->lock)) {
- WARN(true, "devfreq->lock must be locked by the caller.\n");
+ mutex_lock(&devfreq_list_lock);
+ if (IS_ERR(find_device_devfreq(devfreq->dev.parent))) {
+ mutex_unlock(&devfreq_list_lock);
+ dev_warn(&devfreq->dev, "releasing devfreq which doesn't exist\n");
return;
}
- if (!devfreq->governor->no_central_polling &&
- !mutex_is_locked(&devfreq_list_lock)) {
- WARN(true, "devfreq_list_lock must be locked by the caller.\n");
- return;
- }
+ list_del(&devfreq->node);
+ mutex_unlock(&devfreq_list_lock);
- if (devfreq->being_removed)
- return;
-
- devfreq->being_removed = true;
+ if (devfreq->governor)
+ devfreq->governor->event_handler(devfreq,
+ DEVFREQ_GOV_STOP, NULL);
if (devfreq->profile->exit)
devfreq->profile->exit(devfreq->dev.parent);
- if (devfreq->governor->exit)
- devfreq->governor->exit(devfreq);
-
if (!skip && get_device(&devfreq->dev)) {
device_unregister(&devfreq->dev);
put_device(&devfreq->dev);
}
- if (!devfreq->governor->no_central_polling)
- list_del(&devfreq->node);
-
- mutex_unlock(&devfreq->lock);
mutex_destroy(&devfreq->lock);
-
kfree(devfreq);
}
@@ -210,163 +414,39 @@
static void devfreq_dev_release(struct device *dev)
{
struct devfreq *devfreq = to_devfreq(dev);
- bool central_polling = !devfreq->governor->no_central_polling;
- /*
- * If devfreq_dev_release() was called by device_unregister() of
- * _remove_devfreq(), we cannot mutex_lock(&devfreq->lock) and
- * being_removed is already set. This also partially checks the case
- * where devfreq_dev_release() is called from a thread other than
- * the one called _remove_devfreq(); however, this case is
- * dealt completely with another following being_removed check.
- *
- * Because being_removed is never being
- * unset, we do not need to worry about race conditions on
- * being_removed.
- */
- if (devfreq->being_removed)
- return;
-
- if (central_polling)
- mutex_lock(&devfreq_list_lock);
-
- mutex_lock(&devfreq->lock);
-
- /*
- * Check being_removed flag again for the case where
- * devfreq_dev_release() was called in a thread other than the one
- * possibly called _remove_devfreq().
- */
- if (devfreq->being_removed) {
- mutex_unlock(&devfreq->lock);
- goto out;
- }
-
- /* devfreq->lock is unlocked and removed in _removed_devfreq() */
_remove_devfreq(devfreq, true);
-
-out:
- if (central_polling)
- mutex_unlock(&devfreq_list_lock);
-}
-
-/**
- * devfreq_monitor() - Periodically poll devfreq objects.
- * @work: the work struct used to run devfreq_monitor periodically.
- *
- */
-static void devfreq_monitor(struct work_struct *work)
-{
- static unsigned long last_polled_at;
- struct devfreq *devfreq, *tmp;
- int error;
- unsigned long jiffies_passed;
- unsigned long next_jiffies = ULONG_MAX, now = jiffies;
- struct device *dev;
-
- /* Initially last_polled_at = 0, polling every device at bootup */
- jiffies_passed = now - last_polled_at;
- last_polled_at = now;
- if (jiffies_passed == 0)
- jiffies_passed = 1;
-
- mutex_lock(&devfreq_list_lock);
- list_for_each_entry_safe(devfreq, tmp, &devfreq_list, node) {
- mutex_lock(&devfreq->lock);
- dev = devfreq->dev.parent;
-
- /* Do not remove tmp for a while */
- wait_remove_device = tmp;
-
- if (devfreq->governor->no_central_polling ||
- devfreq->next_polling == 0) {
- mutex_unlock(&devfreq->lock);
- continue;
- }
- mutex_unlock(&devfreq_list_lock);
-
- /*
- * Reduce more next_polling if devfreq_wq took an extra
- * delay. (i.e., CPU has been idled.)
- */
- if (devfreq->next_polling <= jiffies_passed) {
- error = update_devfreq(devfreq);
-
- /* Remove a devfreq with an error. */
- if (error && error != -EAGAIN) {
-
- dev_err(dev, "Due to update_devfreq error(%d), devfreq(%s) is removed from the device\n",
- error, devfreq->governor->name);
-
- /*
- * Unlock devfreq before locking the list
- * in order to avoid deadlock with
- * find_device_devfreq or others
- */
- mutex_unlock(&devfreq->lock);
- mutex_lock(&devfreq_list_lock);
- /* Check if devfreq is already removed */
- if (IS_ERR(find_device_devfreq(dev)))
- continue;
- mutex_lock(&devfreq->lock);
- /* This unlocks devfreq->lock and free it */
- _remove_devfreq(devfreq, false);
- continue;
- }
- devfreq->next_polling = devfreq->polling_jiffies;
- } else {
- devfreq->next_polling -= jiffies_passed;
- }
-
- if (devfreq->next_polling)
- next_jiffies = (next_jiffies > devfreq->next_polling) ?
- devfreq->next_polling : next_jiffies;
-
- mutex_unlock(&devfreq->lock);
- mutex_lock(&devfreq_list_lock);
- }
- wait_remove_device = NULL;
- mutex_unlock(&devfreq_list_lock);
-
- if (next_jiffies > 0 && next_jiffies < ULONG_MAX) {
- polling = true;
- queue_delayed_work(devfreq_wq, &devfreq_work, next_jiffies);
- } else {
- polling = false;
- }
}
/**
* devfreq_add_device() - Add devfreq feature to the device
* @dev: the device to add devfreq feature.
* @profile: device-specific profile to run devfreq.
- * @governor: the policy to choose frequency.
+ * @governor_name: name of the policy to choose frequency.
* @data: private data for the governor. The devfreq framework does not
* touch this value.
*/
struct devfreq *devfreq_add_device(struct device *dev,
struct devfreq_dev_profile *profile,
- const struct devfreq_governor *governor,
+ const char *governor_name,
void *data)
{
struct devfreq *devfreq;
+ struct devfreq_governor *governor;
int err = 0;
- if (!dev || !profile || !governor) {
+ if (!dev || !profile || !governor_name) {
dev_err(dev, "%s: Invalid parameters.\n", __func__);
return ERR_PTR(-EINVAL);
}
-
- if (!governor->no_central_polling) {
- mutex_lock(&devfreq_list_lock);
- devfreq = find_device_devfreq(dev);
- mutex_unlock(&devfreq_list_lock);
- if (!IS_ERR(devfreq)) {
- dev_err(dev, "%s: Unable to create devfreq for the device. It already has one.\n", __func__);
- err = -EINVAL;
- goto err_out;
- }
+ mutex_lock(&devfreq_list_lock);
+ devfreq = find_device_devfreq(dev);
+ mutex_unlock(&devfreq_list_lock);
+ if (!IS_ERR(devfreq)) {
+ dev_err(dev, "%s: Unable to create devfreq for the device. It already has one.\n", __func__);
+ err = -EINVAL;
+ goto err_out;
}
devfreq = kzalloc(sizeof(struct devfreq), GFP_KERNEL);
@@ -383,92 +463,316 @@
devfreq->dev.class = devfreq_class;
devfreq->dev.release = devfreq_dev_release;
devfreq->profile = profile;
- devfreq->governor = governor;
+ strncpy(devfreq->governor_name, governor_name, DEVFREQ_NAME_LEN);
devfreq->previous_freq = profile->initial_freq;
devfreq->data = data;
- devfreq->next_polling = devfreq->polling_jiffies
- = msecs_to_jiffies(devfreq->profile->polling_ms);
devfreq->nb.notifier_call = devfreq_notifier_call;
+ devfreq->trans_table = devm_kzalloc(dev, sizeof(unsigned int) *
+ devfreq->profile->max_state *
+ devfreq->profile->max_state,
+ GFP_KERNEL);
+ devfreq->time_in_state = devm_kzalloc(dev, sizeof(unsigned int) *
+ devfreq->profile->max_state,
+ GFP_KERNEL);
+ devfreq->last_stat_updated = jiffies;
+
dev_set_name(&devfreq->dev, dev_name(dev));
err = device_register(&devfreq->dev);
if (err) {
put_device(&devfreq->dev);
+ mutex_unlock(&devfreq->lock);
goto err_dev;
}
- if (governor->init)
- err = governor->init(devfreq);
- if (err)
- goto err_init;
-
mutex_unlock(&devfreq->lock);
- if (governor->no_central_polling)
- goto out;
-
mutex_lock(&devfreq_list_lock);
-
list_add(&devfreq->node, &devfreq_list);
- if (devfreq_wq && devfreq->next_polling && !polling) {
- polling = true;
- queue_delayed_work(devfreq_wq, &devfreq_work,
- devfreq->next_polling);
- }
+ governor = find_devfreq_governor(devfreq->governor_name);
+ if (!IS_ERR(governor))
+ devfreq->governor = governor;
+ if (devfreq->governor)
+ err = devfreq->governor->event_handler(devfreq,
+ DEVFREQ_GOV_START, NULL);
mutex_unlock(&devfreq_list_lock);
-out:
+ if (err) {
+ dev_err(dev, "%s: Unable to start governor for the device\n",
+ __func__);
+ goto err_init;
+ }
+
return devfreq;
err_init:
+ list_del(&devfreq->node);
device_unregister(&devfreq->dev);
err_dev:
- mutex_unlock(&devfreq->lock);
kfree(devfreq);
err_out:
return ERR_PTR(err);
}
+EXPORT_SYMBOL(devfreq_add_device);
/**
* devfreq_remove_device() - Remove devfreq feature from a device.
- * @devfreq the devfreq instance to be removed
+ * @devfreq: the devfreq instance to be removed
*/
int devfreq_remove_device(struct devfreq *devfreq)
{
- bool central_polling;
-
if (!devfreq)
return -EINVAL;
- central_polling = !devfreq->governor->no_central_polling;
-
- if (central_polling) {
- mutex_lock(&devfreq_list_lock);
- while (wait_remove_device == devfreq) {
- mutex_unlock(&devfreq_list_lock);
- schedule();
- mutex_lock(&devfreq_list_lock);
- }
- }
-
- mutex_lock(&devfreq->lock);
- _remove_devfreq(devfreq, false); /* it unlocks devfreq->lock */
-
- if (central_polling)
- mutex_unlock(&devfreq_list_lock);
+ _remove_devfreq(devfreq, false);
return 0;
}
+EXPORT_SYMBOL(devfreq_remove_device);
+
+/**
+ * devfreq_suspend_device() - Suspend devfreq of a device.
+ * @devfreq: the devfreq instance to be suspended
+ */
+int devfreq_suspend_device(struct devfreq *devfreq)
+{
+ if (!devfreq)
+ return -EINVAL;
+
+ if (!devfreq->governor)
+ return 0;
+
+ return devfreq->governor->event_handler(devfreq,
+ DEVFREQ_GOV_SUSPEND, NULL);
+}
+EXPORT_SYMBOL(devfreq_suspend_device);
+
+/**
+ * devfreq_resume_device() - Resume devfreq of a device.
+ * @devfreq: the devfreq instance to be resumed
+ */
+int devfreq_resume_device(struct devfreq *devfreq)
+{
+ if (!devfreq)
+ return -EINVAL;
+
+ if (!devfreq->governor)
+ return 0;
+
+ return devfreq->governor->event_handler(devfreq,
+ DEVFREQ_GOV_RESUME, NULL);
+}
+EXPORT_SYMBOL(devfreq_resume_device);
+
+/**
+ * devfreq_add_governor() - Add devfreq governor
+ * @governor: the devfreq governor to be added
+ */
+int devfreq_add_governor(struct devfreq_governor *governor)
+{
+ struct devfreq_governor *g;
+ struct devfreq *devfreq;
+ int err = 0;
+
+ if (!governor) {
+ pr_err("%s: Invalid parameters.\n", __func__);
+ return -EINVAL;
+ }
+
+ mutex_lock(&devfreq_list_lock);
+ g = find_devfreq_governor(governor->name);
+ if (!IS_ERR(g)) {
+ pr_err("%s: governor %s already registered\n", __func__,
+ g->name);
+ err = -EINVAL;
+ goto err_out;
+ }
+
+ list_add(&governor->node, &devfreq_governor_list);
+
+ list_for_each_entry(devfreq, &devfreq_list, node) {
+ int ret = 0;
+ struct device *dev = devfreq->dev.parent;
+
+ if (!strncmp(devfreq->governor_name, governor->name,
+ DEVFREQ_NAME_LEN)) {
+ /* The following should never occur */
+ if (devfreq->governor) {
+ dev_warn(dev,
+ "%s: Governor %s already present\n",
+ __func__, devfreq->governor->name);
+ ret = devfreq->governor->event_handler(devfreq,
+ DEVFREQ_GOV_STOP, NULL);
+ if (ret) {
+ dev_warn(dev,
+ "%s: Governor %s stop = %d\n",
+ __func__,
+ devfreq->governor->name, ret);
+ }
+ /* Fall through */
+ }
+ devfreq->governor = governor;
+ ret = devfreq->governor->event_handler(devfreq,
+ DEVFREQ_GOV_START, NULL);
+ if (ret) {
+ dev_warn(dev, "%s: Governor %s start=%d\n",
+ __func__, devfreq->governor->name,
+ ret);
+ }
+ }
+ }
+
+err_out:
+ mutex_unlock(&devfreq_list_lock);
+
+ return err;
+}
+EXPORT_SYMBOL(devfreq_add_governor);
+
+/**
+ * devfreq_remove_device() - Remove devfreq feature from a device.
+ * @governor: the devfreq governor to be removed
+ */
+int devfreq_remove_governor(struct devfreq_governor *governor)
+{
+ struct devfreq_governor *g;
+ struct devfreq *devfreq;
+ int err = 0;
+
+ if (!governor) {
+ pr_err("%s: Invalid parameters.\n", __func__);
+ return -EINVAL;
+ }
+
+ mutex_lock(&devfreq_list_lock);
+ g = find_devfreq_governor(governor->name);
+ if (IS_ERR(g)) {
+ pr_err("%s: governor %s not registered\n", __func__,
+ governor->name);
+ err = PTR_ERR(g);
+ goto err_out;
+ }
+ list_for_each_entry(devfreq, &devfreq_list, node) {
+ int ret;
+ struct device *dev = devfreq->dev.parent;
+
+ if (!strncmp(devfreq->governor_name, governor->name,
+ DEVFREQ_NAME_LEN)) {
+ /* we should have a devfreq governor! */
+ if (!devfreq->governor) {
+ dev_warn(dev, "%s: Governor %s NOT present\n",
+ __func__, governor->name);
+ continue;
+ /* Fall through */
+ }
+ ret = devfreq->governor->event_handler(devfreq,
+ DEVFREQ_GOV_STOP, NULL);
+ if (ret) {
+ dev_warn(dev, "%s: Governor %s stop=%d\n",
+ __func__, devfreq->governor->name,
+ ret);
+ }
+ devfreq->governor = NULL;
+ }
+ }
+
+ list_del(&governor->node);
+err_out:
+ mutex_unlock(&devfreq_list_lock);
+
+ return err;
+}
+EXPORT_SYMBOL(devfreq_remove_governor);
static ssize_t show_governor(struct device *dev,
struct device_attribute *attr, char *buf)
{
+ if (!to_devfreq(dev)->governor)
+ return -EINVAL;
+
return sprintf(buf, "%s\n", to_devfreq(dev)->governor->name);
}
+static ssize_t store_governor(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct devfreq *df = to_devfreq(dev);
+ int ret;
+ char str_governor[DEVFREQ_NAME_LEN + 1];
+ struct devfreq_governor *governor;
+
+ ret = sscanf(buf, "%" __stringify(DEVFREQ_NAME_LEN) "s", str_governor);
+ if (ret != 1)
+ return -EINVAL;
+
+ mutex_lock(&devfreq_list_lock);
+ governor = find_devfreq_governor(str_governor);
+ if (IS_ERR(governor)) {
+ ret = PTR_ERR(governor);
+ goto out;
+ }
+ if (df->governor == governor)
+ goto out;
+
+ if (df->governor) {
+ ret = df->governor->event_handler(df, DEVFREQ_GOV_STOP, NULL);
+ if (ret) {
+ dev_warn(dev, "%s: Governor %s not stopped(%d)\n",
+ __func__, df->governor->name, ret);
+ goto out;
+ }
+ }
+ df->governor = governor;
+ strncpy(df->governor_name, governor->name, DEVFREQ_NAME_LEN);
+ ret = df->governor->event_handler(df, DEVFREQ_GOV_START, NULL);
+ if (ret)
+ dev_warn(dev, "%s: Governor %s not started(%d)\n",
+ __func__, df->governor->name, ret);
+out:
+ mutex_unlock(&devfreq_list_lock);
+
+ if (!ret)
+ ret = count;
+ return ret;
+}
+static ssize_t show_available_governors(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct devfreq_governor *tmp_governor;
+ ssize_t count = 0;
+
+ mutex_lock(&devfreq_list_lock);
+ list_for_each_entry(tmp_governor, &devfreq_governor_list, node)
+ count += scnprintf(&buf[count], (PAGE_SIZE - count - 2),
+ "%s ", tmp_governor->name);
+ mutex_unlock(&devfreq_list_lock);
+
+ /* Truncate the trailing space */
+ if (count)
+ count--;
+
+ count += sprintf(&buf[count], "\n");
+
+ return count;
+}
+
static ssize_t show_freq(struct device *dev,
struct device_attribute *attr, char *buf)
{
+ unsigned long freq;
+ struct devfreq *devfreq = to_devfreq(dev);
+
+ if (devfreq->profile->get_cur_freq &&
+ !devfreq->profile->get_cur_freq(devfreq->dev.parent, &freq))
+ return sprintf(buf, "%lu\n", freq);
+
+ return sprintf(buf, "%lu\n", devfreq->previous_freq);
+}
+
+static ssize_t show_target_freq(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
return sprintf(buf, "%lu\n", to_devfreq(dev)->previous_freq);
}
@@ -486,39 +790,19 @@
unsigned int value;
int ret;
+ if (!df->governor)
+ return -EINVAL;
+
ret = sscanf(buf, "%u", &value);
if (ret != 1)
- goto out;
+ return -EINVAL;
- mutex_lock(&df->lock);
- df->profile->polling_ms = value;
- df->next_polling = df->polling_jiffies
- = msecs_to_jiffies(value);
- mutex_unlock(&df->lock);
-
+ df->governor->event_handler(df, DEVFREQ_GOV_INTERVAL, &value);
ret = count;
- if (df->governor->no_central_polling)
- goto out;
-
- mutex_lock(&devfreq_list_lock);
- if (df->next_polling > 0 && !polling) {
- polling = true;
- queue_delayed_work(devfreq_wq, &devfreq_work,
- df->next_polling);
- }
- mutex_unlock(&devfreq_list_lock);
-out:
return ret;
}
-static ssize_t show_central_polling(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- return sprintf(buf, "%d\n",
- !to_devfreq(dev)->governor->no_central_polling);
-}
-
static ssize_t store_min_freq(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
@@ -529,7 +813,7 @@
ret = sscanf(buf, "%lu", &value);
if (ret != 1)
- goto out;
+ return -EINVAL;
mutex_lock(&df->lock);
max = df->max_freq;
@@ -543,7 +827,6 @@
ret = count;
unlock:
mutex_unlock(&df->lock);
-out:
return ret;
}
@@ -563,7 +846,7 @@
ret = sscanf(buf, "%lu", &value);
if (ret != 1)
- goto out;
+ return -EINVAL;
mutex_lock(&df->lock);
min = df->min_freq;
@@ -577,7 +860,6 @@
ret = count;
unlock:
mutex_unlock(&df->lock);
-out:
return ret;
}
@@ -587,34 +869,92 @@
return sprintf(buf, "%lu\n", to_devfreq(dev)->max_freq);
}
+static ssize_t show_available_freqs(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct devfreq *df = to_devfreq(d);
+ struct device *dev = df->dev.parent;
+ struct opp *opp;
+ ssize_t count = 0;
+ unsigned long freq = 0;
+
+ rcu_read_lock();
+ do {
+ opp = opp_find_freq_ceil(dev, &freq);
+ if (IS_ERR(opp))
+ break;
+
+ count += scnprintf(&buf[count], (PAGE_SIZE - count - 2),
+ "%lu ", freq);
+ freq++;
+ } while (1);
+ rcu_read_unlock();
+
+ /* Truncate the trailing space */
+ if (count)
+ count--;
+
+ count += sprintf(&buf[count], "\n");
+
+ return count;
+}
+
+static ssize_t show_trans_table(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct devfreq *devfreq = to_devfreq(dev);
+ ssize_t len;
+ int i, j, err;
+ unsigned int max_state = devfreq->profile->max_state;
+
+ err = devfreq_update_status(devfreq, devfreq->previous_freq);
+ if (err)
+ return 0;
+
+ len = sprintf(buf, " From : To\n");
+ len += sprintf(buf + len, " :");
+ for (i = 0; i < max_state; i++)
+ len += sprintf(buf + len, "%8u",
+ devfreq->profile->freq_table[i]);
+
+ len += sprintf(buf + len, " time(ms)\n");
+
+ for (i = 0; i < max_state; i++) {
+ if (devfreq->profile->freq_table[i]
+ == devfreq->previous_freq) {
+ len += sprintf(buf + len, "*");
+ } else {
+ len += sprintf(buf + len, " ");
+ }
+ len += sprintf(buf + len, "%8u:",
+ devfreq->profile->freq_table[i]);
+ for (j = 0; j < max_state; j++)
+ len += sprintf(buf + len, "%8u",
+ devfreq->trans_table[(i * max_state) + j]);
+ len += sprintf(buf + len, "%10u\n",
+ jiffies_to_msecs(devfreq->time_in_state[i]));
+ }
+
+ len += sprintf(buf + len, "Total transition : %u\n",
+ devfreq->total_trans);
+ return len;
+}
+
static struct device_attribute devfreq_attrs[] = {
- __ATTR(governor, S_IRUGO, show_governor, NULL),
+ __ATTR(governor, S_IRUGO | S_IWUSR, show_governor, store_governor),
+ __ATTR(available_governors, S_IRUGO, show_available_governors, NULL),
__ATTR(cur_freq, S_IRUGO, show_freq, NULL),
- __ATTR(central_polling, S_IRUGO, show_central_polling, NULL),
+ __ATTR(available_frequencies, S_IRUGO, show_available_freqs, NULL),
+ __ATTR(target_freq, S_IRUGO, show_target_freq, NULL),
__ATTR(polling_interval, S_IRUGO | S_IWUSR, show_polling_interval,
store_polling_interval),
__ATTR(min_freq, S_IRUGO | S_IWUSR, show_min_freq, store_min_freq),
__ATTR(max_freq, S_IRUGO | S_IWUSR, show_max_freq, store_max_freq),
+ __ATTR(trans_stat, S_IRUGO, show_trans_table, NULL),
{ },
};
-/**
- * devfreq_start_polling() - Initialize data structure for devfreq framework and
- * start polling registered devfreq devices.
- */
-static int __init devfreq_start_polling(void)
-{
- mutex_lock(&devfreq_list_lock);
- polling = false;
- devfreq_wq = create_freezable_workqueue("devfreq_wq");
- INIT_DELAYED_WORK_DEFERRABLE(&devfreq_work, devfreq_monitor);
- mutex_unlock(&devfreq_list_lock);
-
- devfreq_monitor(&devfreq_work.work);
- return 0;
-}
-late_initcall(devfreq_start_polling);
-
static int __init devfreq_init(void)
{
devfreq_class = class_create(THIS_MODULE, "devfreq");
@@ -622,7 +962,15 @@
pr_err("%s: couldn't create class\n", __FILE__);
return PTR_ERR(devfreq_class);
}
+
+ devfreq_wq = create_freezable_workqueue("devfreq_wq");
+ if (IS_ERR(devfreq_wq)) {
+ class_destroy(devfreq_class);
+ pr_err("%s: couldn't create workqueue\n", __FILE__);
+ return PTR_ERR(devfreq_wq);
+ }
devfreq_class->dev_attrs = devfreq_attrs;
+
return 0;
}
subsys_initcall(devfreq_init);
@@ -630,6 +978,7 @@
static void __exit devfreq_exit(void)
{
class_destroy(devfreq_class);
+ destroy_workqueue(devfreq_wq);
}
module_exit(devfreq_exit);
@@ -641,10 +990,15 @@
/**
* devfreq_recommended_opp() - Helper function to get proper OPP for the
* freq value given to target callback.
- * @dev The devfreq user device. (parent of devfreq)
- * @freq The frequency given to target function
- * @flags Flags handed from devfreq framework.
+ * @dev: The devfreq user device. (parent of devfreq)
+ * @freq: The frequency given to target function
+ * @flags: Flags handed from devfreq framework.
*
+ * Locking: This function must be called under rcu_read_lock(). opp is a rcu
+ * protected pointer. The reason for the same is that the opp pointer which is
+ * returned will remain valid for use with opp_get_{voltage, freq} only while
+ * under the locked area. The pointer returned must be used prior to unlocking
+ * with rcu_read_unlock() to maintain the integrity of the pointer.
*/
struct opp *devfreq_recommended_opp(struct device *dev, unsigned long *freq,
u32 flags)
@@ -656,14 +1010,14 @@
opp = opp_find_freq_floor(dev, freq);
/* If not available, use the closest opp */
- if (opp == ERR_PTR(-ENODEV))
+ if (opp == ERR_PTR(-ERANGE))
opp = opp_find_freq_ceil(dev, freq);
} else {
/* The freq is an lower bound. opp should be higher */
opp = opp_find_freq_ceil(dev, freq);
/* If not available, use the closest opp */
- if (opp == ERR_PTR(-ENODEV))
+ if (opp == ERR_PTR(-ERANGE))
opp = opp_find_freq_floor(dev, freq);
}
@@ -674,35 +1028,49 @@
* devfreq_register_opp_notifier() - Helper function to get devfreq notified
* for any changes in the OPP availability
* changes
- * @dev The devfreq user device. (parent of devfreq)
- * @devfreq The devfreq object.
+ * @dev: The devfreq user device. (parent of devfreq)
+ * @devfreq: The devfreq object.
*/
int devfreq_register_opp_notifier(struct device *dev, struct devfreq *devfreq)
{
- struct srcu_notifier_head *nh = opp_get_notifier(dev);
+ struct srcu_notifier_head *nh;
+ int ret = 0;
+ rcu_read_lock();
+ nh = opp_get_notifier(dev);
if (IS_ERR(nh))
- return PTR_ERR(nh);
- return srcu_notifier_chain_register(nh, &devfreq->nb);
+ ret = PTR_ERR(nh);
+ rcu_read_unlock();
+ if (!ret)
+ ret = srcu_notifier_chain_register(nh, &devfreq->nb);
+
+ return ret;
}
/**
* devfreq_unregister_opp_notifier() - Helper function to stop getting devfreq
* notified for any changes in the OPP
* availability changes anymore.
- * @dev The devfreq user device. (parent of devfreq)
- * @devfreq The devfreq object.
+ * @dev: The devfreq user device. (parent of devfreq)
+ * @devfreq: The devfreq object.
*
* At exit() callback of devfreq_dev_profile, this must be included if
* devfreq_recommended_opp is used.
*/
int devfreq_unregister_opp_notifier(struct device *dev, struct devfreq *devfreq)
{
- struct srcu_notifier_head *nh = opp_get_notifier(dev);
+ struct srcu_notifier_head *nh;
+ int ret = 0;
+ rcu_read_lock();
+ nh = opp_get_notifier(dev);
if (IS_ERR(nh))
- return PTR_ERR(nh);
- return srcu_notifier_chain_unregister(nh, &devfreq->nb);
+ ret = PTR_ERR(nh);
+ rcu_read_unlock();
+ if (!ret)
+ ret = srcu_notifier_chain_unregister(nh, &devfreq->nb);
+
+ return ret;
}
MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
diff --git a/drivers/devfreq/exynos4_bus.c b/drivers/devfreq/exynos4_bus.c
index 88ddc77..f6c54bd 100644
--- a/drivers/devfreq/exynos4_bus.c
+++ b/drivers/devfreq/exynos4_bus.c
@@ -73,6 +73,16 @@
#define EX4210_LV_NUM (LV_2 + 1)
#define EX4x12_LV_NUM (LV_4 + 1)
+/**
+ * struct busfreq_opp_info - opp information for bus
+ * @rate: Frequency in hertz
+ * @volt: Voltage in microvolts corresponding to this OPP
+ */
+struct busfreq_opp_info {
+ unsigned long rate;
+ unsigned long volt;
+};
+
struct busfreq_data {
enum exynos4_busf_type type;
struct device *dev;
@@ -80,7 +90,7 @@
bool disabled;
struct regulator *vdd_int;
struct regulator *vdd_mif; /* Exynos4412/4212 only */
- struct opp *curr_opp;
+ struct busfreq_opp_info curr_oppinfo;
struct exynos4_ppmu dmc[2];
struct notifier_block pm_notifier;
@@ -296,13 +306,14 @@
};
-static int exynos4210_set_busclk(struct busfreq_data *data, struct opp *opp)
+static int exynos4210_set_busclk(struct busfreq_data *data,
+ struct busfreq_opp_info *oppi)
{
unsigned int index;
unsigned int tmp;
for (index = LV_0; index < EX4210_LV_NUM; index++)
- if (opp_get_freq(opp) == exynos4210_busclk_table[index].clk)
+ if (oppi->rate == exynos4210_busclk_table[index].clk)
break;
if (index == EX4210_LV_NUM)
@@ -361,13 +372,14 @@
return 0;
}
-static int exynos4x12_set_busclk(struct busfreq_data *data, struct opp *opp)
+static int exynos4x12_set_busclk(struct busfreq_data *data,
+ struct busfreq_opp_info *oppi)
{
unsigned int index;
unsigned int tmp;
for (index = LV_0; index < EX4x12_LV_NUM; index++)
- if (opp_get_freq(opp) == exynos4x12_mifclk_table[index].clk)
+ if (oppi->rate == exynos4x12_mifclk_table[index].clk)
break;
if (index == EX4x12_LV_NUM)
@@ -576,11 +588,12 @@
return -EINVAL;
}
-static int exynos4_bus_setvolt(struct busfreq_data *data, struct opp *opp,
- struct opp *oldopp)
+static int exynos4_bus_setvolt(struct busfreq_data *data,
+ struct busfreq_opp_info *oppi,
+ struct busfreq_opp_info *oldoppi)
{
int err = 0, tmp;
- unsigned long volt = opp_get_voltage(opp);
+ unsigned long volt = oppi->volt;
switch (data->type) {
case TYPE_BUSF_EXYNOS4210:
@@ -595,11 +608,11 @@
if (err)
break;
- tmp = exynos4x12_get_intspec(opp_get_freq(opp));
+ tmp = exynos4x12_get_intspec(oppi->rate);
if (tmp < 0) {
err = tmp;
regulator_set_voltage(data->vdd_mif,
- opp_get_voltage(oldopp),
+ oldoppi->volt,
MAX_SAFEVOLT);
break;
}
@@ -609,7 +622,7 @@
/* Try to recover */
if (err)
regulator_set_voltage(data->vdd_mif,
- opp_get_voltage(oldopp),
+ oldoppi->volt,
MAX_SAFEVOLT);
break;
default:
@@ -626,17 +639,26 @@
struct platform_device *pdev = container_of(dev, struct platform_device,
dev);
struct busfreq_data *data = platform_get_drvdata(pdev);
- struct opp *opp = devfreq_recommended_opp(dev, _freq, flags);
- unsigned long freq = opp_get_freq(opp);
- unsigned long old_freq = opp_get_freq(data->curr_opp);
+ struct opp *opp;
+ unsigned long freq;
+ unsigned long old_freq = data->curr_oppinfo.rate;
+ struct busfreq_opp_info new_oppinfo;
- if (IS_ERR(opp))
+ rcu_read_lock();
+ opp = devfreq_recommended_opp(dev, _freq, flags);
+ if (IS_ERR(opp)) {
+ rcu_read_unlock();
return PTR_ERR(opp);
+ }
+ new_oppinfo.rate = opp_get_freq(opp);
+ new_oppinfo.volt = opp_get_voltage(opp);
+ rcu_read_unlock();
+ freq = new_oppinfo.rate;
if (old_freq == freq)
return 0;
- dev_dbg(dev, "targetting %lukHz %luuV\n", freq, opp_get_voltage(opp));
+ dev_dbg(dev, "targetting %lukHz %luuV\n", freq, new_oppinfo.volt);
mutex_lock(&data->lock);
@@ -644,17 +666,18 @@
goto out;
if (old_freq < freq)
- err = exynos4_bus_setvolt(data, opp, data->curr_opp);
+ err = exynos4_bus_setvolt(data, &new_oppinfo,
+ &data->curr_oppinfo);
if (err)
goto out;
if (old_freq != freq) {
switch (data->type) {
case TYPE_BUSF_EXYNOS4210:
- err = exynos4210_set_busclk(data, opp);
+ err = exynos4210_set_busclk(data, &new_oppinfo);
break;
case TYPE_BUSF_EXYNOS4x12:
- err = exynos4x12_set_busclk(data, opp);
+ err = exynos4x12_set_busclk(data, &new_oppinfo);
break;
default:
err = -EINVAL;
@@ -664,11 +687,12 @@
goto out;
if (old_freq > freq)
- err = exynos4_bus_setvolt(data, opp, data->curr_opp);
+ err = exynos4_bus_setvolt(data, &new_oppinfo,
+ &data->curr_oppinfo);
if (err)
goto out;
- data->curr_opp = opp;
+ data->curr_oppinfo = new_oppinfo;
out:
mutex_unlock(&data->lock);
return err;
@@ -702,7 +726,7 @@
exynos4_read_ppmu(data);
busier_dmc = exynos4_get_busier_dmc(data);
- stat->current_frequency = opp_get_freq(data->curr_opp);
+ stat->current_frequency = data->curr_oppinfo.rate;
if (busier_dmc)
addr = S5P_VA_DMC1;
@@ -933,6 +957,7 @@
struct busfreq_data *data = container_of(this, struct busfreq_data,
pm_notifier);
struct opp *opp;
+ struct busfreq_opp_info new_oppinfo;
unsigned long maxfreq = ULONG_MAX;
int err = 0;
@@ -943,18 +968,29 @@
data->disabled = true;
+ rcu_read_lock();
opp = opp_find_freq_floor(data->dev, &maxfreq);
+ if (IS_ERR(opp)) {
+ rcu_read_unlock();
+ dev_err(data->dev, "%s: unable to find a min freq\n",
+ __func__);
+ return PTR_ERR(opp);
+ }
+ new_oppinfo.rate = opp_get_freq(opp);
+ new_oppinfo.volt = opp_get_voltage(opp);
+ rcu_read_unlock();
- err = exynos4_bus_setvolt(data, opp, data->curr_opp);
+ err = exynos4_bus_setvolt(data, &new_oppinfo,
+ &data->curr_oppinfo);
if (err)
goto unlock;
switch (data->type) {
case TYPE_BUSF_EXYNOS4210:
- err = exynos4210_set_busclk(data, opp);
+ err = exynos4210_set_busclk(data, &new_oppinfo);
break;
case TYPE_BUSF_EXYNOS4x12:
- err = exynos4x12_set_busclk(data, opp);
+ err = exynos4x12_set_busclk(data, &new_oppinfo);
break;
default:
err = -EINVAL;
@@ -962,7 +998,7 @@
if (err)
goto unlock;
- data->curr_opp = opp;
+ data->curr_oppinfo = new_oppinfo;
unlock:
mutex_unlock(&data->lock);
if (err)
@@ -987,7 +1023,7 @@
struct device *dev = &pdev->dev;
int err = 0;
- data = kzalloc(sizeof(struct busfreq_data), GFP_KERNEL);
+ data = devm_kzalloc(&pdev->dev, sizeof(struct busfreq_data), GFP_KERNEL);
if (data == NULL) {
dev_err(dev, "Cannot allocate memory.\n");
return -ENOMEM;
@@ -1012,63 +1048,52 @@
err = -EINVAL;
}
if (err)
- goto err_regulator;
+ return err;
- data->vdd_int = regulator_get(dev, "vdd_int");
+ data->vdd_int = devm_regulator_get(dev, "vdd_int");
if (IS_ERR(data->vdd_int)) {
dev_err(dev, "Cannot get the regulator \"vdd_int\"\n");
- err = PTR_ERR(data->vdd_int);
- goto err_regulator;
+ return PTR_ERR(data->vdd_int);
}
if (data->type == TYPE_BUSF_EXYNOS4x12) {
- data->vdd_mif = regulator_get(dev, "vdd_mif");
+ data->vdd_mif = devm_regulator_get(dev, "vdd_mif");
if (IS_ERR(data->vdd_mif)) {
dev_err(dev, "Cannot get the regulator \"vdd_mif\"\n");
- err = PTR_ERR(data->vdd_mif);
- regulator_put(data->vdd_int);
- goto err_regulator;
-
+ return PTR_ERR(data->vdd_mif);
}
}
+ rcu_read_lock();
opp = opp_find_freq_floor(dev, &exynos4_devfreq_profile.initial_freq);
if (IS_ERR(opp)) {
+ rcu_read_unlock();
dev_err(dev, "Invalid initial frequency %lu kHz.\n",
- exynos4_devfreq_profile.initial_freq);
- err = PTR_ERR(opp);
- goto err_opp_add;
+ exynos4_devfreq_profile.initial_freq);
+ return PTR_ERR(opp);
}
- data->curr_opp = opp;
+ data->curr_oppinfo.rate = opp_get_freq(opp);
+ data->curr_oppinfo.volt = opp_get_voltage(opp);
+ rcu_read_unlock();
platform_set_drvdata(pdev, data);
busfreq_mon_reset(data);
data->devfreq = devfreq_add_device(dev, &exynos4_devfreq_profile,
- &devfreq_simple_ondemand, NULL);
- if (IS_ERR(data->devfreq)) {
- err = PTR_ERR(data->devfreq);
- goto err_opp_add;
- }
+ "simple_ondemand", NULL);
+ if (IS_ERR(data->devfreq))
+ return PTR_ERR(data->devfreq);
devfreq_register_opp_notifier(dev, data->devfreq);
err = register_pm_notifier(&data->pm_notifier);
if (err) {
dev_err(dev, "Failed to setup pm notifier\n");
- goto err_devfreq_add;
+ devfreq_remove_device(data->devfreq);
+ return err;
}
return 0;
-err_devfreq_add:
- devfreq_remove_device(data->devfreq);
-err_opp_add:
- if (data->vdd_mif)
- regulator_put(data->vdd_mif);
- regulator_put(data->vdd_int);
-err_regulator:
- kfree(data);
- return err;
}
static __devexit int exynos4_busfreq_remove(struct platform_device *pdev)
@@ -1077,10 +1102,6 @@
unregister_pm_notifier(&data->pm_notifier);
devfreq_remove_device(data->devfreq);
- regulator_put(data->vdd_int);
- if (data->vdd_mif)
- regulator_put(data->vdd_mif);
- kfree(data);
return 0;
}
diff --git a/drivers/devfreq/governor.h b/drivers/devfreq/governor.h
index ea7f13c..fad7d63 100644
--- a/drivers/devfreq/governor.h
+++ b/drivers/devfreq/governor.h
@@ -18,7 +18,24 @@
#define to_devfreq(DEV) container_of((DEV), struct devfreq, dev)
+/* Devfreq events */
+#define DEVFREQ_GOV_START 0x1
+#define DEVFREQ_GOV_STOP 0x2
+#define DEVFREQ_GOV_INTERVAL 0x3
+#define DEVFREQ_GOV_SUSPEND 0x4
+#define DEVFREQ_GOV_RESUME 0x5
+
/* Caution: devfreq->lock must be locked before calling update_devfreq */
extern int update_devfreq(struct devfreq *devfreq);
+extern void devfreq_monitor_start(struct devfreq *devfreq);
+extern void devfreq_monitor_stop(struct devfreq *devfreq);
+extern void devfreq_monitor_suspend(struct devfreq *devfreq);
+extern void devfreq_monitor_resume(struct devfreq *devfreq);
+extern void devfreq_interval_update(struct devfreq *devfreq,
+ unsigned int *delay);
+
+extern int devfreq_add_governor(struct devfreq_governor *governor);
+extern int devfreq_remove_governor(struct devfreq_governor *governor);
+
#endif /* _GOVERNOR_H */
diff --git a/drivers/devfreq/governor_performance.c b/drivers/devfreq/governor_performance.c
index 574a06b..c72f942 100644
--- a/drivers/devfreq/governor_performance.c
+++ b/drivers/devfreq/governor_performance.c
@@ -10,6 +10,8 @@
*/
#include <linux/devfreq.h>
+#include <linux/module.h>
+#include "governor.h"
static int devfreq_performance_func(struct devfreq *df,
unsigned long *freq)
@@ -25,8 +27,41 @@
return 0;
}
-const struct devfreq_governor devfreq_performance = {
+static int devfreq_performance_handler(struct devfreq *devfreq,
+ unsigned int event, void *data)
+{
+ int ret = 0;
+
+ if (event == DEVFREQ_GOV_START) {
+ mutex_lock(&devfreq->lock);
+ ret = update_devfreq(devfreq);
+ mutex_unlock(&devfreq->lock);
+ }
+
+ return ret;
+}
+
+static struct devfreq_governor devfreq_performance = {
.name = "performance",
.get_target_freq = devfreq_performance_func,
- .no_central_polling = true,
+ .event_handler = devfreq_performance_handler,
};
+
+static int __init devfreq_performance_init(void)
+{
+ return devfreq_add_governor(&devfreq_performance);
+}
+subsys_initcall(devfreq_performance_init);
+
+static void __exit devfreq_performance_exit(void)
+{
+ int ret;
+
+ ret = devfreq_remove_governor(&devfreq_performance);
+ if (ret)
+ pr_err("%s: failed remove governor %d\n", __func__, ret);
+
+ return;
+}
+module_exit(devfreq_performance_exit);
+MODULE_LICENSE("GPL");
diff --git a/drivers/devfreq/governor_powersave.c b/drivers/devfreq/governor_powersave.c
index d742d4a..0c6bed5 100644
--- a/drivers/devfreq/governor_powersave.c
+++ b/drivers/devfreq/governor_powersave.c
@@ -10,6 +10,8 @@
*/
#include <linux/devfreq.h>
+#include <linux/module.h>
+#include "governor.h"
static int devfreq_powersave_func(struct devfreq *df,
unsigned long *freq)
@@ -22,8 +24,41 @@
return 0;
}
-const struct devfreq_governor devfreq_powersave = {
+static int devfreq_powersave_handler(struct devfreq *devfreq,
+ unsigned int event, void *data)
+{
+ int ret = 0;
+
+ if (event == DEVFREQ_GOV_START) {
+ mutex_lock(&devfreq->lock);
+ ret = update_devfreq(devfreq);
+ mutex_unlock(&devfreq->lock);
+ }
+
+ return ret;
+}
+
+static struct devfreq_governor devfreq_powersave = {
.name = "powersave",
.get_target_freq = devfreq_powersave_func,
- .no_central_polling = true,
+ .event_handler = devfreq_powersave_handler,
};
+
+static int __init devfreq_powersave_init(void)
+{
+ return devfreq_add_governor(&devfreq_powersave);
+}
+subsys_initcall(devfreq_powersave_init);
+
+static void __exit devfreq_powersave_exit(void)
+{
+ int ret;
+
+ ret = devfreq_remove_governor(&devfreq_powersave);
+ if (ret)
+ pr_err("%s: failed remove governor %d\n", __func__, ret);
+
+ return;
+}
+module_exit(devfreq_powersave_exit);
+MODULE_LICENSE("GPL");
diff --git a/drivers/devfreq/governor_simpleondemand.c b/drivers/devfreq/governor_simpleondemand.c
index a2e3eae..0720ba8 100644
--- a/drivers/devfreq/governor_simpleondemand.c
+++ b/drivers/devfreq/governor_simpleondemand.c
@@ -10,8 +10,10 @@
*/
#include <linux/errno.h>
+#include <linux/module.h>
#include <linux/devfreq.h>
#include <linux/math64.h>
+#include "governor.h"
/* Default constants for DevFreq-Simple-Ondemand (DFSO) */
#define DFSO_UPTHRESHOLD (90)
@@ -88,7 +90,58 @@
return 0;
}
-const struct devfreq_governor devfreq_simple_ondemand = {
+static int devfreq_simple_ondemand_handler(struct devfreq *devfreq,
+ unsigned int event, void *data)
+{
+ switch (event) {
+ case DEVFREQ_GOV_START:
+ devfreq_monitor_start(devfreq);
+ break;
+
+ case DEVFREQ_GOV_STOP:
+ devfreq_monitor_stop(devfreq);
+ break;
+
+ case DEVFREQ_GOV_INTERVAL:
+ devfreq_interval_update(devfreq, (unsigned int *)data);
+ break;
+
+ case DEVFREQ_GOV_SUSPEND:
+ devfreq_monitor_suspend(devfreq);
+ break;
+
+ case DEVFREQ_GOV_RESUME:
+ devfreq_monitor_resume(devfreq);
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static struct devfreq_governor devfreq_simple_ondemand = {
.name = "simple_ondemand",
.get_target_freq = devfreq_simple_ondemand_func,
+ .event_handler = devfreq_simple_ondemand_handler,
};
+
+static int __init devfreq_simple_ondemand_init(void)
+{
+ return devfreq_add_governor(&devfreq_simple_ondemand);
+}
+subsys_initcall(devfreq_simple_ondemand_init);
+
+static void __exit devfreq_simple_ondemand_exit(void)
+{
+ int ret;
+
+ ret = devfreq_remove_governor(&devfreq_simple_ondemand);
+ if (ret)
+ pr_err("%s: failed remove governor %d\n", __func__, ret);
+
+ return;
+}
+module_exit(devfreq_simple_ondemand_exit);
+MODULE_LICENSE("GPL");
diff --git a/drivers/devfreq/governor_userspace.c b/drivers/devfreq/governor_userspace.c
index 0681246..35de6e8 100644
--- a/drivers/devfreq/governor_userspace.c
+++ b/drivers/devfreq/governor_userspace.c
@@ -14,6 +14,7 @@
#include <linux/devfreq.h>
#include <linux/pm.h>
#include <linux/mutex.h>
+#include <linux/module.h>
#include "governor.h"
struct userspace_data {
@@ -116,10 +117,46 @@
devfreq->data = NULL;
}
-const struct devfreq_governor devfreq_userspace = {
+static int devfreq_userspace_handler(struct devfreq *devfreq,
+ unsigned int event, void *data)
+{
+ int ret = 0;
+
+ switch (event) {
+ case DEVFREQ_GOV_START:
+ ret = userspace_init(devfreq);
+ break;
+ case DEVFREQ_GOV_STOP:
+ userspace_exit(devfreq);
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+static struct devfreq_governor devfreq_userspace = {
.name = "userspace",
.get_target_freq = devfreq_userspace_func,
- .init = userspace_init,
- .exit = userspace_exit,
- .no_central_polling = true,
+ .event_handler = devfreq_userspace_handler,
};
+
+static int __init devfreq_userspace_init(void)
+{
+ return devfreq_add_governor(&devfreq_userspace);
+}
+subsys_initcall(devfreq_userspace_init);
+
+static void __exit devfreq_userspace_exit(void)
+{
+ int ret;
+
+ ret = devfreq_remove_governor(&devfreq_userspace);
+ if (ret)
+ pr_err("%s: failed remove governor %d\n", __func__, ret);
+
+ return;
+}
+module_exit(devfreq_userspace_exit);
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/ion/ion.c b/drivers/gpu/ion/ion.c
index 0904f9fe..9ab2343 100644
--- a/drivers/gpu/ion/ion.c
+++ b/drivers/gpu/ion/ion.c
@@ -914,7 +914,7 @@
if (type == ION_HEAP_TYPE_SYSTEM_CONTIG ||
type == ION_HEAP_TYPE_CARVEOUT ||
type == (enum ion_heap_type) ION_HEAP_TYPE_CP)
- seq_printf(s, " : %12lx", handle->buffer->priv_phys);
+ seq_printf(s, " : %12pa", &handle->buffer->priv_phys);
else
seq_printf(s, " : %12s", "N/A");
@@ -1988,8 +1988,8 @@
ret = memblock_reserve(data->heaps[i].base,
data->heaps[i].size);
if (ret)
- pr_err("memblock reserve of %x@%lx failed\n",
+ pr_err("memblock reserve of %x@%pa failed\n",
data->heaps[i].size,
- data->heaps[i].base);
+ &data->heaps[i].base);
}
}
diff --git a/drivers/gpu/ion/ion_carveout_heap.c b/drivers/gpu/ion/ion_carveout_heap.c
index 3e55a57..b51fa6a 100644
--- a/drivers/gpu/ion/ion_carveout_heap.c
+++ b/drivers/gpu/ion/ion_carveout_heap.c
@@ -297,8 +297,11 @@
const char *client_name = "(null)";
if (last_end < data->addr) {
- seq_printf(s, "%16.s %14lx %14lx %14lu (%lx)\n",
- "FREE", last_end, data->addr-1,
+ phys_addr_t da;
+
+ da = data->addr-1;
+ seq_printf(s, "%16.s %14pa %14pa %14lu (%lx)\n",
+ "FREE", &last_end, &da,
data->addr-last_end,
data->addr-last_end);
}
@@ -306,9 +309,9 @@
if (data->client_name)
client_name = data->client_name;
- seq_printf(s, "%16.s %14lx %14lx %14lu (%lx)\n",
- client_name, data->addr,
- data->addr_end,
+ seq_printf(s, "%16.s %14pa %14pa %14lu (%lx)\n",
+ client_name, &data->addr,
+ &data->addr_end,
data->size, data->size);
last_end = data->addr_end+1;
}
diff --git a/drivers/gpu/ion/ion_cma_heap.c b/drivers/gpu/ion/ion_cma_heap.c
index 4f5ac75..a01b347 100644
--- a/drivers/gpu/ion/ion_cma_heap.c
+++ b/drivers/gpu/ion/ion_cma_heap.c
@@ -127,8 +127,8 @@
struct device *dev = heap->priv;
struct ion_cma_buffer_info *info = buffer->priv_virt;
- dev_dbg(dev, "Return buffer %p physical address 0x%x\n", buffer,
- info->handle);
+ dev_dbg(dev, "Return buffer %p physical address 0x%pa\n", buffer,
+ &info->handle);
*addr = info->handle;
*len = buffer->size;
@@ -325,9 +325,9 @@
if (data->client_name)
client_name = data->client_name;
- seq_printf(s, "%16.s %14lx %14lx %14lu (%lx)\n",
- client_name, data->addr,
- data->addr_end,
+ seq_printf(s, "%16.s %14pa %14pa %14lu (%lx)\n",
+ client_name, &data->addr,
+ &data->addr_end,
data->size, data->size);
}
}
diff --git a/drivers/gpu/ion/ion_cma_secure_heap.c b/drivers/gpu/ion/ion_cma_secure_heap.c
index 2c0e5ae..3be3a00 100644
--- a/drivers/gpu/ion/ion_cma_secure_heap.c
+++ b/drivers/gpu/ion/ion_cma_secure_heap.c
@@ -164,8 +164,8 @@
struct device *dev = heap->priv;
struct ion_secure_cma_buffer_info *info = buffer->priv_virt;
- dev_dbg(dev, "Return buffer %p physical address 0x%x\n", buffer,
- info->handle);
+ dev_dbg(dev, "Return buffer %p physical address 0x%pa\n", buffer,
+ &info->handle);
*addr = info->handle;
*len = buffer->size;
@@ -359,9 +359,9 @@
if (data->client_name)
client_name = data->client_name;
- seq_printf(s, "%16.s %14lx %14lx %14lu (%lx)\n",
- client_name, data->addr,
- data->addr_end,
+ seq_printf(s, "%16.s %14pa %14pa %14lu (%lx)\n",
+ client_name, &data->addr,
+ &data->addr_end,
data->size, data->size);
}
}
diff --git a/drivers/gpu/ion/ion_cp_heap.c b/drivers/gpu/ion/ion_cp_heap.c
index 56ccc8f..a7473e2 100644
--- a/drivers/gpu/ion/ion_cp_heap.c
+++ b/drivers/gpu/ion/ion_cp_heap.c
@@ -256,8 +256,8 @@
atomic_dec(&cp_heap->protect_cnt);
} else {
cp_heap->heap_protected = HEAP_PROTECTED;
- pr_debug("Protected heap %s @ 0x%lx\n",
- heap->name, cp_heap->base);
+ pr_debug("Protected heap %s @ 0x%pa\n",
+ heap->name, &cp_heap->base);
}
}
out:
@@ -804,8 +804,11 @@
const char *client_name = "(null)";
if (last_end < data->addr) {
- seq_printf(s, "%16.s %14lx %14lx %14lu (%lx)\n",
- "FREE", last_end, data->addr-1,
+ phys_addr_t da;
+
+ da = data->addr-1;
+ seq_printf(s, "%16.s %14pa %14pa %14lu (%lx)\n",
+ "FREE", &last_end, &da,
data->addr-last_end,
data->addr-last_end);
}
@@ -813,9 +816,9 @@
if (data->client_name)
client_name = data->client_name;
- seq_printf(s, "%16.s %14lx %14lx %14lu (%lx)\n",
- client_name, data->addr,
- data->addr_end,
+ seq_printf(s, "%16.s %14pa %14pa %14lu (%lx)\n",
+ client_name, &data->addr,
+ &data->addr_end,
data->size, data->size);
last_end = data->addr_end+1;
}
diff --git a/drivers/gpu/ion/ion_heap.c b/drivers/gpu/ion/ion_heap.c
index ff2b8dd..46fefb5 100644
--- a/drivers/gpu/ion/ion_heap.c
+++ b/drivers/gpu/ion/ion_heap.c
@@ -56,9 +56,9 @@
}
if (IS_ERR_OR_NULL(heap)) {
- pr_err("%s: error creating heap %s type %d base %lu size %u\n",
+ pr_err("%s: error creating heap %s type %d base %pa size %u\n",
__func__, heap_data->name, heap_data->type,
- heap_data->base, heap_data->size);
+ &heap_data->base, heap_data->size);
return ERR_PTR(-EINVAL);
}
diff --git a/drivers/gpu/ion/ion_priv.h b/drivers/gpu/ion/ion_priv.h
index 9d1e90e..2ab2ed6 100644
--- a/drivers/gpu/ion/ion_priv.h
+++ b/drivers/gpu/ion/ion_priv.h
@@ -189,8 +189,8 @@
*/
struct mem_map_data {
struct rb_node node;
- unsigned long addr;
- unsigned long addr_end;
+ ion_phys_addr_t addr;
+ ion_phys_addr_t addr_end;
unsigned long size;
const char *client_name;
};
diff --git a/drivers/gpu/ion/msm/ion_cp_common.c b/drivers/gpu/ion/msm/ion_cp_common.c
index 8c9b95d..48c2efb 100644
--- a/drivers/gpu/ion/msm/ion_cp_common.c
+++ b/drivers/gpu/ion/msm/ion_cp_common.c
@@ -55,7 +55,7 @@
cmd.permission_type = permission_type;
cmd.lock = SCM_CP_PROTECT;
- return scm_call(SCM_SVC_CP, SCM_CP_LOCK_CMD_ID,
+ return scm_call(SCM_SVC_MP, SCM_CP_LOCK_CMD_ID,
&cmd, sizeof(cmd), NULL, 0);
}
@@ -68,7 +68,7 @@
cmd.permission_type = permission_type;
cmd.lock = SCM_CP_UNPROTECT;
- return scm_call(SCM_SVC_CP, SCM_CP_LOCK_CMD_ID,
+ return scm_call(SCM_SVC_MP, SCM_CP_LOCK_CMD_ID,
&cmd, sizeof(cmd), NULL, 0);
}
@@ -154,7 +154,7 @@
request.chunks.chunk_list_size = nchunks;
request.chunks.chunk_size = chunk_size;
- return scm_call(SCM_SVC_CP, MEM_PROTECT_LOCK_ID,
+ return scm_call(SCM_SVC_MP, MEM_PROTECT_LOCK_ID,
&request, sizeof(request), &resp, sizeof(resp));
}
diff --git a/drivers/gpu/ion/msm/msm_ion.c b/drivers/gpu/ion/msm/msm_ion.c
index 7840d87..bd27385 100644
--- a/drivers/gpu/ion/msm/msm_ion.c
+++ b/drivers/gpu/ion/msm/msm_ion.c
@@ -172,7 +172,7 @@
}
EXPORT_SYMBOL(msm_ion_do_cache_op);
-static unsigned long msm_ion_get_base(unsigned long size, int memory_type,
+static ion_phys_addr_t msm_ion_get_base(unsigned long size, int memory_type,
unsigned int align)
{
switch (memory_type) {
@@ -340,10 +340,10 @@
static int is_heap_overlapping(const struct ion_platform_heap *heap1,
const struct ion_platform_heap *heap2)
{
- unsigned long heap1_base = heap1->base;
- unsigned long heap2_base = heap2->base;
- unsigned long heap1_end = heap1->base + heap1->size - 1;
- unsigned long heap2_end = heap2->base + heap2->size - 1;
+ ion_phys_addr_t heap1_base = heap1->base;
+ ion_phys_addr_t heap2_base = heap2->base;
+ ion_phys_addr_t heap1_end = heap1->base + heap1->size - 1;
+ ion_phys_addr_t heap2_end = heap2->base + heap2->size - 1;
if (heap1_base == heap2_base)
return 1;
@@ -792,9 +792,9 @@
continue;
} else {
if (heap_data->size)
- pr_info("ION heap %s created at %lx "
+ pr_info("ION heap %s created at %pa "
"with size %x\n", heap_data->name,
- heap_data->base,
+ &heap_data->base,
heap_data->size);
else
pr_info("ION heap %s created\n",
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index bf45a63..9f4d791 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -17,6 +17,7 @@
#include <linux/sched.h>
#include <linux/of.h>
#include <linux/of_device.h>
+#include <linux/delay.h>
#include <mach/socinfo.h>
#include <mach/msm_bus_board.h>
@@ -121,14 +122,21 @@
* If the values of these registers are same after
* KGSL_TIMEOUT_PART time, GPU hang is reported in
* kernel log.
+ * *****ALERT******ALERT********ALERT*************
+ * Order of registers below is important, registers
+ * from LONG_IB_DETECT_REG_INDEX_START to
+ * LONG_IB_DETECT_REG_INDEX_END are used in long ib detection.
*/
-unsigned int hang_detect_regs[] = {
+#define LONG_IB_DETECT_REG_INDEX_START 1
+#define LONG_IB_DETECT_REG_INDEX_END 5
+
+unsigned int ft_detect_regs[] = {
A3XX_RBBM_STATUS,
- REG_CP_RB_RPTR,
+ REG_CP_RB_RPTR, /* LONG_IB_DETECT_REG_INDEX_START */
REG_CP_IB1_BASE,
REG_CP_IB1_BUFSZ,
REG_CP_IB2_BASE,
- REG_CP_IB2_BUFSZ,
+ REG_CP_IB2_BUFSZ, /* LONG_IB_DETECT_REG_INDEX_END */
0,
0,
0,
@@ -137,7 +145,7 @@
0
};
-const unsigned int hang_detect_regs_count = ARRAY_SIZE(hang_detect_regs);
+const unsigned int ft_detect_regs_count = ARRAY_SIZE(ft_detect_regs);
/*
* This is the master list of all GPU cores that are supported by this
@@ -1222,7 +1230,7 @@
int status = -EINVAL;
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
- if (KGSL_STATE_DUMP_AND_RECOVER != device->state)
+ if (KGSL_STATE_DUMP_AND_FT != device->state)
kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT);
/* Power up the device */
@@ -1277,16 +1285,16 @@
/* Assign correct RBBM status register to hang detect regs
*/
- hang_detect_regs[0] = adreno_dev->gpudev->reg_rbbm_status;
+ ft_detect_regs[0] = adreno_dev->gpudev->reg_rbbm_status;
/* Add A3XX specific registers for hang detection */
if (adreno_is_a3xx(adreno_dev)) {
- hang_detect_regs[6] = A3XX_RBBM_PERFCTR_SP_7_LO;
- hang_detect_regs[7] = A3XX_RBBM_PERFCTR_SP_7_HI;
- hang_detect_regs[8] = A3XX_RBBM_PERFCTR_SP_6_LO;
- hang_detect_regs[9] = A3XX_RBBM_PERFCTR_SP_6_HI;
- hang_detect_regs[10] = A3XX_RBBM_PERFCTR_SP_5_LO;
- hang_detect_regs[11] = A3XX_RBBM_PERFCTR_SP_5_HI;
+ ft_detect_regs[6] = A3XX_RBBM_PERFCTR_SP_7_LO;
+ ft_detect_regs[7] = A3XX_RBBM_PERFCTR_SP_7_HI;
+ ft_detect_regs[8] = A3XX_RBBM_PERFCTR_SP_6_LO;
+ ft_detect_regs[9] = A3XX_RBBM_PERFCTR_SP_6_HI;
+ ft_detect_regs[10] = A3XX_RBBM_PERFCTR_SP_5_LO;
+ ft_detect_regs[11] = A3XX_RBBM_PERFCTR_SP_5_HI;
}
status = kgsl_mmu_start(device);
@@ -1309,12 +1317,9 @@
if (status)
goto error_irq_off;
- /*
- * While recovery is on we do not want timer to
- * fire and attempt to change any device state
- */
-
- if (KGSL_STATE_DUMP_AND_RECOVER != device->state)
+ /* While fault tolerance is on we do not want timer to
+ * fire and attempt to change any device state */
+ if (KGSL_STATE_DUMP_AND_FT != device->state)
mod_timer(&device->idle_timer, jiffies + FIRST_TIMEOUT);
device->reset_counter++;
@@ -1328,7 +1333,8 @@
kgsl_mmu_stop(&device->mmu);
error_clk_off:
- kgsl_pwrctrl_disable(device);
+ if (KGSL_STATE_DUMP_AND_FT != device->state)
+ kgsl_pwrctrl_disable(device);
return status;
}
@@ -1356,26 +1362,26 @@
}
static void adreno_mark_context_status(struct kgsl_device *device,
- int recovery_status)
+ int ft_status)
{
struct kgsl_context *context;
int next = 0;
/*
* Set the reset status of all contexts to
* INNOCENT_CONTEXT_RESET_EXT except for the bad context
- * since thats the guilty party, if recovery failed then
+ * since thats the guilty party, if fault tolerance failed then
* mark all as guilty
*/
while ((context = idr_get_next(&device->context_idr, &next))) {
struct adreno_context *adreno_context = context->devctxt;
- if (recovery_status) {
+ if (ft_status) {
context->reset_status =
KGSL_CTX_STAT_GUILTY_CONTEXT_RESET_EXT;
adreno_context->flags |= CTXT_FLAGS_GPU_HANG;
} else if (KGSL_CTX_STAT_GUILTY_CONTEXT_RESET_EXT !=
context->reset_status) {
if (adreno_context->flags & (CTXT_FLAGS_GPU_HANG |
- CTXT_FLAGS_GPU_HANG_RECOVERED))
+ CTXT_FLAGS_GPU_HANG_FT))
context->reset_status =
KGSL_CTX_STAT_GUILTY_CONTEXT_RESET_EXT;
else
@@ -1410,103 +1416,305 @@
}
}
-static void adreno_destroy_recovery_data(struct adreno_recovery_data *rec_data)
+static void adreno_destroy_ft_data(struct adreno_ft_data *ft_data)
{
- vfree(rec_data->rb_buffer);
- vfree(rec_data->bad_rb_buffer);
+ vfree(ft_data->rb_buffer);
+ vfree(ft_data->bad_rb_buffer);
+ vfree(ft_data->good_rb_buffer);
}
-static int adreno_setup_recovery_data(struct kgsl_device *device,
- struct adreno_recovery_data *rec_data)
+static int _find_start_of_cmd_seq(struct adreno_ringbuffer *rb,
+ unsigned int *ptr,
+ bool inc)
+{
+ int status = -EINVAL;
+ unsigned int val1;
+ unsigned int size = rb->buffer_desc.size;
+ unsigned int start_ptr = *ptr;
+
+ while ((start_ptr / sizeof(unsigned int)) != rb->wptr) {
+ if (inc)
+ start_ptr = adreno_ringbuffer_inc_wrapped(start_ptr,
+ size);
+ else
+ start_ptr = adreno_ringbuffer_dec_wrapped(start_ptr,
+ size);
+ kgsl_sharedmem_readl(&rb->buffer_desc, &val1, start_ptr);
+ if (KGSL_CMD_IDENTIFIER == val1) {
+ if ((start_ptr / sizeof(unsigned int)) != rb->wptr)
+ start_ptr = adreno_ringbuffer_dec_wrapped(
+ start_ptr, size);
+ *ptr = start_ptr;
+ status = 0;
+ break;
+ }
+ }
+ return status;
+}
+
+static int _find_cmd_seq_after_eop_ts(struct adreno_ringbuffer *rb,
+ unsigned int *rb_rptr,
+ unsigned int global_eop,
+ bool inc)
+{
+ int status = -EINVAL;
+ unsigned int temp_rb_rptr = *rb_rptr;
+ unsigned int size = rb->buffer_desc.size;
+ unsigned int val[3];
+ int i = 0;
+ bool check = false;
+
+ if (inc && temp_rb_rptr / sizeof(unsigned int) != rb->wptr)
+ return status;
+
+ do {
+ /*
+ * when decrementing we need to decrement first and
+ * then read make sure we cover all the data
+ */
+ if (!inc)
+ temp_rb_rptr = adreno_ringbuffer_dec_wrapped(
+ temp_rb_rptr, size);
+ kgsl_sharedmem_readl(&rb->buffer_desc, &val[i],
+ temp_rb_rptr);
+
+ if (check && ((inc && val[i] == global_eop) ||
+ (!inc && (val[i] ==
+ cp_type3_packet(CP_MEM_WRITE, 2) ||
+ val[i] == CACHE_FLUSH_TS)))) {
+ /* decrement i, i.e i = (i - 1 + 3) % 3 if
+ * we are going forward, else increment i */
+ i = (i + 2) % 3;
+ if (val[i] == rb->device->memstore.gpuaddr +
+ KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
+ eoptimestamp)) {
+ int j = ((i + 2) % 3);
+ if ((inc && (val[j] == CACHE_FLUSH_TS ||
+ val[j] == cp_type3_packet(
+ CP_MEM_WRITE, 2))) ||
+ (!inc && val[j] == global_eop)) {
+ /* Found the global eop */
+ status = 0;
+ break;
+ }
+ }
+ /* if no match found then increment i again
+ * since we decremented before matching */
+ i = (i + 1) % 3;
+ }
+ if (inc)
+ temp_rb_rptr = adreno_ringbuffer_inc_wrapped(
+ temp_rb_rptr, size);
+
+ i = (i + 1) % 3;
+ if (2 == i)
+ check = true;
+ } while (temp_rb_rptr / sizeof(unsigned int) != rb->wptr);
+ /* temp_rb_rptr points to the command stream after global eop,
+ * move backward till the start of command sequence */
+ if (!status) {
+ status = _find_start_of_cmd_seq(rb, &temp_rb_rptr, false);
+ if (!status) {
+ *rb_rptr = temp_rb_rptr;
+ KGSL_FT_INFO(rb->device,
+ "Offset of cmd sequence after eop timestamp: 0x%x\n",
+ temp_rb_rptr / sizeof(unsigned int));
+ }
+ }
+ if (status)
+ KGSL_FT_ERR(rb->device,
+ "Failed to find the command sequence after eop timestamp\n");
+ return status;
+}
+
+static int _find_hanging_ib_sequence(struct adreno_ringbuffer *rb,
+ unsigned int *rb_rptr,
+ unsigned int ib1)
+{
+ int status = -EINVAL;
+ unsigned int temp_rb_rptr = *rb_rptr;
+ unsigned int size = rb->buffer_desc.size;
+ unsigned int val[2];
+ int i = 0;
+ bool check = false;
+ bool ctx_switch = false;
+
+ while (temp_rb_rptr / sizeof(unsigned int) != rb->wptr) {
+ kgsl_sharedmem_readl(&rb->buffer_desc, &val[i], temp_rb_rptr);
+
+ if (check && val[i] == ib1) {
+ /* decrement i, i.e i = (i - 1 + 2) % 2 */
+ i = (i + 1) % 2;
+ if (adreno_cmd_is_ib(val[i])) {
+ /* go till start of command sequence */
+ status = _find_start_of_cmd_seq(rb,
+ &temp_rb_rptr, false);
+
+ KGSL_FT_INFO(rb->device,
+ "Found the hanging IB at offset 0x%x\n",
+ temp_rb_rptr / sizeof(unsigned int));
+ break;
+ }
+ /* if no match the increment i since we decremented
+ * before checking */
+ i = (i + 1) % 2;
+ }
+ /* Make sure you do not encounter a context switch twice, we can
+ * encounter it once for the bad context as the start of search
+ * can point to the context switch */
+ if (val[i] == KGSL_CONTEXT_TO_MEM_IDENTIFIER) {
+ if (ctx_switch) {
+ KGSL_FT_ERR(rb->device,
+ "Context switch encountered before bad "
+ "IB found\n");
+ break;
+ }
+ ctx_switch = true;
+ }
+ i = (i + 1) % 2;
+ if (1 == i)
+ check = true;
+ temp_rb_rptr = adreno_ringbuffer_inc_wrapped(temp_rb_rptr,
+ size);
+ }
+ if (!status)
+ *rb_rptr = temp_rb_rptr;
+ return status;
+}
+
+static void adreno_setup_ft_data(struct kgsl_device *device,
+ struct adreno_ft_data *ft_data)
{
int ret = 0;
- unsigned int ib1_sz, ib2_sz;
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
+ struct kgsl_context *context;
+ struct adreno_context *adreno_context;
+ unsigned int rb_rptr = rb->wptr * sizeof(unsigned int);
- memset(rec_data, 0, sizeof(*rec_data));
+ memset(ft_data, 0, sizeof(*ft_data));
+ ft_data->start_of_replay_cmds = 0xFFFFFFFF;
+ ft_data->replay_for_snapshot = 0xFFFFFFFF;
- adreno_regread(device, REG_CP_IB1_BUFSZ, &ib1_sz);
- adreno_regread(device, REG_CP_IB2_BUFSZ, &ib2_sz);
- if (ib1_sz || ib2_sz)
- adreno_regread(device, REG_CP_IB1_BASE, &rec_data->ib1);
+ adreno_regread(device, REG_CP_IB1_BASE, &ft_data->ib1);
- kgsl_sharedmem_readl(&device->memstore, &rec_data->context_id,
+ kgsl_sharedmem_readl(&device->memstore, &ft_data->context_id,
KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
current_context));
kgsl_sharedmem_readl(&device->memstore,
- &rec_data->global_eop,
- KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
- eoptimestamp));
+ &ft_data->global_eop,
+ KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
+ eoptimestamp));
- rec_data->rb_buffer = vmalloc(rb->buffer_desc.size);
- if (!rec_data->rb_buffer) {
+ ft_data->rb_buffer = vmalloc(rb->buffer_desc.size);
+ if (!ft_data->rb_buffer) {
KGSL_MEM_ERR(device, "vmalloc(%d) failed\n",
rb->buffer_desc.size);
- return -ENOMEM;
+ return;
}
- rec_data->bad_rb_buffer = vmalloc(rb->buffer_desc.size);
- if (!rec_data->bad_rb_buffer) {
+ ft_data->bad_rb_buffer = vmalloc(rb->buffer_desc.size);
+ if (!ft_data->bad_rb_buffer) {
KGSL_MEM_ERR(device, "vmalloc(%d) failed\n",
rb->buffer_desc.size);
- ret = -ENOMEM;
- goto done;
+ return;
}
- rec_data->fault = device->mmu.fault;
-done:
+ ft_data->good_rb_buffer = vmalloc(rb->buffer_desc.size);
+ if (!ft_data->good_rb_buffer) {
+ KGSL_MEM_ERR(device, "vmalloc(%d) failed\n",
+ rb->buffer_desc.size);
+ return;
+ }
+ ft_data->status = 0;
+
+ /* find the start of bad command sequence in rb */
+ context = idr_find(&device->context_idr, ft_data->context_id);
+ /* Look for the command stream that is right after the global eop */
+
+ if (!context) {
+ /*
+ * If there is no context then fault tolerance does not need to
+ * replay anything, just reset GPU and thats it
+ */
+ return;
+ }
+
+ ft_data->ft_policy = adreno_dev->ft_policy;
+
+ if (!ft_data->ft_policy)
+ ft_data->ft_policy = KGSL_FT_DEFAULT_POLICY;
+
+ ret = _find_cmd_seq_after_eop_ts(rb, &rb_rptr,
+ ft_data->global_eop + 1, false);
if (ret) {
- vfree(rec_data->rb_buffer);
- vfree(rec_data->bad_rb_buffer);
+ ft_data->ft_policy |= KGSL_FT_TEMP_DISABLE;
+ return;
+ } else
+ ft_data->ft_policy &= ~KGSL_FT_TEMP_DISABLE;
+
+ ft_data->start_of_replay_cmds = rb_rptr;
+
+ adreno_context = context->devctxt;
+ if (adreno_context->flags & CTXT_FLAGS_PREAMBLE) {
+ if (ft_data->ib1) {
+ ret = _find_hanging_ib_sequence(rb,
+ &rb_rptr, ft_data->ib1);
+ if (ret) {
+ KGSL_FT_ERR(device,
+ "Start not found for replay IB sequence\n");
+ ret = 0;
+ return;
+ }
+ ft_data->start_of_replay_cmds = rb_rptr;
+ ft_data->replay_for_snapshot = rb_rptr;
+ }
}
- return ret;
}
static int
-_adreno_recover_hang(struct kgsl_device *device,
- struct adreno_recovery_data *rec_data,
- bool try_bad_commands)
+_adreno_check_long_ib(struct kgsl_device *device)
{
- int ret;
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
- struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
- struct kgsl_context *context;
- struct adreno_context *adreno_context = NULL;
- struct adreno_context *last_active_ctx = adreno_dev->drawctxt_active;
+ unsigned int curr_global_ts = 0;
- context = idr_find(&device->context_idr, rec_data->context_id);
- if (context == NULL) {
- KGSL_DRV_ERR(device, "Last context unknown id:%d\n",
- rec_data->context_id);
+ /* check if the global ts is still the same */
+ kgsl_sharedmem_readl(&device->memstore,
+ &curr_global_ts,
+ KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
+ eoptimestamp));
+
+ /* Mark long ib as handled */
+ adreno_dev->long_ib = 0;
+
+ if (curr_global_ts == adreno_dev->long_ib_ts) {
+ KGSL_FT_ERR(device,
+ "IB ran too long, invalidate ctxt\n");
+ return 1;
} else {
- adreno_context = context->devctxt;
- adreno_context->flags |= CTXT_FLAGS_GPU_HANG;
- /*
- * set the invalid ts flag to 0 for this context since we have
- * detected a hang for it
- */
- context->wait_on_invalid_ts = false;
+ /* Do nothing GPU has gone ahead */
+ KGSL_FT_INFO(device, "false long ib detection return\n");
+ return 0;
}
+}
- /* Extract valid contents from rb which can still be executed after
- * hang */
- ret = adreno_ringbuffer_extract(rb, rec_data);
- if (ret)
- goto done;
+static int
+_adreno_ft_restart_device(struct kgsl_device *device,
+ struct kgsl_context *context)
+{
+
+ struct adreno_context *adreno_context = context->devctxt;
/* restart device */
- ret = adreno_stop(device);
- if (ret) {
- KGSL_DRV_ERR(device, "Device stop failed in recovery\n");
- goto done;
+ if (adreno_stop(device)) {
+ KGSL_FT_ERR(device, "Device stop failed\n");
+ return 1;
}
- ret = adreno_start(device, true);
- if (ret) {
- KGSL_DRV_ERR(device, "Device start failed in recovery\n");
- goto done;
+ if (adreno_start(device, true)) {
+ KGSL_FT_ERR(device, "Device start failed\n");
+ return 1;
}
if (context)
@@ -1516,83 +1724,284 @@
/* If iommu is used then we need to make sure that the iommu clocks
* are on since there could be commands in pipeline that touch iommu */
if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_get_mmutype()) {
- ret = kgsl_mmu_enable_clk(&device->mmu,
- KGSL_IOMMU_CONTEXT_USER);
- if (ret)
- goto done;
+ if (kgsl_mmu_enable_clk(&device->mmu,
+ KGSL_IOMMU_CONTEXT_USER))
+ return 1;
}
- /* Do not try the bad commands if recovery has failed bad commands
- * once already or if hang is due to a fault */
- if (!try_bad_commands || rec_data->fault)
- rec_data->bad_rb_size = 0;
+ return 0;
+}
- if (rec_data->bad_rb_size) {
- int idle_ret;
- /* submit the bad and good context commands and wait for
- * them to pass */
- adreno_ringbuffer_restore(rb, rec_data->bad_rb_buffer,
- rec_data->bad_rb_size);
- idle_ret = adreno_idle(device);
- if (idle_ret) {
- ret = adreno_stop(device);
- if (ret) {
- KGSL_DRV_ERR(device,
- "Device stop failed in recovery\n");
- goto done;
- }
- ret = adreno_start(device, true);
- if (ret) {
- KGSL_DRV_ERR(device,
- "Device start failed in recovery\n");
- goto done;
- }
- if (context)
- kgsl_mmu_setstate(&device->mmu,
- adreno_context->pagetable,
- KGSL_MEMSTORE_GLOBAL);
+static inline void
+_adreno_debug_ft_info(struct kgsl_device *device,
+ struct adreno_ft_data *ft_data)
+{
- if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_get_mmutype()) {
- ret = kgsl_mmu_enable_clk(&device->mmu,
- KGSL_IOMMU_CONTEXT_USER);
- if (ret)
- goto done;
- }
+ /*
+ * Dumping rb is a very useful tool to debug FT.
+ * It will tell us if we are extracting the rb correctly
+ * NOP'ing the right IB, skipping the EOF correctly etc.
+ */
+ if (device->ft_log >= 7) {
- ret = idle_ret;
- KGSL_DRV_ERR(device,
- "Bad context commands hung in recovery\n");
- } else {
- KGSL_DRV_ERR(device,
- "Bad context commands succeeded in recovery\n");
- if (adreno_context)
- adreno_context->flags = (adreno_context->flags &
- ~CTXT_FLAGS_GPU_HANG) |
- CTXT_FLAGS_GPU_HANG_RECOVERED;
- adreno_dev->drawctxt_active = last_active_ctx;
- }
+ /* Print fault tolerance data here */
+ KGSL_FT_INFO(device, "Temp RB buffer size 0x%X\n",
+ ft_data->rb_size);
+ adreno_dump_rb(device, ft_data->rb_buffer,
+ ft_data->rb_size<<2, 0, ft_data->rb_size);
+
+ KGSL_FT_INFO(device, "Bad RB buffer size 0x%X\n",
+ ft_data->bad_rb_size);
+ adreno_dump_rb(device, ft_data->bad_rb_buffer,
+ ft_data->bad_rb_size<<2, 0, ft_data->bad_rb_size);
+
+ KGSL_FT_INFO(device, "Good RB buffer size 0x%X\n",
+ ft_data->good_rb_size);
+ adreno_dump_rb(device, ft_data->good_rb_buffer,
+ ft_data->good_rb_size<<2, 0, ft_data->good_rb_size);
+
}
- /* If either the bad command sequence failed or we did not play it */
- if (ret || !rec_data->bad_rb_size) {
- adreno_ringbuffer_restore(rb, rec_data->rb_buffer,
- rec_data->rb_size);
+}
+
+static int
+_adreno_ft_resubmit_rb(struct kgsl_device *device,
+ struct adreno_ringbuffer *rb,
+ struct kgsl_context *context,
+ struct adreno_ft_data *ft_data,
+ unsigned int *buff, unsigned int size)
+{
+ unsigned int ret = 0;
+ unsigned int retry_num = 0;
+
+ _adreno_debug_ft_info(device, ft_data);
+
+ do {
+ ret = _adreno_ft_restart_device(device, context);
+ if (ret == 0)
+ break;
+ /*
+ * If device restart fails sleep for 20ms before
+ * attempting restart. This allows GPU HW to settle
+ * and improve the chances of next restart to be
+ * successful.
+ */
+ msleep(20);
+ KGSL_FT_ERR(device, "Retry device restart %d\n", retry_num);
+ retry_num++;
+ } while (retry_num < 4);
+
+ if (ret) {
+ KGSL_FT_ERR(device, "Device restart failed\n");
+ BUG_ON(1);
+ goto done;
+ }
+
+ if (size) {
+
+ /* submit commands and wait for them to pass */
+ adreno_ringbuffer_restore(rb, buff, size);
+
ret = adreno_idle(device);
- if (ret) {
- /* If we fail here we can try to invalidate another
- * context and try recovering again */
- ret = -EAGAIN;
- goto done;
+ }
+
+done:
+ return ret;
+}
+
+
+static int
+_adreno_ft(struct kgsl_device *device,
+ struct adreno_ft_data *ft_data)
+{
+ int ret = 0, i;
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
+ struct kgsl_context *context;
+ struct adreno_context *adreno_context = NULL;
+ struct adreno_context *last_active_ctx = adreno_dev->drawctxt_active;
+ unsigned int long_ib = 0;
+
+ context = idr_find(&device->context_idr, ft_data->context_id);
+ if (context == NULL) {
+ KGSL_FT_ERR(device, "Last context unknown id:%d\n",
+ ft_data->context_id);
+ goto play_good_cmds;
+ } else {
+ adreno_context = context->devctxt;
+ adreno_context->flags |= CTXT_FLAGS_GPU_HANG;
+ /*
+ * set the invalid ts flag to 0 for this context since we have
+ * detected a hang for it
+ */
+ context->wait_on_invalid_ts = false;
+
+ if (!(adreno_context->flags & CTXT_FLAGS_PER_CONTEXT_TS)) {
+ KGSL_FT_ERR(device, "Fault tolerance not supported\n");
+ goto play_good_cmds;
}
- /* ringbuffer now has data from the last valid context id,
- * so restore the active_ctx to the last valid context */
- if (rec_data->last_valid_ctx_id) {
- struct kgsl_context *last_ctx =
- idr_find(&device->context_idr,
- rec_data->last_valid_ctx_id);
- if (last_ctx)
- adreno_dev->drawctxt_active = last_ctx->devctxt;
+
+ /*
+ * This flag will be set by userspace for contexts
+ * that do not want to be fault tolerant (ex: OPENCL)
+ */
+ if (adreno_context->flags & CTXT_FLAGS_NO_FAULT_TOLERANCE) {
+ ft_data->status = 1;
+ KGSL_FT_ERR(device,
+ "No FT set for this context play good cmds\n");
+ goto play_good_cmds;
+ }
+
+ }
+
+ /* Check if we detected a long running IB, if false return */
+ if (adreno_dev->long_ib) {
+ long_ib = _adreno_check_long_ib(device);
+ if (!long_ib) {
+ adreno_context->flags &= ~CTXT_FLAGS_GPU_HANG;
+ return 0;
}
}
+
+ /*
+ * Extract valid contents from rb which can still be executed after
+ * hang
+ */
+ adreno_ringbuffer_extract(rb, ft_data);
+
+ /* If long IB detected do not attempt replay of bad cmds */
+ if (long_ib) {
+ _adreno_debug_ft_info(device, ft_data);
+ goto play_good_cmds;
+ }
+
+ if ((ft_data->ft_policy & KGSL_FT_DISABLE) ||
+ (ft_data->ft_policy & KGSL_FT_TEMP_DISABLE)) {
+ KGSL_FT_ERR(device, "NO FT policy play only good cmds\n");
+ ft_data->status = 1;
+ goto play_good_cmds;
+ }
+
+ /* Do not try the reply if hang is due to a pagefault */
+ if (adreno_context->pagefault) {
+ if ((ft_data->context_id == adreno_context->id) &&
+ (ft_data->global_eop == adreno_context->pagefault_ts)) {
+ ft_data->ft_policy &= ~KGSL_FT_REPLAY;
+ KGSL_FT_ERR(device, "MMU fault skipping replay\n");
+ }
+
+ adreno_context->pagefault = 0;
+ }
+
+ if (ft_data->ft_policy & KGSL_FT_REPLAY) {
+ ret = _adreno_ft_resubmit_rb(device, rb, context, ft_data,
+ ft_data->bad_rb_buffer, ft_data->bad_rb_size);
+
+ if (ret) {
+ KGSL_FT_ERR(device, "Replay status: 1\n");
+ ft_data->status = 1;
+ } else
+ goto play_good_cmds;
+ }
+
+ if (ft_data->ft_policy & KGSL_FT_SKIPIB) {
+ for (i = 0; i < ft_data->bad_rb_size; i++) {
+ if ((ft_data->bad_rb_buffer[i] ==
+ CP_HDR_INDIRECT_BUFFER_PFD) &&
+ (ft_data->bad_rb_buffer[i+1] == ft_data->ib1)) {
+
+ ft_data->bad_rb_buffer[i] = cp_nop_packet(2);
+ ft_data->bad_rb_buffer[i+1] =
+ KGSL_NOP_IB_IDENTIFIER;
+ ft_data->bad_rb_buffer[i+2] =
+ KGSL_NOP_IB_IDENTIFIER;
+ break;
+ }
+ }
+
+ if ((i == (ft_data->bad_rb_size)) || (!ft_data->ib1)) {
+ KGSL_FT_ERR(device, "Bad IB to NOP not found\n");
+ ft_data->status = 1;
+ goto play_good_cmds;
+ }
+
+ ret = _adreno_ft_resubmit_rb(device, rb, context, ft_data,
+ ft_data->bad_rb_buffer, ft_data->bad_rb_size);
+
+ if (ret) {
+ KGSL_FT_ERR(device, "NOP faulty IB status: 1\n");
+ ft_data->status = 1;
+ } else {
+ ft_data->status = 0;
+ goto play_good_cmds;
+ }
+ }
+
+ if (ft_data->ft_policy & KGSL_FT_SKIPFRAME) {
+ for (i = 0; i < ft_data->bad_rb_size; i++) {
+ if (ft_data->bad_rb_buffer[i] ==
+ KGSL_END_OF_FRAME_IDENTIFIER) {
+ ft_data->bad_rb_buffer[0] = cp_nop_packet(i);
+ break;
+ }
+ }
+
+ /* EOF not found in RB, discard till EOF in
+ next IB submission */
+ if (i == ft_data->bad_rb_size) {
+ adreno_context->flags |= CTXT_FLAGS_SKIP_EOF;
+ KGSL_FT_INFO(device,
+ "EOF not found in RB, skip next issueib till EOF\n");
+ ft_data->bad_rb_buffer[0] = cp_nop_packet(i);
+ }
+
+ ret = _adreno_ft_resubmit_rb(device, rb, context, ft_data,
+ ft_data->bad_rb_buffer, ft_data->bad_rb_size);
+
+ if (ret) {
+ KGSL_FT_ERR(device, "Skip EOF status: 1\n");
+ ft_data->status = 1;
+ } else {
+ ft_data->status = 0;
+ goto play_good_cmds;
+ }
+ }
+
+play_good_cmds:
+
+ if (ft_data->status)
+ KGSL_FT_ERR(device, "Bad context commands failed\n");
+ else {
+ KGSL_FT_INFO(device, "Bad context commands success\n");
+
+ if (adreno_context) {
+ adreno_context->flags = (adreno_context->flags &
+ ~CTXT_FLAGS_GPU_HANG) | CTXT_FLAGS_GPU_HANG_FT;
+ }
+ adreno_dev->drawctxt_active = last_active_ctx;
+ }
+
+ ret = _adreno_ft_resubmit_rb(device, rb, context, ft_data,
+ ft_data->good_rb_buffer, ft_data->good_rb_size);
+
+ if (ret) {
+ /* If we fail here we can try to invalidate another
+ * context and try fault tolerance again */
+ ret = -EAGAIN;
+ KGSL_FT_ERR(device, "Playing good commands unsuccessful\n");
+ goto done;
+ } else
+ KGSL_FT_INFO(device, "Playing good commands successful\n");
+
+ /* ringbuffer now has data from the last valid context id,
+ * so restore the active_ctx to the last valid context */
+ if (ft_data->last_valid_ctx_id) {
+ struct kgsl_context *last_ctx =
+ idr_find(&device->context_idr,
+ ft_data->last_valid_ctx_id);
+ if (last_ctx)
+ adreno_dev->drawctxt_active = last_ctx->devctxt;
+ }
+
done:
/* Turn off iommu clocks */
if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_get_mmutype())
@@ -1601,40 +2010,38 @@
}
static int
-adreno_recover_hang(struct kgsl_device *device,
- struct adreno_recovery_data *rec_data)
+adreno_ft(struct kgsl_device *device,
+ struct adreno_ft_data *ft_data)
{
int ret = 0;
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
unsigned int timestamp;
- KGSL_DRV_ERR(device,
- "Starting recovery from 3D GPU hang. Recovery parameters: IB1: 0x%X, "
+ KGSL_FT_INFO(device,
+ "Start Parameters: IB1: 0x%X, "
"Bad context_id: %u, global_eop: 0x%x\n",
- rec_data->ib1, rec_data->context_id, rec_data->global_eop);
+ ft_data->ib1, ft_data->context_id, ft_data->global_eop);
timestamp = rb->timestamp[KGSL_MEMSTORE_GLOBAL];
- KGSL_DRV_ERR(device, "Last issued global timestamp: %x\n", timestamp);
+ KGSL_FT_INFO(device, "Last issued global timestamp: %x\n", timestamp);
/* We may need to replay commands multiple times based on whether
* multiple contexts hang the GPU */
while (true) {
- if (!ret)
- ret = _adreno_recover_hang(device, rec_data, true);
- else
- ret = _adreno_recover_hang(device, rec_data, false);
+
+ ret = _adreno_ft(device, ft_data);
if (-EAGAIN == ret) {
- /* setup new recovery parameters and retry, this
+ /* setup new fault tolerance parameters and retry, this
* means more than 1 contexts are causing hang */
- adreno_destroy_recovery_data(rec_data);
- adreno_setup_recovery_data(device, rec_data);
- KGSL_DRV_ERR(device,
- "Retry recovery from 3D GPU hang. Recovery parameters: "
+ adreno_destroy_ft_data(ft_data);
+ adreno_setup_ft_data(device, ft_data);
+ KGSL_FT_INFO(device,
+ "Retry. Parameters: "
"IB1: 0x%X, Bad context_id: %u, global_eop: 0x%x\n",
- rec_data->ib1, rec_data->context_id,
- rec_data->global_eop);
+ ft_data->ib1, ft_data->context_id,
+ ft_data->global_eop);
} else {
break;
}
@@ -1643,7 +2050,7 @@
if (ret)
goto done;
- /* Restore correct states after recovery */
+ /* Restore correct states after fault tolerance */
if (adreno_dev->drawctxt_active)
device->mmu.hwpagetable =
adreno_dev->drawctxt_active->pagetable;
@@ -1662,34 +2069,39 @@
done:
adreno_set_max_ts_for_bad_ctxs(device);
adreno_mark_context_status(device, ret);
- if (!ret)
- KGSL_DRV_ERR(device, "Recovery succeeded\n");
- else
- KGSL_DRV_ERR(device, "Recovery failed\n");
+ KGSL_FT_ERR(device, "policy 0x%X status 0x%x\n",
+ ft_data->ft_policy, ret);
return ret;
}
int
-adreno_dump_and_recover(struct kgsl_device *device)
+adreno_dump_and_exec_ft(struct kgsl_device *device)
{
int result = -ETIMEDOUT;
- struct adreno_recovery_data rec_data;
+ struct adreno_ft_data ft_data;
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ struct kgsl_pwrctrl *pwr = &device->pwrctrl;
+ unsigned int curr_pwrlevel;
if (device->state == KGSL_STATE_HUNG)
goto done;
- if (device->state == KGSL_STATE_DUMP_AND_RECOVER) {
+ if (device->state == KGSL_STATE_DUMP_AND_FT) {
mutex_unlock(&device->mutex);
- wait_for_completion(&device->recovery_gate);
+ wait_for_completion(&device->ft_gate);
mutex_lock(&device->mutex);
if (device->state != KGSL_STATE_HUNG)
result = 0;
} else {
- kgsl_pwrctrl_set_state(device, KGSL_STATE_DUMP_AND_RECOVER);
- INIT_COMPLETION(device->recovery_gate);
+ kgsl_pwrctrl_set_state(device, KGSL_STATE_DUMP_AND_FT);
+ INIT_COMPLETION(device->ft_gate);
/* Detected a hang */
- /* Get the recovery data as soon as hang is detected */
- result = adreno_setup_recovery_data(device, &rec_data);
+ /* Run fault tolerance at max power level */
+ curr_pwrlevel = pwr->active_pwrlevel;
+ kgsl_pwrctrl_pwrlevel_change(device, pwr->max_pwrlevel);
+
+ /* Get the fault tolerance data as soon as hang is detected */
+ adreno_setup_ft_data(device, &ft_data);
/*
* Trigger an automatic dump of the state to
* the console
@@ -1697,25 +2109,43 @@
kgsl_postmortem_dump(device, 0);
/*
- * Make a GPU snapshot. For now, do it after the PM dump so we
- * can at least be sure the PM dump will work as it always has
+ * If long ib is detected, do not attempt postmortem or
+ * snapshot, if GPU is still executing commands
+ * we will get errors
*/
- kgsl_device_snapshot(device, 1);
+ if (!adreno_dev->long_ib) {
+ /*
+ * Trigger an automatic dump of the state to
+ * the console
+ */
+ kgsl_postmortem_dump(device, 0);
- result = adreno_recover_hang(device, &rec_data);
- adreno_destroy_recovery_data(&rec_data);
+ /*
+ * Make a GPU snapshot. For now, do it after the
+ * PM dump so we can at least be sure the PM dump
+ * will work as it always has
+ */
+ kgsl_device_snapshot(device, 1);
+ }
+
+ result = adreno_ft(device, &ft_data);
+ adreno_destroy_ft_data(&ft_data);
+
+ /* restore power level */
+ kgsl_pwrctrl_pwrlevel_change(device, curr_pwrlevel);
+
if (result) {
kgsl_pwrctrl_set_state(device, KGSL_STATE_HUNG);
} else {
kgsl_pwrctrl_set_state(device, KGSL_STATE_ACTIVE);
mod_timer(&device->idle_timer, jiffies + FIRST_TIMEOUT);
}
- complete_all(&device->recovery_gate);
+ complete_all(&device->ft_gate);
}
done:
return result;
}
-EXPORT_SYMBOL(adreno_dump_and_recover);
+EXPORT_SYMBOL(adreno_dump_and_exec_ft);
static int adreno_getproperty(struct kgsl_device *device,
enum kgsl_property_type type,
@@ -1882,7 +2312,7 @@
do {
if (time_after(jiffies, wait)) {
/* Check to see if the core is hung */
- if (adreno_hang_detect(device, regs))
+ if (adreno_ft_detect(device, regs))
return -ETIMEDOUT;
wait = jiffies + msecs_to_jiffies(KGSL_TIMEOUT_PART);
@@ -1906,7 +2336,7 @@
unsigned int rbbm_status;
unsigned long wait_time;
unsigned long wait_time_part;
- unsigned int prev_reg_val[hang_detect_regs_count];
+ unsigned int prev_reg_val[ft_detect_regs_count];
memset(prev_reg_val, 0, sizeof(prev_reg_val));
@@ -1939,7 +2369,7 @@
if (time_after(jiffies, wait_time_part)) {
wait_time_part = jiffies +
msecs_to_jiffies(KGSL_TIMEOUT_PART);
- if ((adreno_hang_detect(device, prev_reg_val)))
+ if ((adreno_ft_detect(device, prev_reg_val)))
goto err;
}
@@ -1947,9 +2377,9 @@
err:
KGSL_DRV_ERR(device, "spun too long waiting for RB to idle\n");
- if (KGSL_STATE_DUMP_AND_RECOVER != device->state &&
- !adreno_dump_and_recover(device)) {
- wait_time = jiffies + msecs_to_jiffies(ADRENO_IDLE_TIMEOUT);
+ if (KGSL_STATE_DUMP_AND_FT != device->state &&
+ !adreno_dump_and_exec_ft(device)) {
+ wait_time = jiffies + ADRENO_IDLE_TIMEOUT;
goto retry;
}
return -ETIMEDOUT;
@@ -2297,16 +2727,28 @@
-unsigned int adreno_hang_detect(struct kgsl_device *device,
+unsigned int adreno_ft_detect(struct kgsl_device *device,
unsigned int *prev_reg_val)
{
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
- unsigned int curr_reg_val[hang_detect_regs_count];
- unsigned int hang_detected = 1;
+ unsigned int curr_reg_val[ft_detect_regs_count];
+ unsigned int fast_hang_detected = 1;
+ unsigned int long_ib_detected = 1;
unsigned int i;
static unsigned long next_hang_detect_time;
+ static unsigned int prev_global_ts;
+ unsigned int curr_global_ts = 0;
+ unsigned int curr_context_id = 0;
+ static struct adreno_context *curr_context;
+ static struct kgsl_context *context;
if (!adreno_dev->fast_hang_detect)
+ fast_hang_detected = 0;
+
+ if (!adreno_dev->long_ib_detect)
+ long_ib_detected = 0;
+
+ if (!(adreno_dev->ringbuffer.flags & KGSL_FLAGS_STARTED))
return 0;
if (is_adreno_rbbm_status_idle(device)) {
@@ -2340,20 +2782,125 @@
next_hang_detect_time = (jiffies +
msecs_to_jiffies(KGSL_TIMEOUT_PART-1));
- for (i = 0; i < hang_detect_regs_count; i++) {
-
- if (hang_detect_regs[i] == 0)
+ /* Read the current Hang detect reg values here */
+ for (i = 0; i < ft_detect_regs_count; i++) {
+ if (ft_detect_regs[i] == 0)
continue;
-
- adreno_regread(device, hang_detect_regs[i],
- &curr_reg_val[i]);
- if (curr_reg_val[i] != prev_reg_val[i]) {
- prev_reg_val[i] = curr_reg_val[i];
- hang_detected = 0;
- }
+ adreno_regread(device, ft_detect_regs[i],
+ &curr_reg_val[i]);
}
- return hang_detected;
+ /* Read the current global timestamp here */
+ kgsl_sharedmem_readl(&device->memstore,
+ &curr_global_ts,
+ KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
+ eoptimestamp));
+ /* Make sure the memstore read has posted */
+ mb();
+
+ if (curr_global_ts == prev_global_ts) {
+
+ /* Get the current context here */
+ if (context == NULL) {
+ kgsl_sharedmem_readl(&device->memstore,
+ &curr_context_id,
+ KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
+ current_context));
+ /* Make sure the memstore read has posted */
+ mb();
+ context = idr_find(&device->context_idr,
+ curr_context_id);
+ if (context != NULL) {
+ curr_context = context->devctxt;
+ curr_context->ib_gpu_time_used = 0;
+ } else {
+ KGSL_DRV_ERR(device,
+ "Fault tolerance no context found\n");
+ }
+ }
+
+ if (curr_context != NULL) {
+
+ curr_context->ib_gpu_time_used += KGSL_TIMEOUT_PART;
+ KGSL_FT_INFO(device,
+ "Proc %s used GPU Time %d ms on timestamp 0x%X\n",
+ curr_context->pid_name, curr_context->ib_gpu_time_used,
+ curr_global_ts+1);
+
+ for (i = 0; i < ft_detect_regs_count; i++) {
+ if (curr_reg_val[i] != prev_reg_val[i]) {
+ fast_hang_detected = 0;
+
+ /* Check for long IB here */
+ if ((i >=
+ LONG_IB_DETECT_REG_INDEX_START)
+ &&
+ (i <=
+ LONG_IB_DETECT_REG_INDEX_END))
+ long_ib_detected = 0;
+ }
+ }
+
+ if (fast_hang_detected) {
+ KGSL_FT_ERR(device,
+ "Proc %s, ctxt_id %d ts %d triggered fault tolerance"
+ " on global ts %d\n",
+ curr_context->pid_name, curr_context->id
+ , (kgsl_readtimestamp(device, context,
+ KGSL_TIMESTAMP_RETIRED)+1),
+ curr_global_ts+1);
+ return 1;
+ }
+
+ if ((long_ib_detected) &&
+ (!(curr_context->flags &
+ CTXT_FLAGS_NO_FAULT_TOLERANCE))) {
+ curr_context->ib_gpu_time_used +=
+ KGSL_TIMEOUT_PART;
+ if (curr_context->ib_gpu_time_used >
+ KGSL_TIMEOUT_LONG_IB_DETECTION) {
+ if (adreno_dev->long_ib_ts !=
+ curr_global_ts) {
+ KGSL_FT_ERR(device,
+ "Proc %s, ctxt_id %d ts %d"
+ "used GPU for %d ms long ib "
+ "detected on global ts %d\n",
+ curr_context->pid_name,
+ curr_context->id,
+ (kgsl_readtimestamp(device,
+ context,
+ KGSL_TIMESTAMP_RETIRED)+1),
+ curr_context->ib_gpu_time_used,
+ curr_global_ts+1);
+ adreno_dev->long_ib = 1;
+ adreno_dev->long_ib_ts =
+ curr_global_ts;
+ curr_context->ib_gpu_time_used =
+ 0;
+ return 1;
+ }
+ }
+ }
+ } else {
+ KGSL_FT_ERR(device,
+ "Last context unknown id:%d\n",
+ curr_context_id);
+ }
+ } else {
+ /* GPU is moving forward */
+ prev_global_ts = curr_global_ts;
+ context = NULL;
+ curr_context = NULL;
+ adreno_dev->long_ib = 0;
+ adreno_dev->long_ib_ts = 0;
+ }
+
+
+ /* If hangs are not detected copy the current reg values
+ * to previous values and return no hang */
+ for (i = 0; i < ft_detect_regs_count; i++)
+ prev_reg_val[i] = curr_reg_val[i];
+ return 0;
}
/**
@@ -2362,7 +2909,8 @@
* @context - pointer to the active KGSL context
* @timestamp - the timestamp that the process was waiting for
*
- * Process a possible GPU hang and try to recover from it cleanly
+ * Process a possible GPU hang and try fault tolerance from it
+ * cleanly
*/
static int adreno_handle_hang(struct kgsl_device *device,
struct kgsl_context *context, unsigned int timestamp)
@@ -2370,6 +2918,7 @@
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
unsigned int context_id = _get_context_id(context);
unsigned int ts_issued;
+ unsigned int rptr;
/* Do one last check to see if we somehow made it through */
if (kgsl_check_timestamp(device, context, timestamp))
@@ -2377,15 +2926,22 @@
ts_issued = adreno_dev->ringbuffer.timestamp[context_id];
- KGSL_DRV_ERR(device,
+ adreno_regread(device, REG_CP_RB_RPTR, &rptr);
+
+ /* Make sure timestamp check finished before triggering a hang */
+ mb();
+
+ KGSL_DRV_WARN(device,
"Device hang detected while waiting for timestamp: "
"<%d:0x%x>, last submitted timestamp: <%d:0x%x>, "
- "wptr: 0x%x\n",
- context_id, timestamp, context_id, ts_issued,
- adreno_dev->ringbuffer.wptr);
+ "retired timestamp: <%d:0x%x>, wptr: 0x%x, rptr: 0x%x\n",
+ context_id, timestamp, context_id, ts_issued, context_id,
+ kgsl_readtimestamp(device, context,
+ KGSL_TIMESTAMP_RETIRED),
+ adreno_dev->ringbuffer.wptr, rptr);
- /* Return 0 after a successful recovery */
- if (!adreno_dump_and_recover(device))
+ /* Return 0 after a successful fault tolerance */
+ if (!adreno_dump_and_exec_ft(device))
return 0;
return -ETIMEDOUT;
@@ -2439,7 +2995,7 @@
struct adreno_context *adreno_ctx = context ? context->devctxt : NULL;
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
unsigned int context_id = _get_context_id(context);
- unsigned int prev_reg_val[hang_detect_regs_count];
+ unsigned int prev_reg_val[ft_detect_regs_count];
unsigned int time_elapsed = 0;
unsigned int wait;
int ts_compare = 1;
@@ -2498,7 +3054,7 @@
}
/* Check to see if the GPU is hung */
- if (adreno_hang_detect(device, prev_reg_val)) {
+ if (adreno_ft_detect(device, prev_reg_val)) {
ret = adreno_handle_hang(device, context, timestamp);
break;
}
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index c1f2423..949ac97 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -34,6 +34,7 @@
#define KGSL_CMD_FLAGS_NONE 0x00000000
#define KGSL_CMD_FLAGS_PMODE 0x00000001
#define KGSL_CMD_FLAGS_INTERNAL_ISSUE 0x00000002
+#define KGSL_CMD_FLAGS_EOF 0x00000100
/* Command identifiers */
#define KGSL_CONTEXT_TO_MEM_IDENTIFIER 0x2EADBEEF
@@ -41,6 +42,8 @@
#define KGSL_CMD_INTERNAL_IDENTIFIER 0x2EEDD00D
#define KGSL_START_OF_IB_IDENTIFIER 0x2EADEABE
#define KGSL_END_OF_IB_IDENTIFIER 0x2ABEDEAD
+#define KGSL_END_OF_FRAME_IDENTIFIER 0x2E0F2E0F
+#define KGSL_NOP_IB_IDENTIFIER 0x20F20F20
#ifdef CONFIG_MSM_SCM
#define ADRENO_DEFAULT_PWRSCALE_POLICY (&kgsl_pwrscale_policy_tz)
@@ -101,6 +104,11 @@
unsigned int instruction_size;
unsigned int ib_check_level;
unsigned int fast_hang_detect;
+ unsigned int ft_policy;
+ unsigned int long_ib_detect;
+ unsigned int long_ib;
+ unsigned int long_ib_ts;
+ unsigned int ft_pf_policy;
unsigned int gpulist_index;
struct ocmem_buf *ocmem_hdl;
unsigned int ocmem_base;
@@ -133,8 +141,8 @@
};
/*
- * struct adreno_recovery_data - Structure that contains all information to
- * perform gpu recovery from hangs
+ * struct adreno_ft_data - Structure that contains all information to
+ * perform gpu fault tolerance
* @ib1 - IB1 that the GPU was executing when hang happened
* @context_id - Context which caused the hang
* @global_eop - eoptimestamp at time of hang
@@ -142,11 +150,19 @@
* @rb_size - Number of valid dwords in rb_buffer
* @bad_rb_buffer - Buffer that holds commands from the hanging context
* bad_rb_size - Number of valid dwords in bad_rb_buffer
+ * @good_rb_buffer - Buffer that holds commands from good contexts
+ * good_rb_size - Number of valid dwords in good_rb_buffer
* @last_valid_ctx_id - The last context from which commands were placed in
* ringbuffer before the GPU hung
+ * @step - Current fault tolerance step being executed
+ * @err_code - Fault tolerance error code
* @fault - Indicates whether the hang was caused due to a pagefault
+ * @start_of_replay_cmds - Offset in ringbuffer from where commands can be
+ * replayed during fault tolerance
+ * @replay_for_snapshot - Offset in ringbuffer where IB's can be saved for
+ * replaying with snapshot
*/
-struct adreno_recovery_data {
+struct adreno_ft_data {
unsigned int ib1;
unsigned int context_id;
unsigned int global_eop;
@@ -154,10 +170,32 @@
unsigned int rb_size;
unsigned int *bad_rb_buffer;
unsigned int bad_rb_size;
+ unsigned int *good_rb_buffer;
+ unsigned int good_rb_size;
unsigned int last_valid_ctx_id;
- int fault;
+ unsigned int status;
+ unsigned int ft_policy;
+ unsigned int err_code;
+ unsigned int start_of_replay_cmds;
+ unsigned int replay_for_snapshot;
};
+/* Fault Tolerance policy flags */
+#define KGSL_FT_DISABLE BIT(0)
+#define KGSL_FT_REPLAY BIT(1)
+#define KGSL_FT_SKIPIB BIT(2)
+#define KGSL_FT_SKIPFRAME BIT(3)
+#define KGSL_FT_TEMP_DISABLE BIT(4)
+#define KGSL_FT_DEFAULT_POLICY (KGSL_FT_REPLAY + KGSL_FT_SKIPIB)
+
+/* Pagefault policy flags */
+#define KGSL_FT_PAGEFAULT_INT_ENABLE 0x00000001
+#define KGSL_FT_PAGEFAULT_GPUHALT_ENABLE 0x00000002
+#define KGSL_FT_PAGEFAULT_LOG_ONE_PER_PAGE 0x00000004
+#define KGSL_FT_PAGEFAULT_LOG_ONE_PER_INT 0x00000008
+#define KGSL_FT_PAGEFAULT_DEFAULT_POLICY (KGSL_FT_PAGEFAULT_INT_ENABLE + \
+ KGSL_FT_PAGEFAULT_GPUHALT_ENABLE)
+
extern struct adreno_gpudev adreno_a2xx_gpudev;
extern struct adreno_gpudev adreno_a3xx_gpudev;
@@ -179,8 +217,8 @@
extern const unsigned int a330_registers[];
extern const unsigned int a330_registers_count;
-extern unsigned int hang_detect_regs[];
-extern const unsigned int hang_detect_regs_count;
+extern unsigned int ft_detect_regs[];
+extern const unsigned int ft_detect_regs_count;
int adreno_idle(struct kgsl_device *device);
@@ -211,9 +249,12 @@
void *adreno_snapshot(struct kgsl_device *device, void *snapshot, int *remain,
int hang);
-int adreno_dump_and_recover(struct kgsl_device *device);
+int adreno_dump_and_exec_ft(struct kgsl_device *device);
-unsigned int adreno_hang_detect(struct kgsl_device *device,
+void adreno_dump_rb(struct kgsl_device *device, const void *buf,
+ size_t len, int start, int size);
+
+unsigned int adreno_ft_detect(struct kgsl_device *device,
unsigned int *prev_reg_val);
static inline int adreno_is_a200(struct adreno_device *adreno_dev)
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index 08c800e..9adfe69 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -52,8 +52,8 @@
0x2240, 0x227e,
0x2280, 0x228b, 0x22c0, 0x22c0, 0x22c4, 0x22ce, 0x22d0, 0x22d8,
0x22df, 0x22e6, 0x22e8, 0x22e9, 0x22ec, 0x22ec, 0x22f0, 0x22f7,
- 0x22ff, 0x22ff, 0x2340, 0x2343, 0x2348, 0x2349, 0x2350, 0x2356,
- 0x2360, 0x2360, 0x2440, 0x2440, 0x2444, 0x2444, 0x2448, 0x244d,
+ 0x22ff, 0x22ff, 0x2340, 0x2343,
+ 0x2440, 0x2440, 0x2444, 0x2444, 0x2448, 0x244d,
0x2468, 0x2469, 0x246c, 0x246d, 0x2470, 0x2470, 0x2472, 0x2472,
0x2474, 0x2475, 0x2479, 0x247a, 0x24c0, 0x24d3, 0x24e4, 0x24ef,
0x2500, 0x2509, 0x250c, 0x250c, 0x250e, 0x250e, 0x2510, 0x2511,
@@ -61,8 +61,8 @@
0x25f0, 0x25f0,
0x2640, 0x267e, 0x2680, 0x268b, 0x26c0, 0x26c0, 0x26c4, 0x26ce,
0x26d0, 0x26d8, 0x26df, 0x26e6, 0x26e8, 0x26e9, 0x26ec, 0x26ec,
- 0x26f0, 0x26f7, 0x26ff, 0x26ff, 0x2740, 0x2743, 0x2748, 0x2749,
- 0x2750, 0x2756, 0x2760, 0x2760, 0x300C, 0x300E, 0x301C, 0x301D,
+ 0x26f0, 0x26f7, 0x26ff, 0x26ff, 0x2740, 0x2743,
+ 0x300C, 0x300E, 0x301C, 0x301D,
0x302A, 0x302A, 0x302C, 0x302D, 0x3030, 0x3031, 0x3034, 0x3036,
0x303C, 0x303C, 0x305E, 0x305F,
};
@@ -70,7 +70,7 @@
const unsigned int a3xx_registers_count = ARRAY_SIZE(a3xx_registers) / 2;
/* Removed the following HLSQ register ranges from being read during
- * recovery since reading the registers may cause the device to hang:
+ * fault tolerance since reading the registers may cause the device to hang:
*/
const unsigned int a3xx_hlsq_registers[] = {
0x0e00, 0x0e05, 0x0e0c, 0x0e0c, 0x0e22, 0x0e23,
@@ -2824,10 +2824,6 @@
{ A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303 },
/* Set up VBIF_ROUND_ROBIN_QOS_ARB */
{ A3XX_VBIF_ROUND_ROBIN_QOS_ARB, 0x0003 },
- /* Disable VBIF clock gating. This is to enable AXI running
- * higher frequency than GPU.
- */
- { A3XX_VBIF_CLKON, 1 },
{0, 0},
};
diff --git a/drivers/gpu/msm/adreno_debugfs.c b/drivers/gpu/msm/adreno_debugfs.c
index 1989ff5..ef599e9 100644
--- a/drivers/gpu/msm/adreno_debugfs.c
+++ b/drivers/gpu/msm/adreno_debugfs.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2008-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2008-2013, 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
@@ -64,5 +64,33 @@
adreno_dev->fast_hang_detect = 1;
debugfs_create_u32("fast_hang_detect", 0644, device->d_debugfs,
&adreno_dev->fast_hang_detect);
+ /*
+ * FT policy can be set to any of the options below.
+ * KGSL_FT_DISABLE -> BIT(0) Set to disable FT
+ * KGSL_FT_REPLAY -> BIT(1) Set to enable replay
+ * KGSL_FT_SKIPIB -> BIT(2) Set to skip IB
+ * KGSL_FT_SKIPFRAME -> BIT(3) Set to skip frame
+ * by default set FT policy to KGSL_FT_DEFAULT_POLICY
+ */
+ adreno_dev->ft_policy = KGSL_FT_DEFAULT_POLICY;
+ debugfs_create_u32("ft_policy", 0644, device->d_debugfs,
+ &adreno_dev->ft_policy);
+ /* By default enable long IB detection */
+ adreno_dev->long_ib_detect = 1;
+ debugfs_create_u32("long_ib_detect", 0644, device->d_debugfs,
+ &adreno_dev->long_ib_detect);
+ /*
+ * FT pagefault policy can be set to any of the options below.
+ * KGSL_FT_PAGEFAULT_INT_ENABLE -> BIT(0) set to enable pagefault INT
+ * KGSL_FT_PAGEFAULT_GPUHALT_ENABLE -> BIT(1) Set to enable GPU HALT on
+ * pagefaults. This stalls the GPU on a pagefault on IOMMU v1 HW.
+ * KGSL_FT_PAGEFAULT_LOG_ONE_PER_PAGE -> BIT(2) Set to log only one
+ * pagefault per page.
+ * KGSL_FT_PAGEFAULT_LOG_ONE_PER_INT -> BIT(3) Set to log only one
+ * pagefault per INT.
+ */
+ adreno_dev->ft_pf_policy = KGSL_FT_PAGEFAULT_DEFAULT_POLICY;
+ debugfs_create_u32("ft_pagefault_policy", 0644, device->d_debugfs,
+ &adreno_dev->ft_pf_policy);
}
diff --git a/drivers/gpu/msm/adreno_drawctxt.c b/drivers/gpu/msm/adreno_drawctxt.c
index b109e14..023b057 100644
--- a/drivers/gpu/msm/adreno_drawctxt.c
+++ b/drivers/gpu/msm/adreno_drawctxt.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2007-2013, 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
@@ -155,6 +155,8 @@
if (drawctxt == NULL)
return -ENOMEM;
+ drawctxt->pid = task_pid_nr(current);
+ strlcpy(drawctxt->pid_name, current->comm, TASK_COMM_LEN);
drawctxt->pagetable = pagetable;
drawctxt->bin_base_offset = 0;
drawctxt->id = context->id;
@@ -177,6 +179,9 @@
drawctxt->flags |= CTXT_FLAGS_USER_GENERATED_TS;
}
+ if (flags & KGSL_CONTEXT_NO_FAULT_TOLERANCE)
+ drawctxt->flags |= CTXT_FLAGS_NO_FAULT_TOLERANCE;
+
ret = adreno_dev->gpudev->ctxt_create(adreno_dev, drawctxt);
if (ret)
goto err;
diff --git a/drivers/gpu/msm/adreno_drawctxt.h b/drivers/gpu/msm/adreno_drawctxt.h
index 65dbd4c..aba29ae 100644
--- a/drivers/gpu/msm/adreno_drawctxt.h
+++ b/drivers/gpu/msm/adreno_drawctxt.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2007-2013, 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
@@ -13,6 +13,8 @@
#ifndef __ADRENO_DRAWCTXT_H
#define __ADRENO_DRAWCTXT_H
+#include <linux/sched.h>
+
#include "adreno_pm4types.h"
#include "a2xx_reg.h"
@@ -44,12 +46,16 @@
#define CTXT_FLAGS_TRASHSTATE BIT(10)
/* per context timestamps enabled */
#define CTXT_FLAGS_PER_CONTEXT_TS BIT(11)
-/* Context has caused a GPU hang and recovered properly */
-#define CTXT_FLAGS_GPU_HANG_RECOVERED BIT(12)
+/* Context has caused a GPU hang and fault tolerance successful */
+#define CTXT_FLAGS_GPU_HANG_FT BIT(12)
/* Context is being destroyed so dont save it */
#define CTXT_FLAGS_BEING_DESTROYED BIT(13)
/* User mode generated timestamps enabled */
#define CTXT_FLAGS_USER_GENERATED_TS BIT(14)
+/* Context skip till EOF */
+#define CTXT_FLAGS_SKIP_EOF BIT(15)
+/* Context no fault tolerance */
+#define CTXT_FLAGS_NO_FAULT_TOLERANCE BIT(16)
struct kgsl_device;
struct adreno_device;
@@ -82,8 +88,13 @@
};
struct adreno_context {
+ pid_t pid;
+ char pid_name[TASK_COMM_LEN];
unsigned int id;
+ unsigned int ib_gpu_time_used;
uint32_t flags;
+ uint32_t pagefault;
+ unsigned long pagefault_ts;
struct kgsl_pagetable *pagetable;
struct kgsl_memdesc gpustate;
unsigned int reg_restore[3];
diff --git a/drivers/gpu/msm/adreno_postmortem.c b/drivers/gpu/msm/adreno_postmortem.c
index 2b9c286..29d689b 100644
--- a/drivers/gpu/msm/adreno_postmortem.c
+++ b/drivers/gpu/msm/adreno_postmortem.c
@@ -305,7 +305,7 @@
#endif
}
-static void adreno_dump_rb(struct kgsl_device *device, const void *buf,
+void adreno_dump_rb(struct kgsl_device *device, const void *buf,
size_t len, int start, int size)
{
const uint32_t *ptr = buf;
@@ -729,6 +729,7 @@
unsigned int ts_processed = 0xdeaddead;
struct kgsl_context *context;
unsigned int context_id;
+ unsigned int rbbm_status;
static struct ib_list ib_list;
@@ -738,12 +739,16 @@
mb();
- msm_clk_dump_debug_info();
+ if (device->pm_dump_enable) {
+ msm_clk_dump_debug_info();
- if (adreno_is_a2xx(adreno_dev))
- adreno_dump_a2xx(device);
- else if (adreno_is_a3xx(adreno_dev))
- adreno_dump_a3xx(device);
+ if (adreno_is_a2xx(adreno_dev))
+ adreno_dump_a2xx(device);
+ else if (adreno_is_a3xx(adreno_dev))
+ adreno_dump_a3xx(device);
+ }
+
+ kgsl_regread(device, adreno_dev->gpudev->reg_rbbm_status, &rbbm_status);
pt_base = kgsl_mmu_get_current_ptbase(&device->mmu);
cur_pt_base = pt_base;
@@ -758,6 +763,18 @@
kgsl_regread(device, REG_CP_IB2_BASE, &cp_ib2_base);
kgsl_regread(device, REG_CP_IB2_BUFSZ, &cp_ib2_bufsz);
+ /* If postmortem dump is not enabled, dump minimal set and return */
+ if (!device->pm_dump_enable) {
+
+ KGSL_LOG_DUMP(device,
+ "STATUS %08X | IB1:%08X/%08X | IB2: %08X/%08X"
+ " | RPTR: %04X | WPTR: %04X\n",
+ rbbm_status, cp_ib1_base, cp_ib1_bufsz, cp_ib2_base,
+ cp_ib2_bufsz, cp_rb_rptr, cp_rb_wptr);
+
+ return 0;
+ }
+
kgsl_sharedmem_readl(&device->memstore,
(unsigned int *) &context_id,
KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
@@ -766,7 +783,7 @@
if (context) {
ts_processed = kgsl_readtimestamp(device, context,
KGSL_TIMESTAMP_RETIRED);
- KGSL_LOG_DUMP(device, "CTXT: %d TIMESTM RTRD: %08X\n",
+ KGSL_LOG_DUMP(device, "FT CTXT: %d TIMESTM RTRD: %08X\n",
context->id, ts_processed);
} else
KGSL_LOG_DUMP(device, "BAD CTXT: %d\n", context_id);
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index 69b34fa..4333f2f 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -64,7 +64,7 @@
unsigned long wait_time;
unsigned long wait_timeout = msecs_to_jiffies(ADRENO_IDLE_TIMEOUT);
unsigned long wait_time_part;
- unsigned int prev_reg_val[hang_detect_regs_count];
+ unsigned int prev_reg_val[ft_detect_regs_count];
memset(prev_reg_val, 0, sizeof(prev_reg_val));
@@ -109,7 +109,7 @@
if (time_after(jiffies, wait_time_part)) {
wait_time_part = jiffies +
msecs_to_jiffies(KGSL_TIMEOUT_PART);
- if ((adreno_hang_detect(rb->device,
+ if ((adreno_ft_detect(rb->device,
prev_reg_val))){
KGSL_DRV_ERR(rb->device,
"Hang detected while waiting for freespace in"
@@ -129,7 +129,7 @@
continue;
err:
- if (!adreno_dump_and_recover(rb->device)) {
+ if (!adreno_dump_and_exec_ft(rb->device)) {
if (context && context->flags & CTXT_FLAGS_GPU_HANG) {
KGSL_CTXT_WARN(rb->device,
"Context %p caused a gpu hang. Will not accept commands for context %d\n",
@@ -138,7 +138,7 @@
}
wait_time = jiffies + wait_timeout;
} else {
- /* GPU is hung and we cannot recover */
+ /* GPU is hung and fault tolerance failed */
BUG();
}
}
@@ -581,7 +581,7 @@
if (adreno_is_a2xx(adreno_dev))
total_sizedwords += 2; /* CP_WAIT_FOR_IDLE */
- total_sizedwords += 2; /* scratchpad ts for recovery */
+ total_sizedwords += 2; /* scratchpad ts for fault tolerance */
total_sizedwords += 3; /* sop timestamp */
total_sizedwords += 4; /* eop timestamp */
@@ -629,7 +629,7 @@
}
timestamp = rb->timestamp[context_id];
- /* scratchpad ts for recovery */
+ /* scratchpad ts for fault tolerance */
GSL_RB_WRITE(ringcmds, rcmd_gpu, cp_type0_packet(REG_CP_TIMESTAMP, 1));
GSL_RB_WRITE(ringcmds, rcmd_gpu, rb->timestamp[KGSL_MEMSTORE_GLOBAL]);
@@ -756,6 +756,11 @@
GSL_RB_WRITE(ringcmds, rcmd_gpu, 0);
}
+ if (flags & KGSL_CMD_FLAGS_EOF) {
+ GSL_RB_WRITE(ringcmds, rcmd_gpu, cp_nop_packet(1));
+ GSL_RB_WRITE(ringcmds, rcmd_gpu, KGSL_END_OF_FRAME_IDENTIFIER);
+ }
+
adreno_ringbuffer_submit(rb);
return timestamp;
@@ -999,20 +1004,12 @@
drawctxt = context->devctxt;
if (drawctxt->flags & CTXT_FLAGS_GPU_HANG) {
- KGSL_CTXT_WARN(device, "Context %p caused a gpu hang.."
+ KGSL_CTXT_ERR(device, "proc %s failed fault tolerance"
" will not accept commands for context %d\n",
- drawctxt, drawctxt->id);
+ drawctxt->pid_name, drawctxt->id);
return -EDEADLK;
}
- cmds = link = kzalloc(sizeof(unsigned int) * (numibs * 3 + 4),
- GFP_KERNEL);
- if (!link) {
- KGSL_CORE_ERR("kzalloc(%d) failed\n",
- sizeof(unsigned int) * (numibs * 3 + 4));
- return -ENOMEM;
- }
-
/*When preamble is enabled, the preamble buffer with state restoration
commands are stored in the first node of the IB chain. We can skip that
if a context switch hasn't occured */
@@ -1021,6 +1018,27 @@
adreno_dev->drawctxt_active == drawctxt)
start_index = 1;
+ if (drawctxt->flags & CTXT_FLAGS_SKIP_EOF) {
+ KGSL_CTXT_ERR(device,
+ "proc %s triggered fault tolerance"
+ " skipping commands for context till EOF %d\n",
+ drawctxt->pid_name, drawctxt->id);
+ if (flags & KGSL_CMD_FLAGS_EOF)
+ drawctxt->flags &= ~CTXT_FLAGS_SKIP_EOF;
+ if (start_index)
+ numibs = 1;
+ else
+ numibs = 0;
+ }
+
+ cmds = link = kzalloc(sizeof(unsigned int) * (numibs * 3 + 4),
+ GFP_KERNEL);
+ if (!link) {
+ KGSL_CORE_ERR("kzalloc(%d) failed\n",
+ sizeof(unsigned int) * (numibs * 3 + 4));
+ return -ENOMEM;
+ }
+
if (!start_index) {
*cmds++ = cp_nop_packet(1);
*cmds++ = KGSL_START_OF_IB_IDENTIFIER;
@@ -1060,7 +1078,7 @@
*timestamp = adreno_ringbuffer_addcmds(&adreno_dev->ringbuffer,
drawctxt,
- 0,
+ (flags & KGSL_CMD_FLAGS_EOF),
&link[0], (cmds - link), *timestamp);
#ifdef CONFIG_MSM_KGSL_CFF_DUMP
@@ -1072,173 +1090,21 @@
adreno_idle(device);
#endif
- /* If context hung and recovered then return error so that the
- * application may handle it */
-
- ret = (drawctxt->flags & CTXT_FLAGS_GPU_HANG_RECOVERED) ?
- -EDEADLK : 0;
+ /*
+ * If context hung and recovered then return error so that the
+ * application may handle it
+ */
+ if (drawctxt->flags & CTXT_FLAGS_GPU_HANG_FT) {
+ drawctxt->flags &= ~CTXT_FLAGS_GPU_HANG_FT;
+ ret = -EPROTO;
+ } else
+ ret = 0;
done:
kfree(link);
return ret;
}
-static int _find_start_of_cmd_seq(struct adreno_ringbuffer *rb,
- unsigned int *ptr,
- bool inc)
-{
- int status = -EINVAL;
- unsigned int val1;
- unsigned int size = rb->buffer_desc.size;
- unsigned int start_ptr = *ptr;
-
- while ((start_ptr / sizeof(unsigned int)) != rb->wptr) {
- if (inc)
- start_ptr = adreno_ringbuffer_inc_wrapped(start_ptr,
- size);
- else
- start_ptr = adreno_ringbuffer_dec_wrapped(start_ptr,
- size);
- kgsl_sharedmem_readl(&rb->buffer_desc, &val1, start_ptr);
- if (KGSL_CMD_IDENTIFIER == val1) {
- if ((start_ptr / sizeof(unsigned int)) != rb->wptr)
- start_ptr = adreno_ringbuffer_dec_wrapped(
- start_ptr, size);
- *ptr = start_ptr;
- status = 0;
- break;
- }
- }
- return status;
-}
-
-static int _find_cmd_seq_after_eop_ts(struct adreno_ringbuffer *rb,
- unsigned int *rb_rptr,
- unsigned int global_eop,
- bool inc)
-{
- int status = -EINVAL;
- unsigned int temp_rb_rptr = *rb_rptr;
- unsigned int size = rb->buffer_desc.size;
- unsigned int val[3];
- int i = 0;
- bool check = false;
-
- if (inc && temp_rb_rptr / sizeof(unsigned int) != rb->wptr)
- return status;
-
- do {
- /* when decrementing we need to decrement first and
- * then read make sure we cover all the data */
- if (!inc)
- temp_rb_rptr = adreno_ringbuffer_dec_wrapped(
- temp_rb_rptr, size);
- kgsl_sharedmem_readl(&rb->buffer_desc, &val[i],
- temp_rb_rptr);
-
- if (check && ((inc && val[i] == global_eop) ||
- (!inc && (val[i] ==
- cp_type3_packet(CP_MEM_WRITE, 2) ||
- val[i] == CACHE_FLUSH_TS)))) {
- /* decrement i, i.e i = (i - 1 + 3) % 3 if
- * we are going forward, else increment i */
- i = (i + 2) % 3;
- if (val[i] == rb->device->memstore.gpuaddr +
- KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
- eoptimestamp)) {
- int j = ((i + 2) % 3);
- if ((inc && (val[j] == CACHE_FLUSH_TS ||
- val[j] == cp_type3_packet(
- CP_MEM_WRITE, 2))) ||
- (!inc && val[j] == global_eop)) {
- /* Found the global eop */
- status = 0;
- break;
- }
- }
- /* if no match found then increment i again
- * since we decremented before matching */
- i = (i + 1) % 3;
- }
- if (inc)
- temp_rb_rptr = adreno_ringbuffer_inc_wrapped(
- temp_rb_rptr, size);
-
- i = (i + 1) % 3;
- if (2 == i)
- check = true;
- } while (temp_rb_rptr / sizeof(unsigned int) != rb->wptr);
- /* temp_rb_rptr points to the command stream after global eop,
- * move backward till the start of command sequence */
- if (!status) {
- status = _find_start_of_cmd_seq(rb, &temp_rb_rptr, false);
- if (!status) {
- *rb_rptr = temp_rb_rptr;
- KGSL_DRV_ERR(rb->device,
- "Offset of cmd sequence after eop timestamp: 0x%x\n",
- temp_rb_rptr / sizeof(unsigned int));
- }
- }
- if (status)
- KGSL_DRV_ERR(rb->device,
- "Failed to find the command sequence after eop timestamp\n");
- return status;
-}
-
-static int _find_hanging_ib_sequence(struct adreno_ringbuffer *rb,
- unsigned int *rb_rptr,
- unsigned int ib1)
-{
- int status = -EINVAL;
- unsigned int temp_rb_rptr = *rb_rptr;
- unsigned int size = rb->buffer_desc.size;
- unsigned int val[2];
- int i = 0;
- bool check = false;
- bool ctx_switch = false;
-
- while (temp_rb_rptr / sizeof(unsigned int) != rb->wptr) {
- kgsl_sharedmem_readl(&rb->buffer_desc, &val[i], temp_rb_rptr);
-
- if (check && val[i] == ib1) {
- /* decrement i, i.e i = (i - 1 + 2) % 2 */
- i = (i + 1) % 2;
- if (adreno_cmd_is_ib(val[i])) {
- /* go till start of command sequence */
- status = _find_start_of_cmd_seq(rb,
- &temp_rb_rptr, false);
- KGSL_DRV_ERR(rb->device,
- "Found the hanging IB at offset 0x%x\n",
- temp_rb_rptr / sizeof(unsigned int));
- break;
- }
- /* if no match the increment i since we decremented
- * before checking */
- i = (i + 1) % 2;
- }
- /* Make sure you do not encounter a context switch twice, we can
- * encounter it once for the bad context as the start of search
- * can point to the context switch */
- if (val[i] == KGSL_CONTEXT_TO_MEM_IDENTIFIER) {
- if (ctx_switch) {
- KGSL_DRV_ERR(rb->device,
- "Context switch encountered before bad "
- "IB found\n");
- break;
- }
- ctx_switch = true;
- }
- i = (i + 1) % 2;
- if (1 == i)
- check = true;
- temp_rb_rptr = adreno_ringbuffer_inc_wrapped(temp_rb_rptr,
- size);
- }
- if (!status)
- *rb_rptr = temp_rb_rptr;
- return status;
-}
-
static void _turn_preamble_on_for_ib_seq(struct adreno_ringbuffer *rb,
unsigned int rb_rptr)
{
@@ -1261,7 +1127,7 @@
kgsl_sharedmem_writel(&rb->buffer_desc,
temp_rb_rptr, cp_nop_packet(1));
}
- KGSL_DRV_ERR(rb->device,
+ KGSL_FT_INFO(rb->device,
"Turned preamble on at offset 0x%x\n",
temp_rb_rptr / 4);
break;
@@ -1283,21 +1149,41 @@
}
}
-static void _copy_valid_rb_content(struct adreno_ringbuffer *rb,
- unsigned int rb_rptr, unsigned int *temp_rb_buffer,
- int *rb_size, unsigned int *bad_rb_buffer,
- int *bad_rb_size,
- int *last_valid_ctx_id)
+void adreno_ringbuffer_extract(struct adreno_ringbuffer *rb,
+ struct adreno_ft_data *ft_data)
{
- unsigned int good_rb_idx = 0, cmd_start_idx = 0;
+ struct kgsl_device *device = rb->device;
+ unsigned int rb_rptr = ft_data->start_of_replay_cmds;
+ unsigned int good_rb_idx = 0, bad_rb_idx = 0, temp_rb_idx = 0;
+ unsigned int last_good_cmd_end_idx = 0, last_bad_cmd_end_idx = 0;
+ unsigned int cmd_start_idx = 0;
unsigned int val1 = 0;
- struct kgsl_context *k_ctxt;
- struct adreno_context *a_ctxt;
- unsigned int bad_rb_idx = 0;
int copy_rb_contents = 0;
unsigned int temp_rb_rptr;
+ struct kgsl_context *k_ctxt;
+ struct adreno_context *a_ctxt;
unsigned int size = rb->buffer_desc.size;
- unsigned int good_cmd_start_idx = 0;
+ unsigned int *temp_rb_buffer = ft_data->rb_buffer;
+ int *rb_size = &ft_data->rb_size;
+ unsigned int *bad_rb_buffer = ft_data->bad_rb_buffer;
+ int *bad_rb_size = &ft_data->bad_rb_size;
+ unsigned int *good_rb_buffer = ft_data->good_rb_buffer;
+ int *good_rb_size = &ft_data->good_rb_size;
+
+ /*
+ * If the start index from where commands need to be copied is invalid
+ * then no need to save off any commands
+ */
+ if (0xFFFFFFFF == ft_data->start_of_replay_cmds)
+ return;
+
+ k_ctxt = idr_find(&device->context_idr, ft_data->context_id);
+ if (k_ctxt) {
+ a_ctxt = k_ctxt->devctxt;
+ if (a_ctxt->flags & CTXT_FLAGS_PREAMBLE)
+ _turn_preamble_on_for_ib_seq(rb, rb_rptr);
+ }
+ k_ctxt = NULL;
/* Walk the rb from the context switch. Omit any commands
* for an invalid context. */
@@ -1307,9 +1193,11 @@
if (KGSL_CMD_IDENTIFIER == val1) {
/* Start is the NOP dword that comes before
* KGSL_CMD_IDENTIFIER */
- cmd_start_idx = bad_rb_idx - 1;
- if (copy_rb_contents)
- good_cmd_start_idx = good_rb_idx - 1;
+ cmd_start_idx = temp_rb_idx - 1;
+ if ((copy_rb_contents) && (good_rb_idx))
+ last_good_cmd_end_idx = good_rb_idx - 1;
+ if ((!copy_rb_contents) && (bad_rb_idx))
+ last_bad_cmd_end_idx = bad_rb_idx - 1;
}
/* check for context switch indicator */
@@ -1335,86 +1223,48 @@
!(a_ctxt->flags & CTXT_FLAGS_GPU_HANG)) ||
!k_ctxt)) {
for (temp_idx = cmd_start_idx;
- temp_idx < bad_rb_idx;
+ temp_idx < temp_rb_idx;
temp_idx++)
- temp_rb_buffer[good_rb_idx++] =
- bad_rb_buffer[temp_idx];
- *last_valid_ctx_id = val2;
+ good_rb_buffer[good_rb_idx++] =
+ temp_rb_buffer[temp_idx];
+ ft_data->last_valid_ctx_id = val2;
copy_rb_contents = 1;
+ /* remove the good commands from bad buffer */
+ bad_rb_idx = last_bad_cmd_end_idx;
} else if (copy_rb_contents && k_ctxt &&
(a_ctxt->flags & CTXT_FLAGS_GPU_HANG)) {
- /* If we are changing to bad context then remove
- * the dwords we copied for this sequence from
- * the good buffer */
- good_rb_idx = good_cmd_start_idx;
+
+ /* If we are changing back to a bad context
+ * from good ctxt and were not copying commands
+ * to bad ctxt then copy over commands to
+ * the bad context */
+ for (temp_idx = cmd_start_idx;
+ temp_idx < temp_rb_idx;
+ temp_idx++)
+ bad_rb_buffer[bad_rb_idx++] =
+ temp_rb_buffer[temp_idx];
+ /* If we are changing to bad context then
+ * remove the dwords we copied for this
+ * sequence from the good buffer */
+ good_rb_idx = last_good_cmd_end_idx;
copy_rb_contents = 0;
}
}
}
if (copy_rb_contents)
- temp_rb_buffer[good_rb_idx++] = val1;
- /* Copy both good and bad commands for replay to the bad
- * buffer */
- bad_rb_buffer[bad_rb_idx++] = val1;
+ good_rb_buffer[good_rb_idx++] = val1;
+ else
+ bad_rb_buffer[bad_rb_idx++] = val1;
+
+ /* Copy both good and bad commands to temp buffer */
+ temp_rb_buffer[temp_rb_idx++] = val1;
rb_rptr = adreno_ringbuffer_inc_wrapped(rb_rptr, size);
}
- *rb_size = good_rb_idx;
+ *good_rb_size = good_rb_idx;
*bad_rb_size = bad_rb_idx;
-}
-
-int adreno_ringbuffer_extract(struct adreno_ringbuffer *rb,
- struct adreno_recovery_data *rec_data)
-{
- int status;
- struct kgsl_device *device = rb->device;
- unsigned int rb_rptr = rb->wptr * sizeof(unsigned int);
- struct kgsl_context *context;
- struct adreno_context *adreno_context;
-
- context = idr_find(&device->context_idr, rec_data->context_id);
-
- /* Look for the command stream that is right after the global eop */
- status = _find_cmd_seq_after_eop_ts(rb, &rb_rptr,
- rec_data->global_eop + 1, false);
- if (status)
- goto done;
-
- if (context) {
- adreno_context = context->devctxt;
-
- if (adreno_context->flags & CTXT_FLAGS_PREAMBLE) {
- if (rec_data->ib1) {
- status = _find_hanging_ib_sequence(rb, &rb_rptr,
- rec_data->ib1);
- if (status)
- goto copy_rb_contents;
- }
- _turn_preamble_on_for_ib_seq(rb, rb_rptr);
- } else {
- status = -EINVAL;
- }
- }
-
-copy_rb_contents:
- _copy_valid_rb_content(rb, rb_rptr, rec_data->rb_buffer,
- &rec_data->rb_size,
- rec_data->bad_rb_buffer,
- &rec_data->bad_rb_size,
- &rec_data->last_valid_ctx_id);
- /* If we failed to get the hanging IB sequence then we cannot execute
- * commands from the bad context or preambles not supported */
- if (status) {
- rec_data->bad_rb_size = 0;
- status = 0;
- }
- /* If there is no context then that means there are no commands for
- * good case */
- if (!context)
- rec_data->rb_size = 0;
-done:
- return status;
+ *rb_size = temp_rb_idx;
}
void
diff --git a/drivers/gpu/msm/adreno_ringbuffer.h b/drivers/gpu/msm/adreno_ringbuffer.h
index e87b506..fa03c05 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.h
+++ b/drivers/gpu/msm/adreno_ringbuffer.h
@@ -27,7 +27,7 @@
struct kgsl_device;
struct kgsl_device_private;
-struct adreno_recovery_data;
+struct adreno_ft_data;
#define GSL_RB_MEMPTRS_SCRATCH_COUNT 8
struct kgsl_rbmemptrs {
@@ -114,8 +114,8 @@
void kgsl_cp_intrcallback(struct kgsl_device *device);
-int adreno_ringbuffer_extract(struct adreno_ringbuffer *rb,
- struct adreno_recovery_data *rec_data);
+void adreno_ringbuffer_extract(struct adreno_ringbuffer *rb,
+ struct adreno_ft_data *ft_data);
void
adreno_ringbuffer_restore(struct adreno_ringbuffer *rb, unsigned int *rb_buff,
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 6e1ecd1..2b0d5d9 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -2477,7 +2477,11 @@
mutex_unlock(&dev_priv->device->mutex);
}
- if (ret == 0 && (cmd & IOC_OUT)) {
+ /*
+ * Still copy back on failure, but assume function took
+ * all necessary precautions sanitizing the return values.
+ */
+ if (cmd & IOC_OUT) {
if (copy_to_user((void __user *) arg, uptr, _IOC_SIZE(cmd)))
ret = -EFAULT;
}
@@ -3043,21 +3047,21 @@
kgsl_idle(device);
}
- KGSL_LOG_DUMP(device, "|%s| Dump Started\n", device->name);
- KGSL_LOG_DUMP(device, "POWER: FLAGS = %08lX | ACTIVE POWERLEVEL = %08X",
+
+ if (device->pm_dump_enable) {
+
+ KGSL_LOG_DUMP(device,
+ "POWER: NAP ALLOWED = %d | START_STOP_SLEEP_WAKE = %d\n"
+ , pwr->nap_allowed, pwr->strtstp_sleepwake);
+
+ KGSL_LOG_DUMP(device,
+ "POWER: FLAGS = %08lX | ACTIVE POWERLEVEL = %08X",
pwr->power_flags, pwr->active_pwrlevel);
- KGSL_LOG_DUMP(device, "POWER: INTERVAL TIMEOUT = %08X ",
- pwr->interval_timeout);
+ KGSL_LOG_DUMP(device, "POWER: INTERVAL TIMEOUT = %08X ",
+ pwr->interval_timeout);
- KGSL_LOG_DUMP(device, "POWER: NAP ALLOWED = %d | START_STOP_SLEEP_WAKE = %d\n",
- pwr->nap_allowed, pwr->strtstp_sleepwake);
-
- KGSL_LOG_DUMP(device, "GRP_CLK = %lu ",
- kgsl_get_clkrate(pwr->grp_clks[0]));
-
- KGSL_LOG_DUMP(device, "BUS CLK = %lu ",
- kgsl_get_clkrate(pwr->ebi1_clk));
+ }
/* Disable the idle timer so we don't get interrupted */
del_timer_sync(&device->idle_timer);
@@ -3085,7 +3089,7 @@
/* On a manual trigger, turn on the interrupts and put
the clocks to sleep. They will recover themselves
on the next event. For a hang, leave things as they
- are until recovery kicks in. */
+ are until fault tolerance kicks in. */
if (manual) {
kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_ON);
@@ -3095,8 +3099,6 @@
kgsl_pwrctrl_sleep(device);
}
- KGSL_LOG_DUMP(device, "|%s| Dump Finished\n", device->name);
-
return 0;
}
EXPORT_SYMBOL(kgsl_postmortem_dump);
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index 70a704b..c568db5 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -158,7 +158,7 @@
void *hostptr; /* kernel virtual address */
unsigned long useraddr; /* userspace address */
unsigned int gpuaddr;
- unsigned int physaddr;
+ phys_addr_t physaddr;
unsigned int size;
unsigned int priv; /* Internal flags and settings */
struct scatterlist *sg;
diff --git a/drivers/gpu/msm/kgsl_debugfs.c b/drivers/gpu/msm/kgsl_debugfs.c
index 76998db..9dfda32 100644
--- a/drivers/gpu/msm/kgsl_debugfs.c
+++ b/drivers/gpu/msm/kgsl_debugfs.c
@@ -70,6 +70,20 @@
return 0;
}
+static int pm_enabled_set(void *data, u64 val)
+{
+ struct kgsl_device *device = data;
+ device->pm_dump_enable = val;
+ return 0;
+}
+
+static int pm_enabled_get(void *data, u64 *val)
+{
+ struct kgsl_device *device = data;
+ *val = device->pm_dump_enable;
+ return 0;
+}
+
DEFINE_SIMPLE_ATTRIBUTE(pm_regs_enabled_fops,
pm_regs_enabled_get,
@@ -79,6 +93,10 @@
pm_ib_enabled_get,
pm_ib_enabled_set, "%llu\n");
+DEFINE_SIMPLE_ATTRIBUTE(pm_enabled_fops,
+ pm_enabled_get,
+ pm_enabled_set, "%llu\n");
+
static inline int kgsl_log_set(unsigned int *log_val, void *data, u64 val)
{
*log_val = min((unsigned int)val, (unsigned int)KGSL_LOG_LEVEL_MAX);
@@ -105,6 +123,7 @@
KGSL_DEBUGFS_LOG(ctxt_log);
KGSL_DEBUGFS_LOG(mem_log);
KGSL_DEBUGFS_LOG(pwr_log);
+KGSL_DEBUGFS_LOG(ft_log);
static int memfree_hist_print(struct seq_file *s, void *unused)
{
@@ -166,6 +185,7 @@
device->drv_log = KGSL_LOG_LEVEL_DEFAULT;
device->mem_log = KGSL_LOG_LEVEL_DEFAULT;
device->pwr_log = KGSL_LOG_LEVEL_DEFAULT;
+ device->ft_log = KGSL_LOG_LEVEL_DEFAULT;
debugfs_create_file("log_level_cmd", 0644, device->d_debugfs, device,
&cmd_log_fops);
@@ -179,6 +199,8 @@
&pwr_log_fops);
debugfs_create_file("memfree_history", 0444, device->d_debugfs, device,
&memfree_hist_fops);
+ debugfs_create_file("log_level_ft", 0644, device->d_debugfs, device,
+ &ft_log_fops);
/* Create postmortem dump control files */
@@ -193,6 +215,9 @@
&pm_regs_enabled_fops);
debugfs_create_file("ib_enabled", 0644, pm_d_debugfs, device,
&pm_ib_enabled_fops);
+ device->pm_dump_enable = 0;
+ debugfs_create_file("enable", 0644, pm_d_debugfs, device,
+ &pm_enabled_fops);
}
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index 66390fc..aca5660 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -24,9 +24,10 @@
#include "kgsl_pwrscale.h"
#include <linux/sync.h>
-#define KGSL_TIMEOUT_NONE 0
-#define KGSL_TIMEOUT_DEFAULT 0xFFFFFFFF
-#define KGSL_TIMEOUT_PART 50 /* 50 msec */
+#define KGSL_TIMEOUT_NONE 0
+#define KGSL_TIMEOUT_DEFAULT 0xFFFFFFFF
+#define KGSL_TIMEOUT_PART 50 /* 50 msec */
+#define KGSL_TIMEOUT_LONG_IB_DETECTION 2000 /* 2 sec*/
#define FIRST_TIMEOUT (HZ / 2)
@@ -46,7 +47,7 @@
#define KGSL_STATE_SLEEP 0x00000008
#define KGSL_STATE_SUSPEND 0x00000010
#define KGSL_STATE_HUNG 0x00000020
-#define KGSL_STATE_DUMP_AND_RECOVER 0x00000040
+#define KGSL_STATE_DUMP_AND_FT 0x00000040
#define KGSL_STATE_SLUMBER 0x00000080
#define KGSL_GRAPHICS_MEMORY_LOW_WATERMARK 0x1000000
@@ -185,7 +186,7 @@
wait_queue_head_t wait_queue;
struct workqueue_struct *work_queue;
struct device *parentdev;
- struct completion recovery_gate;
+ struct completion ft_gate;
struct dentry *d_debugfs;
struct idr context_idr;
struct early_suspend display_off;
@@ -211,6 +212,8 @@
int drv_log;
int mem_log;
int pwr_log;
+ int ft_log;
+ int pm_dump_enable;
struct kgsl_pwrscale pwrscale;
struct kobject pwrscale_kobj;
struct work_struct ts_expired_ws;
@@ -230,7 +233,7 @@
#define KGSL_DEVICE_COMMON_INIT(_dev) \
.hwaccess_gate = COMPLETION_INITIALIZER((_dev).hwaccess_gate),\
.suspend_gate = COMPLETION_INITIALIZER((_dev).suspend_gate),\
- .recovery_gate = COMPLETION_INITIALIZER((_dev).recovery_gate),\
+ .ft_gate = COMPLETION_INITIALIZER((_dev).ft_gate),\
.idle_check_ws = __WORK_INITIALIZER((_dev).idle_check_ws,\
kgsl_idle_check),\
.ts_expired_ws = __WORK_INITIALIZER((_dev).ts_expired_ws,\
diff --git a/drivers/gpu/msm/kgsl_gpummu.c b/drivers/gpu/msm/kgsl_gpummu.c
index 8f28505..cb206ac 100644
--- a/drivers/gpu/msm/kgsl_gpummu.c
+++ b/drivers/gpu/msm/kgsl_gpummu.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, 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
@@ -22,6 +22,7 @@
#include "kgsl_device.h"
#include "kgsl_sharedmem.h"
#include "kgsl_trace.h"
+#include "adreno.h"
#define KGSL_PAGETABLE_SIZE \
ALIGN(KGSL_PAGETABLE_ENTRIES(CONFIG_MSM_KGSL_PAGE_TABLE_SIZE) * \
@@ -161,7 +162,7 @@
}
static void *
-_kgsl_ptpool_get_entry(struct kgsl_ptpool *pool, unsigned int *physaddr)
+_kgsl_ptpool_get_entry(struct kgsl_ptpool *pool, phys_addr_t *physaddr)
{
struct kgsl_ptpool_chunk *chunk;
@@ -227,7 +228,7 @@
*/
static void *kgsl_ptpool_alloc(struct kgsl_ptpool *pool,
- unsigned int *physaddr)
+ phys_addr_t *physaddr)
{
void *addr = NULL;
int ret;
@@ -403,11 +404,22 @@
{
unsigned int reg;
unsigned int ptbase;
+ struct kgsl_device *device;
+ struct adreno_device *adreno_dev;
+ unsigned int no_page_fault_log = 0;
- kgsl_regread(mmu->device, MH_MMU_PAGE_FAULT, ®);
- kgsl_regread(mmu->device, MH_MMU_PT_BASE, &ptbase);
+ device = mmu->device;
+ adreno_dev = ADRENO_DEVICE(device);
- KGSL_MEM_CRIT(mmu->device,
+ kgsl_regread(device, MH_MMU_PAGE_FAULT, ®);
+ kgsl_regread(device, MH_MMU_PT_BASE, &ptbase);
+
+
+ if (adreno_dev->ft_pf_policy & KGSL_FT_PAGEFAULT_LOG_ONE_PER_PAGE)
+ no_page_fault_log = kgsl_mmu_log_fault_addr(mmu, ptbase, reg);
+
+ if (!no_page_fault_log)
+ KGSL_MEM_CRIT(mmu->device,
"mmu page fault: page=0x%lx pt=%d op=%s axi=%d\n",
reg & ~(PAGE_SIZE - 1),
kgsl_mmu_get_ptname_from_ptbase(mmu, ptbase),
diff --git a/drivers/gpu/msm/kgsl_gpummu.h b/drivers/gpu/msm/kgsl_gpummu.h
index 99e7d5f..1753aff 100644
--- a/drivers/gpu/msm/kgsl_gpummu.h
+++ b/drivers/gpu/msm/kgsl_gpummu.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, 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
@@ -57,7 +57,7 @@
int dynamic;
void *data;
- unsigned int phys;
+ phys_addr_t phys;
unsigned long *bitmap;
struct list_head list;
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index 93b7e5d..e3cea88 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -283,10 +283,16 @@
struct kgsl_iommu_device *iommu_dev;
unsigned int ptbase, fsr;
unsigned int pid;
-
struct _mem_entry prev, next;
unsigned int fsynr0, fsynr1;
int write;
+ struct kgsl_device *device;
+ struct adreno_device *adreno_dev;
+ unsigned int no_page_fault_log = 0;
+ unsigned int curr_context_id = 0;
+ unsigned int curr_global_ts = 0;
+ static struct adreno_context *curr_context;
+ static struct kgsl_context *context;
ret = get_iommu_unit(dev, &mmu, &iommu_unit);
if (ret)
@@ -298,6 +304,8 @@
goto done;
}
iommu = mmu->priv;
+ device = mmu->device;
+ adreno_dev = ADRENO_DEVICE(device);
ptbase = KGSL_IOMMU_GET_CTX_REG(iommu, iommu_unit,
iommu_dev->ctx_id, TTBR0);
@@ -324,27 +332,55 @@
iommu_dev->ctx_id, fsr, fsynr0, fsynr1,
write ? "write" : "read");
- _check_if_freed(iommu_dev, addr, pid);
+ if (adreno_dev->ft_pf_policy & KGSL_FT_PAGEFAULT_LOG_ONE_PER_PAGE)
+ no_page_fault_log = kgsl_mmu_log_fault_addr(mmu, ptbase, addr);
- KGSL_LOG_DUMP(iommu_dev->kgsldev, "---- nearby memory ----\n");
+ if (!no_page_fault_log) {
+ KGSL_MEM_CRIT(iommu_dev->kgsldev,
+ "GPU PAGE FAULT: addr = %lX pid = %d\n",
+ addr, kgsl_mmu_get_ptname_from_ptbase(mmu, ptbase));
+ KGSL_MEM_CRIT(iommu_dev->kgsldev, "context = %d FSR = %X\n",
+ iommu_dev->ctx_id, fsr);
- _find_mem_entries(mmu, addr, ptbase, &prev, &next);
+ _check_if_freed(iommu_dev, addr, pid);
- if (prev.gpuaddr)
- _print_entry(iommu_dev->kgsldev, &prev);
- else
- KGSL_LOG_DUMP(iommu_dev->kgsldev, "*EMPTY*\n");
+ KGSL_LOG_DUMP(iommu_dev->kgsldev, "---- nearby memory ----\n");
- KGSL_LOG_DUMP(iommu_dev->kgsldev, " <- fault @ %8.8lX\n", addr);
+ _find_mem_entries(mmu, addr, ptbase, &prev, &next);
- if (next.gpuaddr != 0xFFFFFFFF)
- _print_entry(iommu_dev->kgsldev, &next);
- else
- KGSL_LOG_DUMP(iommu_dev->kgsldev, "*EMPTY*\n");
+ if (prev.gpuaddr)
+ _print_entry(iommu_dev->kgsldev, &prev);
+ else
+ KGSL_LOG_DUMP(iommu_dev->kgsldev, "*EMPTY*\n");
+
+ KGSL_LOG_DUMP(iommu_dev->kgsldev, " <- fault @ %8.8lX\n", addr);
+
+ if (next.gpuaddr != 0xFFFFFFFF)
+ _print_entry(iommu_dev->kgsldev, &next);
+ else
+ KGSL_LOG_DUMP(iommu_dev->kgsldev, "*EMPTY*\n");
+
+ }
mmu->fault = 1;
iommu_dev->fault = 1;
+ kgsl_sharedmem_readl(&device->memstore, &curr_context_id,
+ KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL, current_context));
+ context = idr_find(&device->context_idr, curr_context_id);
+ if (context != NULL)
+ curr_context = context->devctxt;
+
+ kgsl_sharedmem_readl(&device->memstore, &curr_global_ts,
+ KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL, eoptimestamp));
+
+ /*
+ * Store pagefault's timestamp in adreno context,
+ * this information will be used in GFT
+ */
+ curr_context->pagefault = 1;
+ curr_context->pagefault_ts = curr_global_ts;
+
trace_kgsl_mmu_pagefault(iommu_dev->kgsldev, addr,
kgsl_mmu_get_ptname_from_ptbase(mmu, ptbase),
write ? "write" : "read");
@@ -355,7 +391,8 @@
* the GPU and trigger a snapshot. To stall the transaction return
* EBUSY error.
*/
- ret = -EBUSY;
+ if (adreno_dev->ft_pf_policy & KGSL_FT_PAGEFAULT_GPUHALT_ENABLE)
+ ret = -EBUSY;
done:
return ret;
}
@@ -722,17 +759,23 @@
{
struct kgsl_iommu *iommu = mmu->priv;
struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[unit_id];
- int i;
+ int i, j;
+ int found_ctx;
- if (data->iommu_ctx_count > KGSL_IOMMU_MAX_DEVS_PER_UNIT) {
- KGSL_CORE_ERR("Too many iommu devices defined for an "
- "IOMMU unit\n");
- return -EINVAL;
- }
-
- for (i = 0; i < data->iommu_ctx_count; i++) {
- if (!data->iommu_ctxs[i].iommu_ctx_name)
- continue;
+ for (j = 0; j < KGSL_IOMMU_MAX_DEVS_PER_UNIT; j++) {
+ found_ctx = 0;
+ for (i = 0; i < data->iommu_ctx_count; i++) {
+ if (j == data->iommu_ctxs[i].ctx_id) {
+ found_ctx = 1;
+ break;
+ }
+ }
+ if (!found_ctx)
+ break;
+ if (!data->iommu_ctxs[i].iommu_ctx_name) {
+ KGSL_CORE_ERR("Context name invalid\n");
+ return -EINVAL;
+ }
iommu_unit->dev[iommu_unit->dev_count].dev =
msm_iommu_get_ctx(data->iommu_ctxs[i].iommu_ctx_name);
@@ -741,12 +784,6 @@
"device %s\n", data->iommu_ctxs[i].iommu_ctx_name);
return -EINVAL;
}
- if (KGSL_IOMMU_CONTEXT_USER != data->iommu_ctxs[i].ctx_id &&
- KGSL_IOMMU_CONTEXT_PRIV != data->iommu_ctxs[i].ctx_id) {
- KGSL_CORE_ERR("Invalid context ID defined: %d\n",
- data->iommu_ctxs[i].ctx_id);
- return -EINVAL;
- }
iommu_unit->dev[iommu_unit->dev_count].ctx_id =
data->iommu_ctxs[i].ctx_id;
iommu_unit->dev[iommu_unit->dev_count].kgsldev = mmu->device;
@@ -758,6 +795,10 @@
iommu_unit->dev_count++;
}
+ if (!j) {
+ KGSL_CORE_ERR("No ctxts initialized, user ctxt absent\n ");
+ return -EINVAL;
+ }
return 0;
}
diff --git a/drivers/gpu/msm/kgsl_log.h b/drivers/gpu/msm/kgsl_log.h
index 81a35e0..a7832e4 100644
--- a/drivers/gpu/msm/kgsl_log.h
+++ b/drivers/gpu/msm/kgsl_log.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2008-2011, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2008-2011,2013, 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
@@ -103,6 +103,15 @@
#define KGSL_PWR_CRIT(_dev, fmt, args...) \
KGSL_LOG_CRIT(_dev->dev, _dev->pwr_log, fmt, ##args)
+#define KGSL_FT_INFO(_dev, fmt, args...) \
+KGSL_LOG_INFO(_dev->dev, _dev->ft_log, fmt, ##args)
+#define KGSL_FT_WARN(_dev, fmt, args...) \
+KGSL_LOG_WARN(_dev->dev, _dev->ft_log, fmt, ##args)
+#define KGSL_FT_ERR(_dev, fmt, args...) \
+KGSL_LOG_ERR(_dev->dev, _dev->ft_log, fmt, ##args)
+#define KGSL_FT_CRIT(_dev, fmt, args...) \
+KGSL_LOG_CRIT(_dev->dev, _dev->ft_log, fmt, ##args)
+
/* Core error messages - these are for core KGSL functions that have
no device associated with them (such as memory) */
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index 83cf83d..ccaceb3 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -333,6 +333,35 @@
}
EXPORT_SYMBOL(kgsl_mmu_get_ptname_from_ptbase);
+unsigned int
+kgsl_mmu_log_fault_addr(struct kgsl_mmu *mmu, unsigned int pt_base,
+ unsigned int addr)
+{
+ struct kgsl_pagetable *pt;
+ unsigned int ret = 0;
+
+ if (!mmu->mmu_ops || !mmu->mmu_ops->mmu_pt_equal)
+ return 0;
+ spin_lock(&kgsl_driver.ptlock);
+ list_for_each_entry(pt, &kgsl_driver.pagetable_list, list) {
+ if (mmu->mmu_ops->mmu_pt_equal(mmu, pt, pt_base)) {
+ if ((addr & ~(PAGE_SIZE-1)) == pt->fault_addr) {
+ ret = 1;
+ break;
+ } else {
+ pt->fault_addr = (addr & ~(PAGE_SIZE-1));
+ ret = 0;
+ break;
+ }
+
+ }
+ }
+ spin_unlock(&kgsl_driver.ptlock);
+
+ return ret;
+}
+EXPORT_SYMBOL(kgsl_mmu_log_fault_addr);
+
int kgsl_mmu_init(struct kgsl_device *device)
{
int status = 0;
@@ -438,6 +467,7 @@
pagetable->name = name;
pagetable->max_entries = KGSL_PAGETABLE_ENTRIES(ptsize);
+ pagetable->fault_addr = 0xFFFFFFFF;
/*
* create a separate kgsl pool for IOMMU, global mappings can be mapped
@@ -693,6 +723,8 @@
{
struct gen_pool *pool;
int size;
+ unsigned int start_addr = 0;
+ unsigned int end_addr = 0;
if (memdesc->size == 0 || memdesc->gpuaddr == 0)
return 0;
@@ -704,10 +736,19 @@
size = kgsl_sg_size(memdesc->sg, memdesc->sglen);
+ start_addr = memdesc->gpuaddr;
+ end_addr = (memdesc->gpuaddr + size);
+
if (KGSL_MMU_TYPE_IOMMU != kgsl_mmu_get_mmutype())
spin_lock(&pagetable->lock);
pagetable->pt_ops->mmu_unmap(pagetable->priv, memdesc,
&pagetable->tlb_flags);
+
+ /* If buffer is unmapped 0 fault addr */
+ if ((pagetable->fault_addr >= start_addr) &&
+ (pagetable->fault_addr < end_addr))
+ pagetable->fault_addr = 0;
+
if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_get_mmutype())
spin_lock(&pagetable->lock);
/* Remove the statistics */
@@ -759,9 +800,8 @@
/*global mappings must have the same gpu address in all pagetables*/
if (gpuaddr && gpuaddr != memdesc->gpuaddr) {
- KGSL_CORE_ERR("pt %p addr mismatch phys 0x%08x"
- "gpu 0x%0x 0x%08x", pagetable, memdesc->physaddr,
- gpuaddr, memdesc->gpuaddr);
+ KGSL_CORE_ERR("pt %p addr mismatch phys %pa gpu 0x%0x 0x%08x",
+ pagetable, &memdesc->physaddr, gpuaddr, memdesc->gpuaddr);
goto error_unmap;
}
return result;
diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h
index 0458a13..2d48e86 100644
--- a/drivers/gpu/msm/kgsl_mmu.h
+++ b/drivers/gpu/msm/kgsl_mmu.h
@@ -114,6 +114,7 @@
} stats;
const struct kgsl_mmu_pt_ops *pt_ops;
unsigned int tlb_flags;
+ unsigned int fault_addr;
void *priv;
};
@@ -211,6 +212,8 @@
uint32_t flags);
int kgsl_mmu_get_ptname_from_ptbase(struct kgsl_mmu *mmu,
unsigned int pt_base);
+unsigned int kgsl_mmu_log_fault_addr(struct kgsl_mmu *mmu,
+ unsigned int pt_base, unsigned int addr);
int kgsl_mmu_pt_get_flags(struct kgsl_pagetable *pt,
enum kgsl_deviceid id);
void kgsl_mmu_ptpool_destroy(void *ptpool);
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 0dcbfdf..c716731 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -130,6 +130,16 @@
*/
pwr->active_pwrlevel = new_level;
+ pwrlevel = &pwr->pwrlevels[pwr->active_pwrlevel];
+
+ if (test_bit(KGSL_PWRFLAGS_AXI_ON, &pwr->power_flags)) {
+
+ if (pwr->pcl)
+ msm_bus_scale_client_update_request(pwr->pcl,
+ pwrlevel->bus_freq);
+ else if (pwr->ebi1_clk)
+ clk_set_rate(pwr->ebi1_clk, pwrlevel->bus_freq);
+ }
if (test_bit(KGSL_PWRFLAGS_CLK_ON, &pwr->power_flags) ||
(device->state == KGSL_STATE_NAP)) {
@@ -156,16 +166,6 @@
}
}
- pwrlevel = &pwr->pwrlevels[pwr->active_pwrlevel];
-
- if (test_bit(KGSL_PWRFLAGS_AXI_ON, &pwr->power_flags)) {
-
- if (pwr->pcl)
- msm_bus_scale_client_update_request(pwr->pcl,
- pwrlevel->bus_freq);
- else if (pwr->ebi1_clk)
- clk_set_rate(pwr->ebi1_clk, pwrlevel->bus_freq);
- }
trace_kgsl_pwrlevel(device, pwr->active_pwrlevel, pwrlevel->gpu_freq);
}
@@ -1081,7 +1081,7 @@
}
}
} else if (device->state & (KGSL_STATE_HUNG |
- KGSL_STATE_DUMP_AND_RECOVER)) {
+ KGSL_STATE_DUMP_AND_FT)) {
kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
}
@@ -1120,7 +1120,7 @@
break;
case KGSL_STATE_INIT:
case KGSL_STATE_HUNG:
- case KGSL_STATE_DUMP_AND_RECOVER:
+ case KGSL_STATE_DUMP_AND_FT:
if (test_bit(KGSL_PWRFLAGS_CLK_ON,
&device->pwrctrl.power_flags))
break;
@@ -1144,9 +1144,9 @@
mutex_unlock(&device->mutex);
wait_for_completion(&device->hwaccess_gate);
mutex_lock(&device->mutex);
- } else if (device->state == KGSL_STATE_DUMP_AND_RECOVER) {
+ } else if (device->state == KGSL_STATE_DUMP_AND_FT) {
mutex_unlock(&device->mutex);
- wait_for_completion(&device->recovery_gate);
+ wait_for_completion(&device->ft_gate);
mutex_lock(&device->mutex);
} else if (device->state == KGSL_STATE_SLUMBER)
kgsl_pwrctrl_wake(device);
@@ -1385,7 +1385,7 @@
return "SUSPEND";
case KGSL_STATE_HUNG:
return "HUNG";
- case KGSL_STATE_DUMP_AND_RECOVER:
+ case KGSL_STATE_DUMP_AND_FT:
return "DNR";
case KGSL_STATE_SLUMBER:
return "SLUMBER";
diff --git a/drivers/gpu/msm/kgsl_pwrscale.c b/drivers/gpu/msm/kgsl_pwrscale.c
index dffae70..02ada38 100644
--- a/drivers/gpu/msm/kgsl_pwrscale.c
+++ b/drivers/gpu/msm/kgsl_pwrscale.c
@@ -237,16 +237,14 @@
void kgsl_pwrscale_busy(struct kgsl_device *device)
{
if (PWRSCALE_ACTIVE(device) && device->pwrscale.policy->busy)
- if (device->requested_state != KGSL_STATE_SLUMBER)
- device->pwrscale.policy->busy(device,
- &device->pwrscale);
+ device->pwrscale.policy->busy(device,
+ &device->pwrscale);
}
void kgsl_pwrscale_idle(struct kgsl_device *device)
{
if (PWRSCALE_ACTIVE(device) && device->pwrscale.policy->idle)
- if (device->requested_state != KGSL_STATE_SLUMBER &&
- device->requested_state != KGSL_STATE_SLEEP)
+ if (device->state == KGSL_STATE_ACTIVE)
device->pwrscale.policy->idle(device,
&device->pwrscale);
}
diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c
index c4647a1..42e79a0 100644
--- a/drivers/gpu/msm/kgsl_snapshot.c
+++ b/drivers/gpu/msm/kgsl_snapshot.c
@@ -572,10 +572,9 @@
/* Freeze the snapshot on a hang until it gets read */
device->snapshot_frozen = (hang) ? 1 : 0;
- /* log buffer info to aid in ramdump recovery */
- KGSL_DRV_ERR(device, "snapshot created at va %p pa %lx size %d\n",
- device->snapshot, __pa(device->snapshot),
- device->snapshot_size);
+ /* log buffer info to aid in ramdump fault tolerance */
+ KGSL_DRV_ERR(device, "snapshot created at pa %lx size %d\n",
+ __pa(device->snapshot), device->snapshot_size);
if (hang)
sysfs_notify(&device->snapshot_kobj, NULL, "timestamp");
return 0;
diff --git a/drivers/hwmon/epm_adc.c b/drivers/hwmon/epm_adc.c
index c2b5f38..51ffd21 100644
--- a/drivers/hwmon/epm_adc.c
+++ b/drivers/hwmon/epm_adc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, 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
@@ -586,12 +586,16 @@
return 0;
}
-static int epm_psoc_scale_result(uint32_t result, uint32_t index)
+static int epm_psoc_scale_result(int16_t result, uint32_t index)
{
struct epm_adc_drv *epm_adc = epm_adc_drv;
- int32_t result_cur;
+ int32_t result_cur, neg = 0;
if ((1 << index) & epm_adc->channel_mask) {
+ if (result & 0x800) {
+ neg = 1;
+ result = result & 0x7ff;
+ }
/* result = (2.048V * code)/(4096 * gain * rsense) */
result_cur = ((EPM_PSOC_VREF_VOLTAGE * result)/
EPM_PSOC_MAX_ADC_CODE_12_BIT);
@@ -599,14 +603,22 @@
result_cur = (result_cur/
(epm_adc->epm_psoc_ch_prop[index].gain *
epm_adc->epm_psoc_ch_prop[index].resistorvalue));
+ if (neg)
+ result_cur -= result_cur;
} else {
+ if (result & 0x8000) {
+ neg = 1;
+ result = result & 0x7fff;
+ }
/* result = (2.048V * code)/(32767 * gain * rsense) */
- result_cur = (((EPM_PSOC_VREF_VOLTAGE * result)/
+ result_cur = (((EPM_PSOC_VREF_VOLTAGE * (int) result)/
EPM_PSOC_MAX_ADC_CODE_15_BIT) * 1000);
result_cur = (result_cur/
(epm_adc->epm_psoc_ch_prop[index].gain *
epm_adc->epm_psoc_ch_prop[index].resistorvalue));
+ if (neg)
+ result_cur -= result_cur;
}
return result_cur;
@@ -869,10 +881,8 @@
psoc_get_meas->timestamp_resp_value = (rx_buf[3] << 24) |
(rx_buf[4] << 16) | (rx_buf[5] << 8) |
rx_buf[6];
- psoc_get_meas->reading_value = (rx_buf[7] << 8) | rx_buf[8];
+ psoc_get_meas->reading_raw = (rx_buf[7] << 8) | rx_buf[8];
- pr_debug("dev_num:%d, chan_num:%d\n", rx_buf[1], rx_buf[2]);
- pr_debug("data %d\n", psoc_get_meas->reading_value);
return rc;
}
@@ -1336,7 +1346,7 @@
}
psoc_get_data.reading_value = epm_psoc_scale_result(
- psoc_get_data.reading_value,
+ psoc_get_data.reading_raw,
psoc_get_data.chan_num);
if (copy_to_user((void __user *)arg, &psoc_get_data,
@@ -1753,8 +1763,6 @@
conv.device_idx = attr->index / pdata->chan_per_adc;
conv.channel_idx = attr->index % pdata->chan_per_adc;
conv.physical = 0;
- pr_info("%s: device_idx=%d channel_idx=%d", __func__, conv.device_idx,
- conv.channel_idx);
if (!epm_adc_expander_register) {
rc = epm_adc_i2c_expander_register();
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index 9ed3d53..41f79be 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -693,8 +693,8 @@
spin_lock_irq(&client->buffer_lock);
client->use_wake_lock = false;
- wake_lock_destroy(&client->wake_lock);
spin_unlock_irq(&client->buffer_lock);
+ wake_lock_destroy(&client->wake_lock);
return 0;
}
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index 4c72b65..bfa48de 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -411,13 +411,6 @@
To compile this driver as a module, choose M here; the
module will be called opencores-kbd.
-config KEYBOARD_PM8058
- bool "Qualcomm PM8058 Matrix Keypad support"
- depends on PM8058
- help
- Say Y here to enable the driver for the keypad matrix interface
- on the Qualcomm PM8058 power management I/C device.
-
config KEYBOARD_PXA27x
tristate "PXA27x/PXA3xx keypad support"
depends on PXA27x || PXA3xx || ARCH_MMP
@@ -623,5 +616,3 @@
module will be called w90p910_keypad.
endif
-
-
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index 833904a..85f1d86 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -54,4 +54,3 @@
obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o
obj-$(CONFIG_KEYBOARD_QCIKBD) += qci_kbd.o
obj-$(CONFIG_KEYBOARD_W90P910) += w90p910_keypad.o
-obj-$(CONFIG_KEYBOARD_PMIC8058) += pmic8058-keypad.o
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index ad43bbf..1f309d8 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -17,7 +17,6 @@
obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC) += atmel_tsadcc.o
obj-$(CONFIG_TOUCHSCREEN_AUO_PIXCIR) += auo-pixcir-ts.o
obj-$(CONFIG_TOUCHSCREEN_BITSY) += h3600_ts_input.o
-obj-$(CONFIG_TOUCHSCREEN_BU21013) += bu21013_ts.o
obj-$(CONFIG_TOUCHSCREEN_CYPRESS_TMG) += cy8c_tmg_ts.o
obj-$(CONFIG_TOUCHSCREEN_BU21013) += bu21013_ts.o
obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110) += cy8ctmg110_ts.o
@@ -29,7 +28,6 @@
obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE) += hampshire.o
obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o
obj-$(CONFIG_TOUCHSCREEN_EETI) += eeti_ts.o
-obj-$(CONFIG_TOUCHSCREEN_ELAN_I2C_8232) += elan8232_i2c.o
obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o
obj-$(CONFIG_TOUCHSCREEN_EGALAX) += egalax_ts.o
obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index db4ec9d..330c850 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -16,7 +16,7 @@
# MSM IOMMU support
config MSM_IOMMU
bool "MSM IOMMU Support"
- depends on ARCH_MSM8X60 || ARCH_MSM8960 || ARCH_APQ8064 || ARCH_MSM8974 || ARCH_MPQ8092 || ARCH_MSM8610 || ARCH_MSM8226
+ depends on ARCH_MSM8X60 || ARCH_MSM8960 || ARCH_APQ8064 || ARCH_MSM8974 || ARCH_MPQ8092 || ARCH_MSM8610 || ARCH_MSM8226 || ARCH_MSMZINC
select IOMMU_API
help
Support for the IOMMUs found on certain Qualcomm SOCs.
diff --git a/drivers/iommu/msm_iommu_sec.c b/drivers/iommu/msm_iommu_sec.c
index 29cf0c1..44146a4 100644
--- a/drivers/iommu/msm_iommu_sec.c
+++ b/drivers/iommu/msm_iommu_sec.c
@@ -88,7 +88,7 @@
return 0;
of_node_put(np);
- ret = scm_call(SCM_SVC_CP, IOMMU_SECURE_PTBL_SIZE, &spare,
+ ret = scm_call(SCM_SVC_MP, IOMMU_SECURE_PTBL_SIZE, &spare,
sizeof(spare), psize, sizeof(psize));
if (ret) {
pr_err("scm call IOMMU_SECURE_PTBL_SIZE failed\n");
@@ -111,7 +111,7 @@
pinit.paddr = virt_to_phys(buf);
pinit.size = psize[0];
- ret = scm_call(SCM_SVC_CP, IOMMU_SECURE_PTBL_INIT, &pinit,
+ ret = scm_call(SCM_SVC_MP, IOMMU_SECURE_PTBL_INIT, &pinit,
sizeof(pinit), &ptbl_ret, sizeof(ptbl_ret));
if (ret) {
pr_err("scm call IOMMU_SECURE_PTBL_INIT failed\n");
@@ -142,7 +142,7 @@
cfg.id = sec_id;
- ret = scm_call(SCM_SVC_CP, IOMMU_SECURE_CFG, &cfg, sizeof(cfg),
+ ret = scm_call(SCM_SVC_MP, IOMMU_SECURE_CFG, &cfg, sizeof(cfg),
&scm_ret, sizeof(scm_ret));
if (ret || scm_ret) {
pr_err("scm call IOMMU_SECURE_CFG failed\n");
@@ -167,7 +167,7 @@
map.info.va = va;
map.info.size = len;
- if (scm_call(SCM_SVC_CP, IOMMU_SECURE_MAP, &map, sizeof(map), &ret,
+ if (scm_call(SCM_SVC_MP, IOMMU_SECURE_MAP, &map, sizeof(map), &ret,
sizeof(ret)))
return -EINVAL;
if (ret)
@@ -242,7 +242,7 @@
map.plist.size = SZ_1M;
}
- ret = scm_call(SCM_SVC_CP, IOMMU_SECURE_MAP, &map, sizeof(map),
+ ret = scm_call(SCM_SVC_MP, IOMMU_SECURE_MAP, &map, sizeof(map),
&scm_ret, sizeof(scm_ret));
kfree(pa_list);
return ret;
@@ -260,7 +260,7 @@
mi.va = va;
mi.size = len;
- ret = scm_call(SCM_SVC_CP, IOMMU_SECURE_UNMAP, &mi, sizeof(mi),
+ ret = scm_call(SCM_SVC_MP, IOMMU_SECURE_UNMAP, &mi, sizeof(mi),
&scm_ret, sizeof(scm_ret));
return ret;
}
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 26e8496..f13e55a 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -195,23 +195,6 @@
To compile this driver as a module, choose M here: the
module will be called leds-msm-tricolor.
-config LEDS_GPIO_PLATFORM
- bool "Platform device bindings for GPIO LEDs"
- depends on LEDS_GPIO
- default y
- help
- Let the leds-gpio driver drive LEDs which have been defined as
- platform devices. If you don't know what this means, say yes.
-
-config LEDS_GPIO_OF
- bool "OpenFirmware platform device bindings for GPIO LEDs"
- depends on LEDS_GPIO && OF_DEVICE
- default y
- help
- Let the leds-gpio driver drive LEDs which have been defined as
- of_platform devices. For instance, LEDs which are listed in a "dts"
- file.
-
config LEDS_LP3944
tristate "LED Support for N.S. LP3944 (Fun Light) I2C chip"
depends on LEDS_CLASS
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index da5db8b..d749d92 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -42,7 +42,7 @@
unsigned int idx_in;
unsigned int idx_out;
sector_t sector;
- atomic_t cc_pending;
+ atomic_t pending;
struct ablkcipher_request *req;
};
@@ -56,7 +56,7 @@
struct convert_context ctx;
- atomic_t io_pending;
+ atomic_t pending;
int error;
sector_t sector;
struct dm_crypt_io *base_io;
@@ -740,14 +740,14 @@
{
int r;
- atomic_set(&ctx->cc_pending, 1);
+ atomic_set(&ctx->pending, 1);
while(ctx->idx_in < ctx->bio_in->bi_vcnt &&
ctx->idx_out < ctx->bio_out->bi_vcnt) {
crypt_alloc_req(cc, ctx);
- atomic_inc(&ctx->cc_pending);
+ atomic_inc(&ctx->pending);
r = crypt_convert_block(cc, ctx, ctx->req);
@@ -764,14 +764,14 @@
/* sync */
case 0:
- atomic_dec(&ctx->cc_pending);
+ atomic_dec(&ctx->pending);
ctx->sector++;
cond_resched();
continue;
/* error */
default:
- atomic_dec(&ctx->cc_pending);
+ atomic_dec(&ctx->pending);
return r;
}
}
@@ -868,14 +868,14 @@
io->error = 0;
io->base_io = NULL;
io->ctx.req = NULL;
- atomic_set(&io->io_pending, 0);
+ atomic_set(&io->pending, 0);
return io;
}
static void crypt_inc_pending(struct dm_crypt_io *io)
{
- atomic_inc(&io->io_pending);
+ atomic_inc(&io->pending);
}
/*
@@ -890,7 +890,7 @@
struct dm_crypt_io *base_io = io->base_io;
int error = io->error;
- if (!atomic_dec_and_test(&io->io_pending))
+ if (!atomic_dec_and_test(&io->pending))
return;
if (io->ctx.req)
@@ -1080,7 +1080,8 @@
r = crypt_convert(cc, &io->ctx);
if (r < 0)
io->error = -EIO;
- crypt_finished = atomic_dec_and_test(&io->ctx.cc_pending);
+
+ crypt_finished = atomic_dec_and_test(&io->ctx.pending);
/* Encryption was already finished, submit io now */
if (crypt_finished) {
@@ -1151,11 +1152,10 @@
io->sector);
r = crypt_convert(cc, &io->ctx);
-
if (r < 0)
io->error = -EIO;
- if (atomic_dec_and_test(&io->ctx.cc_pending))
+ if (atomic_dec_and_test(&io->ctx.pending))
kcryptd_crypt_read_done(io);
crypt_dec_pending(io);
@@ -1182,7 +1182,7 @@
mempool_free(req_of_dmreq(cc, dmreq), cc->req_pool);
- if (!atomic_dec_and_test(&ctx->cc_pending))
+ if (!atomic_dec_and_test(&ctx->pending))
return;
if (bio_data_dir(io->base_bio) == READ)
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c
index 5a61c5f..754f38f 100644
--- a/drivers/md/dm-mpath.c
+++ b/drivers/md/dm-mpath.c
@@ -770,11 +770,6 @@
if (!argc)
return 0;
- if (argc > as->argc) {
- ti->error = "not enough arguments for features";
- return -EINVAL;
- }
-
do {
arg_name = dm_shift_arg(as);
argc--;
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index 52b7994..dce37e5 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -121,6 +121,7 @@
events->notified_index = 0;
events->bytes_read_no_event = 0;
events->current_event_data_size = 0;
+ events->wakeup_events_counter = 0;
}
static inline void dvb_dmxdev_flush_output(struct dvb_ringbuffer *buffer,
@@ -222,6 +223,10 @@
int new_write_index;
int data_event;
+ /* Check if the event is disabled */
+ if (events->event_mask.disable_mask & event->type)
+ return 0;
+
/* Check if we are adding an event that user already read its data */
if (events->bytes_read_no_event) {
data_event = 1;
@@ -241,7 +246,7 @@
if (data_event) {
if (res) {
/*
- * Data relevent to this event was fully
+ * Data relevant to this event was fully
* consumed already, discard event.
*/
events->bytes_read_no_event -= res;
@@ -266,6 +271,9 @@
events->queue[events->write_index] = *event;
events->write_index = new_write_index;
+ if (!(events->event_mask.no_wakeup_mask & event->type))
+ events->wakeup_events_counter++;
+
return 0;
}
@@ -280,6 +288,9 @@
events->notified_index =
dvb_dmxdev_advance_event_idx(events->notified_index);
+ if (!(events->event_mask.no_wakeup_mask & event->type))
+ events->wakeup_events_counter--;
+
return 0;
}
@@ -291,6 +302,13 @@
int data_event;
/*
+ * If data events are not enabled on this filter,
+ * there's nothing to update.
+ */
+ if (events->data_read_event_masked)
+ return 0;
+
+ /*
* Go through all events that were notified and
* remove them from the events queue if their respective
* data was read.
@@ -364,7 +382,7 @@
if (data_event) {
if (res) {
/*
- * Data relevent to this event was
+ * Data relevant to this event was
* fully consumed, remove it from the queue.
*/
bytes_read -= res;
@@ -616,6 +634,9 @@
}
dvb_ringbuffer_init(&dmxdev->dvr_buffer, mem, DVR_BUFFER_SIZE);
dvb_dmxdev_flush_events(&dmxdev->dvr_output_events);
+ dmxdev->dvr_output_events.event_mask.disable_mask = 0;
+ dmxdev->dvr_output_events.event_mask.no_wakeup_mask = 0;
+ dmxdev->dvr_output_events.event_mask.wakeup_threshold = 1;
dmxdev->dvr_feeds_count = 0;
dmxdev->dvr_buffer_mode = DMX_BUFFER_MODE_INTERNAL;
dmxdev->dvr_priv_buff_handle = NULL;
@@ -1429,24 +1450,58 @@
static int dvb_dmxdev_reuse_decoder_buf(struct dmxdev_filter *dmxdevfilter,
int cookie)
{
- if ((dmxdevfilter->type == DMXDEV_TYPE_PES) &&
- (dmxdevfilter->params.pes.output == DMX_OUT_DECODER)) {
- struct dmxdev_feed *feed;
- int ret = -ENODEV;
+ struct dmxdev_feed *feed;
- /* Only one feed should be in the list in case of decoder */
- feed = list_first_entry(&dmxdevfilter->feed.ts,
- struct dmxdev_feed, next);
+ if ((dmxdevfilter->type != DMXDEV_TYPE_PES) ||
+ (dmxdevfilter->params.pes.output != DMX_OUT_DECODER) ||
+ (dmxdevfilter->events.event_mask.disable_mask &
+ DMX_EVENT_NEW_ES_DATA))
+ return -EPERM;
- if (feed->ts->reuse_decoder_buffer)
- ret = feed->ts->reuse_decoder_buffer(
- feed->ts,
- cookie);
+ /* Only one feed should be in the list in case of decoder */
+ feed = list_first_entry(&dmxdevfilter->feed.ts,
+ struct dmxdev_feed, next);
- return ret;
- }
+ if (feed->ts->reuse_decoder_buffer)
+ return feed->ts->reuse_decoder_buffer(feed->ts, cookie);
- return -EPERM;
+ return -ENODEV;
+}
+
+static int dvb_dmxdev_set_event_mask(struct dmxdev_filter *dmxdevfilter,
+ struct dmx_events_mask *event_mask)
+{
+ if (!event_mask ||
+ (event_mask->wakeup_threshold >= DMX_EVENT_QUEUE_SIZE))
+ return -EINVAL;
+
+ if (dmxdevfilter->state == DMXDEV_STATE_GO)
+ return -EBUSY;
+
+ /*
+ * Overflow event is not allowed to be masked.
+ * This is because if overflow occurs, demux stops outputting data
+ * until user is notified. If user is using events to read the data,
+ * the overflow event must be always enabled or otherwise we would
+ * never recover from overflow state.
+ */
+ event_mask->disable_mask &= ~(u32)DMX_EVENT_BUFFER_OVERFLOW;
+ event_mask->no_wakeup_mask &= ~(u32)DMX_EVENT_BUFFER_OVERFLOW;
+
+ dmxdevfilter->events.event_mask = *event_mask;
+
+ return 0;
+}
+
+static int dvb_dmxdev_get_event_mask(struct dmxdev_filter *dmxdevfilter,
+ struct dmx_events_mask *event_mask)
+{
+ if (!event_mask)
+ return -EINVAL;
+
+ *event_mask = dmxdevfilter->events.event_mask;
+
+ return 0;
}
static int dvb_dmxdev_ts_fullness_callback(
@@ -1708,11 +1763,13 @@
}
/*
- * Decoder filters have no data in the data buffer and their
- * events can be removed now from the queue.
+ * If no-data events are enabled on this filter,
+ * the events can be removed from the queue when
+ * user gets them.
+ * For filters with data events enabled, the event is removed
+ * from the queue only when the respective data is read.
*/
- if ((dmxdevfilter->type == DMXDEV_TYPE_PES) &&
- (dmxdevfilter->params.pes.output == DMX_OUT_DECODER))
+ if (dmxdevfilter->events.data_read_event_masked)
dmxdevfilter->events.read_index =
dvb_dmxdev_advance_event_idx(
dmxdevfilter->events.read_index);
@@ -2538,6 +2595,9 @@
(*secfilter)->filter_mask[2] = 0;
filter->todo = 0;
+ filter->events.data_read_event_masked =
+ filter->events.event_mask.disable_mask &
+ DMX_EVENT_NEW_SECTION;
ret = filter->feed.sec.feed->start_filtering(
filter->feed.sec.feed);
@@ -2558,6 +2618,21 @@
filter->params.pes.rec_chunk_size =
filter->buffer.size >> 2;
+ if (filter->params.pes.output == DMX_OUT_TS_TAP)
+ dmxdev->dvr_output_events.data_read_event_masked =
+ dmxdev->dvr_output_events.event_mask.disable_mask &
+ DMX_EVENT_NEW_REC_CHUNK;
+ else if (filter->params.pes.output == DMX_OUT_TSDEMUX_TAP)
+ filter->events.data_read_event_masked =
+ filter->events.event_mask.disable_mask &
+ DMX_EVENT_NEW_REC_CHUNK;
+ else if (filter->params.pes.output == DMX_OUT_TAP)
+ filter->events.data_read_event_masked =
+ filter->events.event_mask.disable_mask &
+ DMX_EVENT_NEW_PES;
+ else
+ filter->events.data_read_event_masked = 1;
+
ret = 0;
list_for_each_entry(feed, &filter->feed.ts, next) {
ret = dvb_dmxdev_start_feed(dmxdev, filter, feed);
@@ -2627,6 +2702,9 @@
dmxdevfilter->priv_buff_handle = NULL;
dvb_ringbuffer_init(&dmxdevfilter->buffer, NULL, 8192);
dvb_dmxdev_flush_events(&dmxdevfilter->events);
+ dmxdevfilter->events.event_mask.disable_mask = DMX_EVENT_NEW_ES_DATA;
+ dmxdevfilter->events.event_mask.no_wakeup_mask = 0;
+ dmxdevfilter->events.event_mask.wakeup_threshold = 1;
dmxdevfilter->type = DMXDEV_TYPE_NONE;
dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED);
@@ -3223,6 +3301,24 @@
mutex_unlock(&dmxdevfilter->mutex);
break;
+ case DMX_SET_EVENTS_MASK:
+ if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+ mutex_unlock(&dmxdev->mutex);
+ return -ERESTARTSYS;
+ }
+ ret = dvb_dmxdev_set_event_mask(dmxdevfilter, parg);
+ mutex_unlock(&dmxdevfilter->mutex);
+ break;
+
+ case DMX_GET_EVENTS_MASK:
+ if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+ mutex_unlock(&dmxdev->mutex);
+ return -ERESTARTSYS;
+ }
+ ret = dvb_dmxdev_get_event_mask(dmxdevfilter, parg);
+ mutex_unlock(&dmxdevfilter->mutex);
+ break;
+
default:
ret = -EINVAL;
break;
@@ -3258,10 +3354,9 @@
if (!dvb_ringbuffer_empty(&dmxdevfilter->buffer))
mask |= (POLLIN | POLLRDNORM);
- if (dmxdevfilter->events.notified_index !=
- dmxdevfilter->events.write_index) {
+ if (dmxdevfilter->events.wakeup_events_counter >=
+ dmxdevfilter->events.event_mask.wakeup_threshold)
mask |= POLLPRI;
- }
return mask;
}
@@ -3430,8 +3525,8 @@
if (!dvb_ringbuffer_empty(&dmxdev->dvr_buffer))
mask |= (POLLIN | POLLRDNORM);
- if (dmxdev->dvr_output_events.notified_index !=
- dmxdev->dvr_output_events.write_index)
+ if (dmxdev->dvr_output_events.wakeup_events_counter >=
+ dmxdev->dvr_output_events.event_mask.wakeup_threshold)
mask |= POLLPRI;
} else {
poll_wait(file, &dmxdev->dvr_input_buffer.queue, wait);
diff --git a/drivers/media/dvb/dvb-core/dmxdev.h b/drivers/media/dvb/dvb-core/dmxdev.h
index a55b4f0..1443de5 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.h
+++ b/drivers/media/dvb/dvb-core/dmxdev.h
@@ -68,8 +68,8 @@
struct dmx_section_feed *feed;
};
-struct dmxdev_events_queue {
#define DMX_EVENT_QUEUE_SIZE 500 /* number of events */
+struct dmxdev_events_queue {
/*
* indices used to manage events queue.
* read_index advanced when relevent data is read
@@ -94,6 +94,22 @@
u32 current_event_data_size;
u32 current_event_start_offset;
+ /* current setting of the events masking */
+ struct dmx_events_mask event_mask;
+
+ /*
+ * indicates if an event used for data-reading from demux
+ * filter is enabled or not. These are events on which
+ * user may wait for before calling read() on the demux filter.
+ */
+ int data_read_event_masked;
+
+ /*
+ * holds the current number of pending events in the
+ * events queue that are considered as a wake-up source
+ */
+ u32 wakeup_events_counter;
+
struct dmx_filter_event queue[DMX_EVENT_QUEUE_SIZE];
};
diff --git a/drivers/media/platform/msm/camera_v1/gemini/msm_gemini_platform.c b/drivers/media/platform/msm/camera_v1/gemini/msm_gemini_platform.c
index d5a8098..f0882f7 100644
--- a/drivers/media/platform/msm/camera_v1/gemini/msm_gemini_platform.c
+++ b/drivers/media/platform/msm/camera_v1/gemini/msm_gemini_platform.c
@@ -15,7 +15,7 @@
#include <linux/clk.h>
#include <mach/clk.h>
#include <linux/io.h>
-#include <linux/android_pmem.h>
+
#include <mach/camera.h>
#include <mach/iommu_domains.h>
@@ -35,8 +35,6 @@
ion_unmap_iommu(gemini_client, *ionhandle, CAMERA_DOMAIN, GEN_POOL);
ion_free(gemini_client, *ionhandle);
*ionhandle = NULL;
-#elif CONFIG_ANDROID_PMEM
- put_pmem_file(file);
#endif
}
@@ -53,9 +51,6 @@
rc = ion_map_iommu(gemini_client, *ionhandle, CAMERA_DOMAIN, GEN_POOL,
SZ_4K, 0, &paddr, (unsigned long *)&size, 0, 0);
-#elif CONFIG_ANDROID_PMEM
- unsigned long kvstart;
- rc = get_pmem_file(fd, &paddr, &kvstart, &size, file_p);
#else
rc = 0;
paddr = 0;
diff --git a/drivers/media/platform/msm/camera_v1/mercury/msm_mercury_platform.c b/drivers/media/platform/msm/camera_v1/mercury/msm_mercury_platform.c
index e6392fe..3607f2e 100644
--- a/drivers/media/platform/msm/camera_v1/mercury/msm_mercury_platform.c
+++ b/drivers/media/platform/msm/camera_v1/mercury/msm_mercury_platform.c
@@ -13,7 +13,7 @@
#include <linux/module.h>
#include <linux/clk.h>
#include <linux/io.h>
-#include <linux/android_pmem.h>
+
#include <mach/clk.h>
#include <mach/camera.h>
#include <mach/msm_subsystem_map.h>
@@ -39,8 +39,6 @@
GEN_POOL);
ion_free(mercury_client, *ionhandle);
*ionhandle = NULL;
-#elif CONFIG_ANDROID_PMEM
- put_pmem_file(file);
#endif
}
@@ -59,10 +57,6 @@
rc = ion_map_iommu(mercury_client, *ionhandle, CAMERA_DOMAIN,
GEN_POOL, SZ_4K, 0, &paddr,
(unsigned long *)&size, 0, 0);
-#elif CONFIG_ANDROID_PMEM
- unsigned long kvstart;
- rc = get_pmem_file(fd, &paddr, &kvstart, &size, file_p);
-#else
rc = 0;
paddr = 0;
size = 0;
diff --git a/drivers/media/platform/msm/camera_v1/msm_camera.c b/drivers/media/platform/msm/camera_v1/msm_camera.c
index 622ecfd..213ccc7 100644
--- a/drivers/media/platform/msm/camera_v1/msm_camera.c
+++ b/drivers/media/platform/msm/camera_v1/msm_camera.c
@@ -28,7 +28,7 @@
#include <linux/fs.h>
#include <linux/list.h>
#include <linux/uaccess.h>
-#include <linux/android_pmem.h>
+
#include <linux/poll.h>
#include <media/msm_camera.h>
#include <mach/camera.h>
@@ -319,15 +319,6 @@
goto out1;
ion_phys(client_for_ion, region->handle,
&paddr, (size_t *)&len);
-#else
- rc = get_pmem_file(info->fd, &paddr, &kvstart, &len, &file);
- if (rc < 0) {
- pr_err("%s: get_pmem_file fd %d error %d\n",
- __func__,
- info->fd, rc);
- goto out1;
- }
- region->file = file;
#endif
if (!info->len)
info->len = len;
@@ -364,8 +355,6 @@
out2:
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
ion_free(client_for_ion, region->handle);
-#else
- put_pmem_file(region->file);
#endif
out1:
kfree(region);
@@ -649,8 +638,6 @@
hlist_del(node);
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
ion_free(client_for_ion, region->handle);
-#else
- put_pmem_file(region->file);
#endif
kfree(region);
CDBG("%s: type %d, vaddr 0x%p\n",
@@ -673,8 +660,6 @@
hlist_del(node);
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
ion_free(client_for_ion, region->handle);
-#else
- put_pmem_file(region->file);
#endif
kfree(region);
CDBG("%s: type %d, vaddr 0x%p\n",
@@ -696,8 +681,6 @@
hlist_del(node);
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
ion_free(client_for_ion, region->handle);
-#else
- put_pmem_file(region->file);
#endif
kfree(region);
CDBG("%s: type %d, vaddr 0x%p\n",
@@ -3012,8 +2995,6 @@
hlist_del(hnode);
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
ion_free(client_for_ion, region->handle);
-#else
- put_pmem_file(region->file);
#endif
kfree(region);
}
@@ -3023,8 +3004,6 @@
hlist_del(hnode);
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
ion_free(client_for_ion, region->handle);
-#else
- put_pmem_file(region->file);
#endif
kfree(region);
}
diff --git a/drivers/media/platform/msm/camera_v1/msm_isp.c b/drivers/media/platform/msm/camera_v1/msm_isp.c
index f646f09..59290ec 100644
--- a/drivers/media/platform/msm/camera_v1/msm_isp.c
+++ b/drivers/media/platform/msm/camera_v1/msm_isp.c
@@ -21,7 +21,7 @@
#include <linux/videodev2.h>
#include <linux/proc_fs.h>
#include <linux/vmalloc.h>
-#include <linux/android_pmem.h>
+
#include <media/v4l2-dev.h>
#include <media/v4l2-ioctl.h>
diff --git a/drivers/media/platform/msm/camera_v1/msm_mctl.c b/drivers/media/platform/msm/camera_v1/msm_mctl.c
index 0210d23..95e889d 100644
--- a/drivers/media/platform/msm/camera_v1/msm_mctl.c
+++ b/drivers/media/platform/msm/camera_v1/msm_mctl.c
@@ -26,7 +26,7 @@
#include <media/v4l2-ioctl.h>
#include <media/v4l2-device.h>
-#include <linux/android_pmem.h>
+
#include "msm.h"
#include "msm_cam_server.h"
diff --git a/drivers/media/platform/msm/camera_v1/msm_mctl_buf.c b/drivers/media/platform/msm/camera_v1/msm_mctl_buf.c
index 3ccd258..041f674 100644
--- a/drivers/media/platform/msm/camera_v1/msm_mctl_buf.c
+++ b/drivers/media/platform/msm/camera_v1/msm_mctl_buf.c
@@ -23,7 +23,7 @@
#include <media/v4l2-ioctl.h>
#include <media/v4l2-device.h>
-#include <linux/android_pmem.h>
+
#include "msm.h"
#include "msm_cam_server.h"
@@ -1015,78 +1015,6 @@
D("%s Frame mapped successfully ", __func__);
return 0;
}
-#else
-/* Unmap using PMEM APIs */
-static int __msm_mctl_unmap_user_frame(struct msm_cam_meta_frame *meta_frame,
- struct ion_client *client, int domain_num)
-{
- int i = 0, rc = 0;
-
- for (i = 0; i < meta_frame->frame.num_planes; i++) {
- D("%s Plane %d handle %p", __func__, i,
- meta_frame->map[i].handle);
- put_pmem_file(meta_frame->map[i].file);
- }
-}
-
-/* Map using PMEM APIs */
-static int __msm_mctl_map_user_frame(struct msm_cam_meta_frame *meta_frame,
- struct ion_client *client, int domain_num)
-{
- unsigned long kvstart = 0;
- unsigned long paddr = 0;
- struct file *file = NULL;
- unsigned long len;
- int i = 0, j = 0;
-
- for (i = 0; i < meta_frame->frame.num_planes; i++) {
- rc = get_pmem_file(meta_frame->frame.mp[i].fd,
- &paddr, &kvstart, &len, &file);
- if (rc < 0) {
- pr_err("%s: get_pmem_file fd %d error %d\n",
- __func__, meta_frame->frame.mp[i].fd, rc);
- /* Roll back previous plane mappings, if any */
- for (j = i-1; j >= 0; j--)
- if (meta_frame->map[j].file)
- put_pmem_file(meta_frame->map[j].file);
-
- return -EACCES;
- }
- D("%s Got pmem file for fd %d plane %d as %p", __func__,
- meta_frame->frame.mp[i].fd, i, file);
- meta_frame->map[i].file = file;
- /* Validate the offsets with the mapped length. */
- if ((meta_frame->frame.mp[i].addr_offset > len) ||
- (meta_frame->frame.mp[i].data_offset +
- meta_frame->frame.mp[i].length > len)) {
- pr_err("%s: Invalid offsets A %d D %d L %d len %ld",
- __func__, meta_frame->frame.mp[i].addr_offset,
- meta_frame->frame.mp[i].data_offset,
- meta_frame->frame.mp[i].length, len);
- /* Roll back previous plane mappings, if any */
- for (j = i; j >= 0; j--)
- if (meta_frame->map[j].file)
- put_pmem_file(meta_frame->map[j].file);
-
- return -EINVAL;
- }
- meta_frame->map[i].data_offset =
- meta_frame->frame.mp[i].data_offset;
- /* Add the addr_offset to the paddr here itself. The addr_offset
- * will be non-zero only if the user has allocated a buffer with
- * a single fd, but logically partitioned it into
- * multiple planes or buffers.*/
- paddr += meta_frame->frame.mp[i].addr_offset;
- meta_frame->map[i].paddr = paddr;
- meta_frame->map[i].len = len;
- D("%s Plane %d fd %d handle %p paddr %x", __func__,
- i, meta_frame->frame.mp[i].fd,
- meta_frame->map[i].handle,
- (uint32_t)meta_frame->map[i].paddr);
- }
- D("%s Frame mapped successfully ", __func__);
- return 0;
-}
#endif
int msm_mctl_map_user_frame(struct msm_cam_meta_frame *meta_frame,
diff --git a/drivers/media/platform/msm/camera_v1/msm_mctl_pp.c b/drivers/media/platform/msm/camera_v1/msm_mctl_pp.c
index 9267c9f..ae3ce63 100644
--- a/drivers/media/platform/msm/camera_v1/msm_mctl_pp.c
+++ b/drivers/media/platform/msm/camera_v1/msm_mctl_pp.c
@@ -25,7 +25,7 @@
#include <media/v4l2-ioctl.h>
#include <media/v4l2-device.h>
-#include <linux/android_pmem.h>
+
#include "msm.h"
#include "msm_vpe.h"
diff --git a/drivers/media/platform/msm/camera_v1/msm_mem.c b/drivers/media/platform/msm/camera_v1/msm_mem.c
index 8144415..c9a87d7 100644
--- a/drivers/media/platform/msm/camera_v1/msm_mem.c
+++ b/drivers/media/platform/msm/camera_v1/msm_mem.c
@@ -25,7 +25,7 @@
#include <media/v4l2-ioctl.h>
#include <media/v4l2-device.h>
-#include <linux/android_pmem.h>
+
#include "msm.h"
@@ -71,26 +71,6 @@
static DEFINE_MUTEX(hlist_mut);
-#ifdef CONFIG_ANDROID_PMEM
-static int check_pmem_info(struct msm_pmem_info *info, int len)
-{
- if (info->offset < len &&
- info->offset + info->len <= len &&
- info->planar0_off < len &&
- info->planar1_off < len)
- return 0;
-
- pr_err("%s: check failed: off %d len %d y %d cbcr %d (total len %d)\n",
- __func__,
- info->offset,
- info->len,
- info->planar0_off,
- info->planar1_off,
- len);
- return -EINVAL;
-}
-#endif
-
static int check_overlap(struct hlist_head *ptype,
unsigned long paddr,
unsigned long len)
@@ -138,14 +118,6 @@
if (ion_map_iommu(client, region->handle, domain_num, 0,
SZ_4K, 0, &paddr, &len, 0, 0) < 0)
goto out2;
-#elif CONFIG_ANDROID_PMEM
- rc = get_pmem_file(info->fd, &paddr, &kvstart, &len, &file);
- if (rc < 0) {
- pr_err("%s: get_pmem_file fd %d error %d\n",
- __func__, info->fd, rc);
- goto out1;
- }
- region->file = file;
#else
paddr = 0;
file = NULL;
@@ -153,9 +125,6 @@
#endif
if (!info->len)
info->len = len;
- rc = check_pmem_info(info, len);
- if (rc < 0)
- goto out3;
paddr += info->offset;
len = info->len;
@@ -185,8 +154,6 @@
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
out2:
ion_free(client, region->handle);
-#elif CONFIG_ANDROID_PMEM
- put_pmem_file(region->file);
#endif
out1:
kfree(region);
@@ -256,8 +223,6 @@
ion_unmap_iommu(client, region->handle,
domain_num, 0);
ion_free(client, region->handle);
-#else
- put_pmem_file(region->file);
#endif
kfree(region);
}
diff --git a/drivers/media/platform/msm/camera_v1/vfe/msm_vfe7x.c b/drivers/media/platform/msm/camera_v1/vfe/msm_vfe7x.c
index bbf9d1b..d7ec547 100644
--- a/drivers/media/platform/msm/camera_v1/vfe/msm_vfe7x.c
+++ b/drivers/media/platform/msm/camera_v1/vfe/msm_vfe7x.c
@@ -14,7 +14,7 @@
#include <linux/msm_adsp.h>
#include <linux/uaccess.h>
#include <linux/fs.h>
-#include <linux/android_pmem.h>
+
#include <linux/slab.h>
#include <mach/msm_adsp.h>
#include <mach/clk.h>
diff --git a/drivers/media/platform/msm/camera_v1/vfe/msm_vfe7x27a.c b/drivers/media/platform/msm/camera_v1/vfe/msm_vfe7x27a.c
index 0279c78..6b41b03 100644
--- a/drivers/media/platform/msm/camera_v1/vfe/msm_vfe7x27a.c
+++ b/drivers/media/platform/msm/camera_v1/vfe/msm_vfe7x27a.c
@@ -13,7 +13,7 @@
#include <linux/msm_adsp.h>
#include <linux/uaccess.h>
#include <linux/fs.h>
-#include <linux/android_pmem.h>
+
#include <linux/slab.h>
#include <linux/pm_qos.h>
#include <linux/delay.h>
diff --git a/drivers/media/platform/msm/camera_v1/vfe/msm_vfe7x27a_v4l2.c b/drivers/media/platform/msm/camera_v1/vfe/msm_vfe7x27a_v4l2.c
index f3388d9..3a8f1b2 100644
--- a/drivers/media/platform/msm/camera_v1/vfe/msm_vfe7x27a_v4l2.c
+++ b/drivers/media/platform/msm/camera_v1/vfe/msm_vfe7x27a_v4l2.c
@@ -13,7 +13,7 @@
#include <linux/msm_adsp.h>
#include <linux/uaccess.h>
#include <linux/fs.h>
-#include <linux/android_pmem.h>
+
#include <linux/slab.h>
#include <linux/pm_qos.h>
#include <linux/delay.h>
diff --git a/drivers/media/platform/msm/camera_v1/vfe/msm_vfe_stats_buf.c b/drivers/media/platform/msm/camera_v1/vfe/msm_vfe_stats_buf.c
index a6807ed..a550d78 100644
--- a/drivers/media/platform/msm/camera_v1/vfe/msm_vfe_stats_buf.c
+++ b/drivers/media/platform/msm/camera_v1/vfe/msm_vfe_stats_buf.c
@@ -25,7 +25,7 @@
#include <media/v4l2-ioctl.h>
#include <media/v4l2-device.h>
-#include <linux/android_pmem.h>
+
#include <media/msm_camera.h>
#include <media/msm_isp.h>
#include "msm.h"
@@ -162,25 +162,6 @@
return rc;
}
-#ifdef CONFIG_ANDROID_PMEM
-static int msm_stats_check_pmem_info(struct msm_stats_buf_info *info, int len)
-{
- if (info->offset < len &&
- info->offset + info->len <= len &&
- info->planar0_off < len && info->planar1_off < len)
- return 0;
-
- pr_err("%s: check failed: off %d len %d y %d cbcr %d (total len %d)\n",
- __func__,
- info->offset,
- info->len,
- info->planar0_off,
- info->planar1_off,
- len);
- return -EINVAL;
-}
-#endif
-
static int msm_stats_buf_prepare(struct msm_stats_bufq_ctrl *stats_ctrl,
struct msm_stats_buf_info *info, struct ion_client *client,
int domain_num)
@@ -226,14 +207,6 @@
pr_err("%s: cannot map address", __func__);
goto out2;
}
-#elif CONFIG_ANDROID_PMEM
- rc = get_pmem_file(info->fd, &paddr, &kvstart, &len, &file);
- if (rc < 0) {
- pr_err("%s: get_pmem_file fd %d error %d\n",
- __func__, info->fd, rc);
- goto out1;
- }
- stats_buf->file = file;
#else
paddr = 0;
file = NULL;
@@ -241,11 +214,6 @@
#endif
if (!info->len)
info->len = len;
- rc = msm_stats_check_pmem_info(info, len);
- if (rc < 0) {
- pr_err("%s: msm_stats_check_pmem_info err = %d", __func__, rc);
- goto out3;
- }
paddr += info->offset;
len = info->len;
stats_buf->paddr = paddr;
@@ -256,15 +224,12 @@
D("%s pmem_stats address is 0x%ld\n", __func__, paddr);
stats_buf->state = MSM_STATS_BUFFER_STATE_PREPARED;
return 0;
-out3:
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
ion_unmap_iommu(client, stats_buf->handle, domain_num, 0);
#endif
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
out2:
ion_free(client, stats_buf->handle);
-#elif CONFIG_ANDROID_PMEM
- put_pmem_file(stats_buf->file);
#endif
out1:
return rc;
@@ -295,8 +260,6 @@
ion_unmap_iommu(client, stats_buf->handle,
domain_num, 0);
ion_free(client, stats_buf->handle);
-#else
- put_pmem_file(stats_buf->file);
#endif
if (stats_buf->state == MSM_STATS_BUFFER_STATE_QUEUED) {
/* buf queued need delete from list */
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 c8873b8..3a24428 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
@@ -20,7 +20,7 @@
#include <linux/proc_fs.h>
#include <linux/videodev2.h>
#include <linux/vmalloc.h>
-#include <linux/android_pmem.h>
+
#include <media/v4l2-dev.h>
#include <media/v4l2-ioctl.h>
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
index 69d523c..38130db 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
@@ -378,8 +378,8 @@
struct msm_vfe_tasklet_queue_cmd
tasklet_queue_cmd[MSM_VFE_TASKLETQ_SIZE];
+ uint32_t vfe_hw_version;
struct msm_vfe_hardware_info *hw_info;
-
struct msm_vfe_axi_shared_data axi_data;
struct msm_vfe_stats_shared_data stats_data;
struct msm_vfe_error_info error_info;
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
index fc0a8b5..a786750 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
@@ -29,6 +29,9 @@
#define CDBG(fmt, args...) do { } while (0)
#endif
+#define VFE40_V1_VERSION 0x10000018
+#define VFE40_V2_VERSION 0x1001001A
+
#define VFE40_BURST_LEN 3
#define VFE40_STATS_BURST_LEN 2
#define VFE40_UB_SIZE 1536
@@ -117,59 +120,104 @@
{"camss_csi_vfe_clk", -1},
{"iface_clk", -1},
{"bus_clk", -1},
- {"alt_bus_clk", -1},
};
static void msm_vfe40_init_qos_parms(struct vfe_device *vfe_dev)
{
void __iomem *vfebase = vfe_dev->vfe_base;
- msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_0);
- msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_1);
- msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_2);
- msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_3);
- msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_4);
- msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_5);
- msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_6);
- msm_camera_io_w(0x0002AAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_7);
+ if (vfe_dev->vfe_hw_version == VFE40_V1_VERSION) {
+ msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_0);
+ msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_1);
+ msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_2);
+ msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_3);
+ msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_4);
+ msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_5);
+ msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_6);
+ msm_camera_io_w(0x0002AAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_7);
+ } else if (vfe_dev->vfe_hw_version == VFE40_V2_VERSION) {
+ msm_camera_io_w(0xAAA9AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_0);
+ msm_camera_io_w(0xAAA9AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_1);
+ msm_camera_io_w(0xAAA9AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_2);
+ msm_camera_io_w(0xAAA9AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_3);
+ msm_camera_io_w(0xAAA9AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_4);
+ msm_camera_io_w(0xAAA9AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_5);
+ msm_camera_io_w(0xAAA9AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_6);
+ msm_camera_io_w(0x0001AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_7);
+ }
}
-static void msm_vfe40_init_vbif_parms(
- void __iomem *vfe_vbif_base)
+static void msm_vfe40_init_vbif_parms(struct vfe_device *vfe_dev)
{
- msm_camera_io_w(0x1,
- vfe_vbif_base + VFE40_VBIF_CLKON);
- msm_camera_io_w(0x01010101,
- vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF0);
- msm_camera_io_w(0x01010101,
- vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF1);
- msm_camera_io_w(0x10010110,
- vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF2);
- msm_camera_io_w(0x10101010,
- vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF0);
- msm_camera_io_w(0x10101010,
- vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF1);
- msm_camera_io_w(0x10101010,
- vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF2);
- msm_camera_io_w(0x00001010,
- vfe_vbif_base + VFE40_VBIF_OUT_RD_LIM_CONF0);
- msm_camera_io_w(0x00001010,
- vfe_vbif_base + VFE40_VBIF_OUT_WR_LIM_CONF0);
- msm_camera_io_w(0x00000707,
- vfe_vbif_base + VFE40_VBIF_DDR_OUT_MAX_BURST);
- msm_camera_io_w(0x00000707,
- vfe_vbif_base + VFE40_VBIF_OCMEM_OUT_MAX_BURST);
- msm_camera_io_w(0x00000030,
- vfe_vbif_base + VFE40_VBIF_ARB_CTL);
- msm_camera_io_w(0x00000FFF,
- vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO_EN);
- msm_camera_io_w(0x0FFF0FFF,
- vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO);
- msm_camera_io_w(0x00000001,
- vfe_vbif_base + VFE40_VBIF_ROUND_ROBIN_QOS_ARB);
- msm_camera_io_w(0x22222222,
- vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF0);
- msm_camera_io_w(0x00002222,
- vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF1);
+ void __iomem *vfe_vbif_base = vfe_dev->vfe_vbif_base;
+ if (vfe_dev->vfe_hw_version == VFE40_V1_VERSION) {
+ msm_camera_io_w(0x1,
+ vfe_vbif_base + VFE40_VBIF_CLKON);
+ msm_camera_io_w(0x01010101,
+ vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF0);
+ msm_camera_io_w(0x01010101,
+ vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF1);
+ msm_camera_io_w(0x10010110,
+ vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF2);
+ msm_camera_io_w(0x10101010,
+ vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF0);
+ msm_camera_io_w(0x10101010,
+ vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF1);
+ msm_camera_io_w(0x10101010,
+ vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF2);
+ msm_camera_io_w(0x00001010,
+ vfe_vbif_base + VFE40_VBIF_OUT_RD_LIM_CONF0);
+ msm_camera_io_w(0x00001010,
+ vfe_vbif_base + VFE40_VBIF_OUT_WR_LIM_CONF0);
+ msm_camera_io_w(0x00000707,
+ vfe_vbif_base + VFE40_VBIF_DDR_OUT_MAX_BURST);
+ msm_camera_io_w(0x00000707,
+ vfe_vbif_base + VFE40_VBIF_OCMEM_OUT_MAX_BURST);
+ msm_camera_io_w(0x00000030,
+ vfe_vbif_base + VFE40_VBIF_ARB_CTL);
+ msm_camera_io_w(0x00000FFF,
+ vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO_EN);
+ msm_camera_io_w(0x0FFF0FFF,
+ vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO);
+ msm_camera_io_w(0x00000001,
+ vfe_vbif_base + VFE40_VBIF_ROUND_ROBIN_QOS_ARB);
+ msm_camera_io_w(0x22222222,
+ vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF0);
+ msm_camera_io_w(0x00002222,
+ vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF1);
+ } else if (vfe_dev->vfe_hw_version == VFE40_V2_VERSION) {
+ msm_camera_io_w(0x1,
+ vfe_vbif_base + VFE40_VBIF_CLKON);
+ msm_camera_io_w(0x10101010,
+ vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF0);
+ msm_camera_io_w(0x10101010,
+ vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF1);
+ msm_camera_io_w(0x10101010,
+ vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF2);
+ msm_camera_io_w(0x10101010,
+ vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF0);
+ msm_camera_io_w(0x10101010,
+ vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF1);
+ msm_camera_io_w(0x10101010,
+ vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF2);
+ msm_camera_io_w(0x00000010,
+ vfe_vbif_base + VFE40_VBIF_OUT_RD_LIM_CONF0);
+ msm_camera_io_w(0x00000010,
+ vfe_vbif_base + VFE40_VBIF_OUT_WR_LIM_CONF0);
+ msm_camera_io_w(0x00000707,
+ vfe_vbif_base + VFE40_VBIF_DDR_OUT_MAX_BURST);
+ msm_camera_io_w(0x00000010,
+ vfe_vbif_base + VFE40_VBIF_ARB_CTL);
+ msm_camera_io_w(0x00000FFF,
+ vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO_EN);
+ msm_camera_io_w(0x0FFF0FFF,
+ vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO);
+ msm_camera_io_w(0x00000003,
+ vfe_vbif_base + VFE40_VBIF_ROUND_ROBIN_QOS_ARB);
+ msm_camera_io_w(0x22222222,
+ vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF0);
+ msm_camera_io_w(0x00002222,
+ vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF1);
+ }
}
static int msm_vfe40_init_hardware(struct vfe_device *vfe_dev)
@@ -254,7 +302,7 @@
static void msm_vfe40_init_hardware_reg(struct vfe_device *vfe_dev)
{
msm_vfe40_init_qos_parms(vfe_dev);
- msm_vfe40_init_vbif_parms(vfe_dev->vfe_vbif_base);
+ msm_vfe40_init_vbif_parms(vfe_dev);
/* CGC_OVERRIDE */
msm_camera_io_w(0x3FFFFFFF, vfe_dev->vfe_base + 0x14);
msm_camera_io_w(0xC001FF7F, vfe_dev->vfe_base + 0x974);
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 5baeb28..f337e27 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
@@ -637,6 +637,9 @@
mutex_unlock(&vfe_dev->mutex);
return -EINVAL;
}
+ vfe_dev->vfe_hw_version = msm_camera_io_r(vfe_dev->vfe_base);
+ ISP_DBG("%s: HW Version: 0x%x\n", __func__, vfe_dev->vfe_hw_version);
+
vfe_dev->hw_info->vfe_ops.core_ops.init_hw_reg(vfe_dev);
for (i = 0; i < vfe_dev->hw_info->num_iommu_ctx; i++)
@@ -649,10 +652,6 @@
sizeof(struct msm_vfe_stats_shared_data));
memset(&vfe_dev->error_info, 0, sizeof(vfe_dev->error_info));
vfe_dev->axi_data.hw_info = vfe_dev->hw_info->axi_hw_info;
-
- ISP_DBG("%s: HW Version: 0x%x\n",
- __func__, msm_camera_io_r(vfe_dev->vfe_base));
-
vfe_dev->vfe_open_cnt++;
vfe_dev->taskletq_idx = 0;
mutex_unlock(&vfe_dev->mutex);
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 691edc3..ddf4c67 100644
--- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
@@ -59,6 +59,79 @@
false : true;
}
+static struct msm_cam_clk_info ispif_8960_clk_info[] = {
+ {"csi_pix_clk", 0},
+ {"csi_rdi_clk", 0},
+ {"csi_pix1_clk", 0},
+ {"csi_rdi1_clk", 0},
+ {"csi_rdi2_clk", 0},
+};
+
+static struct msm_cam_clk_info ispif_8974_clk_info_vfe0[] = {
+ {"camss_vfe_vfe_clk", -1},
+ {"camss_csi_vfe_clk", -1},
+};
+
+static struct msm_cam_clk_info ispif_8974_clk_info_vfe1[] = {
+ {"camss_vfe_vfe_clk1", -1},
+ {"camss_csi_vfe_clk1", -1},
+};
+
+static int msm_ispif_clk_enable(struct ispif_device *ispif,
+ enum msm_ispif_vfe_intf vfe_intf, int enable)
+{
+ int rc = 0;
+
+ if (enable)
+ pr_debug("enable clk for VFE%d\n", vfe_intf);
+ else
+ pr_debug("disable clk for VFE%d\n", vfe_intf);
+
+ if (ispif->csid_version < CSID_VERSION_V2) {
+ rc = msm_cam_clk_enable(&ispif->pdev->dev, ispif_8960_clk_info,
+ ispif->ispif_clk[vfe_intf], 2, enable);
+ if (rc) {
+ pr_err("%s: cannot enable clock, error = %d\n",
+ __func__, rc);
+ goto end;
+ }
+ } else if (ispif->csid_version == CSID_VERSION_V2) {
+ rc = msm_cam_clk_enable(&ispif->pdev->dev, ispif_8960_clk_info,
+ ispif->ispif_clk[vfe_intf],
+ ARRAY_SIZE(ispif_8960_clk_info),
+ enable);
+ if (rc) {
+ pr_err("%s: cannot enable clock, error = %d\n",
+ __func__, rc);
+ goto end;
+ }
+ } else if (ispif->csid_version >= CSID_VERSION_V3) {
+ if (vfe_intf == VFE0) {
+ rc = msm_cam_clk_enable(&ispif->pdev->dev,
+ ispif_8974_clk_info_vfe0,
+ ispif->ispif_clk[vfe_intf],
+ ARRAY_SIZE(ispif_8974_clk_info_vfe0), enable);
+ } else {
+ rc = msm_cam_clk_enable(&ispif->pdev->dev,
+ ispif_8974_clk_info_vfe1,
+ ispif->ispif_clk[vfe_intf],
+ ARRAY_SIZE(ispif_8974_clk_info_vfe1), enable);
+ }
+ if (rc) {
+ pr_err("%s: cannot enable clock, error = %d\n",
+ __func__, rc);
+ goto end;
+ }
+ } else {
+ pr_err("%s: unsupported version=%d\n", __func__,
+ ispif->csid_version);
+ goto end;
+ }
+
+end:
+ return rc;
+}
+
static int msm_ispif_intf_reset(struct ispif_device *ispif,
struct msm_ispif_param_data *params)
{
@@ -97,8 +170,8 @@
unsigned long flags;
spin_lock_irqsave(&ispif->auto_complete_lock, flags);
- ispif->wait_timeout = 0;
- init_completion(&ispif->reset_complete);
+ ispif->wait_timeout[params->vfe_intf] = 0;
+ init_completion(&ispif->reset_complete[params->vfe_intf]);
spin_unlock_irqrestore(&ispif->auto_complete_lock, flags);
if (params->vfe_intf == VFE0)
@@ -106,14 +179,15 @@
else
msm_camera_io_w(data, ispif->base +
ISPIF_RST_CMD_1_ADDR);
+
lrc = wait_for_completion_interruptible_timeout(
- &ispif->reset_complete, jiffes);
+ &ispif->reset_complete[params->vfe_intf], jiffes);
if (lrc < 0 || !lrc) {
pr_err("%s: wait timeout ret = %ld\n", __func__, lrc);
rc = -EIO;
spin_lock_irqsave(&ispif->auto_complete_lock, flags);
- ispif->wait_timeout = 1;
+ ispif->wait_timeout[params->vfe_intf] = 1;
spin_unlock_irqrestore(
&ispif->auto_complete_lock, flags);
}
@@ -129,8 +203,12 @@
unsigned long flags;
spin_lock_irqsave(&ispif->auto_complete_lock, flags);
- ispif->wait_timeout = 0;
- init_completion(&ispif->reset_complete);
+ ispif->wait_timeout[VFE0] = 0;
+ init_completion(&ispif->reset_complete[VFE0]);
+ if (ispif->csid_version >= CSID_VERSION_V3) {
+ ispif->wait_timeout[VFE1] = 0;
+ init_completion(&ispif->reset_complete[VFE1]);
+ }
spin_unlock_irqrestore(&ispif->auto_complete_lock, flags);
BUG_ON(!ispif);
@@ -139,22 +217,40 @@
msm_camera_io_w(ISPIF_RST_CMD_MASK, ispif->base + ISPIF_RST_CMD_ADDR);
- if (ispif->csid_version >= CSID_VERSION_V3)
- msm_camera_io_w_mb(ISPIF_RST_CMD_1_MASK, ispif->base +
- ISPIF_RST_CMD_1_ADDR);
-
lrc = wait_for_completion_interruptible_timeout(
- &ispif->reset_complete, jiffes);
+ &ispif->reset_complete[VFE0], jiffes);
if (lrc < 0 || !lrc) {
pr_err("%s: wait timeout ret = %ld\n", __func__, lrc);
rc = -EIO;
spin_lock_irqsave(&ispif->auto_complete_lock, flags);
- ispif->wait_timeout = 1;
+ ispif->wait_timeout[VFE0] = 1;
spin_unlock_irqrestore(&ispif->auto_complete_lock, flags);
+
+ goto end;
}
+ if (ispif->csid_version >= CSID_VERSION_V3) {
+ msm_camera_io_w_mb(ISPIF_RST_CMD_1_MASK, ispif->base +
+ ISPIF_RST_CMD_1_ADDR);
+
+ lrc = wait_for_completion_interruptible_timeout(
+ &ispif->reset_complete[VFE1], jiffes);
+
+ if (lrc < 0 || !lrc) {
+ pr_err("%s: wait timeout ret = %ld\n", __func__, lrc);
+ rc = -EIO;
+
+ spin_lock_irqsave(&ispif->auto_complete_lock, flags);
+ ispif->wait_timeout[VFE1] = 1;
+ spin_unlock_irqrestore(&ispif->auto_complete_lock,
+ flags);
+ }
+
+ }
+
+end:
return rc;
}
@@ -181,20 +277,19 @@
}
if (ispif->csid_version <= CSID_VERSION_V2) {
- if (ispif->ispif_clk[intftype] == NULL) {
+ if (ispif->ispif_clk[vfe_intf][intftype] == NULL) {
CDBG("%s: ispif NULL clk\n", __func__);
return;
}
- rc = clk_set_rate(ispif->ispif_clk[intftype], csid);
+ rc = clk_set_rate(ispif->ispif_clk[vfe_intf][intftype], csid);
if (rc) {
pr_err("%s: clk_set_rate failed %d\n", __func__, rc);
return;
}
}
- data = msm_camera_io_r(ispif->base + ISPIF_INPUT_SEL_ADDR +
- (0x200 * vfe_intf));
+ data = msm_camera_io_r(ispif->base + ISPIF_VFE_m_INPUT_SEL(vfe_intf));
switch (intftype) {
case PIX0:
data &= ~(BIT(1) | BIT(0));
@@ -218,8 +313,8 @@
break;
}
if (data)
- msm_camera_io_w_mb(data, ispif->base + ISPIF_INPUT_SEL_ADDR +
- (0x200 * vfe_intf));
+ msm_camera_io_w_mb(data, ispif->base +
+ ISPIF_VFE_m_INPUT_SEL(vfe_intf));
}
static void msm_ispif_enable_intf_cids(struct ispif_device *ispif,
@@ -236,19 +331,19 @@
switch (intftype) {
case PIX0:
- intf_addr = ISPIF_PIX_0_INTF_CID_MASK_ADDR + (0x200 * vfe_intf);
+ intf_addr = ISPIF_VFE_m_PIX_INTF_n_CID_MASK(vfe_intf, 0);
break;
case RDI0:
- intf_addr = ISPIF_RDI_0_INTF_CID_MASK_ADDR + (0x200 * vfe_intf);
+ intf_addr = ISPIF_VFE_m_RDI_INTF_n_CID_MASK(vfe_intf, 0);
break;
case PIX1:
- intf_addr = ISPIF_PIX_1_INTF_CID_MASK_ADDR + (0x200 * vfe_intf);
+ intf_addr = ISPIF_VFE_m_PIX_INTF_n_CID_MASK(vfe_intf, 1);
break;
case RDI1:
- intf_addr = ISPIF_RDI_1_INTF_CID_MASK_ADDR + (0x200 * vfe_intf);
+ intf_addr = ISPIF_VFE_m_RDI_INTF_n_CID_MASK(vfe_intf, 1);
break;
case RDI2:
- intf_addr = ISPIF_RDI_2_INTF_CID_MASK_ADDR + (0x200 * vfe_intf);
+ intf_addr = ISPIF_VFE_m_RDI_INTF_n_CID_MASK(vfe_intf, 2);
break;
default:
pr_err("%s: invalid intftype=%d\n", __func__, intftype);
@@ -280,23 +375,23 @@
switch (intftype) {
case PIX0:
data = msm_camera_io_r(ispif->base +
- ISPIF_PIX_0_STATUS_ADDR + (0x200 * vfe_intf));
+ ISPIF_VFE_m_PIX_INTF_n_STATUS(vfe_intf, 0));
break;
case RDI0:
data = msm_camera_io_r(ispif->base +
- ISPIF_RDI_0_STATUS_ADDR + (0x200 * vfe_intf));
+ ISPIF_VFE_m_RDI_INTF_n_STATUS(vfe_intf, 0));
break;
case PIX1:
data = msm_camera_io_r(ispif->base +
- ISPIF_PIX_1_STATUS_ADDR + (0x200 * vfe_intf));
+ ISPIF_VFE_m_PIX_INTF_n_STATUS(vfe_intf, 1));
break;
case RDI1:
data = msm_camera_io_r(ispif->base +
- ISPIF_RDI_1_STATUS_ADDR + (0x200 * vfe_intf));
+ ISPIF_VFE_m_RDI_INTF_n_STATUS(vfe_intf, 1));
break;
case RDI2:
data = msm_camera_io_r(ispif->base +
- ISPIF_RDI_2_STATUS_ADDR + (0x200 * vfe_intf));
+ ISPIF_VFE_m_RDI_INTF_n_STATUS(vfe_intf, 2));
break;
}
if ((data & 0xf) != 0xf)
@@ -330,14 +425,22 @@
BUG_ON(!params);
vfe_intf = params->vfe_intf;
+
+ rc = msm_ispif_clk_enable(ispif, vfe_intf, 1);
+ if (rc < 0) {
+ pr_err("%s: unable to enable clocks for VFE%d", __func__,
+ vfe_intf);
+ return rc;
+ }
+
if (!msm_ispif_is_intf_valid(ispif->csid_version, vfe_intf)) {
pr_err("%s: invalid interface type\n", __func__);
return -EINVAL;
}
- msm_camera_io_w(0x0, ispif->base + ISPIF_IRQ_MASK_ADDR);
- msm_camera_io_w(0x0, ispif->base + ISPIF_IRQ_MASK_1_ADDR);
- msm_camera_io_w_mb(0x0, ispif->base + ISPIF_IRQ_MASK_2_ADDR);
+ msm_camera_io_w(0x0, ispif->base + ISPIF_VFE_m_IRQ_MASK_0(vfe_intf));
+ msm_camera_io_w(0x0, ispif->base + ISPIF_VFE_m_IRQ_MASK_1(vfe_intf));
+ msm_camera_io_w_mb(0x0, ispif->base + ISPIF_VFE_m_IRQ_MASK_2(vfe_intf));
for (i = 0; i < params->num; i++) {
intftype = params->entries[i].intftype;
@@ -371,26 +474,29 @@
}
msm_camera_io_w(ISPIF_IRQ_STATUS_MASK, ispif->base +
- ISPIF_IRQ_MASK_ADDR);
+ ISPIF_VFE_m_IRQ_MASK_0(vfe_intf));
msm_camera_io_w(ISPIF_IRQ_STATUS_MASK, ispif->base +
- ISPIF_IRQ_CLEAR_ADDR);
+ ISPIF_VFE_m_IRQ_CLEAR_0(vfe_intf));
msm_camera_io_w(ISPIF_IRQ_STATUS_1_MASK, ispif->base +
- ISPIF_IRQ_MASK_1_ADDR);
+ ISPIF_VFE_m_IRQ_MASK_1(vfe_intf));
msm_camera_io_w(ISPIF_IRQ_STATUS_1_MASK, ispif->base +
- ISPIF_IRQ_CLEAR_1_ADDR);
+ ISPIF_VFE_m_IRQ_CLEAR_1(vfe_intf));
msm_camera_io_w(ISPIF_IRQ_STATUS_2_MASK, ispif->base +
- ISPIF_IRQ_MASK_2_ADDR);
+ ISPIF_VFE_m_IRQ_MASK_2(vfe_intf));
msm_camera_io_w(ISPIF_IRQ_STATUS_2_MASK, ispif->base +
- ISPIF_IRQ_CLEAR_2_ADDR);
+ ISPIF_VFE_m_IRQ_CLEAR_2(vfe_intf));
msm_camera_io_w_mb(ISPIF_IRQ_GLOBAL_CLEAR_CMD, ispif->base +
ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR);
+
+ rc = msm_ispif_clk_enable(ispif, vfe_intf, 0);
+
return rc;
}
@@ -436,14 +542,12 @@
/* cmd for PIX0, PIX1, RDI0, RDI1 */
if (ispif->applied_intf_cmd[vfe_intf].intf_cmd != 0xFFFFFFFF) {
msm_camera_io_w_mb(ispif->applied_intf_cmd[vfe_intf].intf_cmd,
- ispif->base + ISPIF_INTF_CMD_ADDR +
- (0x200 * vfe_intf));
+ ispif->base + ISPIF_VFE_m_INTF_CMD_0(vfe_intf));
}
/* cmd for RDI2 */
if (ispif->applied_intf_cmd[vfe_intf].intf_cmd1 != 0xFFFFFFFF)
msm_camera_io_w_mb(ispif->applied_intf_cmd[vfe_intf].intf_cmd1,
- ispif->base + ISPIF_INTF_CMD_1_ADDR +
- (0x200 * vfe_intf));
+ ispif->base + ISPIF_VFE_m_INTF_CMD_1(vfe_intf));
}
static int msm_ispif_stop_immediately(struct ispif_device *ispif,
@@ -464,6 +568,7 @@
msm_ispif_enable_intf_cids(ispif, params->entries[i].intftype,
cid_mask, params->vfe_intf, 0);
}
+
return rc;
}
@@ -472,6 +577,13 @@
{
int rc;
+ rc = msm_ispif_clk_enable(ispif, params->vfe_intf, 1);
+ if (rc < 0) {
+ pr_err("%s: unable to enable clocks for VFE%d", __func__,
+ params->vfe_intf);
+ return rc;
+ }
+
rc = msm_ispif_intf_reset(ispif, params);
if (rc) {
pr_err("%s: msm_ispif_intf_reset failed. rc=%d\n",
@@ -480,6 +592,9 @@
}
msm_ispif_intf_cmd(ispif, ISPIF_INTF_CMD_ENABLE_FRAME_BOUNDARY, params);
+
+ msm_ispif_clk_enable(ispif, params->vfe_intf, 0);
+
return rc;
}
@@ -489,11 +604,21 @@
int i, rc = 0;
uint16_t cid_mask = 0;
uint32_t intf_addr;
+ enum msm_ispif_vfe_intf vfe_intf;
BUG_ON(!ispif);
BUG_ON(!params);
- if (!msm_ispif_is_intf_valid(ispif->csid_version, params->vfe_intf)) {
+ vfe_intf = params->vfe_intf;
+
+ rc = msm_ispif_clk_enable(ispif, params->vfe_intf, 1);
+ if (rc < 0) {
+ pr_err("%s: unable to enable clocks for VFE%d", __func__,
+ params->vfe_intf);
+ return rc;
+ }
+
+ if (!msm_ispif_is_intf_valid(ispif->csid_version, vfe_intf)) {
pr_err("%s: invalid interface type\n", __func__);
return -EINVAL;
}
@@ -507,24 +632,19 @@
switch (params->entries[i].intftype) {
case PIX0:
- intf_addr = ISPIF_PIX_0_STATUS_ADDR +
- (0x200 * params->vfe_intf);
+ intf_addr = ISPIF_VFE_m_PIX_INTF_n_STATUS(vfe_intf, 0);
break;
case RDI0:
- intf_addr = ISPIF_RDI_0_STATUS_ADDR +
- (0x200 * params->vfe_intf);
+ intf_addr = ISPIF_VFE_m_RDI_INTF_n_STATUS(vfe_intf, 0);
break;
case PIX1:
- intf_addr = ISPIF_PIX_1_STATUS_ADDR +
- (0x200 * params->vfe_intf);
+ intf_addr = ISPIF_VFE_m_PIX_INTF_n_STATUS(vfe_intf, 1);
break;
case RDI1:
- intf_addr = ISPIF_RDI_1_STATUS_ADDR +
- (0x200 * params->vfe_intf);
+ intf_addr = ISPIF_VFE_m_RDI_INTF_n_STATUS(vfe_intf, 1);
break;
case RDI2:
- intf_addr = ISPIF_RDI_2_STATUS_ADDR +
- (0x200 * params->vfe_intf);
+ intf_addr = ISPIF_VFE_m_RDI_INTF_n_STATUS(vfe_intf, 2);
break;
default:
pr_err("%s: invalid intftype=%d\n", __func__,
@@ -539,8 +659,11 @@
/* disable CIDs in CID_MASK register */
msm_ispif_enable_intf_cids(ispif, params->entries[i].intftype,
- cid_mask, params->vfe_intf, 0);
+ cid_mask, vfe_intf, 0);
}
+
+ msm_ispif_clk_enable(ispif, vfe_intf, 0);
+
return rc;
}
@@ -577,26 +700,26 @@
BUG_ON(!out);
out[VFE0].ispifIrqStatus0 = msm_camera_io_r(ispif->base +
- ISPIF_IRQ_STATUS_ADDR);
+ ISPIF_VFE_m_IRQ_STATUS_0(VFE0));
msm_camera_io_w(out[VFE0].ispifIrqStatus0,
- ispif->base + ISPIF_IRQ_CLEAR_ADDR);
+ ispif->base + ISPIF_VFE_m_IRQ_CLEAR_0(VFE0));
out[VFE0].ispifIrqStatus1 = msm_camera_io_r(ispif->base +
- ISPIF_IRQ_STATUS_1_ADDR);
+ ISPIF_VFE_m_IRQ_STATUS_1(VFE0));
msm_camera_io_w(out[VFE0].ispifIrqStatus1,
- ispif->base + ISPIF_IRQ_CLEAR_1_ADDR);
+ ispif->base + ISPIF_VFE_m_IRQ_CLEAR_1(VFE0));
out[VFE0].ispifIrqStatus2 = msm_camera_io_r(ispif->base +
- ISPIF_IRQ_STATUS_2_ADDR);
+ ISPIF_VFE_m_IRQ_STATUS_2(VFE0));
msm_camera_io_w_mb(out[VFE0].ispifIrqStatus2,
- ispif->base + ISPIF_IRQ_CLEAR_2_ADDR);
+ ispif->base + ISPIF_VFE_m_IRQ_CLEAR_2(VFE0));
if (out[VFE0].ispifIrqStatus0 & ISPIF_IRQ_STATUS_MASK) {
if (out[VFE0].ispifIrqStatus0 & RESET_DONE_IRQ) {
unsigned long flags;
spin_lock_irqsave(&ispif->auto_complete_lock, flags);
- if (ispif->wait_timeout == 0)
- complete(&ispif->reset_complete);
+ if (ispif->wait_timeout[VFE0] == 0)
+ complete(&ispif->reset_complete[VFE0]);
spin_unlock_irqrestore(
&ispif->auto_complete_lock, flags);
}
@@ -617,19 +740,29 @@
}
if (ispif->csid_version >= CSID_VERSION_V3) {
out[VFE1].ispifIrqStatus0 = msm_camera_io_r(ispif->base +
- ISPIF_IRQ_STATUS_ADDR + 0x200);
+ ISPIF_VFE_m_IRQ_STATUS_0(VFE1));
msm_camera_io_w(out[VFE1].ispifIrqStatus0,
- ispif->base + ISPIF_IRQ_CLEAR_ADDR + 0x200);
+ ispif->base + ISPIF_VFE_m_IRQ_CLEAR_0(VFE1));
out[VFE1].ispifIrqStatus1 = msm_camera_io_r(ispif->base +
- ISPIF_IRQ_STATUS_1_ADDR + 0x200);
+ ISPIF_VFE_m_IRQ_STATUS_1(VFE1));
msm_camera_io_w(out[VFE1].ispifIrqStatus1,
+ ispif->base + ISPIF_VFE_m_IRQ_CLEAR_1(VFE1));
- ispif->base + ISPIF_IRQ_CLEAR_1_ADDR + 0x200);
out[VFE1].ispifIrqStatus2 = msm_camera_io_r(ispif->base +
- ISPIF_IRQ_STATUS_2_ADDR + 0x200);
+ ISPIF_VFE_m_IRQ_STATUS_2(VFE1));
msm_camera_io_w_mb(out[VFE1].ispifIrqStatus2,
- ispif->base + ISPIF_IRQ_CLEAR_2_ADDR + 0x200);
+ ispif->base + ISPIF_VFE_m_IRQ_CLEAR_2(VFE1));
+
+
+ if (out[VFE1].ispifIrqStatus0 & RESET_DONE_IRQ) {
+ unsigned long flags;
+ spin_lock_irqsave(&ispif->auto_complete_lock, flags);
+ if (ispif->wait_timeout[VFE1] == 0)
+ complete(&ispif->reset_complete[VFE1]);
+ spin_unlock_irqrestore(
+ &ispif->auto_complete_lock, flags);
+ }
if (out[VFE1].ispifIrqStatus0 & PIX_INTF_0_OVERFLOW_IRQ)
pr_err("%s: VFE1 pix0 overflow.\n", __func__);
@@ -657,20 +790,6 @@
return IRQ_HANDLED;
}
-static struct msm_cam_clk_info ispif_8960_clk_info[] = {
- {"csi_pix_clk", 0},
- {"csi_rdi_clk", 0},
- {"csi_pix1_clk", 0},
- {"csi_rdi1_clk", 0},
- {"csi_rdi2_clk", 0},
-};
-static struct msm_cam_clk_info ispif_8974_clk_info[] = {
- {"camss_vfe_vfe_clk", -1},
- {"camss_csi_vfe_clk", -1},
- {"camss_vfe_vfe_clk1", -1},
- {"camss_csi_vfe_clk1", -1},
-};
-
static int msm_ispif_init(struct ispif_device *ispif,
uint32_t csid_version)
{
@@ -693,41 +812,27 @@
memset(ispif->sof_count, 0, sizeof(ispif->sof_count));
ispif->csid_version = csid_version;
- if (ispif->csid_version < CSID_VERSION_V2) {
- rc = msm_cam_clk_enable(&ispif->pdev->dev, ispif_8960_clk_info,
- ispif->ispif_clk, 2, 1);
- if (rc) {
- pr_err("%s: cannot enable clock, error = %d\n",
- __func__, rc);
- goto end;
- }
- } else if (ispif->csid_version == CSID_VERSION_V2) {
- rc = msm_cam_clk_enable(&ispif->pdev->dev, ispif_8960_clk_info,
- ispif->ispif_clk, ARRAY_SIZE(ispif_8960_clk_info), 1);
- if (rc) {
- pr_err("%s: cannot enable clock, error = %d\n",
- __func__, rc);
- goto end;
- }
- } else if (ispif->csid_version >= CSID_VERSION_V3) {
- rc = msm_cam_clk_enable(&ispif->pdev->dev, ispif_8974_clk_info,
- ispif->ispif_clk, ARRAY_SIZE(ispif_8974_clk_info), 1);
- if (rc) {
- pr_err("%s: cannot enable clock, error = %d\n",
- __func__, rc);
- goto end;
- }
- } else {
- pr_err("%s: unsupported version=%d\n", __func__,
- ispif->csid_version);
- goto end;
+ rc = msm_ispif_clk_enable(ispif, VFE0, 1);
+ if (rc < 0) {
+ pr_err("%s: unable to enable clocks for VFE0", __func__);
+ goto error_clk0;
}
+
+ if (ispif->csid_version >= CSID_VERSION_V3) {
+ rc = msm_ispif_clk_enable(ispif, VFE1, 1);
+ if (rc < 0) {
+ pr_err("%s: unable to enable clocks for VFE1",
+ __func__);
+ goto error_clk1;
+ }
+ }
+
ispif->base = ioremap(ispif->mem->start,
resource_size(ispif->mem));
if (!ispif->base) {
rc = -ENOMEM;
pr_err("%s: nomem\n", __func__);
- goto error_clk;
+ goto end;
}
rc = request_irq(ispif->irq->start, msm_io_ispif_irq,
IRQF_TRIGGER_RISING, "ispif", ispif);
@@ -745,23 +850,21 @@
free_irq(ispif->irq->start, ispif);
error_irq:
iounmap(ispif->base);
-error_clk:
- if (ispif->csid_version < CSID_VERSION_V2) {
- msm_cam_clk_enable(&ispif->pdev->dev, ispif_8960_clk_info,
- ispif->ispif_clk, 2, 0);
- } else if (ispif->csid_version == CSID_VERSION_V2) {
- msm_cam_clk_enable(&ispif->pdev->dev, ispif_8960_clk_info,
- ispif->ispif_clk, ARRAY_SIZE(ispif_8960_clk_info), 0);
- } else if (ispif->csid_version >= CSID_VERSION_V3) {
- msm_cam_clk_enable(&ispif->pdev->dev, ispif_8974_clk_info,
- ispif->ispif_clk, ARRAY_SIZE(ispif_8974_clk_info), 0);
- }
+
end:
+ if (ispif->csid_version >= CSID_VERSION_V3)
+ msm_ispif_clk_enable(ispif, VFE1, 0);
+
+error_clk1:
+ msm_ispif_clk_enable(ispif, VFE0, 0);
+
+error_clk0:
return rc;
}
static void msm_ispif_release(struct ispif_device *ispif)
{
+ int i;
BUG_ON(!ispif);
if (ispif->ispif_state != ISPIF_POWER_UP) {
@@ -770,6 +873,9 @@
return;
}
+ for (i = 0; i < VFE_MAX; i++)
+ msm_ispif_clk_enable(ispif, i, 1);
+
/* make sure no streaming going on */
msm_ispif_reset(ispif);
@@ -777,16 +883,9 @@
iounmap(ispif->base);
- if (ispif->csid_version < CSID_VERSION_V2) {
- msm_cam_clk_enable(&ispif->pdev->dev, ispif_8960_clk_info,
- ispif->ispif_clk, 2, 0);
- } else if (ispif->csid_version == CSID_VERSION_V2) {
- msm_cam_clk_enable(&ispif->pdev->dev, ispif_8960_clk_info,
- ispif->ispif_clk, ARRAY_SIZE(ispif_8960_clk_info), 0);
- } else if (ispif->csid_version >= CSID_VERSION_V3) {
- msm_cam_clk_enable(&ispif->pdev->dev, ispif_8974_clk_info,
- ispif->ispif_clk, ARRAY_SIZE(ispif_8974_clk_info), 0);
- }
+ for (i = 0; i < VFE_MAX; i++)
+ msm_ispif_clk_enable(ispif, i, 0);
+
ispif->ispif_state = ISPIF_POWER_DOWN;
}
@@ -801,7 +900,6 @@
BUG_ON(!pcdata);
mutex_lock(&ispif->mutex);
-
switch (pcdata->cfg_type) {
case ISPIF_ENABLE_REG_DUMP:
ispif->enb_dump_reg = pcdata->reg_dump; /* save dump config */
@@ -903,6 +1001,7 @@
{
int rc;
struct ispif_device *ispif;
+ int i;
ispif = kzalloc(sizeof(struct ispif_device), GFP_KERNEL);
if (!ispif) {
@@ -961,7 +1060,9 @@
ispif->ispif_state = ISPIF_POWER_DOWN;
ispif->open_cnt = 0;
spin_lock_init(&ispif->auto_complete_lock);
- ispif->wait_timeout = 0;
+ for (i = 0; i < VFE_MAX; i++)
+ ispif->wait_timeout[i] = 0;
+
return 0;
error:
diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.h b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.h
index f8c3cce..ef7a1bf 100644
--- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.h
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.h
@@ -47,15 +47,15 @@
void __iomem *base;
struct mutex mutex;
uint8_t start_ack_pending;
- struct completion reset_complete;
+ struct completion reset_complete[VFE_MAX];
spinlock_t auto_complete_lock;
- uint8_t wait_timeout;
+ uint8_t wait_timeout[VFE_MAX];
uint32_t csid_version;
int enb_dump_reg;
uint32_t open_cnt;
struct ispif_sof_count sof_count[VFE_MAX];
struct ispif_intf_cmd applied_intf_cmd[VFE_MAX];
enum msm_ispif_state_t ispif_state;
- struct clk *ispif_clk[INTF_MAX];
+ struct clk *ispif_clk[VFE_MAX][INTF_MAX];
};
#endif
diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v1.h b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v1.h
index cdbebea..afd91d1 100644
--- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v1.h
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v1.h
@@ -14,32 +14,41 @@
#define __MSM_ISPIF_HWREG_V1_H__
/* common registers */
-#define ISPIF_RST_CMD_ADDR 0x0000
-#define ISPIF_RST_CMD_1_ADDR 0x0000 /* undefined */
-#define ISPIF_INTF_CMD_ADDR 0x0004
-#define ISPIF_INTF_CMD_1_ADDR 0x0030
-#define ISPIF_CTRL_ADDR 0x0008
-#define ISPIF_INPUT_SEL_ADDR 0x000C
-#define ISPIF_PIX_0_INTF_CID_MASK_ADDR 0x0010
-#define ISPIF_RDI_0_INTF_CID_MASK_ADDR 0x0014
-#define ISPIF_PIX_1_INTF_CID_MASK_ADDR 0x0038
-#define ISPIF_RDI_1_INTF_CID_MASK_ADDR 0x003C
-#define ISPIF_RDI_2_INTF_CID_MASK_ADDR 0x0044
-#define ISPIF_PIX_0_STATUS_ADDR 0x0024
-#define ISPIF_RDI_0_STATUS_ADDR 0x0028
-#define ISPIF_PIX_1_STATUS_ADDR 0x0060
-#define ISPIF_RDI_1_STATUS_ADDR 0x0064
-#define ISPIF_RDI_2_STATUS_ADDR 0x006C
-#define ISPIF_IRQ_MASK_ADDR 0x0100
-#define ISPIF_IRQ_CLEAR_ADDR 0x0104
-#define ISPIF_IRQ_STATUS_ADDR 0x0108
-#define ISPIF_IRQ_MASK_1_ADDR 0x010C
-#define ISPIF_IRQ_CLEAR_1_ADDR 0x0110
-#define ISPIF_IRQ_STATUS_1_ADDR 0x0114
-#define ISPIF_IRQ_MASK_2_ADDR 0x0118
-#define ISPIF_IRQ_CLEAR_2_ADDR 0x011C
-#define ISPIF_IRQ_STATUS_2_ADDR 0x0120
-#define ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR 0x0124
+#define ISPIF_RST_CMD_ADDR 0x0000
+#define ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR 0x0124
+
+#define ISPIF_VFE(m) (0x0)
+
+#define ISPIF_VFE_m_CTRL_0(m) (0x0008 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_IRQ_MASK_0(m) (0x0100 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_IRQ_MASK_1(m) (0x010C + ISPIF_VFE(m))
+#define ISPIF_VFE_m_IRQ_MASK_2(m) (0x0118 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_IRQ_STATUS_0(m) (0x0108 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_IRQ_STATUS_1(m) (0x0114 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_IRQ_STATUS_2(m) (0x0120 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_IRQ_CLEAR_0(m) (0x0104 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_IRQ_CLEAR_1(m) (0x0110 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_IRQ_CLEAR_2(m) (0x011C + ISPIF_VFE(m))
+#define ISPIF_VFE_m_INPUT_SEL(m) (0x000C + ISPIF_VFE(m))
+#define ISPIF_VFE_m_INTF_CMD_0(m) (0x0004 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_INTF_CMD_1(m) (0x0030 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_PIX_INTF_n_CID_MASK(m, n) (0x0010 + ISPIF_VFE(m) + 4*(n))
+#define ISPIF_VFE_m_RDI_INTF_n_CID_MASK(m, n) (0x0014 + ISPIF_VFE(m) + 4*(n))
+#define ISPIF_VFE_m_PIX_OUTPUT_n_MISR(m, n) (0x0290 + ISPIF_VFE(m) + 4*(n))
+#define ISPIF_VFE_m_RDI_OUTPUT_n_MISR_0(m, n) (0x0298 + ISPIF_VFE(m) + 8*(n))
+#define ISPIF_VFE_m_RDI_OUTPUT_n_MISR_1(m, n) (0x029C + ISPIF_VFE(m) + 8*(n))
+#define ISPIF_VFE_m_PIX_INTF_n_STATUS(m, n) (0x0024 + ISPIF_VFE(m) + 4*(n))
+#define ISPIF_VFE_m_RDI_INTF_n_STATUS(m, n) (0x0028 + ISPIF_VFE(m) + 4*(n))
+
+/* Defines for compatibility with newer ISPIF versions */
+#define ISPIF_RST_CMD_1_ADDR (0x0000)
+#define ISPIF_VFE_m_PIX_INTF_n_CROP(m, n) (0x0000 + ISPIF_VFE(m) + 4*(n))
+#define ISPIF_VFE_m_3D_THRESHOLD(m) (0x0000 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_OUTPUT_SEL(m) (0x0000 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_3D_DESKEW_SIZE(m) (0x0000 + ISPIF_VFE(m))
+
+
+
/*ISPIF RESET BITS*/
#define VFE_CLK_DOMAIN_RST BIT(31)
diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v2.h b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v2.h
index 37b19f5..80b32d4 100644
--- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v2.h
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v2.h
@@ -16,42 +16,34 @@
/* common registers */
#define ISPIF_RST_CMD_ADDR 0x008
#define ISPIF_RST_CMD_1_ADDR 0x00C
-#define ISPIF_INTF_CMD_ADDR 0x248
-#define ISPIF_INTF_CMD_1_ADDR 0x24C
-#define ISPIF_CTRL_ADDR 0x008
-#define ISPIF_INPUT_SEL_ADDR 0x244
-#define ISPIF_PIX_0_INTF_CID_MASK_ADDR 0x254
-#define ISPIF_RDI_0_INTF_CID_MASK_ADDR 0x264
-#define ISPIF_PIX_1_INTF_CID_MASK_ADDR 0x258
-#define ISPIF_RDI_1_INTF_CID_MASK_ADDR 0x268
-#define ISPIF_RDI_2_INTF_CID_MASK_ADDR 0x26C
-#define ISPIF_PIX_0_STATUS_ADDR 0x2C0
-#define ISPIF_RDI_0_STATUS_ADDR 0x2D0
-#define ISPIF_PIX_1_STATUS_ADDR 0x2C4
-#define ISPIF_RDI_1_STATUS_ADDR 0x2D4
-#define ISPIF_RDI_2_STATUS_ADDR 0x2D8
-#define ISPIF_IRQ_MASK_ADDR 0x208
-#define ISPIF_IRQ_CLEAR_ADDR 0x230
-#define ISPIF_IRQ_STATUS_ADDR 0x21C
-#define ISPIF_IRQ_MASK_1_ADDR 0x20C
-#define ISPIF_IRQ_CLEAR_1_ADDR 0x234
-#define ISPIF_IRQ_STATUS_1_ADDR 0x220
-#define ISPIF_IRQ_MASK_2_ADDR 0x210
-#define ISPIF_IRQ_CLEAR_2_ADDR 0x238
-#define ISPIF_IRQ_STATUS_2_ADDR 0x224
#define ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR 0x01C
-/* new */
-#define ISPIF_VFE_m_CTRL_0_ADDR 0x200
-#define ISPIF_VFE_m_IRQ_MASK_0 0x208
-#define ISPIF_VFE_m_IRQ_MASK_1 0x20C
-#define ISPIF_VFE_m_IRQ_MASK_2 0x210
-#define ISPIF_VFE_m_IRQ_STATUS_0 0x21C
-#define ISPIF_VFE_m_IRQ_STATUS_1 0x220
-#define ISPIF_VFE_m_IRQ_STATUS_2 0x224
-#define ISPIF_VFE_m_IRQ_CLEAR_0 0x230
-#define ISPIF_VFE_m_IRQ_CLEAR_1 0x234
-#define ISPIF_VFE_m_IRQ_CLEAR_2 0x238
+#define ISPIF_VFE(m) ((m) * 0x200)
+
+#define ISPIF_VFE_m_CTRL_0(m) (0x200 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_IRQ_MASK_0(m) (0x208 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_IRQ_MASK_1(m) (0x20C + ISPIF_VFE(m))
+#define ISPIF_VFE_m_IRQ_MASK_2(m) (0x210 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_IRQ_STATUS_0(m) (0x21C + ISPIF_VFE(m))
+#define ISPIF_VFE_m_IRQ_STATUS_1(m) (0x220 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_IRQ_STATUS_2(m) (0x224 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_IRQ_CLEAR_0(m) (0x230 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_IRQ_CLEAR_1(m) (0x234 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_IRQ_CLEAR_2(m) (0x238 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_INPUT_SEL(m) (0x244 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_INTF_CMD_0(m) (0x248 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_INTF_CMD_1(m) (0x24C + ISPIF_VFE(m))
+#define ISPIF_VFE_m_PIX_INTF_n_CID_MASK(m, n) (0x254 + ISPIF_VFE(m) + 4*(n))
+#define ISPIF_VFE_m_RDI_INTF_n_CID_MASK(m, n) (0x264 + ISPIF_VFE(m) + 4*(n))
+#define ISPIF_VFE_m_PIX_INTF_n_CROP(m, n) (0x278 + ISPIF_VFE(m) + 4*(n))
+#define ISPIF_VFE_m_3D_THRESHOLD(m) (0x288 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_OUTPUT_SEL(m) (0x28C + ISPIF_VFE(m))
+#define ISPIF_VFE_m_PIX_OUTPUT_n_MISR(m, n) (0x290 + ISPIF_VFE(m) + 4*(n))
+#define ISPIF_VFE_m_RDI_OUTPUT_n_MISR_0(m, n) (0x298 + ISPIF_VFE(m) + 8*(n))
+#define ISPIF_VFE_m_RDI_OUTPUT_n_MISR_1(m, n) (0x29C + ISPIF_VFE(m) + 8*(n))
+#define ISPIF_VFE_m_PIX_INTF_n_STATUS(m, n) (0x2C0 + ISPIF_VFE(m) + 4*(n))
+#define ISPIF_VFE_m_RDI_INTF_n_STATUS(m, n) (0x2D0 + ISPIF_VFE(m) + 4*(n))
+#define ISPIF_VFE_m_3D_DESKEW_SIZE(m) (0x2E4 + ISPIF_VFE(m))
/*ISPIF RESET BITS*/
#define VFE_CLK_DOMAIN_RST BIT(31)
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.c b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.c
index 8c484e7..b1253fa 100644
--- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.c
+++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.c
@@ -17,7 +17,7 @@
#include <linux/clk.h>
#include <mach/clk.h>
#include <linux/io.h>
-#include <linux/android_pmem.h>
+
#include <mach/camera.h>
#include <mach/iommu_domains.h>
#include <mach/msm_bus.h>
diff --git a/drivers/media/platform/msm/camera_v2/msm.c b/drivers/media/platform/msm/camera_v2/msm.c
index f8cddb2..fbc2b93 100644
--- a/drivers/media/platform/msm/camera_v2/msm.c
+++ b/drivers/media/platform/msm/camera_v2/msm.c
@@ -268,6 +268,8 @@
msm_enqueue(&session->stream_q, &stream->list);
session->stream_q.len++;
+ INIT_LIST_HEAD(&stream->queued_list);
+
return 0;
}
@@ -353,7 +355,7 @@
if (WARN_ON(!msm_subdev))
return -EINVAL;
- if (WARN_ON(!msm_v4l2_dev) && WARN_ON(!msm_v4l2_dev->dev))
+ if (WARN_ON(!msm_v4l2_dev) || WARN_ON(!msm_v4l2_dev->dev))
return -EIO;
return __msm_sd_register_subdev(&msm_subdev->sd);
@@ -852,6 +854,31 @@
return stream->vb2_q;
}
+struct msm_stream *msm_get_stream_from_vb2q(struct vb2_queue *q)
+{
+ struct msm_session *session;
+ struct msm_stream *stream;
+ unsigned long flags1;
+ unsigned long flags2;
+ spin_lock_irqsave(&msm_session_q->lock, flags1);
+ list_for_each_entry(session, &(msm_session_q->list), list) {
+ spin_lock_irqsave(&(session->stream_q.lock), flags2);
+ list_for_each_entry(
+ stream, &(session->stream_q.list), list) {
+ if (stream->vb2_q == q) {
+ spin_unlock_irqrestore
+ (&(session->stream_q.lock), flags2);
+ spin_unlock_irqrestore
+ (&msm_session_q->lock, flags1);
+ return stream;
+ }
+ }
+ spin_unlock_irqrestore(&(session->stream_q.lock), flags2);
+ }
+ spin_unlock_irqrestore(&msm_session_q->lock, flags1);
+ return NULL;
+}
+
static struct v4l2_subdev *msm_sd_find(const char *name)
{
unsigned long flags;
diff --git a/drivers/media/platform/msm/camera_v2/msm.h b/drivers/media/platform/msm/camera_v2/msm.h
index eb15cab..39901ad 100644
--- a/drivers/media/platform/msm/camera_v2/msm.h
+++ b/drivers/media/platform/msm/camera_v2/msm.h
@@ -51,5 +51,6 @@
unsigned int stream_id);
struct vb2_queue *msm_get_stream_vb2q(unsigned int session_id,
unsigned int stream_id);
+struct msm_stream *msm_get_stream_from_vb2q(struct vb2_queue *q);
#endif /*_MSM_H */
diff --git a/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c b/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c
index 079dbb5..29262af 100644
--- a/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c
+++ b/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c
@@ -38,22 +38,107 @@
int msm_vb2_buf_init(struct vb2_buffer *vb)
{
+ struct msm_stream *stream;
struct msm_vb2_buffer *msm_vb2_buf;
+ stream = msm_get_stream_from_vb2q(vb->vb2_queue);
+ if (!stream) {
+ pr_err("%s: Couldn't find stream\n", __func__);
+ return -EINVAL;
+ }
msm_vb2_buf = container_of(vb, struct msm_vb2_buffer, vb2_buf);
msm_vb2_buf->in_freeq = 0;
+ msm_vb2_buf->stream = stream;
return 0;
}
static void msm_vb2_buf_queue(struct vb2_buffer *vb)
{
+ struct msm_vb2_buffer *msm_vb2;
+ struct msm_stream *stream;
+ unsigned long flags;
+
+ msm_vb2 = container_of(vb, struct msm_vb2_buffer, vb2_buf);
+
+ if (!msm_vb2) {
+ pr_err("%s:%d] vb2_buf NULL", __func__, __LINE__);
+ return;
+ }
+
+ stream = msm_vb2->stream;
+ if (!stream) {
+ pr_err("%s:%d] NULL stream", __func__, __LINE__);
+ return;
+ }
+
+ spin_lock_irqsave(&stream->stream_lock, flags);
+ list_add_tail(&msm_vb2->list, &stream->queued_list);
+ spin_unlock_irqrestore(&stream->stream_lock, flags);
+}
+
+static int msm_vb2_buf_finish(struct vb2_buffer *vb)
+{
+ struct msm_vb2_buffer *msm_vb2;
+ struct msm_stream *stream;
+ unsigned long flags;
+ struct msm_vb2_buffer *msm_vb2_entry, *temp;
+
+ msm_vb2 = container_of(vb, struct msm_vb2_buffer, vb2_buf);
+
+ if (!msm_vb2) {
+ pr_err("%s:%d] vb2_buf NULL", __func__, __LINE__);
+ return -EINVAL;
+ }
+
+ stream = msm_vb2->stream;
+ if (!stream) {
+ pr_err("%s:%d] NULL stream", __func__, __LINE__);
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&stream->stream_lock, flags);
+ list_for_each_entry_safe(msm_vb2_entry, temp, &(stream->queued_list),
+ list) {
+ if (msm_vb2_entry == msm_vb2) {
+ list_del_init(&msm_vb2_entry->list);
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&stream->stream_lock, flags);
+ return 0;
+}
+
+static void msm_vb2_buf_cleanup(struct vb2_buffer *vb)
+{
+ struct msm_vb2_buffer *msm_vb2;
+ struct msm_stream *stream;
+ unsigned long flags;
+
+ msm_vb2 = container_of(vb, struct msm_vb2_buffer, vb2_buf);
+
+ if (!msm_vb2) {
+ pr_err("%s:%d] vb2 NULL", __func__, __LINE__);
+ return;
+ }
+
+ stream = msm_vb2->stream;
+ if (!stream) {
+ pr_err("%s:%d] NULL stream", __func__, __LINE__);
+ return;
+ }
+
+ spin_lock_irqsave(&stream->stream_lock, flags);
+ INIT_LIST_HEAD(&stream->queued_list);
+ spin_unlock_irqrestore(&stream->stream_lock, flags);
}
static struct vb2_ops msm_vb2_get_q_op = {
- .queue_setup = msm_vb2_queue_setup,
- .buf_init = msm_vb2_buf_init,
- .buf_queue = msm_vb2_buf_queue,
+ .queue_setup = msm_vb2_queue_setup,
+ .buf_init = msm_vb2_buf_init,
+ .buf_queue = msm_vb2_buf_queue,
+ .buf_cleanup = msm_vb2_buf_cleanup,
+ .buf_finish = msm_vb2_buf_finish,
};
@@ -101,7 +186,7 @@
{
struct msm_stream *stream;
struct vb2_buffer *vb2_buf = NULL;
- struct msm_vb2_buffer *msm_vb2;
+ struct msm_vb2_buffer *msm_vb2 = NULL;
unsigned long flags;
stream = msm_get_stream(session_id, stream_id);
@@ -115,18 +200,18 @@
goto end;
}
- list_for_each_entry(vb2_buf, &(stream->vb2_q->queued_list),
- queued_entry) {
+ list_for_each_entry(msm_vb2, &(stream->queued_list), list) {
+ vb2_buf = &(msm_vb2->vb2_buf);
if (vb2_buf->state != VB2_BUF_STATE_ACTIVE)
continue;
- msm_vb2 = container_of(vb2_buf, struct msm_vb2_buffer, vb2_buf);
if (msm_vb2->in_freeq)
continue;
msm_vb2->in_freeq = 1;
goto end;
}
+ msm_vb2 = NULL;
vb2_buf = NULL;
end:
spin_unlock_irqrestore(&stream->stream_lock, flags);
@@ -136,9 +221,15 @@
static int msm_vb2_put_buf(struct vb2_buffer *vb, int session_id,
unsigned int stream_id)
{
+ struct msm_stream *stream;
struct msm_vb2_buffer *msm_vb2;
int rc = 0;
+ unsigned long flags;
+ stream = msm_get_stream(session_id, stream_id);
+ if (IS_ERR_OR_NULL(stream))
+ return -EINVAL;
+ spin_lock_irqsave(&stream->stream_lock, flags);
if (vb) {
msm_vb2 =
container_of(vb, struct msm_vb2_buffer, vb2_buf);
@@ -151,6 +242,7 @@
pr_err("%s: VB buffer is null\n", __func__);
rc = -EINVAL;
}
+ spin_unlock_irqrestore(&stream->stream_lock, flags);
return rc;
}
diff --git a/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.h b/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.h
index cecc85e..027d344 100644
--- a/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.h
+++ b/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.h
@@ -42,6 +42,7 @@
struct vb2_buffer vb2_buf;
struct list_head list;
int in_freeq;
+ struct msm_stream *stream;
};
struct msm_vb2_private_data {
@@ -60,6 +61,7 @@
/* vb2 buffer handling */
struct vb2_queue *vb2_q;
spinlock_t stream_lock;
+ struct list_head queued_list;
};
struct vb2_ops *msm_vb2_get_q_ops(void);
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 41234c3..8f63d33 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
@@ -563,6 +563,44 @@
return 0;
}
+static int msm_cpp_flush_frames(struct cpp_device *cpp_dev)
+{
+ struct v4l2_event v4l2_evt;
+ struct msm_queue_cmd *frame_qcmd;
+ struct msm_cpp_frame_info_t *process_frame;
+ struct msm_device_queue *queue;
+ struct msm_queue_cmd *event_qcmd;
+
+ do {
+ if (cpp_dev->realtime_q.len != 0) {
+ queue = &cpp_dev->realtime_q;
+ } else if (cpp_dev->offline_q.len != 0) {
+ queue = &cpp_dev->offline_q;
+ } else {
+ pr_debug("All frames flushed\n");
+ break;
+ }
+ frame_qcmd = msm_dequeue(queue, list_frame);
+ process_frame = frame_qcmd->command;
+ kfree(frame_qcmd);
+ event_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_ATOMIC);
+ if (!event_qcmd) {
+ pr_err("Insufficient memory. return");
+ return -ENOMEM;
+ }
+ atomic_set(&event_qcmd->on_heap, 1);
+ event_qcmd->command = process_frame;
+ CPP_DBG("fid %d\n", process_frame->frame_id);
+ msm_enqueue(&cpp_dev->eventData_q, &event_qcmd->list_eventdata);
+
+ v4l2_evt.id = process_frame->inst_id;
+ v4l2_evt.type = V4L2_EVENT_CPP_FRAME_DONE;
+ v4l2_event_queue(cpp_dev->msm_sd.sd.devnode, &v4l2_evt);
+ } while ((cpp_dev->realtime_q.len != 0) ||
+ (cpp_dev->offline_q.len != 0));
+ return 0;
+}
+
static int msm_cpp_cfg(struct cpp_device *cpp_dev,
struct msm_camera_v4l2_ioctl_t *ioctl_ptr)
{
@@ -754,6 +792,9 @@
case VIDIOC_MSM_CPP_CFG:
rc = msm_cpp_cfg(cpp_dev, ioctl_ptr);
break;
+ case VIDIOC_MSM_CPP_FLUSH_QUEUE:
+ rc = msm_cpp_flush_frames(cpp_dev);
+ break;
case VIDIOC_MSM_CPP_GET_EVENTPAYLOAD: {
struct msm_device_queue *queue = &cpp_dev->eventData_q;
struct msm_queue_cmd *event_qcmd;
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
index 499b36c..9be4704 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
@@ -75,10 +75,6 @@
module_param(video_nonsecure_ion_heap, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(video_nonsecure_ion_heap, "ION heap for non-secure video buffer allocation");
-static int generate_es_events;
-module_param(generate_es_events, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(generate_es_events, "Generate new elementary stream data events");
-
/* Value of TS packet scramble bits field for even key */
static int mpq_sdmx_scramble_even = 0x2;
module_param(mpq_sdmx_scramble_even, int, S_IRUGO | S_IWUSR);
@@ -1224,13 +1220,6 @@
{
struct mpq_demux *mpq_demux = feed->demux->priv;
- if (!generate_es_events) {
- MPQ_DVB_ERR_PRINT(
- "%s: Cannot release decoder buffer when not working with new elementary stream data events\n",
- __func__);
- return -EPERM;
- }
-
if (cookie < 0) {
MPQ_DVB_ERR_PRINT("%s: invalid cookie parameter\n", __func__);
return -EINVAL;
@@ -2834,13 +2823,11 @@
__func__);
}
- if (generate_es_events) {
- mpq_dmx_prepare_es_event_data(
- &packet, &meta_data, feed_data,
- stream_buffer, &data);
+ mpq_dmx_prepare_es_event_data(
+ &packet, &meta_data, feed_data,
+ stream_buffer, &data);
- feed->data_ready_cb.ts(&feed->feed.ts, &data);
- }
+ feed->data_ready_cb.ts(&feed->feed.ts, &data);
feed_data->pending_pattern_len = 0;
mpq_streambuffer_get_data_rw_offset(
@@ -2975,15 +2962,13 @@
NULL,
&feed_data->frame_offset);
- if (generate_es_events) {
- mpq_dmx_prepare_es_event_data(
- &packet, &meta_data,
- feed_data,
- stream_buffer, &data);
+ mpq_dmx_prepare_es_event_data(
+ &packet, &meta_data,
+ feed_data,
+ stream_buffer, &data);
- feed->data_ready_cb.ts(
- &feed->feed.ts, &data);
- }
+ feed->data_ready_cb.ts(
+ &feed->feed.ts, &data);
} else {
MPQ_DVB_ERR_PRINT(
"%s: received PUSI"
@@ -4122,6 +4107,8 @@
int ret;
int pes_cnt = 0;
struct dmx_data_ready data_event;
+ struct dmx_data_ready data;
+ struct dvb_demux_feed *feed = mpq_feed->dvb_demux_feed;
if ((!sts->metadata_fill_count) && (!sts->data_fill_count))
goto decoder_filter_check_overflow;
@@ -4249,15 +4236,11 @@
mpq_dmx_update_decoder_stat(mpq_demux);
mpq_streambuffer_pkt_write(sbuf, &packet, (u8 *)&meta_data);
- if (generate_es_events) {
- struct dmx_data_ready data;
- struct dvb_demux_feed *feed = mpq_feed->dvb_demux_feed;
- mpq_dmx_prepare_es_event_data(
- &packet, &meta_data, &mpq_feed->video_info,
- sbuf, &data);
- MPQ_DVB_DBG_PRINT("%s: Notify ES Event\n", __func__);
- feed->data_ready_cb.ts(&feed->feed.ts, &data);
- }
+ mpq_dmx_prepare_es_event_data(
+ &packet, &meta_data, &mpq_feed->video_info,
+ sbuf, &data);
+ MPQ_DVB_DBG_PRINT("%s: Notify ES Event\n", __func__);
+ feed->data_ready_cb.ts(&feed->feed.ts, &data);
spin_unlock(&mpq_feed->video_info.video_buffer_lock);
}
diff --git a/drivers/media/platform/msm/dvb/video/mpq_dvb_video.c b/drivers/media/platform/msm/dvb/video/mpq_dvb_video.c
index 46002c3..b9fdc5e 100644
--- a/drivers/media/platform/msm/dvb/video/mpq_dvb_video.c
+++ b/drivers/media/platform/msm/dvb/video/mpq_dvb_video.c
@@ -28,7 +28,7 @@
#include <linux/uaccess.h>
#include <linux/wait.h>
#include <linux/workqueue.h>
-#include <linux/android_pmem.h>
+
#include <linux/clk.h>
#include <linux/timer.h>
#include <mach/msm_subsystem_map.h>
@@ -43,8 +43,6 @@
#define ERR(x...) pr_err(x)
#define MPQ_VID_DEC_NAME "mpq_vidc_dec"
-static unsigned int vidc_mmu_subsystem[] = {
- MSM_SUBSYSTEM_VIDEO};
static char vid_thread_names[DVB_MPQ_NUM_VIDEO_DEVICES][10] = {
"dvb-vid-0",
@@ -1060,10 +1058,7 @@
{
struct vcd_property_hdr vcd_property_hdr;
struct vcd_property_h264_mv_buffer *vcd_h264_mv_buffer = NULL;
- struct msm_mapped_buffer *mapped_buffer = NULL;
u32 vcd_status = VCD_ERR_FAIL;
- u32 len = 0, flags = 0;
- struct file *file;
int rc = 0;
unsigned long ionflag = 0;
unsigned long buffer_size = 0;
@@ -1084,28 +1079,8 @@
vcd_h264_mv_buffer->offset = mv_data->offset;
if (!vcd_get_ion_status()) {
- if (get_pmem_file(vcd_h264_mv_buffer->pmem_fd,
- (unsigned long *) (&(vcd_h264_mv_buffer->
- physical_addr)),
- (unsigned long *) (&vcd_h264_mv_buffer->
- kernel_virtual_addr),
- (unsigned long *) (&len), &file)) {
- ERR("%s(): get_pmem_file failed\n", __func__);
- return -EIO;
- }
- put_pmem_file(file);
- flags = MSM_SUBSYSTEM_MAP_IOVA;
- mapped_buffer = msm_subsystem_map_buffer(
- (unsigned long)vcd_h264_mv_buffer->physical_addr, len,
- flags, vidc_mmu_subsystem,
- sizeof(vidc_mmu_subsystem)/
- sizeof(unsigned int));
- if (IS_ERR(mapped_buffer)) {
- ERR("buffer map failed");
- return PTR_ERR(mapped_buffer);
- }
- vcd_h264_mv_buffer->client_data = (void *) mapped_buffer;
- vcd_h264_mv_buffer->dev_addr = (u8 *)mapped_buffer->iova[0];
+ pr_err("PMEM not available");
+ return -EINVAL;
} else {
client_ctx->h264_mv_ion_handle = ion_import_dma_buf(
client_ctx->user_ion_client,
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c
index f8460be..40e09b6 100644
--- a/drivers/media/platform/msm/vidc/hfi_packetization.c
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.c
@@ -1165,6 +1165,16 @@
sizeof(struct hfi_index_extradata_config);
break;
}
+ case HAL_PARAM_VENC_SLICE_DELIVERY_MODE:
+ {
+ struct hfi_enable *hfi;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_VENC_SLICE_DELIVERY_MODE;
+ hfi = (struct hfi_enable *) &pkt->rg_property_data[1];
+ hfi->enable = ((struct hal_enable *) pdata)->enable;
+ pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
+ break;
+ }
case HAL_CONFIG_VPE_DEINTERLACE:
break;
/* FOLLOWING PROPERTIES ARE NOT IMPLEMENTED IN CORE YET */
@@ -1187,7 +1197,6 @@
case HAL_PARAM_VDEC_MB_QUANTIZATION:
case HAL_PARAM_VDEC_NUM_CONCEALED_MB:
case HAL_PARAM_VDEC_H264_ENTROPY_SWITCHING:
- case HAL_PARAM_VENC_SLICE_DELIVERY_MODE:
case HAL_PARAM_VENC_MPEG4_DATA_PARTITIONING:
case HAL_CONFIG_BUFFER_COUNT_ACTUAL:
case HAL_CONFIG_VDEC_MULTI_STREAM:
diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c
index be9458d..102e1ec 100644
--- a/drivers/media/platform/msm/vidc/hfi_response_handler.c
+++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c
@@ -305,11 +305,213 @@
callback(RELEASE_RESOURCE_DONE, &cmd_done);
}
+static inline void copy_cap_prop(
+ struct hfi_capability_supported *in,
+ struct vidc_hal_session_init_done *sess_init_done)
+{
+ struct hal_capability_supported *out = NULL;
+ switch (in->capability_type) {
+ case HFI_CAPABILITY_FRAME_WIDTH:
+ out = &sess_init_done->width;
+ break;
+
+ case HFI_CAPABILITY_FRAME_HEIGHT:
+ out = &sess_init_done->height;
+ break;
+
+ case HFI_CAPABILITY_MBS_PER_FRAME:
+ out = &sess_init_done->mbs_per_frame;
+ break;
+
+ case HFI_CAPABILITY_MBS_PER_SECOND:
+ out = &sess_init_done->mbs_per_sec;
+ break;
+
+ case HFI_CAPABILITY_FRAMERATE:
+ out = &sess_init_done->frame_rate;
+ break;
+
+ case HFI_CAPABILITY_SCALE_X:
+ out = &sess_init_done->scale_x;
+ break;
+
+ case HFI_CAPABILITY_SCALE_Y:
+ out = &sess_init_done->scale_y;
+ break;
+
+ case HFI_CAPABILITY_BITRATE:
+ out = &sess_init_done->bitrate;
+ break;
+ }
+
+ if (in && out) {
+ out->capability_type =
+ (enum hal_capability)in->capability_type;
+ out->min = in->min;
+ out->max = in->max;
+ out->step_size = in->step_size;
+ }
+}
+
enum vidc_status hfi_process_sess_init_done_prop_read(
struct hfi_msg_sys_session_init_done_packet *pkt,
- struct msm_vidc_cb_cmd_done *cmddone)
+ struct vidc_hal_session_init_done *sess_init_done)
{
- return VIDC_ERR_NONE;
+ u32 rem_bytes, num_properties;
+ u8 *data_ptr;
+ u32 status = VIDC_ERR_NONE;
+ u32 prop_id, next_offset = 0;
+
+ rem_bytes = pkt->size - sizeof(struct
+ hfi_msg_sys_session_init_done_packet) + sizeof(u32);
+
+ if (rem_bytes == 0) {
+ dprintk(VIDC_ERR,
+ "hfi_msg_sys_session_init_done:missing_prop_info");
+ return VIDC_ERR_FAIL;
+ }
+
+ status = hfi_map_err_status((u32)pkt->error_type);
+
+ if (status)
+ return status;
+
+ data_ptr = (u8 *) &pkt->rg_property_data[0];
+ num_properties = pkt->num_properties;
+
+ while ((status == VIDC_ERR_NONE) && num_properties &&
+ (rem_bytes >= sizeof(u32))) {
+ prop_id = *((u32 *)data_ptr);
+ next_offset = sizeof(u32);
+
+ switch (prop_id) {
+ case HFI_PROPERTY_PARAM_CAPABILITY_SUPPORTED:
+ {
+ struct hfi_capability_supported_info *prop =
+ (struct hfi_capability_supported_info *)
+ (data_ptr + next_offset);
+ u32 num_capabilities;
+ struct hfi_capability_supported *cap_ptr;
+
+ if ((rem_bytes - next_offset) < sizeof(*cap_ptr)) {
+ status = VIDC_ERR_BAD_PARAM;
+ break;
+ }
+
+ num_capabilities = prop->num_capabilities;
+ cap_ptr = &prop->rg_data[0];
+ next_offset += sizeof(u32);
+
+ while (num_capabilities &&
+ ((rem_bytes - next_offset) >= sizeof(u32))) {
+ copy_cap_prop(cap_ptr, sess_init_done);
+ cap_ptr++;
+ next_offset += sizeof(*cap_ptr);
+ num_capabilities--;
+ }
+ num_properties--;
+ break;
+ }
+ case HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SUPPORTED:
+ {
+ struct hfi_uncompressed_format_supported *prop =
+ (struct hfi_uncompressed_format_supported *)
+ (data_ptr + next_offset);
+
+ u32 num_format_entries;
+ char *fmt_ptr;
+ struct hfi_uncompressed_plane_info *plane_info;
+
+ if ((rem_bytes - next_offset) < sizeof(*prop)) {
+ status = VIDC_ERR_BAD_PARAM;
+ break;
+ }
+ num_format_entries = prop->format_entries;
+ next_offset = sizeof(*prop) - sizeof(u32);
+ fmt_ptr = (char *)&prop->rg_format_info[0];
+
+ while (num_format_entries) {
+ u32 bytes_to_skip;
+ plane_info =
+ (struct hfi_uncompressed_plane_info *) fmt_ptr;
+
+ if ((rem_bytes - next_offset) <
+ sizeof(*plane_info)) {
+ status = VIDC_ERR_BAD_PARAM;
+ break;
+ }
+ bytes_to_skip = sizeof(*plane_info) -
+ sizeof(struct
+ hfi_uncompressed_plane_constraints) +
+ plane_info->num_planes *
+ sizeof(struct
+ hfi_uncompressed_plane_constraints);
+
+ fmt_ptr += bytes_to_skip;
+ next_offset += bytes_to_skip;
+ num_format_entries--;
+ }
+ num_properties--;
+ break;
+ }
+ case HFI_PROPERTY_PARAM_PROPERTIES_SUPPORTED:
+ {
+ struct hfi_properties_supported *prop =
+ (struct hfi_properties_supported *)
+ (data_ptr + next_offset);
+
+ next_offset += sizeof(*prop) - sizeof(u32)
+ + prop->num_properties * sizeof(u32);
+ num_properties--;
+ break;
+ }
+ case HFI_PROPERTY_PARAM_PROFILE_LEVEL_SUPPORTED:
+ {
+ struct hfi_profile_level_supported *prop =
+ (struct hfi_profile_level_supported *)
+ (data_ptr + next_offset);
+
+ next_offset += sizeof(*prop) -
+ sizeof(struct hfi_profile_level) +
+ prop->profile_count *
+ sizeof(struct hfi_profile_level);
+ num_properties--;
+ break;
+ }
+ case HFI_PROPERTY_PARAM_NAL_STREAM_FORMAT_SUPPORTED:
+ {
+ next_offset +=
+ sizeof(struct hfi_nal_stream_format_supported);
+ num_properties--;
+ break;
+ }
+ case HFI_PROPERTY_PARAM_NAL_STREAM_FORMAT_SELECT:
+ {
+ next_offset += sizeof(u32);
+ num_properties--;
+ break;
+ }
+ case HFI_PROPERTY_PARAM_MAX_SEQUENCE_HEADER_SIZE:
+ {
+ next_offset += sizeof(u32);
+ num_properties--;
+ break;
+ }
+ case HFI_PROPERTY_PARAM_VENC_INTRA_REFRESH:
+ {
+ next_offset +=
+ sizeof(struct hfi_intra_refresh);
+ num_properties--;
+ break;
+ }
+ default:
+ dprintk(VIDC_DBG,
+ "%s default case - 0x%x", __func__, prop_id);
+ }
+ rem_bytes -= next_offset;
+ data_ptr += next_offset;
+ }
+ return status;
}
static void hfi_process_sess_get_prop_buf_req(
@@ -493,7 +695,7 @@
cmd_done.data = &session_init_done;
if (!cmd_done.status) {
cmd_done.status = hfi_process_sess_init_done_prop_read(
- pkt, &cmd_done);
+ pkt, &session_init_done);
}
cmd_done.size = sizeof(struct vidc_hal_session_init_done);
callback(SESSION_INIT_DONE, &cmd_done);
diff --git a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
index 4f8c257..d782227 100644
--- a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
@@ -682,6 +682,13 @@
{
return 0;
}
+
+static int msm_v4l2_enum_framesizes(struct file *file, void *fh,
+ struct v4l2_frmsizeenum *fsize)
+{
+ struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+ return msm_vidc_enum_framesizes((void *)vidc_inst, fsize);
+}
static const struct v4l2_ioctl_ops msm_v4l2_ioctl_ops = {
.vidioc_querycap = msm_v4l2_querycap,
.vidioc_enum_fmt_vid_cap_mplane = msm_v4l2_enum_fmt,
@@ -703,7 +710,8 @@
.vidioc_decoder_cmd = msm_v4l2_decoder_cmd,
.vidioc_encoder_cmd = msm_v4l2_encoder_cmd,
.vidioc_s_parm = msm_v4l2_s_parm,
- .vidioc_g_parm = msm_v4l2_g_parm
+ .vidioc_g_parm = msm_v4l2_g_parm,
+ .vidioc_enum_framesizes = msm_v4l2_enum_framesizes,
};
static const struct v4l2_ioctl_ops msm_v4l2_enc_ioctl_ops = {
@@ -1006,6 +1014,13 @@
goto err_mem_alloc;
}
for (i = 0; i < num_bus_pdata; i++) {
+ if (!res->has_ocmem &&
+ (!strcmp(bus_pdata_config_vector[i].name,
+ "qcom,enc-ocmem-ab-ib")
+ || !strcmp(bus_pdata_config_vector[i].name,
+ "qcom,dec-ocmem-ab-ib"))) {
+ continue;
+ }
res->bus_pdata[i].num_usecases = get_u32_array_num_elements(
pdev, bus_pdata_config_vector[i].name);
if (res->bus_pdata[i].num_usecases == 0) {
@@ -1201,6 +1216,9 @@
kres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
res->irq = kres ? kres->start : -1;
+ res->has_ocmem = of_property_read_bool(pdev->dev.of_node,
+ "qcom,has-ocmem");
+
rc = msm_vidc_load_freq_table(res);
if (rc) {
dprintk(VIDC_ERR, "Failed to load freq table: %d\n", rc);
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index 5966d12..8f8e723 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -20,10 +20,6 @@
#include "msm_vidc_debug.h"
#define MSM_VDEC_DVC_NAME "msm_vdec_8974"
-#define DEFAULT_HEIGHT 720
-#define DEFAULT_WIDTH 1280
-#define MAX_SUPPORTED_WIDTH 3820
-#define MAX_SUPPORTED_HEIGHT 2160
#define MIN_NUM_OUTPUT_BUFFERS 4
#define MAX_NUM_OUTPUT_BUFFERS 6
@@ -248,7 +244,7 @@
return (MAX_SUPPORTED_WIDTH * MAX_SUPPORTED_HEIGHT * 3/2)/2;
}
-static const struct msm_vidc_format vdec_formats[] = {
+struct msm_vidc_format vdec_formats[] = {
{
.name = "YCbCr Semiplanar 4:2:0",
.description = "Y/CbCr 4:2:0",
@@ -582,7 +578,6 @@
int stride, scanlines;
int extra_idx = 0;
int rc = 0;
- int ret;
int i;
struct hal_buffer_requirements *buff_req_buffer;
if (!inst || !f || !inst->core || !inst->core->device) {
@@ -602,6 +597,12 @@
if (inst->in_reconfig == true) {
inst->prop.height = inst->reconfig_height;
inst->prop.width = inst->reconfig_width;
+ rc = msm_vidc_check_session_supported(inst);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "%s: session not supported\n", __func__);
+ goto exit;
+ }
}
f->fmt.pix_mp.height = inst->prop.height;
f->fmt.pix_mp.width = inst->prop.width;
@@ -612,10 +613,20 @@
frame_sz.height = inst->prop.height;
dprintk(VIDC_DBG, "width = %d, height = %d\n",
frame_sz.width, frame_sz.height);
- ret = msm_comm_try_set_prop(inst,
+ rc = msm_comm_try_set_prop(inst,
HAL_PARAM_FRAME_SIZE, &frame_sz);
- ret = ret || msm_comm_try_get_bufreqs(inst);
- if (ret || (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)) {
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "%s: Failed : Frame size setting\n", __func__);
+ goto exit;
+ }
+ rc = msm_comm_try_get_bufreqs(inst);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "%s: Failed : Buffer requirements\n", __func__);
+ goto exit;
+ }
+ if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
for (i = 0; i < fmt->num_planes; ++i) {
f->fmt.pix_mp.plane_fmt[i].sizeimage =
fmt->get_frame_size(i,
@@ -680,6 +691,7 @@
f->type);
rc = -EINVAL;
}
+exit:
return rc;
}
int msm_vdec_s_parm(struct msm_vidc_inst *inst, struct v4l2_streamparm *a)
@@ -717,7 +729,7 @@
}
int msm_vdec_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
{
- const struct msm_vidc_format *fmt = NULL;
+ struct msm_vidc_format *fmt = NULL;
struct hal_frame_size frame_sz;
int extra_idx = 0;
int rc = 0;
@@ -787,6 +799,12 @@
} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
inst->prop.width = f->fmt.pix_mp.width;
inst->prop.height = f->fmt.pix_mp.height;
+ rc = msm_vidc_check_session_supported(inst);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "%s: session not supported\n", __func__);
+ goto err_invalid_fmt;
+ }
fmt = msm_comm_get_pixel_fmt_fourcc(vdec_formats,
ARRAY_SIZE(vdec_formats),
f->fmt.pix_mp.pixelformat,
@@ -1161,6 +1179,10 @@
inst->fmts[CAPTURE_PORT] = &vdec_formats[0];
inst->prop.height = DEFAULT_HEIGHT;
inst->prop.width = DEFAULT_WIDTH;
+ inst->capability.height.min = MIN_SUPPORTED_HEIGHT;
+ inst->capability.height.max = DEFAULT_HEIGHT;
+ inst->capability.width.min = MIN_SUPPORTED_WIDTH;
+ inst->capability.width.max = DEFAULT_WIDTH;
inst->prop.fps = 30;
inst->prop.prev_time_stamp = 0;
return rc;
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index 072f4ab..9aa8175 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -19,10 +19,7 @@
#include "msm_vidc_debug.h"
#define MSM_VENC_DVC_NAME "msm_venc_8974"
-#define DEFAULT_HEIGHT 720
-#define DEFAULT_WIDTH 1280
#define MIN_NUM_OUTPUT_BUFFERS 4
-#define MAX_NUM_OUTPUT_BUFFERS 8
#define MIN_BIT_RATE 64000
#define MAX_BIT_RATE 160000000
#define DEFAULT_BIT_RATE 64000
@@ -88,6 +85,27 @@
"High Latency",
};
+static const char *const mpeg_video_vidc_extradata[] = {
+ "Extradata none",
+ "Extradata MB Quantization",
+ "Extradata Interlace Video",
+ "Extradata VC1 Framedisp",
+ "Extradata VC1 Seqdisp",
+ "Extradata timestamp",
+ "Extradata S3D Frame Packing",
+ "Extradata Frame Rate",
+ "Extradata Panscan Window",
+ "Extradata Recovery point SEI",
+ "Extradata Closed Caption UD",
+ "Extradata AFD UD",
+ "Extradata Multislice info",
+ "Extradata number of concealed MB",
+ "Extradata metadata filler",
+ "Extradata input crop",
+ "Extradata digital zoom",
+ "Extradata aspect ratio",
+};
+
enum msm_venc_ctrl_cluster {
MSM_VENC_CTRL_CLUSTER_QP = 1,
MSM_VENC_CTRL_CLUSTER_INTRA_PERIOD,
@@ -439,6 +457,18 @@
.cluster = MSM_VENC_CTRL_CLUSTER_SLICING,
},
{
+ .id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_DELIVERY_MODE,
+ .name = "Slice delivery mode",
+ .type = V4L2_CTRL_TYPE_BUTTON,
+ .minimum = 0,
+ .maximum = 1,
+ .default_value = 0,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ .cluster = MSM_VENC_CTRL_CLUSTER_SLICING,
+ },
+ {
.id = V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_MODE,
.name = "Intra Refresh Mode",
.type = V4L2_CTRL_TYPE_MENU,
@@ -557,6 +587,36 @@
.qmenu = NULL,
.cluster = 0,
},
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA,
+ .name = "Extradata Type",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDC_EXTRADATA_NONE,
+ .maximum = V4L2_MPEG_VIDC_INDEX_EXTRADATA_ASPECT_RATIO,
+ .default_value = V4L2_MPEG_VIDC_EXTRADATA_NONE,
+ .menu_skip_mask = ~(
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_NONE) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_MB_QUANTIZATION) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_INTERLACE_VIDEO) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_VC1_FRAMEDISP) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_VC1_SEQDISP) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_TIMESTAMP) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_S3D_FRAME_PACKING) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_FRAME_RATE) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_PANSCAN_WINDOW) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_RECOVERY_POINT_SEI) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_CLOSED_CAPTION_UD) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_AFD_UD) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_MULTISLICE_INFO) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_NUM_CONCEALED_MB) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_METADATA_FILLER) |
+ (1 << V4L2_MPEG_VIDC_INDEX_EXTRADATA_INPUT_CROP) |
+ (1 << V4L2_MPEG_VIDC_INDEX_EXTRADATA_DIGITAL_ZOOM) |
+ (1 << V4L2_MPEG_VIDC_INDEX_EXTRADATA_ASPECT_RATIO)
+ ),
+ .qmenu = mpeg_video_vidc_extradata,
+ .step = 0,
+ },
};
#define NUM_CTRLS ARRAY_SIZE(msm_venc_ctrls)
@@ -578,7 +638,7 @@
return sz;
}
-static const struct msm_vidc_format venc_formats[] = {
+static struct msm_vidc_format venc_formats[] = {
{
.name = "YCbCr Semiplanar 4:2:0",
.description = "Y/CbCr 4:2:0",
@@ -640,6 +700,9 @@
struct hal_buffer_count_actual new_buf_count;
enum hal_property property_id;
struct hfi_device *hdev;
+ struct hal_buffer_requirements *buff_req;
+ struct v4l2_ctrl *ctrl = NULL;
+ u32 extradata = 0;
if (!q || !q->drv_priv) {
dprintk(VIDC_ERR, "Invalid input, q = %p\n", q);
return -EINVAL;
@@ -655,13 +718,33 @@
switch (q->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
*num_planes = 1;
- if (*num_buffers < MIN_NUM_OUTPUT_BUFFERS ||
- *num_buffers > MAX_NUM_OUTPUT_BUFFERS)
- *num_buffers = MIN_NUM_OUTPUT_BUFFERS;
+ buff_req = get_buff_req_buffer(inst, HAL_BUFFER_OUTPUT);
+ *num_buffers = buff_req->buffer_count_actual =
+ max(*num_buffers, buff_req->buffer_count_actual);
+ if (*num_buffers > VIDEO_MAX_FRAME) {
+ dprintk(VIDC_ERR,
+ "Failed : No of slices requested = %d"\
+ " Max supported slices = %d",
+ *num_buffers, VIDEO_MAX_FRAME);
+ rc = -EINVAL;
+ break;
+ }
+ ctrl = v4l2_ctrl_find(&inst->ctrl_handler,
+ V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA);
+ if (ctrl)
+ extradata = v4l2_ctrl_g_ctrl(ctrl);
+ if (extradata)
+ *num_planes = *num_planes + 1;
+ inst->fmts[CAPTURE_PORT]->num_planes = *num_planes;
for (i = 0; i < *num_planes; i++) {
sizes[i] = inst->fmts[CAPTURE_PORT]->get_frame_size(
i, inst->prop.height, inst->prop.width);
}
+ property_id = HAL_PARAM_BUFFER_COUNT_ACTUAL;
+ new_buf_count.buffer_type = HAL_BUFFER_OUTPUT;
+ new_buf_count.buffer_count_actual = *num_buffers;
+ rc = call_hfi_op(hdev, session_set_property, inst->session,
+ property_id, &new_buf_count);
break;
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
@@ -1342,6 +1425,25 @@
multi_slice_control.slice_size = ctrl->val;
pdata = &multi_slice_control;
break;
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_DELIVERY_MODE: {
+ temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE);
+ if ((temp_ctrl->val ==
+ V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) &&
+ (inst->fmts[CAPTURE_PORT]->fourcc ==
+ V4L2_PIX_FMT_H264 ||
+ inst->fmts[CAPTURE_PORT]->fourcc ==
+ V4L2_PIX_FMT_H264_NO_SC)) {
+ property_id = HAL_PARAM_VENC_SLICE_DELIVERY_MODE;
+ enable.enable = true;
+ } else {
+ dprintk(VIDC_WARN,
+ "Failed : slice delivery mode is valid "\
+ "only for H264 encoder and MB based slicing");
+ enable.enable = false;
+ }
+ pdata = &enable;
+ break;
+ }
case V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_MODE: {
struct v4l2_ctrl *air_mbs, *air_ref, *cir_mbs;
air_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS);
@@ -1452,6 +1554,15 @@
inst->mode = VIDC_SECURE;
dprintk(VIDC_INFO, "Setting secure mode to :%d\n", inst->mode);
break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA:
+ {
+ struct hal_extradata_enable extra;
+ property_id = HAL_PARAM_INDEX_EXTRADATA;
+ extra.index = msm_comm_get_hal_extradata_index(ctrl->val);
+ extra.enable = 1;
+ pdata = &extra;
+ break;
+ }
default:
rc = -ENOTSUPP;
break;
@@ -1676,7 +1787,7 @@
}
int msm_venc_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
{
- const struct msm_vidc_format *fmt = NULL;
+ struct msm_vidc_format *fmt = NULL;
struct hal_frame_size frame_sz;
int rc = 0;
int i;
@@ -1707,6 +1818,12 @@
} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
inst->prop.width = f->fmt.pix_mp.width;
inst->prop.height = f->fmt.pix_mp.height;
+ rc = msm_vidc_check_session_supported(inst);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "%s: session not supported\n", __func__);
+ goto exit;
+ }
frame_sz.buffer_type = HAL_BUFFER_INPUT;
frame_sz.width = inst->prop.width;
frame_sz.height = inst->prop.height;
@@ -1768,6 +1885,7 @@
const struct msm_vidc_format *fmt = NULL;
int rc = 0;
int i;
+ int extra_idx = 0;
if (!inst || !f) {
dprintk(VIDC_ERR,
"Invalid input, inst = %p, format = %p\n", inst, f);
@@ -1788,6 +1906,16 @@
fmt->get_frame_size(i, inst->prop.height,
inst->prop.width);
}
+ extra_idx = EXTRADATA_IDX(fmt->num_planes);
+ if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) {
+ f->fmt.pix_mp.plane_fmt[extra_idx].sizeimage =
+ inst->buff_req.buffer
+ [HAL_BUFFER_EXTRADATA_OUTPUT].buffer_size;
+ }
+ for (i = 0; i < fmt->num_planes; ++i) {
+ inst->bufq[CAPTURE_PORT].vb2_bufq.plane_sizes[i] =
+ f->fmt.pix_mp.plane_fmt[i].sizeimage;
+ }
} else {
dprintk(VIDC_ERR,
"Buf type not recognized, type = %d\n", f->type);
@@ -1827,6 +1955,7 @@
int i;
struct vidc_buffer_addr_info buffer_info;
struct hfi_device *hdev;
+ int extra_idx = 0;
if (!inst || !inst->core || !inst->core->device) {
dprintk(VIDC_ERR, "%s invalid parameters", __func__);
@@ -1839,24 +1968,41 @@
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
- for (i = 0; i < b->length; i++) {
- dprintk(VIDC_DBG,
- "device_addr = %ld, size = %d\n",
+ if (b->length != inst->fmts[CAPTURE_PORT]->num_planes) {
+ dprintk(VIDC_ERR,
+ "Planes mismatch: needed: %d, allocated: %d\n",
+ inst->fmts[CAPTURE_PORT]->num_planes,
+ b->length);
+ rc = -EINVAL;
+ break;
+ }
+
+ for (i = 0; (i < b->length) && (i < VIDEO_MAX_PLANES); i++) {
+ dprintk(VIDC_DBG, "device_addr = 0x%lx, size = %d\n",
b->m.planes[i].m.userptr,
b->m.planes[i].length);
- buffer_info.buffer_size = b->m.planes[i].length;
- buffer_info.buffer_type = HAL_BUFFER_OUTPUT;
- buffer_info.num_buffers = 1;
- buffer_info.align_device_addr =
- b->m.planes[i].m.userptr;
- buffer_info.extradata_size = 0;
- buffer_info.extradata_addr = 0;
- rc = call_hfi_op(hdev, session_set_buffers,
- (void *)inst->session, &buffer_info);
- if (rc)
- dprintk(VIDC_ERR,
- "vidc_hal_session_set_buffers failed");
}
+ buffer_info.buffer_size = b->m.planes[0].length;
+ buffer_info.buffer_type = HAL_BUFFER_OUTPUT;
+ buffer_info.num_buffers = 1;
+ buffer_info.align_device_addr =
+ b->m.planes[0].m.userptr;
+
+ extra_idx = EXTRADATA_IDX(b->length);
+ if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) {
+ buffer_info.extradata_addr =
+ b->m.planes[extra_idx].m.userptr;
+ dprintk(VIDC_DBG, "extradata: 0x%lx\n",
+ b->m.planes[extra_idx].m.userptr);
+ buffer_info.extradata_size =
+ b->m.planes[extra_idx].length;
+ }
+
+ rc = call_hfi_op(hdev, session_set_buffers,
+ (void *)inst->session, &buffer_info);
+ if (rc)
+ dprintk(VIDC_ERR,
+ "vidc_hal_session_set_buffers failed");
break;
default:
dprintk(VIDC_ERR,
@@ -1869,8 +2015,7 @@
int msm_venc_release_buf(struct msm_vidc_inst *inst,
struct v4l2_buffer *b)
{
- int rc = 0;
- int i;
+ int i, rc = 0, extra_idx = 0;
struct vidc_buffer_addr_info buffer_info;
struct hfi_device *hdev;
@@ -1891,24 +2036,36 @@
switch (b->type) {
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
break;
- case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: {
+ if (b->length !=
+ inst->fmts[CAPTURE_PORT]->num_planes) {
+ dprintk(VIDC_ERR,
+ "Planes mismatch: needed: %d, to release: %d\n",
+ inst->fmts[CAPTURE_PORT]->num_planes,
+ b->length);
+ rc = -EINVAL;
+ break;
+ }
for (i = 0; i < b->length; i++) {
dprintk(VIDC_DBG,
- "Release device_addr = %ld, size = %d, %d\n",
+ "Release device_addr = 0x%lx, size = %d, %d\n",
b->m.planes[i].m.userptr,
b->m.planes[i].length, inst->state);
- buffer_info.buffer_size = b->m.planes[i].length;
- buffer_info.buffer_type = HAL_BUFFER_OUTPUT;
- buffer_info.num_buffers = 1;
- buffer_info.align_device_addr =
- b->m.planes[i].m.userptr;
- buffer_info.extradata_size = 0;
- buffer_info.extradata_addr = 0;
- buffer_info.response_required = false;
- rc = call_hfi_op(hdev, session_release_buffers,
+ }
+ buffer_info.buffer_size = b->m.planes[0].length;
+ buffer_info.buffer_type = HAL_BUFFER_OUTPUT;
+ buffer_info.num_buffers = 1;
+ buffer_info.align_device_addr =
+ b->m.planes[0].m.userptr;
+ extra_idx = EXTRADATA_IDX(b->length);
+ if (extra_idx && (extra_idx < VIDEO_MAX_PLANES))
+ buffer_info.extradata_addr =
+ b->m.planes[extra_idx].m.userptr;
+ buffer_info.response_required = false;
+ rc = call_hfi_op(hdev, session_release_buffers,
(void *)inst->session, &buffer_info);
- if (rc)
- dprintk(VIDC_ERR,
+ if (rc)
+ dprintk(VIDC_ERR,
"vidc_hal_session_release_buffers failed\n");
}
break;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index 218987e..0fbfd72 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -299,6 +299,30 @@
return -EINVAL;
}
+
+int msm_vidc_enum_framesizes(void *instance, struct v4l2_frmsizeenum *fsize)
+{
+ struct msm_vidc_inst *inst = instance;
+ struct msm_vidc_core_capability *capability = NULL;
+
+ if (!inst || !fsize) {
+ dprintk(VIDC_ERR, "%s: invalid parameter: %p %p\n",
+ __func__, inst, fsize);
+ return -EINVAL;
+ }
+ if (!inst->core)
+ return -EINVAL;
+
+ capability = &inst->capability;
+ fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
+ fsize->stepwise.min_width = capability->width.min;
+ fsize->stepwise.max_width = capability->width.max;
+ fsize->stepwise.step_width = capability->width.step_size;
+ fsize->stepwise.min_height = capability->height.min;
+ fsize->stepwise.max_height = capability->height.max;
+ fsize->stepwise.step_height = capability->height.step_size;
+ return 0;
+}
static void *vidc_get_userptr(void *alloc_ctx, unsigned long vaddr,
unsigned long size, int write)
{
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index e55c0f1..4346a4e 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -11,6 +11,7 @@
*
*/
+#include <linux/jiffies.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <asm/div64.h>
@@ -21,7 +22,7 @@
#include "msm_smem.h"
#include "msm_vidc_debug.h"
-#define HW_RESPONSE_TIMEOUT (5 * 60 * 1000)
+#define HW_RESPONSE_TIMEOUT msecs_to_jiffies(200)
#define IS_ALREADY_IN_STATE(__p, __d) ({\
int __rc = (__p >= __d);\
@@ -173,8 +174,8 @@
}
return &fmt[i];
}
-const struct msm_vidc_format *msm_comm_get_pixel_fmt_fourcc(
- const struct msm_vidc_format fmt[], int size, int fourcc, int fmt_type)
+struct msm_vidc_format *msm_comm_get_pixel_fmt_fourcc(
+ struct msm_vidc_format fmt[], int size, int fourcc, int fmt_type)
{
int i;
if (!fmt) {
@@ -313,7 +314,7 @@
enum command_response cmd)
{
int rc = 0;
- rc = wait_for_completion_interruptible_timeout(
+ rc = wait_for_completion_timeout(
&inst->completions[SESSION_MSG_INDEX(cmd)],
msecs_to_jiffies(HW_RESPONSE_TIMEOUT));
if (!rc) {
@@ -349,7 +350,15 @@
struct msm_vidc_cb_cmd_done *response = data;
struct msm_vidc_inst *inst;
if (response) {
+ struct vidc_hal_session_init_done *session_init_done =
+ (struct vidc_hal_session_init_done *) response->data;
inst = (struct msm_vidc_inst *)response->session_id;
+
+ inst->capability.width = session_init_done->width;
+ inst->capability.height = session_init_done->height;
+ inst->capability.frame_rate =
+ session_init_done->frame_rate;
+ inst->capability.capability_set = true;
signal_session_msg_receipt(cmd, inst);
} else {
dprintk(VIDC_ERR,
@@ -393,8 +402,11 @@
inst->reconfig_height = event_notify->height;
inst->reconfig_width = event_notify->width;
inst->in_reconfig = true;
- v4l2_event_queue_fh(&inst->event_handler, &dqevent);
- wake_up(&inst->kernel_event_queue);
+ rc = msm_vidc_check_session_supported(inst);
+ if (!rc) {
+ v4l2_event_queue_fh(&inst->event_handler, &dqevent);
+ wake_up(&inst->kernel_event_queue);
+ }
return;
} else {
dprintk(VIDC_ERR,
@@ -948,7 +960,7 @@
dprintk(VIDC_WARN,
"Failed to scale DDR bus. Performance might be impacted\n");
}
- if (call_hfi_op(hdev, is_ocmem_present, hdev->hfi_device_data)) {
+ if (core->resources.has_ocmem) {
if (msm_comm_scale_bus(core, inst->session_type,
OCMEM_MEM))
dprintk(VIDC_WARN,
@@ -1111,9 +1123,11 @@
}
msm_comm_scale_clocks_and_bus(inst);
if (list_empty(&core->instances)) {
- if (inst->state != MSM_VIDC_CORE_INVALID)
- msm_comm_unset_ocmem(core);
- call_hfi_op(hdev, free_ocmem, hdev->hfi_device_data);
+ if (core->resources.has_ocmem) {
+ if (inst->state != MSM_VIDC_CORE_INVALID)
+ msm_comm_unset_ocmem(core);
+ call_hfi_op(hdev, free_ocmem, hdev->hfi_device_data);
+ }
dprintk(VIDC_DBG, "Calling vidc_hal_core_release\n");
rc = call_hfi_op(hdev, core_release, hdev->hfi_device_data);
if (rc) {
@@ -1125,7 +1139,10 @@
core->state = VIDC_CORE_UNINIT;
mutex_unlock(&core->lock);
call_hfi_op(hdev, unload_fw, hdev->hfi_device_data);
- msm_comm_unvote_buses(core, DDR_MEM|OCMEM_MEM);
+ if (core->resources.has_ocmem)
+ msm_comm_unvote_buses(core, DDR_MEM|OCMEM_MEM);
+ else
+ msm_comm_unvote_buses(core, DDR_MEM);
}
core_already_uninited:
change_inst_state(inst, MSM_VIDC_CORE_UNINIT);
@@ -1272,21 +1289,26 @@
inst, inst->state);
goto exit;
}
- ocmem_sz = get_ocmem_requirement(inst->prop.height, inst->prop.width);
- rc = msm_comm_scale_bus(inst->core, inst->session_type, OCMEM_MEM);
- if (!rc) {
- mutex_lock(&inst->core->sync_lock);
- rc = call_hfi_op(hdev, alloc_ocmem, hdev->hfi_device_data,
- ocmem_sz);
- mutex_unlock(&inst->core->sync_lock);
- if (rc) {
+ if (inst->core->resources.has_ocmem) {
+ ocmem_sz = get_ocmem_requirement(inst->prop.height,
+ inst->prop.width);
+ rc = msm_comm_scale_bus(inst->core, inst->session_type,
+ OCMEM_MEM);
+ if (!rc) {
+ mutex_lock(&inst->core->sync_lock);
+ rc = call_hfi_op(hdev, alloc_ocmem,
+ hdev->hfi_device_data,
+ ocmem_sz);
+ mutex_unlock(&inst->core->sync_lock);
+ if (rc) {
+ dprintk(VIDC_WARN,
+ "Failed to allocate OCMEM. Performance will be impacted\n");
+ msm_comm_unvote_buses(inst->core, OCMEM_MEM);
+ }
+ } else {
dprintk(VIDC_WARN,
- "Failed to allocate OCMEM. Performance will be impacted\n");
- msm_comm_unvote_buses(inst->core, OCMEM_MEM);
+ "Failed to vote for OCMEM BW. Performance will be impacted\n");
}
- } else {
- dprintk(VIDC_WARN,
- "Failed to vote for OCMEM BW. Performance will be impacted\n");
}
rc = call_hfi_op(hdev, session_load_res, (void *) inst->session);
if (rc) {
@@ -1778,6 +1800,13 @@
mutex_unlock(&inst->sync_lock);
} else {
int64_t time_usec = timeval_to_ns(&vb->v4l2_buf.timestamp);
+
+ rc = msm_vidc_check_session_supported(inst);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "%s: session not supported\n", __func__);
+ goto err_no_mem;
+ }
do_div(time_usec, NSEC_PER_USEC);
memset(&frame_data, 0 , sizeof(struct vidc_frame_data));
frame_data.alloc_len = vb->v4l2_planes[0].length;
@@ -2348,3 +2377,54 @@
hdev->hfi_device_data, type);
return rc;
}
+
+int msm_vidc_check_session_supported(struct msm_vidc_inst *inst)
+{
+ struct msm_vidc_core_capability *capability;
+ int rc = 0;
+ struct v4l2_event dqevent;
+
+ if (!inst) {
+ dprintk(VIDC_WARN, "%s: Invalid parameter\n", __func__);
+ return -EINVAL;
+ }
+ capability = &inst->capability;
+
+ if (inst->capability.capability_set) {
+ if (msm_vp8_low_tier &&
+ inst->fmts[OUTPUT_PORT]->fourcc == V4L2_PIX_FMT_VP8) {
+ capability->width.max = DEFAULT_WIDTH;
+ capability->height.max = DEFAULT_HEIGHT;
+ }
+ if (inst->prop.width < capability->width.min ||
+ inst->prop.width > capability->width.max ||
+ (inst->prop.width % capability->width.step_size != 0)) {
+ dprintk(VIDC_ERR,
+ "Unsupported width = %d range min(%u) - max(%u) step_size(%u)",
+ inst->prop.width, capability->width.min,
+ capability->width.max, capability->width.step_size);
+ rc = -ENOTSUPP;
+ }
+
+ if (inst->prop.height < capability->height.min ||
+ inst->prop.height > capability->height.max ||
+ (inst->prop.height %
+ capability->height.step_size != 0)) {
+ dprintk(VIDC_ERR,
+ "Unsupported height = %d range min(%u) - max(%u) step_size(%u)",
+ inst->prop.height, capability->height.min,
+ capability->height.max, capability->height.step_size);
+ rc = -ENOTSUPP;
+ }
+ }
+ if (rc) {
+ mutex_lock(&inst->sync_lock);
+ inst->state = MSM_VIDC_CORE_INVALID;
+ mutex_unlock(&inst->sync_lock);
+ dqevent.type = V4L2_EVENT_MSM_VIDC_SYS_ERROR;
+ dqevent.id = 0;
+ v4l2_event_queue_fh(&inst->event_handler, &dqevent);
+ wake_up(&inst->kernel_event_queue);
+ }
+ return rc;
+}
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.h b/drivers/media/platform/msm/vidc/msm_vidc_common.h
index 4f3deb6..862dfab 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.h
@@ -21,8 +21,8 @@
struct msm_vidc_core *get_vidc_core(int core_id);
const struct msm_vidc_format *msm_comm_get_pixel_fmt_index(
const struct msm_vidc_format fmt[], int size, int index, int fmt_type);
-const struct msm_vidc_format *msm_comm_get_pixel_fmt_fourcc(
- const struct msm_vidc_format fmt[], int size, int fourcc, int fmt_type);
+struct msm_vidc_format *msm_comm_get_pixel_fmt_fourcc(
+ struct msm_vidc_format fmt[], int size, int fourcc, int fmt_type);
struct buf_queue *msm_comm_get_vb2q(
struct msm_vidc_inst *inst, enum v4l2_buf_type type);
int msm_comm_try_state(struct msm_vidc_inst *inst, int state);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.c b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
index 65542bc..5948c7c 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_debug.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
@@ -19,6 +19,7 @@
int msm_fw_debug = 0x18;
int msm_fw_debug_mode = 0x1;
int msm_fw_low_power_mode = 0x1;
+int msm_vp8_low_tier = 0x1;
struct debug_buffer {
char ptr[MAX_DBG_BUF_SIZE];
@@ -165,6 +166,11 @@
dprintk(VIDC_ERR, "debugfs_create_file: fail\n");
goto failed_create_dir;
}
+ if (!debugfs_create_u32("vp8_low_tier", S_IRUGO | S_IWUSR,
+ parent, &msm_vp8_low_tier)) {
+ dprintk(VIDC_ERR, "debugfs_create_file: fail\n");
+ goto failed_create_dir;
+ }
failed_create_dir:
return dir;
}
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.h b/drivers/media/platform/msm/vidc/msm_vidc_debug.h
index fb06af6..ea6dd70 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_debug.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.h
@@ -45,6 +45,7 @@
extern int msm_fw_debug;
extern int msm_fw_debug_mode;
extern int msm_fw_low_power_mode;
+extern int msm_vp8_low_tier;
#define dprintk(__level, __fmt, arg...) \
do { \
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
index 8238d42..1bfbaa6 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
@@ -37,6 +37,14 @@
#define MSM_VIDC_VERSION KERNEL_VERSION(0, 0, 1);
#define MAX_DEBUGFS_NAME 50
#define DEFAULT_TIMEOUT 3
+#define DEFAULT_HEIGHT 1080
+#define DEFAULT_WIDTH 1920
+#define MIN_SUPPORTED_WIDTH 32
+#define MIN_SUPPORTED_HEIGHT 32
+#define MAX_SUPPORTED_WIDTH 3820
+#define MAX_SUPPORTED_HEIGHT 2160
+
+
#define V4L2_EVENT_VIDC_BASE 10
@@ -166,6 +174,13 @@
VIDC_SECURE,
};
+struct msm_vidc_core_capability {
+ struct hal_capability_supported width;
+ struct hal_capability_supported height;
+ struct hal_capability_supported frame_rate;
+ u32 capability_set;
+};
+
struct msm_vidc_core {
struct list_head list;
struct mutex sync_lock, lock;
@@ -189,7 +204,7 @@
void *session;
struct session_prop prop;
int state;
- const struct msm_vidc_format *fmts[MAX_PORT_NUM];
+ struct msm_vidc_format *fmts[MAX_PORT_NUM];
struct buf_queue bufq[MAX_PORT_NUM];
struct list_head pendingq;
struct list_head internalbufs;
@@ -212,6 +227,7 @@
struct msm_vidc_debug debug;
struct buf_count count;
enum msm_vidc_mode mode;
+ struct msm_vidc_core_capability capability;
};
extern struct msm_vidc_drv *vidc_driver;
@@ -238,4 +254,5 @@
void handle_cmd_response(enum command_response cmd, void *data);
int msm_vidc_trigger_ssr(struct msm_vidc_core *core,
enum hal_ssr_trigger_type type);
+int msm_vidc_check_session_supported(struct msm_vidc_inst *inst);
#endif
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_resources.h b/drivers/media/platform/msm/vidc/msm_vidc_resources.h
index 54c0878..86b824b 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_resources.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_resources.h
@@ -73,6 +73,7 @@
struct msm_bus_scale_pdata *bus_pdata;
struct iommu_set iommu_group_set;
struct buffer_usage_set buffer_usage_set;
+ bool has_ocmem;
struct platform_device *pdev;
};
diff --git a/drivers/media/platform/msm/vidc/q6_hfi.c b/drivers/media/platform/msm/vidc/q6_hfi.c
index 88dc4fe..f0ca050 100644
--- a/drivers/media/platform/msm/vidc/q6_hfi.c
+++ b/drivers/media/platform/msm/vidc/q6_hfi.c
@@ -1105,14 +1105,6 @@
return 0;
}
-static int q6_hfi_is_ocmem_present(void *dev)
-{
- (void)dev;
-
- /* Q6 does not support ocmem */
- return 0;
-}
-
static int q6_hfi_iommu_get_domain_partition(void *dev, u32 flags,
u32 buffer_type, int *domain, int *partition)
{
@@ -1188,6 +1180,13 @@
return 0;
}
+static int q6_hfi_get_stride_scanline(int color_fmt,
+ int width, int height, int *stride, int *scanlines) {
+ *stride = VENUS_Y_STRIDE(color_fmt, width);
+ *scanlines = VENUS_Y_SCANLINES(color_fmt, height);
+ return 0;
+}
+
static void q6_init_hfi_callbacks(struct hfi_device *hdev)
{
hdev->core_init = q6_hfi_core_init;
@@ -1218,11 +1217,11 @@
hdev->unset_ocmem = q6_hfi_unset_ocmem;
hdev->alloc_ocmem = q6_hfi_alloc_ocmem;
hdev->free_ocmem = q6_hfi_free_ocmem;
- hdev->is_ocmem_present = q6_hfi_is_ocmem_present;
hdev->iommu_get_domain_partition = q6_hfi_iommu_get_domain_partition;
hdev->load_fw = q6_hfi_load_fw;
hdev->unload_fw = q6_hfi_unload_fw;
hdev->get_fw_info = q6_hfi_get_fw_info;
+ hdev->get_stride_scanline = q6_hfi_get_stride_scanline;
}
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index 1b7ecf0..995c655 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -1941,8 +1941,11 @@
sizeof(clock[VCODEC_AHB_CLK].name));
strlcpy(clock[VCODEC_AXI_CLK].name, "bus_clk",
sizeof(clock[VCODEC_AXI_CLK].name));
- strlcpy(clock[VCODEC_OCMEM_CLK].name, "mem_clk",
- sizeof(clock[VCODEC_OCMEM_CLK].name));
+
+ if (res->has_ocmem) {
+ strlcpy(clock[VCODEC_OCMEM_CLK].name, "mem_clk",
+ sizeof(clock[VCODEC_OCMEM_CLK].name));
+ }
clock[VCODEC_CLK].count = res->load_freq_tbl_size;
memcpy((void *)clock[VCODEC_CLK].load_freq_tbl, res->load_freq_tbl,
@@ -1962,6 +1965,8 @@
}
for (i = 0; i < VCODEC_MAX_CLKS; i++) {
+ if (i == VCODEC_OCMEM_CLK && !res->has_ocmem)
+ continue;
cl = &device->resources.clock[i];
if (!cl->clk) {
cl->clk = devm_clk_get(&res->pdev->dev, cl->name);
@@ -1976,6 +1981,8 @@
if (i < VCODEC_MAX_CLKS) {
for (--i; i >= 0; i--) {
+ if (i == VCODEC_OCMEM_CLK && !res->has_ocmem)
+ continue;
cl = &device->resources.clock[i];
clk_put(cl->clk);
}
@@ -1991,8 +1998,12 @@
dprintk(VIDC_ERR, "Invalid args\n");
return;
}
- for (i = 0; i < VCODEC_MAX_CLKS; i++)
+
+ for (i = 0; i < VCODEC_MAX_CLKS; i++) {
+ if (i == VCODEC_OCMEM_CLK && !device->res->has_ocmem)
+ continue;
clk_put(device->resources.clock[i].clk);
+ }
}
static inline void venus_hfi_disable_clks(struct venus_hfi_device *device)
{
@@ -2002,12 +2013,10 @@
dprintk(VIDC_ERR, "Invalid params: %p\n", device);
return;
}
- if (device->clocks_enabled) {
- cl = &device->resources.clock[VCODEC_CLK];
- clk_disable_unprepare(cl->clk);
- }
for (i = VCODEC_CLK; i < VCODEC_MAX_CLKS; i++) {
+ if (i == VCODEC_OCMEM_CLK && !device->res->has_ocmem)
+ continue;
cl = &device->resources.clock[i];
clk_disable_unprepare(cl->clk);
}
@@ -2022,17 +2031,10 @@
dprintk(VIDC_ERR, "Invalid params: %p\n", device);
return -EINVAL;
}
- if (!device->clocks_enabled) {
- cl = &device->resources.clock[VCODEC_CLK];
- rc = clk_prepare_enable(cl->clk);
- if (rc) {
- dprintk(VIDC_ERR, "Failed to enable clocks\n");
- goto fail_clk_enable;
- } else {
- dprintk(VIDC_DBG, "Clock: %s enabled\n", cl->name);
- }
- }
+
for (i = VCODEC_CLK; i < VCODEC_MAX_CLKS; i++) {
+ if (i == VCODEC_OCMEM_CLK && !device->res->has_ocmem)
+ continue;
cl = &device->resources.clock[i];
rc = clk_prepare_enable(cl->clk);
if (rc) {
@@ -2165,18 +2167,27 @@
dprintk(VIDC_ERR, "Failed to register bus scale client\n");
goto err_init_bus;
}
- bus_info->ocmem_handle[MSM_VIDC_ENCODER] =
- msm_bus_scale_register_client(&device->res->bus_pdata[0]);
- if (!bus_info->ocmem_handle[MSM_VIDC_ENCODER]) {
- dprintk(VIDC_ERR, "Failed to register bus scale client\n");
- goto err_init_bus;
+
+ if (device->res->has_ocmem) {
+ bus_info->ocmem_handle[MSM_VIDC_ENCODER] =
+ msm_bus_scale_register_client(
+ &device->res->bus_pdata[0]);
+ if (!bus_info->ocmem_handle[MSM_VIDC_ENCODER]) {
+ dprintk(VIDC_ERR,
+ "Failed to register bus scale client\n");
+ goto err_init_bus;
+ }
+
+ bus_info->ocmem_handle[MSM_VIDC_DECODER] =
+ msm_bus_scale_register_client(
+ &device->res->bus_pdata[1]);
+ if (!bus_info->ocmem_handle[MSM_VIDC_DECODER]) {
+ dprintk(VIDC_ERR,
+ "Failed to register bus scale client\n");
+ goto err_init_bus;
+ }
}
- bus_info->ocmem_handle[MSM_VIDC_DECODER] =
- msm_bus_scale_register_client(&device->res->bus_pdata[1]);
- if (!bus_info->ocmem_handle[MSM_VIDC_DECODER]) {
- dprintk(VIDC_ERR, "Failed to register bus scale client\n");
- goto err_init_bus;
- }
+
return rc;
err_init_bus:
venus_hfi_deinit_bus(device);
@@ -2420,18 +2431,6 @@
return rc;
}
-static int venus_hfi_is_ocmem_present(void *dev)
-{
- struct venus_hfi_device *device = dev;
- if (!device) {
- dprintk(VIDC_ERR, "%s invalid device handle %p",
- __func__, device);
- return -EINVAL;
- }
-
- return device->resources.ocmem.buf ? 1 : 0;
-}
-
static void venus_hfi_deinit_ocmem(struct venus_hfi_device *device)
{
if (device->resources.ocmem.handle)
@@ -2465,7 +2464,9 @@
goto err_register_iommu_domain;
}
- venus_hfi_ocmem_init(device);
+ if (res->has_ocmem)
+ venus_hfi_ocmem_init(device);
+
return rc;
err_register_iommu_domain:
@@ -2478,7 +2479,8 @@
static void venus_hfi_deinit_resources(struct venus_hfi_device *device)
{
- venus_hfi_deinit_ocmem(device);
+ if (device->res->has_ocmem)
+ venus_hfi_deinit_ocmem(device);
venus_hfi_deregister_iommu_domains(device);
venus_hfi_deinit_bus(device);
venus_hfi_deinit_clocks(device);
@@ -2602,7 +2604,7 @@
}
}
- rc = scm_call(SCM_SVC_CP, TZBSP_MEM_PROTECT_VIDEO_VAR, &memprot,
+ rc = scm_call(SCM_SVC_MP, TZBSP_MEM_PROTECT_VIDEO_VAR, &memprot,
sizeof(memprot), &resp, sizeof(resp));
if (rc)
dprintk(VIDC_ERR,
@@ -2672,8 +2674,8 @@
}
if (device->resources.fw.cookie) {
venus_hfi_disable_clks(device);
- subsystem_put(device->resources.fw.cookie);
venus_hfi_iommu_detach(device);
+ subsystem_put(device->resources.fw.cookie);
device->resources.fw.cookie = NULL;
}
}
@@ -2853,7 +2855,6 @@
hdev->unset_ocmem = venus_hfi_unset_ocmem;
hdev->alloc_ocmem = venus_hfi_alloc_ocmem;
hdev->free_ocmem = venus_hfi_free_ocmem;
- hdev->is_ocmem_present = venus_hfi_is_ocmem_present;
hdev->iommu_get_domain_partition = venus_hfi_iommu_get_domain_partition;
hdev->load_fw = venus_hfi_load_fw;
hdev->unload_fw = venus_hfi_unload_fw;
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index 0c88866..5ad0bb5 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -1047,7 +1047,6 @@
int (*unset_ocmem)(void *dev);
int (*alloc_ocmem)(void *dev, unsigned long size);
int (*free_ocmem)(void *dev);
- int (*is_ocmem_present)(void *dev);
int (*iommu_get_domain_partition)(void *dev, u32 flags, u32 buffer_type,
int *domain_num, int *partition_num);
int (*load_fw)(void *dev);
diff --git a/drivers/media/platform/msm/wfd/wfd-ioctl.c b/drivers/media/platform/msm/wfd/wfd-ioctl.c
index 9fb7c6d..3d11400 100644
--- a/drivers/media/platform/msm/wfd/wfd-ioctl.c
+++ b/drivers/media/platform/msm/wfd/wfd-ioctl.c
@@ -271,11 +271,15 @@
mmap_context.ion_client = wfd_dev->ion_client;
rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
ENC_MMAP, &mmap_context);
- if (rc || !enc_mregion->paddr) {
+ if (rc) {
WFD_MSG_ERR("Failed to map input memory\n");
goto alloc_fail;
+ } else if (!enc_mregion->paddr) {
+ WFD_MSG_ERR("ENC_MMAP returned success" \
+ "but failed to map input memory\n");
+ rc = -EINVAL;
+ goto alloc_fail;
}
-
WFD_MSG_DBG("NOTE: enc paddr = [%p->%p], kvaddr = %p\n",
enc_mregion->paddr, (int8_t *)
enc_mregion->paddr + enc_mregion->size,
@@ -303,7 +307,7 @@
rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl,
MDP_MMAP, (void *)&mmap_context);
- if (rc || !mdp_mregion->paddr) {
+ if (rc) {
WFD_MSG_ERR(
"Failed to map to mdp, rc = %d, paddr = 0x%p\n",
rc, mdp_mregion->paddr);
@@ -311,6 +315,14 @@
mdp_mregion->paddr = NULL;
mdp_mregion->ion_handle = NULL;
goto mdp_mmap_fail;
+ } else if (!mdp_mregion->paddr) {
+ WFD_MSG_ERR("MDP_MMAP returned success" \
+ "but failed to map to MDP\n");
+ rc = -EINVAL;
+ mdp_mregion->kvaddr = NULL;
+ mdp_mregion->paddr = NULL;
+ mdp_mregion->ion_handle = NULL;
+ goto mdp_mmap_fail;
}
mdp_buf.inst = inst->mdp_inst;
diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c
index 8a99968..f3a979b 100644
--- a/drivers/media/rc/gpio-ir-recv.c
+++ b/drivers/media/rc/gpio-ir-recv.c
@@ -41,7 +41,7 @@
struct rc_dev *rcdev;
struct pm_qos_request pm_qos_req;
struct timer_list gpio_ir_timer;
- unsigned int gpio_nr;
+ int gpio_nr;
bool active_low;
int can_sleep;
bool can_wakeup;
@@ -52,7 +52,7 @@
static irqreturn_t gpio_ir_recv_irq(int irq, void *dev_id)
{
struct gpio_rc_dev *gpio_dev = dev_id;
- unsigned int gval;
+ int gval;
int rc = 0;
enum raw_event_type type = IR_SPACE;
diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c
index b2ef948..ff2cddd 100644
--- a/drivers/media/video/uvc/uvc_v4l2.c
+++ b/drivers/media/video/uvc/uvc_v4l2.c
@@ -68,15 +68,6 @@
goto done;
}
- /* Prevent excessive memory consumption, as well as integer
- * overflows.
- */
- if (xmap->menu_count == 0 ||
- xmap->menu_count > UVC_MAX_CONTROL_MENU_ENTRIES) {
- ret = -EINVAL;
- goto done;
- }
-
size = xmap->menu_count * sizeof(*map->menu_info);
map->menu_info = kmalloc(size, GFP_KERNEL);
if (map->menu_info == NULL) {
diff --git a/drivers/media/video/videobuf-msm-mem.c b/drivers/media/video/videobuf-msm-mem.c
index 9e2cc22..eeda13a 100644
--- a/drivers/media/video/videobuf-msm-mem.c
+++ b/drivers/media/video/videobuf-msm-mem.c
@@ -24,7 +24,7 @@
#include <linux/pagemap.h>
#include <linux/sched.h>
#include <linux/io.h>
-#include <linux/android_pmem.h>
+
#include <linux/memory_alloc.h>
#include <media/videobuf-msm-mem.h>
#include <media/msm_camera.h>
@@ -140,55 +140,6 @@
.close = videobuf_vm_close,
};
-/**
- * videobuf_pmem_contig_user_put() - reset pointer to user space buffer
- * @mem: per-buffer private videobuf-contig-pmem data
- *
- * This function resets the user space pointer
- */
-static void videobuf_pmem_contig_user_put(struct videobuf_contig_pmem *mem)
-{
- if (mem->phyaddr) {
- put_pmem_file(mem->file);
- mem->is_userptr = 0;
- mem->phyaddr = 0;
- mem->size = 0;
- }
-}
-
-/**
- * videobuf_pmem_contig_user_get() - setup user space memory pointer
- * @mem: per-buffer private videobuf-contig-pmem data
- * @vb: video buffer to map
- *
- * This function validates and sets up a pointer to user space memory.
- * Only physically contiguous pfn-mapped memory is accepted.
- *
- * Returns 0 if successful.
- */
-static int videobuf_pmem_contig_user_get(struct videobuf_contig_pmem *mem,
- struct videobuf_buffer *vb)
-{
- unsigned long kvstart;
- unsigned long len;
- int rc;
-
- mem->size = PAGE_ALIGN(vb->size);
- rc = get_pmem_file(vb->baddr, (unsigned long *)&mem->phyaddr,
- &kvstart, &len, &mem->file);
- if (rc < 0) {
- pr_err("%s: get_pmem_file fd %lu error %d\n",
- __func__, vb->baddr,
- rc);
- return rc;
- }
- mem->phyaddr += vb->boff;
- mem->y_off = 0;
- mem->cbcr_off = (vb->size)*2/3;
- mem->is_userptr = 1;
- return rc;
-}
-
static struct videobuf_buffer *__videobuf_alloc(size_t size)
{
struct videobuf_contig_pmem *mem;
@@ -229,12 +180,6 @@
/* All handling should be done by __videobuf_mmap_mapper() */
break;
- case V4L2_MEMORY_USERPTR:
- D("%s memory method USERPTR\n", __func__);
-
- /* handle pointer from user space */
- rc = videobuf_pmem_contig_user_get(mem, vb);
- break;
case V4L2_MEMORY_OVERLAY:
default:
pr_err("%s memory method OVERLAY/unknown\n", __func__);
@@ -383,7 +328,6 @@
/* handle user space pointer case */
if (buf->baddr) {
- videobuf_pmem_contig_user_put(mem);
return 0;
} else {
/* don't support read() method */
diff --git a/drivers/media/video/videobuf2-msm-mem.c b/drivers/media/video/videobuf2-msm-mem.c
index cd07db8..8dbb522 100644
--- a/drivers/media/video/videobuf2-msm-mem.c
+++ b/drivers/media/video/videobuf2-msm-mem.c
@@ -24,7 +24,7 @@
#include <linux/pagemap.h>
#include <linux/sched.h>
#include <linux/io.h>
-#include <linux/android_pmem.h>
+
#include <linux/memory_alloc.h>
#include <media/videobuf2-msm-mem.h>
#include <media/msm_camera.h>
@@ -177,15 +177,14 @@
struct ion_client *client,
int domain_num)
{
- unsigned long len;
int rc = 0;
-#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
- unsigned long kvstart;
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+ unsigned long len;
#endif
unsigned long paddr = 0;
if (mem->phyaddr != 0)
return 0;
-#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+#if defined(CONFIG_MSM_MULTIMEDIA_USE_ION)
mem->ion_handle = ion_import_dma_buf(client, (int)mem->vaddr);
if (IS_ERR_OR_NULL(mem->ion_handle)) {
pr_err("%s ION import failed\n", __func__);
@@ -195,17 +194,8 @@
SZ_4K, 0, (unsigned long *)&mem->phyaddr, &len, 0, 0);
if (rc < 0)
ion_free(client, mem->ion_handle);
-#elif CONFIG_ANDROID_PMEM
- rc = get_pmem_file((int)mem->vaddr, (unsigned long *)&mem->phyaddr,
- &kvstart, &len, &mem->file);
- if (rc < 0) {
- pr_err("%s: get_pmem_file fd %d error %d\n",
- __func__, (int)mem->vaddr, rc);
- return rc;
- }
#else
paddr = 0;
- kvstart = 0;
#endif
if (offset)
mem->offset = *offset;
@@ -224,12 +214,10 @@
struct ion_client *client, int domain_num)
{
if (mem->is_userptr) {
-#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+#if defined(CONFIG_MSM_MULTIMEDIA_USE_ION)
ion_unmap_iommu(client, mem->ion_handle,
domain_num, 0);
ion_free(client, mem->ion_handle);
-#elif CONFIG_ANDROID_PMEM
- put_pmem_file(mem->file);
#endif
}
mem->is_userptr = 0;
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index ce65e3f..c99bed1 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -58,11 +58,8 @@
obj-$(CONFIG_TIMPANI_CODEC) += timpani-codec.o
-ifdef CONFIG_TIMPANI_CODEC
obj-$(CONFIG_TIMPANI_CODEC) += msm-adie-codec.o
-else ifdef CONFIG_MARIMBA_CODEC
obj-$(CONFIG_MARIMBA_CODEC) += msm-adie-codec.o
-endif
obj-$(CONFIG_TWL6030_PWM) += twl6030-pwm.o
obj-$(CONFIG_TWL6040_CORE) += twl6040-core.o twl6040-irq.o
@@ -127,6 +124,10 @@
obj-$(CONFIG_MFD_WL1273_CORE) += wl1273-core.o
obj-$(CONFIG_MFD_CS5535) += cs5535-mfd.o
obj-$(CONFIG_MFD_OMAP_USB_HOST) += omap-usb-host.o
+obj-$(CONFIG_MFD_PM8921_CORE) += pm8921-core.o
+obj-$(CONFIG_MFD_PM8821_CORE) += pm8821-core.o
+obj-$(CONFIG_MFD_PM8018_CORE) += pm8018-core.o
+obj-$(CONFIG_MFD_PM8XXX_IRQ) += pm8xxx-irq.o
obj-$(CONFIG_TPS65911_COMPARATOR) += tps65911-comparator.o
obj-$(CONFIG_MFD_TPS65090) += tps65090.o
obj-$(CONFIG_MFD_AAT2870_CORE) += aat2870-core.o
@@ -135,11 +136,7 @@
obj-$(CONFIG_MFD_S5M_CORE) += s5m-core.o s5m-irq.o
obj-$(CONFIG_PMIC8058) += pmic8058.o
obj-$(CONFIG_PMIC8901) += pmic8901.o
-obj-$(CONFIG_MFD_PM8921_CORE) += pm8921-core.o
-obj-$(CONFIG_MFD_PM8821_CORE) += pm8821-core.o
-obj-$(CONFIG_MFD_PM8018_CORE) += pm8018-core.o
obj-$(CONFIG_MFD_PM8038_CORE) += pm8038-core.o
-obj-$(CONFIG_MFD_PM8XXX_IRQ) += pm8xxx-irq.o
obj-$(CONFIG_MFD_PM8821_IRQ) += pm8821-irq.o
obj-$(CONFIG_MFD_PM8XXX_DEBUG) += pm8xxx-debug.o
obj-$(CONFIG_MFD_PM8XXX_PWM) += pm8xxx-pwm.o
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index cfa5487..e8096d1 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -523,7 +523,7 @@
TI wl127x chips.
config TSIF
- depends on ARCH_MSM
+ depends on ARCH_MSM8X60 || ARCH_MSM8960 || ARCH_APQ8064
tristate "TSIF (Transport Stream InterFace) support"
default n
---help---
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index b0222ec..f80f3f2 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -54,8 +54,6 @@
obj-$(CONFIG_MAX8997_MUIC) += max8997-muic.o
obj-$(CONFIG_WL127X_RFKILL) += wl127x-rfkill.o
obj-$(CONFIG_SENSORS_AK8975) += akm8975.o
-obj-$(CONFIG_WL127X_RFKILL) += wl127x-rfkill.o
-obj-$(CONFIG_SENSORS_AK8975) += akm8975.o
obj-$(CONFIG_TSIF) += msm_tsif.o
msm_tsif-objs := tsif.o
obj-$(CONFIG_TSIF_CHRDEV) += tsif_chrdev.o
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 834e0e2..b075435 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -34,6 +34,7 @@
#include <linux/delay.h>
#include <linux/capability.h>
#include <linux/compat.h>
+#include <linux/pm_runtime.h>
#include <linux/mmc/ioctl.h>
#include <linux/mmc/card.h>
@@ -2497,6 +2498,7 @@
#endif
if (req && !mq->mqrq_prev->req) {
+ mmc_rpm_hold(host, &card->dev);
/* claim host only for the first request */
mmc_claim_host(card->host);
if (card->ext_csd.bkops_en)
@@ -2558,6 +2560,7 @@
mmc_start_bkops(card, false);
/* release host only when there are no more requests */
mmc_release_host(card->host);
+ mmc_rpm_release(host, &card->dev);
}
return ret;
}
diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c
index 58efd5e..96e3dc0 100644
--- a/drivers/mmc/card/mmc_test.c
+++ b/drivers/mmc/card/mmc_test.c
@@ -2695,6 +2695,7 @@
pr_info("%s: Starting tests of card %s...\n",
mmc_hostname(test->card->host), mmc_card_id(test->card));
+ mmc_rpm_hold(test->card->host, &test->card->dev);
mmc_claim_host(test->card->host);
for (i = 0;i < ARRAY_SIZE(mmc_test_cases);i++) {
@@ -2778,6 +2779,7 @@
}
mmc_release_host(test->card->host);
+ mmc_rpm_release(test->card->host, &test->card->dev);
pr_info("%s: Tests completed.\n",
mmc_hostname(test->card->host));
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index f46b5d0..7b9e133 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -26,6 +26,7 @@
#include "bus.h"
#define to_mmc_driver(d) container_of(d, struct mmc_driver, drv)
+#define RUNTIME_SUSPEND_DELAY_MS 10000
static ssize_t mmc_type_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -152,19 +153,38 @@
{
struct mmc_card *card = mmc_dev_to_card(dev);
- return mmc_power_save_host(card->host);
+ if (mmc_use_core_runtime_pm(card->host))
+ return 0;
+ else
+ return mmc_power_save_host(card->host);
}
static int mmc_runtime_resume(struct device *dev)
{
struct mmc_card *card = mmc_dev_to_card(dev);
- return mmc_power_restore_host(card->host);
+ if (mmc_use_core_runtime_pm(card->host))
+ return 0;
+ else
+ return mmc_power_restore_host(card->host);
}
static int mmc_runtime_idle(struct device *dev)
{
- return pm_runtime_suspend(dev);
+ struct mmc_card *card = mmc_dev_to_card(dev);
+ struct mmc_host *host = card->host;
+ int ret = 0;
+
+ if (mmc_use_core_runtime_pm(card->host)) {
+ ret = pm_schedule_suspend(dev, card->idle_timeout);
+ if (ret) {
+ pr_err("%s: %s: pm_schedule_suspend failed: err: %d\n",
+ mmc_hostname(host), __func__, ret);
+ return ret;
+ }
+ }
+
+ return ret;
}
#endif /* !CONFIG_PM_RUNTIME */
@@ -175,6 +195,42 @@
SET_SYSTEM_SLEEP_PM_OPS(mmc_bus_suspend, mmc_bus_resume)
};
+static ssize_t show_rpm_delay(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct mmc_card *card = mmc_dev_to_card(dev);
+
+ if (!card) {
+ pr_err("%s: %s: card is NULL\n", dev_name(dev), __func__);
+ return -EINVAL;
+ }
+
+ return snprintf(buf, PAGE_SIZE, "%u\n", card->idle_timeout);
+}
+
+static ssize_t store_rpm_delay(struct device *dev, struct device_attribute
+ *attr, const char *buf, size_t count)
+{
+ struct mmc_card *card = mmc_dev_to_card(dev);
+ unsigned int delay;
+
+ if (!card) {
+ pr_err("%s: %s: card is NULL\n", dev_name(dev), __func__);
+ return -EINVAL;
+ }
+
+ if (!kstrtou32(buf, 0, &delay)) {
+ if (delay < 2000) {
+ pr_err("%s: %s: less than 2 sec delay is unsupported\n",
+ mmc_hostname(card->host), __func__);
+ return -EINVAL;
+ }
+ card->idle_timeout = delay;
+ }
+
+ return count;
+}
+
static struct bus_type mmc_bus_type = {
.name = "mmc",
.dev_attrs = mmc_dev_attrs,
@@ -327,10 +383,34 @@
#endif
mmc_init_context_info(card->host);
+ if (mmc_use_core_runtime_pm(card->host)) {
+ ret = pm_runtime_set_active(&card->dev);
+ if (ret)
+ pr_err("%s: %s: failed setting runtime active: ret: %d\n",
+ mmc_hostname(card->host), __func__, ret);
+ else
+ pm_runtime_enable(&card->dev);
+ }
+
ret = device_add(&card->dev);
if (ret)
return ret;
+ if (mmc_use_core_runtime_pm(card->host)) {
+ card->rpm_attrib.show = show_rpm_delay;
+ card->rpm_attrib.store = store_rpm_delay;
+ sysfs_attr_init(&card->rpm_attrib.attr);
+ card->rpm_attrib.attr.name = "runtime_pm_timeout";
+ card->rpm_attrib.attr.mode = S_IRUGO | S_IWUSR;
+
+ ret = device_create_file(&card->dev, &card->rpm_attrib);
+ if (ret)
+ pr_err("%s: %s: creating runtime pm sysfs entry: failed: %d\n",
+ mmc_hostname(card->host), __func__, ret);
+ /* Default timeout is 10 seconds */
+ card->idle_timeout = RUNTIME_SUSPEND_DELAY_MS;
+ }
+
mmc_card_set_present(card);
return 0;
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 993aa37..bea8428 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -409,9 +409,12 @@
return;
}
+ mmc_rpm_hold(card->host, &card->dev);
/* In case of delayed bkops we might be in race with suspend. */
- if (!mmc_try_claim_host(card->host))
+ if (!mmc_try_claim_host(card->host)) {
+ mmc_rpm_release(card->host, &card->dev);
return;
+ }
/*
* Since the cancel_delayed_work can be changed while we are waiting
@@ -486,6 +489,7 @@
out:
mmc_release_host(card->host);
+ mmc_rpm_release(card->host, &card->dev);
}
EXPORT_SYMBOL(mmc_start_bkops);
@@ -515,6 +519,7 @@
* the host from getting into suspend
*/
do {
+ mmc_rpm_hold(card->host, &card->dev);
mmc_claim_host(card->host);
if (!mmc_card_doing_bkops(card))
@@ -541,6 +546,7 @@
}
mmc_release_host(card->host);
+ mmc_rpm_release(card->host, &card->dev);
/*
* Sleep before checking the card status again to allow the
@@ -559,6 +565,7 @@
return;
out:
mmc_release_host(card->host);
+ mmc_rpm_release(card->host, &card->dev);
}
/**
@@ -1016,7 +1023,7 @@
if (host->areq)
mmc_post_req(host, host->areq->mrq, 0);
- /* Cancel a prepared request if it was not started. */
+ /* Cancel a prepared request if it was not started. */
if ((err || start_err) && areq)
mmc_post_req(host, areq->mrq, -EINVAL);
@@ -2786,8 +2793,9 @@
if (!host->card || !host->bus_ops ||
!host->bus_ops->change_bus_speed ||
!host->clk_scaling.enable || !host->ios.clock)
- goto out;
+ return;
+ mmc_rpm_hold(host, &host->card->dev);
if (!mmc_try_claim_host(host)) {
/* retry after a timer tick */
queue_delayed_work(system_nrt_wq, &host->clk_scaling.work, 1);
@@ -2797,6 +2805,7 @@
mmc_clk_scaling(host, true);
mmc_release_host(host);
out:
+ mmc_rpm_release(host, &host->card->dev);
return;
}
@@ -3139,11 +3148,12 @@
if (host->ops->get_cd && host->ops->get_cd(host) == 0)
goto out;
+ mmc_rpm_hold(host, &host->class_dev);
mmc_claim_host(host);
if (!mmc_rescan_try_freq(host, host->f_min))
extend_wakelock = true;
mmc_release_host(host);
-
+ mmc_rpm_release(host, &host->class_dev);
out:
if (extend_wakelock)
wake_lock_timeout(&host->detect_wake_lock, HZ / 2);
@@ -3366,9 +3376,6 @@
if (mmc_bus_needs_resume(host))
return 0;
- cancel_delayed_work(&host->detect);
- mmc_flush_scheduled_work();
-
mmc_bus_get(host);
if (host->bus_ops && !host->bus_dead) {
/*
@@ -3579,6 +3586,37 @@
EXPORT_SYMBOL(mmc_set_embedded_sdio_data);
#endif
+void mmc_rpm_hold(struct mmc_host *host, struct device *dev)
+{
+ int ret = 0;
+
+ if (!mmc_use_core_runtime_pm(host))
+ return;
+
+ ret = pm_runtime_get_sync(dev);
+ if (ret < 0) {
+ pr_err("%s: %s: %s: error resuming device: %d\n",
+ dev_name(dev), mmc_hostname(host), __func__, ret);
+ if (pm_runtime_suspended(dev))
+ BUG_ON(1);
+ }
+}
+EXPORT_SYMBOL(mmc_rpm_hold);
+
+void mmc_rpm_release(struct mmc_host *host, struct device *dev)
+{
+ int ret = 0;
+
+ if (!mmc_use_core_runtime_pm(host))
+ return;
+
+ ret = pm_runtime_put_sync(dev);
+ if (ret < 0 && ret != -EBUSY)
+ pr_err("%s: %s: %s: put sync ret: %d\n",
+ dev_name(dev), mmc_hostname(host), __func__, ret);
+}
+EXPORT_SYMBOL(mmc_rpm_release);
+
/**
* mmc_init_context_info() - init synchronization context
* @host: mmc host
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index 9dda847..c0a4cef 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -4,7 +4,7 @@
* Copyright (C) 2003 Russell King, All Rights Reserved.
* Copyright (C) 2007-2008 Pierre Ossman
* Copyright (C) 2010 Linus Walleij
- * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2013, 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 as
@@ -21,6 +21,7 @@
#include <linux/leds.h>
#include <linux/slab.h>
#include <linux/suspend.h>
+#include <linux/pm_runtime.h>
#include <linux/mmc/host.h>
#include <linux/mmc/card.h>
@@ -37,9 +38,85 @@
kfree(host);
}
+static int mmc_host_runtime_suspend(struct device *dev)
+{
+ struct mmc_host *host = cls_dev_to_mmc_host(dev);
+ int ret = 0;
+
+ if (!mmc_use_core_runtime_pm(host))
+ return 0;
+
+ ret = mmc_suspend_host(host);
+ if (ret < 0)
+ pr_err("%s: %s: suspend host failed: %d\n", mmc_hostname(host),
+ __func__, ret);
+
+ return ret;
+}
+
+static int mmc_host_runtime_resume(struct device *dev)
+{
+ struct mmc_host *host = cls_dev_to_mmc_host(dev);
+ int ret = 0;
+
+ if (!mmc_use_core_runtime_pm(host))
+ return 0;
+
+ ret = mmc_resume_host(host);
+ if (ret < 0) {
+ pr_err("%s: %s: resume host: failed: ret: %d\n",
+ mmc_hostname(host), __func__, ret);
+ if (pm_runtime_suspended(dev))
+ BUG_ON(1);
+ }
+
+ return ret;
+}
+
+static int mmc_host_suspend(struct device *dev)
+{
+ struct mmc_host *host = cls_dev_to_mmc_host(dev);
+ int ret = 0;
+
+ if (!mmc_use_core_runtime_pm(host))
+ return 0;
+
+ if (!pm_runtime_suspended(dev)) {
+ ret = mmc_suspend_host(host);
+ if (ret < 0)
+ pr_err("%s: %s: failed: ret: %d\n", mmc_hostname(host),
+ __func__, ret);
+ }
+ return ret;
+}
+
+static int mmc_host_resume(struct device *dev)
+{
+ struct mmc_host *host = cls_dev_to_mmc_host(dev);
+ int ret = 0;
+
+ if (!mmc_use_core_runtime_pm(host))
+ return 0;
+
+ if (!pm_runtime_suspended(dev)) {
+ ret = mmc_resume_host(host);
+ if (ret < 0)
+ pr_err("%s: %s: failed: ret: %d\n", mmc_hostname(host),
+ __func__, ret);
+ }
+ return ret;
+}
+
+static const struct dev_pm_ops mmc_host_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(mmc_host_suspend, mmc_host_resume)
+ SET_RUNTIME_PM_OPS(mmc_host_runtime_suspend, mmc_host_runtime_resume,
+ pm_generic_runtime_idle)
+};
+
static struct class mmc_host_class = {
.name = "mmc_host",
.dev_release = mmc_host_classdev_release,
+ .pm = &mmc_host_pm_ops,
};
int mmc_register_host_class(void)
@@ -529,7 +606,7 @@
static ssize_t
show_perf(struct device *dev, struct device_attribute *attr, char *buf)
{
- struct mmc_host *host = dev_get_drvdata(dev);
+ struct mmc_host *host = cls_dev_to_mmc_host(dev);
int64_t rtime_drv, wtime_drv;
unsigned long rbytes_drv, wbytes_drv;
@@ -555,8 +632,8 @@
set_perf(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
+ struct mmc_host *host = cls_dev_to_mmc_host(dev);
int64_t value;
- struct mmc_host *host = dev_get_drvdata(dev);
sscanf(buf, "%lld", &value);
spin_lock(&host->lock);
@@ -601,6 +678,14 @@
WARN_ON((host->caps & MMC_CAP_SDIO_IRQ) &&
!host->ops->enable_sdio_irq);
+ if (mmc_use_core_runtime_pm(host)) {
+ err = pm_runtime_set_active(&host->class_dev);
+ if (err)
+ pr_err("%s: %s: failed setting runtime active: err: %d\n",
+ mmc_hostname(host), __func__, err);
+ else
+ pm_runtime_enable(&host->class_dev);
+ }
err = device_add(&host->class_dev);
if (err)
return err;
@@ -621,7 +706,7 @@
pr_err("%s: failed to create clk scale sysfs group with err %d\n",
__func__, err);
- err = sysfs_create_group(&host->parent->kobj, &dev_attr_grp);
+ err = sysfs_create_group(&host->class_dev.kobj, &dev_attr_grp);
if (err)
pr_err("%s: failed to create sysfs group with err %d\n",
__func__, err);
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 219d38b..8a866cf 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -17,6 +17,7 @@
#include <linux/mmc/host.h>
#include <linux/mmc/card.h>
#include <linux/mmc/mmc.h>
+#include <linux/pm_runtime.h>
#include "core.h"
#include "bus.h"
@@ -1495,6 +1496,7 @@
BUG_ON(!host);
BUG_ON(!host->card);
+ mmc_rpm_hold(host, &host->card->dev);
mmc_claim_host(host);
/*
@@ -1504,6 +1506,13 @@
mmc_release_host(host);
+ /*
+ * if detect fails, the device would be removed anyway;
+ * the rpm framework would mark the device state suspended.
+ */
+ if (!err)
+ mmc_rpm_release(host, &host->card->dev);
+
if (err) {
mmc_remove(host);
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index fd083df..dc129f7 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -18,6 +18,7 @@
#include <linux/mmc/card.h>
#include <linux/mmc/mmc.h>
#include <linux/mmc/sd.h>
+#include <linux/pm_runtime.h>
#include "core.h"
#include "bus.h"
@@ -1145,7 +1146,8 @@
BUG_ON(!host);
BUG_ON(!host->card);
-
+
+ mmc_rpm_hold(host, &host->card->dev);
mmc_claim_host(host);
/*
@@ -1170,6 +1172,13 @@
#endif
mmc_release_host(host);
+ /*
+ * if detect fails, the device would be removed anyway;
+ * the rpm framework would mark the device state suspended.
+ */
+ if (!err)
+ mmc_rpm_release(host, &host->card->dev);
+
if (err) {
mmc_sd_remove(host);
diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c
index fca3274..3d8ceb4 100644
--- a/drivers/mmc/core/sdio_irq.c
+++ b/drivers/mmc/core/sdio_irq.c
@@ -215,14 +215,14 @@
card->sdio_single_irq = NULL;
if ((card->host->caps & MMC_CAP_SDIO_IRQ) &&
- card->host->sdio_irqs == 1)
+ card->host->sdio_irqs == 1)
for (i = 0; i < card->sdio_funcs; i++) {
- func = card->sdio_func[i];
- if (func && func->irq_handler) {
- card->sdio_single_irq = func;
- break;
- }
- }
+ func = card->sdio_func[i];
+ if (func && func->irq_handler) {
+ card->sdio_single_irq = func;
+ break;
+ }
+ }
}
/**
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 27e6c79..7bae401 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -32,6 +32,9 @@
#include <linux/scatterlist.h>
#include <linux/slab.h>
#include <linux/mmc/mmc.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/mmc/cd-gpio.h>
#include <mach/gpio.h>
#include <mach/msm_bus.h>
@@ -200,6 +203,7 @@
bool nonremovable;
struct sdhci_msm_pin_data *pin_data;
u32 cpu_dma_latency_us;
+ int status_gpio; /* card detection GPIO that is configured as IRQ */
struct sdhci_msm_bus_voting_data *voting_data;
};
@@ -216,6 +220,7 @@
struct sdhci_msm_host {
struct platform_device *pdev;
void __iomem *core_mem; /* MSM SDCC mapped address */
+ int pwr_irq; /* power irq */
struct clk *clk; /* main SD/MMC bus clock */
struct clk *pclk; /* SDHC peripheral bus clock */
struct clk *bus_clk; /* SDHC bus voter clock */
@@ -1075,6 +1080,8 @@
goto out;
}
+ pdata->status_gpio = of_get_named_gpio_flags(np, "cd-gpios", 0, 0);
+
of_property_read_u32(np, "qcom,bus-width", &bus_width);
if (bus_width == 8)
pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
@@ -1864,7 +1871,7 @@
struct sdhci_pltfm_host *pltfm_host;
struct sdhci_msm_host *msm_host;
struct resource *core_memres = NULL;
- int ret = 0, pwr_irq = 0, dead = 0;
+ int ret = 0, dead = 0;
u32 vdd_max_current;
u32 host_version;
@@ -1987,18 +1994,18 @@
}
/* Setup PWRCTL irq */
- pwr_irq = platform_get_irq_byname(pdev, "pwr_irq");
- if (pwr_irq < 0) {
+ msm_host->pwr_irq = platform_get_irq_byname(pdev, "pwr_irq");
+ if (msm_host->pwr_irq < 0) {
dev_err(&pdev->dev, "Failed to get pwr_irq by name (%d)\n",
- pwr_irq);
+ msm_host->pwr_irq);
goto vreg_deinit;
}
- ret = devm_request_threaded_irq(&pdev->dev, pwr_irq, NULL,
+ ret = devm_request_threaded_irq(&pdev->dev, msm_host->pwr_irq, NULL,
sdhci_msm_pwr_irq, IRQF_ONESHOT,
dev_name(&pdev->dev), host);
if (ret) {
dev_err(&pdev->dev, "Request threaded irq(%d) failed (%d)\n",
- pwr_irq, ret);
+ msm_host->pwr_irq, ret);
goto vreg_deinit;
}
@@ -2029,6 +2036,7 @@
msm_host->mmc->caps |= MMC_CAP_HW_RESET;
msm_host->mmc->caps2 |= msm_host->pdata->caps2;
+ msm_host->mmc->caps2 |= MMC_CAP2_CORE_RUNTIME_PM;
msm_host->mmc->caps2 |= MMC_CAP2_PACKED_WR;
msm_host->mmc->caps2 |= MMC_CAP2_PACKED_WR_CONTROL;
msm_host->mmc->caps2 |= (MMC_CAP2_BOOTPART_NOACC |
@@ -2051,10 +2059,20 @@
INIT_DELAYED_WORK(&msm_host->msm_bus_vote.vote_work,
sdhci_msm_bus_work);
+ if (gpio_is_valid(msm_host->pdata->status_gpio)) {
+ ret = mmc_cd_gpio_request(msm_host->mmc,
+ msm_host->pdata->status_gpio);
+ if (ret) {
+ dev_err(&pdev->dev, "%s: Failed to request card detection IRQ %d\n",
+ __func__, ret);
+ goto bus_unregister;
+ }
+ }
+
ret = sdhci_add_host(host);
if (ret) {
dev_err(&pdev->dev, "Add host failed (%d)\n", ret);
- goto bus_unregister;
+ goto free_cd_gpio;
}
/* Set core clk rate, optionally override from dts */
@@ -2076,12 +2094,22 @@
if (ret)
goto remove_host;
+ ret = pm_runtime_set_active(&pdev->dev);
+ if (ret)
+ pr_err("%s: %s: pm_runtime_set_active failed: err: %d\n",
+ mmc_hostname(host->mmc), __func__, ret);
+ else
+ pm_runtime_enable(&pdev->dev);
+
/* Successful initialization */
goto out;
remove_host:
dead = (readl_relaxed(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);
sdhci_remove_host(host, dead);
+free_cd_gpio:
+ if (gpio_is_valid(msm_host->pdata->status_gpio))
+ mmc_cd_gpio_free(msm_host->mmc);
bus_unregister:
sdhci_msm_bus_unregister(msm_host);
vreg_deinit:
@@ -2114,7 +2142,12 @@
pr_debug("%s: %s\n", dev_name(&pdev->dev), __func__);
device_remove_file(&pdev->dev, &msm_host->msm_bus_vote.max_bus_bw);
sdhci_remove_host(host, dead);
+ pm_runtime_disable(&pdev->dev);
sdhci_pltfm_free(pdev);
+
+ if (gpio_is_valid(msm_host->pdata->status_gpio))
+ mmc_cd_gpio_free(msm_host->mmc);
+
sdhci_msm_vreg_init(&pdev->dev, msm_host->pdata, false);
if (pdata->pin_data)
@@ -2127,6 +2160,92 @@
return 0;
}
+static int sdhci_msm_runtime_suspend(struct device *dev)
+{
+ struct sdhci_host *host = dev_get_drvdata(dev);
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_msm_host *msm_host = pltfm_host->priv;
+
+ disable_irq(host->irq);
+ disable_irq(msm_host->pwr_irq);
+
+ return 0;
+}
+
+static int sdhci_msm_runtime_resume(struct device *dev)
+{
+ struct sdhci_host *host = dev_get_drvdata(dev);
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_msm_host *msm_host = pltfm_host->priv;
+
+ enable_irq(msm_host->pwr_irq);
+ enable_irq(host->irq);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+
+static int sdhci_msm_suspend(struct device *dev)
+{
+ struct sdhci_host *host = dev_get_drvdata(dev);
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_msm_host *msm_host = pltfm_host->priv;
+ int ret = 0;
+
+ if (gpio_is_valid(msm_host->pdata->status_gpio))
+ mmc_cd_gpio_free(msm_host->mmc);
+
+ if (pm_runtime_suspended(dev)) {
+ pr_debug("%s: %s: already runtime suspended\n",
+ mmc_hostname(host->mmc), __func__);
+ goto out;
+ }
+
+ return sdhci_msm_runtime_suspend(dev);
+out:
+ return ret;
+}
+
+static int sdhci_msm_resume(struct device *dev)
+{
+ struct sdhci_host *host = dev_get_drvdata(dev);
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_msm_host *msm_host = pltfm_host->priv;
+ int ret = 0;
+
+ if (gpio_is_valid(msm_host->pdata->status_gpio)) {
+ ret = mmc_cd_gpio_request(msm_host->mmc,
+ msm_host->pdata->status_gpio);
+ if (ret)
+ pr_err("%s: %s: Failed to request card detection IRQ %d\n",
+ mmc_hostname(host->mmc), __func__, ret);
+ }
+
+ if (pm_runtime_suspended(dev)) {
+ pr_debug("%s: %s: runtime suspended, defer system resume\n",
+ mmc_hostname(host->mmc), __func__);
+ goto out;
+ }
+
+ return sdhci_msm_runtime_resume(dev);
+out:
+ return ret;
+}
+#endif
+
+#ifdef CONFIG_PM
+static const struct dev_pm_ops sdhci_msm_pmops = {
+ SET_SYSTEM_SLEEP_PM_OPS(sdhci_msm_suspend, sdhci_msm_resume)
+ SET_RUNTIME_PM_OPS(sdhci_msm_runtime_suspend, sdhci_msm_runtime_resume,
+ NULL)
+};
+
+#define SDHCI_MSM_PMOPS (&sdhci_msm_pmops)
+
+#else
+#define SDHCI_PM_OPS NULL
+#endif
static const struct of_device_id sdhci_msm_dt_match[] = {
{.compatible = "qcom,sdhci-msm"},
};
@@ -2139,6 +2258,7 @@
.name = "sdhci_msm",
.owner = THIS_MODULE,
.of_match_table = sdhci_msm_dt_match,
+ .pm = SDHCI_MSM_PMOPS,
},
};
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 97c1013..0a89ea2 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -453,6 +453,44 @@
dataddr[0] = cpu_to_le32(addr);
}
+static int sdhci_pre_dma_transfer(struct sdhci_host *host,
+ struct mmc_data *data,
+ struct sdhci_next *next)
+{
+ int sg_count;
+
+ if (!next && data->host_cookie &&
+ data->host_cookie != host->next_data.cookie) {
+ printk(KERN_WARNING "[%s] invalid cookie: data->host_cookie %d"
+ " host->next_data.cookie %d\n",
+ __func__, data->host_cookie, host->next_data.cookie);
+ data->host_cookie = 0;
+ }
+
+ /* Check if next job is already prepared */
+ if (next ||
+ (!next && data->host_cookie != host->next_data.cookie)) {
+ sg_count = dma_map_sg(mmc_dev(host->mmc), data->sg,
+ data->sg_len,
+ (data->flags & MMC_DATA_WRITE) ?
+ DMA_TO_DEVICE : DMA_FROM_DEVICE);
+ } else {
+ sg_count = host->next_data.sg_count;
+ host->next_data.sg_count = 0;
+ }
+
+ if (sg_count == 0)
+ return -EINVAL;
+
+ if (next) {
+ next->sg_count = sg_count;
+ data->host_cookie = ++next->cookie < 0 ? 1 : next->cookie;
+ } else
+ host->sg_count = sg_count;
+
+ return sg_count;
+}
+
static int sdhci_adma_table_pre(struct sdhci_host *host,
struct mmc_data *data)
{
@@ -491,9 +529,8 @@
goto fail;
BUG_ON(host->align_addr & 0x3);
- host->sg_count = dma_map_sg(mmc_dev(host->mmc),
- data->sg, data->sg_len, direction);
- if (host->sg_count == 0)
+ host->sg_count = sdhci_pre_dma_transfer(host, data, NULL);
+ if (host->sg_count < 0)
goto unmap_align;
desc = host->adma_desc;
@@ -638,8 +675,9 @@
}
}
- dma_unmap_sg(mmc_dev(host->mmc), data->sg,
- data->sg_len, direction);
+ if (!data->host_cookie)
+ dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
+ direction);
}
static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
@@ -819,11 +857,7 @@
} else {
int sg_cnt;
- sg_cnt = dma_map_sg(mmc_dev(host->mmc),
- data->sg, data->sg_len,
- (data->flags & MMC_DATA_READ) ?
- DMA_FROM_DEVICE :
- DMA_TO_DEVICE);
+ sg_cnt = sdhci_pre_dma_transfer(host, data, NULL);
if (sg_cnt == 0) {
/*
* This only happens when someone fed
@@ -927,9 +961,11 @@
if (host->flags & SDHCI_USE_ADMA)
sdhci_adma_table_post(host, data);
else {
- dma_unmap_sg(mmc_dev(host->mmc), data->sg,
- data->sg_len, (data->flags & MMC_DATA_READ) ?
- DMA_FROM_DEVICE : DMA_TO_DEVICE);
+ if (!data->host_cookie)
+ dma_unmap_sg(mmc_dev(host->mmc), data->sg,
+ data->sg_len,
+ (data->flags & MMC_DATA_READ) ?
+ DMA_FROM_DEVICE : DMA_TO_DEVICE);
}
}
@@ -1304,6 +1340,35 @@
return 0;
}
+static void sdhci_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
+ bool is_first_req)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+
+ if (mrq->data->host_cookie) {
+ mrq->data->host_cookie = 0;
+ return;
+ }
+
+ if (host->flags & SDHCI_REQ_USE_DMA)
+ if (sdhci_pre_dma_transfer(host, mrq->data, &host->next_data) < 0)
+ mrq->data->host_cookie = 0;
+}
+
+static void sdhci_post_req(struct mmc_host *mmc, struct mmc_request *mrq,
+ int err)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+ struct mmc_data *data = mrq->data;
+
+ if (host->flags & SDHCI_REQ_USE_DMA) {
+ dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
+ (data->flags & MMC_DATA_WRITE) ?
+ DMA_TO_DEVICE : DMA_FROM_DEVICE);
+ data->host_cookie = 0;
+ }
+}
+
static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
{
struct sdhci_host *host;
@@ -2016,6 +2081,8 @@
}
static const struct mmc_host_ops sdhci_ops = {
+ .pre_req = sdhci_pre_req,
+ .post_req = sdhci_post_req,
.request = sdhci_request,
.set_ios = sdhci_set_ios,
.get_ro = sdhci_get_ro,
@@ -2598,13 +2665,20 @@
static int sdhci_runtime_pm_get(struct sdhci_host *host)
{
- return pm_runtime_get_sync(host->mmc->parent);
+ if (!mmc_use_core_runtime_pm(host->mmc))
+ return pm_runtime_get_sync(host->mmc->parent);
+ else
+ return 0;
}
static int sdhci_runtime_pm_put(struct sdhci_host *host)
{
- pm_runtime_mark_last_busy(host->mmc->parent);
- return pm_runtime_put_autosuspend(host->mmc->parent);
+ if (!mmc_use_core_runtime_pm(host->mmc)) {
+ pm_runtime_mark_last_busy(host->mmc->parent);
+ return pm_runtime_put_autosuspend(host->mmc->parent);
+ } else {
+ return 0;
+ }
}
int sdhci_runtime_suspend_host(struct sdhci_host *host)
@@ -2805,6 +2879,8 @@
}
}
+ host->next_data.cookie = 1;
+
/*
* If we use DMA, then it's up to the caller to set the DMA
* mask, but PIO does not need the hw shim so we set a new
diff --git a/drivers/mtd/devices/msm_qpic_nand.c b/drivers/mtd/devices/msm_qpic_nand.c
index f7e8c9f..c37a4a4 100644
--- a/drivers/mtd/devices/msm_qpic_nand.c
+++ b/drivers/mtd/devices/msm_qpic_nand.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2013, 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
@@ -2264,19 +2264,22 @@
*/
bam.manage = SPS_BAM_MGR_DEVICE_REMOTE | SPS_BAM_MGR_MULTI_EE;
+ rc = sps_phy2h(bam.phys_addr, &nand_info->sps.bam_handle);
+ if (!rc)
+ goto init_sps_ep;
rc = sps_register_bam_device(&bam, &nand_info->sps.bam_handle);
if (rc) {
- pr_err("sps_register_bam_device() failed with %d\n", rc);
+ pr_err("%s: sps_register_bam_device() failed with %d\n",
+ __func__, rc);
goto out;
}
- pr_info("BAM device registered: bam_handle 0x%x\n",
- nand_info->sps.bam_handle);
-
+ pr_info("%s: BAM device registered: bam_handle 0x%x\n",
+ __func__, nand_info->sps.bam_handle);
+init_sps_ep:
rc = msm_nand_init_endpoint(nand_info, &nand_info->sps.data_prod,
SPS_DATA_PROD_PIPE_INDEX);
if (rc)
- goto unregister_bam;
-
+ goto out;
rc = msm_nand_init_endpoint(nand_info, &nand_info->sps.data_cons,
SPS_DATA_CONS_PIPE_INDEX);
if (rc)
@@ -2291,22 +2294,20 @@
msm_nand_deinit_endpoint(nand_info, &nand_info->sps.data_cons);
deinit_data_prod:
msm_nand_deinit_endpoint(nand_info, &nand_info->sps.data_prod);
-unregister_bam:
- sps_deregister_bam_device(nand_info->sps.bam_handle);
out:
return rc;
}
/*
- * This function de-registers BAM device, disconnects and frees its end points
- * for all the pipes.
+ * This function disconnects and frees its end points for all the pipes.
+ * Since the BAM is shared resource, it is not deregistered as its handle
+ * might be in use with LCDC.
*/
static void msm_nand_bam_free(struct msm_nand_info *nand_info)
{
msm_nand_deinit_endpoint(nand_info, &nand_info->sps.data_prod);
msm_nand_deinit_endpoint(nand_info, &nand_info->sps.data_cons);
msm_nand_deinit_endpoint(nand_info, &nand_info->sps.cmd_pipe);
- sps_deregister_bam_device(nand_info->sps.bam_handle);
}
/* This function enables DMA support for the NANDc in BAM mode. */
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 315efbb..47b19c0 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -3219,44 +3219,6 @@
}
EXPORT_SYMBOL(nand_scan_ident);
-static void nand_panic_wait(struct mtd_info *mtd)
-{
- struct nand_chip *chip = mtd->priv;
- int i;
-
- if (chip->state != FL_READY)
- for (i = 0; i < 40; i++) {
- if (chip->dev_ready(mtd))
- break;
- mdelay(10);
- }
- chip->state = FL_READY;
-}
-
-static int nand_panic_write(struct mtd_info *mtd, loff_t to, size_t len,
- size_t *retlen, const u_char *buf)
-{
- struct nand_chip *chip = mtd->priv;
- int ret;
-
- /* Do not allow reads past end of device */
- if ((to + len) > mtd->size)
- return -EINVAL;
- if (!len)
- return 0;
-
- nand_panic_wait(mtd);
-
- chip->ops.len = len;
- chip->ops.datbuf = (uint8_t *)buf;
- chip->ops.oobbuf = NULL;
-
- ret = nand_do_write_ops(mtd, to, &chip->ops);
-
- *retlen = chip->ops.retlen;
- return ret;
-}
-
/**
* nand_scan_tail - [NAND Interface] Scan for the NAND device
diff --git a/drivers/net/ethernet/msm/ecm_ipa.c b/drivers/net/ethernet/msm/ecm_ipa.c
index 28ba41a..41dd6e7 100644
--- a/drivers/net/ethernet/msm/ecm_ipa.c
+++ b/drivers/net/ethernet/msm/ecm_ipa.c
@@ -118,8 +118,8 @@
static int ecm_ipa_rules_cfg(struct ecm_ipa_dev *dev,
const void *dst_mac, const void *src_mac);
-static int ecm_ipa_register_tx(struct ecm_ipa_dev *dev);
-static void ecm_ipa_deregister_tx(struct ecm_ipa_dev *dev);
+static int ecm_ipa_register_properties(void);
+static void ecm_ipa_deregister_properties(void);
static int ecm_ipa_debugfs_init(struct ecm_ipa_dev *dev);
static void ecm_ipa_debugfs_destroy(struct ecm_ipa_dev *dev);
static int ecm_ipa_debugfs_tx_open(struct inode *inode, struct file *file);
@@ -262,13 +262,13 @@
strlcpy(ipv4_hdr->name, ECM_IPA_IPV4_HDR_NAME, IPA_RESOURCE_NAME_MAX);
memcpy(eth_ipv4->h_dest, dst_mac, ETH_ALEN);
memcpy(eth_ipv4->h_source, src_mac, ETH_ALEN);
- eth_ipv4->h_proto = ETH_P_IP;
+ eth_ipv4->h_proto = htons(ETH_P_IP);
ipv4_hdr->hdr_len = ETH_HLEN;
ipv4_hdr->is_partial = 0;
strlcpy(ipv6_hdr->name, ECM_IPA_IPV6_HDR_NAME, IPA_RESOURCE_NAME_MAX);
memcpy(eth_ipv6->h_dest, dst_mac, ETH_ALEN);
memcpy(eth_ipv6->h_source, src_mac, ETH_ALEN);
- eth_ipv6->h_proto = ETH_P_IPV6;
+ eth_ipv6->h_proto = htons(ETH_P_IPV6);
ipv6_hdr->hdr_len = ETH_HLEN;
ipv6_hdr->is_partial = 0;
hdrs->commit = 1;
@@ -320,14 +320,29 @@
ECM_IPA_ERROR("ipa_del_hdr failed");
}
-static int ecm_ipa_register_tx(struct ecm_ipa_dev *dev)
+/* ecm_ipa_register_properties() - set Tx/Rx properties for ipacm
+ *
+ * Register ecm0 interface with 2 Tx properties and 2 Rx properties:
+ * The 2 Tx properties are for data flowing from IPA to USB, they
+ * have Header-Insertion properties both for Ipv4 and Ipv6 Ethernet framing.
+ * The 2 Rx properties are for data flowing from USB to IPA, they have
+ * simple rule which always "hit".
+ *
+ */
+static int ecm_ipa_register_properties(void)
{
struct ipa_tx_intf tx_properties = {0};
struct ipa_ioc_tx_intf_prop properties[2] = { {0}, {0} };
struct ipa_ioc_tx_intf_prop *ipv4_property;
struct ipa_ioc_tx_intf_prop *ipv6_property;
+ struct ipa_ioc_rx_intf_prop rx_ioc_properties[2] = { {0}, {0} };
+ struct ipa_rx_intf rx_properties = {0};
+ struct ipa_ioc_rx_intf_prop *rx_ipv4_property;
+ struct ipa_ioc_rx_intf_prop *rx_ipv6_property;
int result = 0;
+
ECM_IPA_LOG_ENTRY();
+
tx_properties.prop = properties;
ipv4_property = &tx_properties.prop[0];
ipv4_property->ip = IPA_IP_v4;
@@ -340,18 +355,32 @@
strlcpy(ipv6_property->hdr_name, ECM_IPA_IPV6_HDR_NAME,
IPA_RESOURCE_NAME_MAX);
tx_properties.num_props = 2;
- result = ipa_register_intf("ecm0", &tx_properties, NULL);
+
+ rx_properties.prop = rx_ioc_properties;
+ rx_ipv4_property = &rx_properties.prop[0];
+ rx_ipv4_property->ip = IPA_IP_v4;
+ rx_ipv4_property->attrib.attrib_mask = 0;
+ rx_ipv4_property->src_pipe = IPA_CLIENT_USB_PROD;
+ rx_ipv6_property = &rx_properties.prop[1];
+ rx_ipv6_property->ip = IPA_IP_v6;
+ rx_ipv6_property->attrib.attrib_mask = 0;
+ rx_ipv6_property->src_pipe = IPA_CLIENT_USB_PROD;
+ rx_properties.num_props = 2;
+
+ result = ipa_register_intf("ecm0", &tx_properties, &rx_properties);
if (result)
- ECM_IPA_ERROR("fail on Tx_prop registration\n");
+ ECM_IPA_ERROR("fail on Tx/Rx properties registration\n");
+
ECM_IPA_LOG_EXIT();
+
return result;
}
-static void ecm_ipa_deregister_tx(struct ecm_ipa_dev *dev)
+static void ecm_ipa_deregister_properties(void)
{
int result;
ECM_IPA_LOG_ENTRY();
- result = ipa_deregister_intf(dev->net->name);
+ result = ipa_deregister_intf("ecm0");
if (result)
ECM_IPA_DEBUG("Fail on Tx prop deregister\n");
ECM_IPA_LOG_EXIT();
@@ -407,12 +436,12 @@
goto fail_set_device_ethernet;
}
ECM_IPA_DEBUG("Ethernet header insertion was set\n");
- result = ecm_ipa_register_tx(dev);
+ result = ecm_ipa_register_properties();
if (result) {
ECM_IPA_ERROR("fail on properties set\n");
goto fail_register_tx;
}
- ECM_IPA_DEBUG("ECM Tx properties were registered\n");
+ ECM_IPA_DEBUG("ECM 2 Tx and 2 Rx properties were registered\n");
result = register_netdev(net);
if (result) {
ECM_IPA_ERROR("register_netdev failed: %d\n", result);
@@ -422,7 +451,7 @@
ECM_IPA_LOG_EXIT();
return 0;
fail_register_netdev:
- ecm_ipa_deregister_tx(dev);
+ ecm_ipa_deregister_properties();
fail_register_tx:
fail_set_device_ethernet:
ecm_ipa_rules_destroy(dev);
diff --git a/drivers/net/pppolac.c b/drivers/net/pppolac.c
deleted file mode 100644
index a5d3d63..0000000
--- a/drivers/net/pppolac.c
+++ /dev/null
@@ -1,449 +0,0 @@
-/* drivers/net/pppolac.c
- *
- * Driver for PPP on L2TP Access Concentrator / PPPoLAC Socket (RFC 2661)
- *
- * Copyright (C) 2009 Google, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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 driver handles L2TP data packets between a UDP socket and a PPP channel.
- * The socket must keep connected, and only one session per socket is permitted.
- * Sequencing of outgoing packets is controlled by LNS. Incoming packets with
- * sequences are reordered within a sliding window of one second. Currently
- * reordering only happens when a packet is received. It is done for simplicity
- * since no additional locks or threads are required. This driver only works on
- * IPv4 due to the lack of UDP encapsulation support in IPv6. */
-
-#include <linux/module.h>
-#include <linux/jiffies.h>
-#include <linux/workqueue.h>
-#include <linux/skbuff.h>
-#include <linux/file.h>
-#include <linux/netdevice.h>
-#include <linux/net.h>
-#include <linux/udp.h>
-#include <linux/ppp_defs.h>
-#include <linux/if_ppp.h>
-#include <linux/if_pppox.h>
-#include <linux/ppp_channel.h>
-#include <net/tcp_states.h>
-#include <asm/uaccess.h>
-
-#define L2TP_CONTROL_BIT 0x80
-#define L2TP_LENGTH_BIT 0x40
-#define L2TP_SEQUENCE_BIT 0x08
-#define L2TP_OFFSET_BIT 0x02
-#define L2TP_VERSION 0x02
-#define L2TP_VERSION_MASK 0x0F
-
-#define PPP_ADDR 0xFF
-#define PPP_CTRL 0x03
-
-union unaligned {
- __u32 u32;
-} __attribute__((packed));
-
-static inline union unaligned *unaligned(void *ptr)
-{
- return (union unaligned *)ptr;
-}
-
-struct meta {
- __u32 sequence;
- __u32 timestamp;
-};
-
-static inline struct meta *skb_meta(struct sk_buff *skb)
-{
- return (struct meta *)skb->cb;
-}
-
-/******************************************************************************/
-
-static int pppolac_recv_core(struct sock *sk_udp, struct sk_buff *skb)
-{
- struct sock *sk = (struct sock *)sk_udp->sk_user_data;
- struct pppolac_opt *opt = &pppox_sk(sk)->proto.lac;
- struct meta *meta = skb_meta(skb);
- __u32 now = jiffies;
- __u8 bits;
- __u8 *ptr;
-
- /* Drop the packet if L2TP header is missing. */
- if (skb->len < sizeof(struct udphdr) + 6)
- goto drop;
-
- /* Put it back if it is a control packet. */
- if (skb->data[sizeof(struct udphdr)] & L2TP_CONTROL_BIT)
- return opt->backlog_rcv(sk_udp, skb);
-
- /* Skip UDP header. */
- skb_pull(skb, sizeof(struct udphdr));
-
- /* Check the version. */
- if ((skb->data[1] & L2TP_VERSION_MASK) != L2TP_VERSION)
- goto drop;
- bits = skb->data[0];
- ptr = &skb->data[2];
-
- /* Check the length if it is present. */
- if (bits & L2TP_LENGTH_BIT) {
- if ((ptr[0] << 8 | ptr[1]) != skb->len)
- goto drop;
- ptr += 2;
- }
-
- /* Skip all fields including optional ones. */
- if (!skb_pull(skb, 6 + (bits & L2TP_SEQUENCE_BIT ? 4 : 0) +
- (bits & L2TP_LENGTH_BIT ? 2 : 0) +
- (bits & L2TP_OFFSET_BIT ? 2 : 0)))
- goto drop;
-
- /* Skip the offset padding if it is present. */
- if (bits & L2TP_OFFSET_BIT &&
- !skb_pull(skb, skb->data[-2] << 8 | skb->data[-1]))
- goto drop;
-
- /* Check the tunnel and the session. */
- if (unaligned(ptr)->u32 != opt->local)
- goto drop;
-
- /* Check the sequence if it is present. */
- if (bits & L2TP_SEQUENCE_BIT) {
- meta->sequence = ptr[4] << 8 | ptr[5];
- if ((__s16)(meta->sequence - opt->recv_sequence) < 0)
- goto drop;
- }
-
- /* Skip PPP address and control if they are present. */
- if (skb->len >= 2 && skb->data[0] == PPP_ADDR &&
- skb->data[1] == PPP_CTRL)
- skb_pull(skb, 2);
-
- /* Fix PPP protocol if it is compressed. */
- if (skb->len >= 1 && skb->data[0] & 1)
- skb_push(skb, 1)[0] = 0;
-
- /* Drop the packet if PPP protocol is missing. */
- if (skb->len < 2)
- goto drop;
-
- /* Perform reordering if sequencing is enabled. */
- atomic_set(&opt->sequencing, bits & L2TP_SEQUENCE_BIT);
- if (bits & L2TP_SEQUENCE_BIT) {
- struct sk_buff *skb1;
-
- /* Insert the packet into receive queue in order. */
- skb_set_owner_r(skb, sk);
- skb_queue_walk(&sk->sk_receive_queue, skb1) {
- struct meta *meta1 = skb_meta(skb1);
- __s16 order = meta->sequence - meta1->sequence;
- if (order == 0)
- goto drop;
- if (order < 0) {
- meta->timestamp = meta1->timestamp;
- skb_insert(skb1, skb, &sk->sk_receive_queue);
- skb = NULL;
- break;
- }
- }
- if (skb) {
- meta->timestamp = now;
- skb_queue_tail(&sk->sk_receive_queue, skb);
- }
-
- /* Remove packets from receive queue as long as
- * 1. the receive buffer is full,
- * 2. they are queued longer than one second, or
- * 3. there are no missing packets before them. */
- skb_queue_walk_safe(&sk->sk_receive_queue, skb, skb1) {
- meta = skb_meta(skb);
- if (atomic_read(&sk->sk_rmem_alloc) < sk->sk_rcvbuf &&
- now - meta->timestamp < HZ &&
- meta->sequence != opt->recv_sequence)
- break;
- skb_unlink(skb, &sk->sk_receive_queue);
- opt->recv_sequence = (__u16)(meta->sequence + 1);
- skb_orphan(skb);
- ppp_input(&pppox_sk(sk)->chan, skb);
- }
- return NET_RX_SUCCESS;
- }
-
- /* Flush receive queue if sequencing is disabled. */
- skb_queue_purge(&sk->sk_receive_queue);
- skb_orphan(skb);
- ppp_input(&pppox_sk(sk)->chan, skb);
- return NET_RX_SUCCESS;
-drop:
- kfree_skb(skb);
- return NET_RX_DROP;
-}
-
-static int pppolac_recv(struct sock *sk_udp, struct sk_buff *skb)
-{
- sock_hold(sk_udp);
- sk_receive_skb(sk_udp, skb, 0);
- return 0;
-}
-
-static struct sk_buff_head delivery_queue;
-
-static void pppolac_xmit_core(struct work_struct *delivery_work)
-{
- mm_segment_t old_fs = get_fs();
- struct sk_buff *skb;
-
- set_fs(KERNEL_DS);
- while ((skb = skb_dequeue(&delivery_queue))) {
- struct sock *sk_udp = skb->sk;
- struct kvec iov = {.iov_base = skb->data, .iov_len = skb->len};
- struct msghdr msg = {
- .msg_iov = (struct iovec *)&iov,
- .msg_iovlen = 1,
- .msg_flags = MSG_NOSIGNAL | MSG_DONTWAIT,
- };
- sk_udp->sk_prot->sendmsg(NULL, sk_udp, &msg, skb->len);
- kfree_skb(skb);
- }
- set_fs(old_fs);
-}
-
-static DECLARE_WORK(delivery_work, pppolac_xmit_core);
-
-static int pppolac_xmit(struct ppp_channel *chan, struct sk_buff *skb)
-{
- struct sock *sk_udp = (struct sock *)chan->private;
- struct pppolac_opt *opt = &pppox_sk(sk_udp->sk_user_data)->proto.lac;
-
- /* Install PPP address and control. */
- skb_push(skb, 2);
- skb->data[0] = PPP_ADDR;
- skb->data[1] = PPP_CTRL;
-
- /* Install L2TP header. */
- if (atomic_read(&opt->sequencing)) {
- skb_push(skb, 10);
- skb->data[0] = L2TP_SEQUENCE_BIT;
- skb->data[6] = opt->xmit_sequence >> 8;
- skb->data[7] = opt->xmit_sequence;
- skb->data[8] = 0;
- skb->data[9] = 0;
- opt->xmit_sequence++;
- } else {
- skb_push(skb, 6);
- skb->data[0] = 0;
- }
- skb->data[1] = L2TP_VERSION;
- unaligned(&skb->data[2])->u32 = opt->remote;
-
- /* Now send the packet via the delivery queue. */
- skb_set_owner_w(skb, sk_udp);
- skb_queue_tail(&delivery_queue, skb);
- schedule_work(&delivery_work);
- return 1;
-}
-
-/******************************************************************************/
-
-static struct ppp_channel_ops pppolac_channel_ops = {
- .start_xmit = pppolac_xmit,
-};
-
-static int pppolac_connect(struct socket *sock, struct sockaddr *useraddr,
- int addrlen, int flags)
-{
- struct sock *sk = sock->sk;
- struct pppox_sock *po = pppox_sk(sk);
- struct sockaddr_pppolac *addr = (struct sockaddr_pppolac *)useraddr;
- struct socket *sock_udp = NULL;
- struct sock *sk_udp;
- int error;
-
- if (addrlen != sizeof(struct sockaddr_pppolac) ||
- !addr->local.tunnel || !addr->local.session ||
- !addr->remote.tunnel || !addr->remote.session) {
- return -EINVAL;
- }
-
- lock_sock(sk);
- error = -EALREADY;
- if (sk->sk_state != PPPOX_NONE)
- goto out;
-
- sock_udp = sockfd_lookup(addr->udp_socket, &error);
- if (!sock_udp)
- goto out;
- sk_udp = sock_udp->sk;
- lock_sock(sk_udp);
-
- /* Remove this check when IPv6 supports UDP encapsulation. */
- error = -EAFNOSUPPORT;
- if (sk_udp->sk_family != AF_INET)
- goto out;
- error = -EPROTONOSUPPORT;
- if (sk_udp->sk_protocol != IPPROTO_UDP)
- goto out;
- error = -EDESTADDRREQ;
- if (sk_udp->sk_state != TCP_ESTABLISHED)
- goto out;
- error = -EBUSY;
- if (udp_sk(sk_udp)->encap_type || sk_udp->sk_user_data)
- goto out;
- if (!sk_udp->sk_bound_dev_if) {
- struct dst_entry *dst = sk_dst_get(sk_udp);
- error = -ENODEV;
- if (!dst)
- goto out;
- sk_udp->sk_bound_dev_if = dst->dev->ifindex;
- dst_release(dst);
- }
-
- po->chan.hdrlen = 12;
- po->chan.private = sk_udp;
- po->chan.ops = &pppolac_channel_ops;
- po->chan.mtu = PPP_MRU - 80;
- po->proto.lac.local = unaligned(&addr->local)->u32;
- po->proto.lac.remote = unaligned(&addr->remote)->u32;
- atomic_set(&po->proto.lac.sequencing, 1);
- po->proto.lac.backlog_rcv = sk_udp->sk_backlog_rcv;
-
- error = ppp_register_channel(&po->chan);
- if (error)
- goto out;
-
- sk->sk_state = PPPOX_CONNECTED;
- udp_sk(sk_udp)->encap_type = UDP_ENCAP_L2TPINUDP;
- udp_sk(sk_udp)->encap_rcv = pppolac_recv;
- sk_udp->sk_backlog_rcv = pppolac_recv_core;
- sk_udp->sk_user_data = sk;
-out:
- if (sock_udp) {
- release_sock(sk_udp);
- if (error)
- sockfd_put(sock_udp);
- }
- release_sock(sk);
- return error;
-}
-
-static int pppolac_release(struct socket *sock)
-{
- struct sock *sk = sock->sk;
-
- if (!sk)
- return 0;
-
- lock_sock(sk);
- if (sock_flag(sk, SOCK_DEAD)) {
- release_sock(sk);
- return -EBADF;
- }
-
- if (sk->sk_state != PPPOX_NONE) {
- struct sock *sk_udp = (struct sock *)pppox_sk(sk)->chan.private;
- lock_sock(sk_udp);
- skb_queue_purge(&sk->sk_receive_queue);
- pppox_unbind_sock(sk);
- udp_sk(sk_udp)->encap_type = 0;
- udp_sk(sk_udp)->encap_rcv = NULL;
- sk_udp->sk_backlog_rcv = pppox_sk(sk)->proto.lac.backlog_rcv;
- sk_udp->sk_user_data = NULL;
- release_sock(sk_udp);
- sockfd_put(sk_udp->sk_socket);
- }
-
- sock_orphan(sk);
- sock->sk = NULL;
- release_sock(sk);
- sock_put(sk);
- return 0;
-}
-
-/******************************************************************************/
-
-static struct proto pppolac_proto = {
- .name = "PPPOLAC",
- .owner = THIS_MODULE,
- .obj_size = sizeof(struct pppox_sock),
-};
-
-static struct proto_ops pppolac_proto_ops = {
- .family = PF_PPPOX,
- .owner = THIS_MODULE,
- .release = pppolac_release,
- .bind = sock_no_bind,
- .connect = pppolac_connect,
- .socketpair = sock_no_socketpair,
- .accept = sock_no_accept,
- .getname = sock_no_getname,
- .poll = sock_no_poll,
- .ioctl = pppox_ioctl,
- .listen = sock_no_listen,
- .shutdown = sock_no_shutdown,
- .setsockopt = sock_no_setsockopt,
- .getsockopt = sock_no_getsockopt,
- .sendmsg = sock_no_sendmsg,
- .recvmsg = sock_no_recvmsg,
- .mmap = sock_no_mmap,
-};
-
-static int pppolac_create(struct net *net, struct socket *sock)
-{
- struct sock *sk;
-
- sk = sk_alloc(net, PF_PPPOX, GFP_KERNEL, &pppolac_proto);
- if (!sk)
- return -ENOMEM;
-
- sock_init_data(sock, sk);
- sock->state = SS_UNCONNECTED;
- sock->ops = &pppolac_proto_ops;
- sk->sk_protocol = PX_PROTO_OLAC;
- sk->sk_state = PPPOX_NONE;
- return 0;
-}
-
-/******************************************************************************/
-
-static struct pppox_proto pppolac_pppox_proto = {
- .create = pppolac_create,
- .owner = THIS_MODULE,
-};
-
-static int __init pppolac_init(void)
-{
- int error;
-
- error = proto_register(&pppolac_proto, 0);
- if (error)
- return error;
-
- error = register_pppox_proto(PX_PROTO_OLAC, &pppolac_pppox_proto);
- if (error)
- proto_unregister(&pppolac_proto);
- else
- skb_queue_head_init(&delivery_queue);
- return error;
-}
-
-static void __exit pppolac_exit(void)
-{
- unregister_pppox_proto(PX_PROTO_OLAC);
- proto_unregister(&pppolac_proto);
-}
-
-module_init(pppolac_init);
-module_exit(pppolac_exit);
-
-MODULE_DESCRIPTION("PPP on L2TP Access Concentrator (PPPoLAC)");
-MODULE_AUTHOR("Chia-chi Yeh <chiachi@android.com>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/net/pppopns.c b/drivers/net/pppopns.c
deleted file mode 100644
index 6016d29..0000000
--- a/drivers/net/pppopns.c
+++ /dev/null
@@ -1,428 +0,0 @@
-/* drivers/net/pppopns.c
- *
- * Driver for PPP on PPTP Network Server / PPPoPNS Socket (RFC 2637)
- *
- * Copyright (C) 2009 Google, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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 driver handles PPTP data packets between a RAW socket and a PPP channel.
- * The socket is created in the kernel space and connected to the same address
- * of the control socket. Outgoing packets are always sent with sequences but
- * without acknowledgements. Incoming packets with sequences are reordered
- * within a sliding window of one second. Currently reordering only happens when
- * a packet is received. It is done for simplicity since no additional locks or
- * threads are required. This driver should work on both IPv4 and IPv6. */
-
-#include <linux/module.h>
-#include <linux/jiffies.h>
-#include <linux/workqueue.h>
-#include <linux/skbuff.h>
-#include <linux/file.h>
-#include <linux/netdevice.h>
-#include <linux/net.h>
-#include <linux/ppp_defs.h>
-#include <linux/if.h>
-#include <linux/if_ppp.h>
-#include <linux/if_pppox.h>
-#include <linux/ppp_channel.h>
-#include <asm/uaccess.h>
-
-#define GRE_HEADER_SIZE 8
-
-#define PPTP_GRE_BITS htons(0x2001)
-#define PPTP_GRE_BITS_MASK htons(0xEF7F)
-#define PPTP_GRE_SEQ_BIT htons(0x1000)
-#define PPTP_GRE_ACK_BIT htons(0x0080)
-#define PPTP_GRE_TYPE htons(0x880B)
-
-#define PPP_ADDR 0xFF
-#define PPP_CTRL 0x03
-
-struct header {
- __u16 bits;
- __u16 type;
- __u16 length;
- __u16 call;
- __u32 sequence;
-} __attribute__((packed));
-
-struct meta {
- __u32 sequence;
- __u32 timestamp;
-};
-
-static inline struct meta *skb_meta(struct sk_buff *skb)
-{
- return (struct meta *)skb->cb;
-}
-
-/******************************************************************************/
-
-static int pppopns_recv_core(struct sock *sk_raw, struct sk_buff *skb)
-{
- struct sock *sk = (struct sock *)sk_raw->sk_user_data;
- struct pppopns_opt *opt = &pppox_sk(sk)->proto.pns;
- struct meta *meta = skb_meta(skb);
- __u32 now = jiffies;
- struct header *hdr;
-
- /* Skip transport header */
- skb_pull(skb, skb_transport_header(skb) - skb->data);
-
- /* Drop the packet if GRE header is missing. */
- if (skb->len < GRE_HEADER_SIZE)
- goto drop;
- hdr = (struct header *)skb->data;
-
- /* Check the header. */
- if (hdr->type != PPTP_GRE_TYPE || hdr->call != opt->local ||
- (hdr->bits & PPTP_GRE_BITS_MASK) != PPTP_GRE_BITS)
- goto drop;
-
- /* Skip all fields including optional ones. */
- if (!skb_pull(skb, GRE_HEADER_SIZE +
- (hdr->bits & PPTP_GRE_SEQ_BIT ? 4 : 0) +
- (hdr->bits & PPTP_GRE_ACK_BIT ? 4 : 0)))
- goto drop;
-
- /* Check the length. */
- if (skb->len != ntohs(hdr->length))
- goto drop;
-
- /* Check the sequence if it is present. */
- if (hdr->bits & PPTP_GRE_SEQ_BIT) {
- meta->sequence = ntohl(hdr->sequence);
- if ((__s32)(meta->sequence - opt->recv_sequence) < 0)
- goto drop;
- }
-
- /* Skip PPP address and control if they are present. */
- if (skb->len >= 2 && skb->data[0] == PPP_ADDR &&
- skb->data[1] == PPP_CTRL)
- skb_pull(skb, 2);
-
- /* Fix PPP protocol if it is compressed. */
- if (skb->len >= 1 && skb->data[0] & 1)
- skb_push(skb, 1)[0] = 0;
-
- /* Drop the packet if PPP protocol is missing. */
- if (skb->len < 2)
- goto drop;
-
- /* Perform reordering if sequencing is enabled. */
- if (hdr->bits & PPTP_GRE_SEQ_BIT) {
- struct sk_buff *skb1;
-
- /* Insert the packet into receive queue in order. */
- skb_set_owner_r(skb, sk);
- skb_queue_walk(&sk->sk_receive_queue, skb1) {
- struct meta *meta1 = skb_meta(skb1);
- __s32 order = meta->sequence - meta1->sequence;
- if (order == 0)
- goto drop;
- if (order < 0) {
- meta->timestamp = meta1->timestamp;
- skb_insert(skb1, skb, &sk->sk_receive_queue);
- skb = NULL;
- break;
- }
- }
- if (skb) {
- meta->timestamp = now;
- skb_queue_tail(&sk->sk_receive_queue, skb);
- }
-
- /* Remove packets from receive queue as long as
- * 1. the receive buffer is full,
- * 2. they are queued longer than one second, or
- * 3. there are no missing packets before them. */
- skb_queue_walk_safe(&sk->sk_receive_queue, skb, skb1) {
- meta = skb_meta(skb);
- if (atomic_read(&sk->sk_rmem_alloc) < sk->sk_rcvbuf &&
- now - meta->timestamp < HZ &&
- meta->sequence != opt->recv_sequence)
- break;
- skb_unlink(skb, &sk->sk_receive_queue);
- opt->recv_sequence = meta->sequence + 1;
- skb_orphan(skb);
- ppp_input(&pppox_sk(sk)->chan, skb);
- }
- return NET_RX_SUCCESS;
- }
-
- /* Flush receive queue if sequencing is disabled. */
- skb_queue_purge(&sk->sk_receive_queue);
- skb_orphan(skb);
- ppp_input(&pppox_sk(sk)->chan, skb);
- return NET_RX_SUCCESS;
-drop:
- kfree_skb(skb);
- return NET_RX_DROP;
-}
-
-static void pppopns_recv(struct sock *sk_raw, int length)
-{
- struct sk_buff *skb;
- while ((skb = skb_dequeue(&sk_raw->sk_receive_queue))) {
- sock_hold(sk_raw);
- sk_receive_skb(sk_raw, skb, 0);
- }
-}
-
-static struct sk_buff_head delivery_queue;
-
-static void pppopns_xmit_core(struct work_struct *delivery_work)
-{
- mm_segment_t old_fs = get_fs();
- struct sk_buff *skb;
-
- set_fs(KERNEL_DS);
- while ((skb = skb_dequeue(&delivery_queue))) {
- struct sock *sk_raw = skb->sk;
- struct kvec iov = {.iov_base = skb->data, .iov_len = skb->len};
- struct msghdr msg = {
- .msg_iov = (struct iovec *)&iov,
- .msg_iovlen = 1,
- .msg_flags = MSG_NOSIGNAL | MSG_DONTWAIT,
- };
- sk_raw->sk_prot->sendmsg(NULL, sk_raw, &msg, skb->len);
- kfree_skb(skb);
- }
- set_fs(old_fs);
-}
-
-static DECLARE_WORK(delivery_work, pppopns_xmit_core);
-
-static int pppopns_xmit(struct ppp_channel *chan, struct sk_buff *skb)
-{
- struct sock *sk_raw = (struct sock *)chan->private;
- struct pppopns_opt *opt = &pppox_sk(sk_raw->sk_user_data)->proto.pns;
- struct header *hdr;
- __u16 length;
-
- /* Install PPP address and control. */
- skb_push(skb, 2);
- skb->data[0] = PPP_ADDR;
- skb->data[1] = PPP_CTRL;
- length = skb->len;
-
- /* Install PPTP GRE header. */
- hdr = (struct header *)skb_push(skb, 12);
- hdr->bits = PPTP_GRE_BITS | PPTP_GRE_SEQ_BIT;
- hdr->type = PPTP_GRE_TYPE;
- hdr->length = htons(length);
- hdr->call = opt->remote;
- hdr->sequence = htonl(opt->xmit_sequence);
- opt->xmit_sequence++;
-
- /* Now send the packet via the delivery queue. */
- skb_set_owner_w(skb, sk_raw);
- skb_queue_tail(&delivery_queue, skb);
- schedule_work(&delivery_work);
- return 1;
-}
-
-/******************************************************************************/
-
-static struct ppp_channel_ops pppopns_channel_ops = {
- .start_xmit = pppopns_xmit,
-};
-
-static int pppopns_connect(struct socket *sock, struct sockaddr *useraddr,
- int addrlen, int flags)
-{
- struct sock *sk = sock->sk;
- struct pppox_sock *po = pppox_sk(sk);
- struct sockaddr_pppopns *addr = (struct sockaddr_pppopns *)useraddr;
- struct sockaddr_storage ss;
- struct socket *sock_tcp = NULL;
- struct socket *sock_raw = NULL;
- struct sock *sk_tcp;
- struct sock *sk_raw;
- int error;
-
- if (addrlen != sizeof(struct sockaddr_pppopns))
- return -EINVAL;
-
- lock_sock(sk);
- error = -EALREADY;
- if (sk->sk_state != PPPOX_NONE)
- goto out;
-
- sock_tcp = sockfd_lookup(addr->tcp_socket, &error);
- if (!sock_tcp)
- goto out;
- sk_tcp = sock_tcp->sk;
- error = -EPROTONOSUPPORT;
- if (sk_tcp->sk_protocol != IPPROTO_TCP)
- goto out;
- addrlen = sizeof(struct sockaddr_storage);
- error = kernel_getpeername(sock_tcp, (struct sockaddr *)&ss, &addrlen);
- if (error)
- goto out;
- if (!sk_tcp->sk_bound_dev_if) {
- struct dst_entry *dst = sk_dst_get(sk_tcp);
- error = -ENODEV;
- if (!dst)
- goto out;
- sk_tcp->sk_bound_dev_if = dst->dev->ifindex;
- dst_release(dst);
- }
-
- error = sock_create(ss.ss_family, SOCK_RAW, IPPROTO_GRE, &sock_raw);
- if (error)
- goto out;
- sk_raw = sock_raw->sk;
- sk_raw->sk_bound_dev_if = sk_tcp->sk_bound_dev_if;
- error = kernel_connect(sock_raw, (struct sockaddr *)&ss, addrlen, 0);
- if (error)
- goto out;
-
- po->chan.hdrlen = 14;
- po->chan.private = sk_raw;
- po->chan.ops = &pppopns_channel_ops;
- po->chan.mtu = PPP_MRU - 80;
- po->proto.pns.local = addr->local;
- po->proto.pns.remote = addr->remote;
- po->proto.pns.data_ready = sk_raw->sk_data_ready;
- po->proto.pns.backlog_rcv = sk_raw->sk_backlog_rcv;
-
- error = ppp_register_channel(&po->chan);
- if (error)
- goto out;
-
- sk->sk_state = PPPOX_CONNECTED;
- lock_sock(sk_raw);
- sk_raw->sk_data_ready = pppopns_recv;
- sk_raw->sk_backlog_rcv = pppopns_recv_core;
- sk_raw->sk_user_data = sk;
- release_sock(sk_raw);
-out:
- if (sock_tcp)
- sockfd_put(sock_tcp);
- if (error && sock_raw)
- sock_release(sock_raw);
- release_sock(sk);
- return error;
-}
-
-static int pppopns_release(struct socket *sock)
-{
- struct sock *sk = sock->sk;
-
- if (!sk)
- return 0;
-
- lock_sock(sk);
- if (sock_flag(sk, SOCK_DEAD)) {
- release_sock(sk);
- return -EBADF;
- }
-
- if (sk->sk_state != PPPOX_NONE) {
- struct sock *sk_raw = (struct sock *)pppox_sk(sk)->chan.private;
- lock_sock(sk_raw);
- skb_queue_purge(&sk->sk_receive_queue);
- pppox_unbind_sock(sk);
- sk_raw->sk_data_ready = pppox_sk(sk)->proto.pns.data_ready;
- sk_raw->sk_backlog_rcv = pppox_sk(sk)->proto.pns.backlog_rcv;
- sk_raw->sk_user_data = NULL;
- release_sock(sk_raw);
- sock_release(sk_raw->sk_socket);
- }
-
- sock_orphan(sk);
- sock->sk = NULL;
- release_sock(sk);
- sock_put(sk);
- return 0;
-}
-
-/******************************************************************************/
-
-static struct proto pppopns_proto = {
- .name = "PPPOPNS",
- .owner = THIS_MODULE,
- .obj_size = sizeof(struct pppox_sock),
-};
-
-static struct proto_ops pppopns_proto_ops = {
- .family = PF_PPPOX,
- .owner = THIS_MODULE,
- .release = pppopns_release,
- .bind = sock_no_bind,
- .connect = pppopns_connect,
- .socketpair = sock_no_socketpair,
- .accept = sock_no_accept,
- .getname = sock_no_getname,
- .poll = sock_no_poll,
- .ioctl = pppox_ioctl,
- .listen = sock_no_listen,
- .shutdown = sock_no_shutdown,
- .setsockopt = sock_no_setsockopt,
- .getsockopt = sock_no_getsockopt,
- .sendmsg = sock_no_sendmsg,
- .recvmsg = sock_no_recvmsg,
- .mmap = sock_no_mmap,
-};
-
-static int pppopns_create(struct net *net, struct socket *sock)
-{
- struct sock *sk;
-
- sk = sk_alloc(net, PF_PPPOX, GFP_KERNEL, &pppopns_proto);
- if (!sk)
- return -ENOMEM;
-
- sock_init_data(sock, sk);
- sock->state = SS_UNCONNECTED;
- sock->ops = &pppopns_proto_ops;
- sk->sk_protocol = PX_PROTO_OPNS;
- sk->sk_state = PPPOX_NONE;
- return 0;
-}
-
-/******************************************************************************/
-
-static struct pppox_proto pppopns_pppox_proto = {
- .create = pppopns_create,
- .owner = THIS_MODULE,
-};
-
-static int __init pppopns_init(void)
-{
- int error;
-
- error = proto_register(&pppopns_proto, 0);
- if (error)
- return error;
-
- error = register_pppox_proto(PX_PROTO_OPNS, &pppopns_pppox_proto);
- if (error)
- proto_unregister(&pppopns_proto);
- else
- skb_queue_head_init(&delivery_queue);
- return error;
-}
-
-static void __exit pppopns_exit(void)
-{
- unregister_pppox_proto(PX_PROTO_OPNS);
- proto_unregister(&pppopns_proto);
-}
-
-module_init(pppopns_init);
-module_exit(pppopns_exit);
-
-MODULE_DESCRIPTION("PPP on PPTP Network Server (PPPoPNS)");
-MODULE_AUTHOR("Chia-chi Yeh <chiachi@android.com>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index e9130f6..fa0c568 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -35,7 +35,6 @@
#include <linux/module.h>
#include <linux/init.h>
-#include <linux/if_arp.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/ctype.h>
@@ -362,9 +361,6 @@
return -ENOMEM;
}
- if (dev->net->type != ARPHRD_RAWIP)
- skb_reserve(skb, NET_IP_ALIGN);
-
entry = (struct skb_data *) skb->cb;
entry->urb = urb;
entry->dev = dev;
diff --git a/drivers/platform/msm/ipa/teth_bridge.c b/drivers/platform/msm/ipa/teth_bridge.c
index 29253cd..5b26e41 100644
--- a/drivers/platform/msm/ipa/teth_bridge.c
+++ b/drivers/platform/msm/ipa/teth_bridge.c
@@ -29,7 +29,6 @@
#define TETH_BRIDGE_DRV_NAME "ipa_tethering_bridge"
-#ifdef TETH_DEBUG
#define TETH_DBG(fmt, args...) \
pr_debug(TETH_BRIDGE_DRV_NAME " %s:%d " fmt, \
__func__, __LINE__, ## args)
@@ -37,12 +36,6 @@
pr_debug(TETH_BRIDGE_DRV_NAME " %s:%d ENTRY\n", __func__, __LINE__)
#define TETH_DBG_FUNC_EXIT() \
pr_debug(TETH_BRIDGE_DRV_NAME " %s:%d EXIT\n", __func__, __LINE__)
-#else
-#define TETH_DBG(fmt, args...)
-#define TETH_DBG_FUNC_ENTRY()
-#define TETH_DBG_FUNC_EXIT()
-#endif
-
#define TETH_ERR(fmt, args...) \
pr_err(TETH_BRIDGE_DRV_NAME " %s:%d " fmt, __func__, __LINE__, ## args)
@@ -62,6 +55,9 @@
#define ETHERTYPE_IPV4 0x0800
#define ETHERTYPE_IPV6 0x86DD
+#define TETH_AGGR_MAX_DATAGRAMS_DEFAULT 16
+#define TETH_AGGR_MAX_AGGR_PACKET_SIZE_DEFAULT (8*1024)
+
struct mac_addresses_type {
u8 host_pc_mac_addr[ETH_ALEN];
bool host_pc_mac_addr_known;
@@ -905,7 +901,6 @@
int teth_bridge_init(ipa_notify_cb *usb_notify_cb_ptr, void **private_data_ptr)
{
int res = 0;
- struct ipa_rm_create_params bridge_prod_params;
TETH_DBG_FUNC_ENTRY();
if (usb_notify_cb_ptr == NULL) {
@@ -918,48 +913,34 @@
*private_data_ptr = NULL;
/* Build IPA Resource manager dependency graph */
- bridge_prod_params.name = IPA_RM_RESOURCE_BRIDGE_PROD;
- bridge_prod_params.reg_params.user_data = NULL;
- bridge_prod_params.reg_params.notify_cb = bridge_prod_notify_cb;
- res = ipa_rm_create_resource(&bridge_prod_params);
- if (res) {
- TETH_ERR("ipa_rm_create_resource() failed\n");
- goto bail;
- }
-
res = ipa_rm_add_dependency(IPA_RM_RESOURCE_BRIDGE_PROD,
IPA_RM_RESOURCE_USB_CONS);
- if (res) {
+ if (res && res != -EEXIST) {
TETH_ERR("ipa_rm_add_dependency() failed\n");
goto bail;
}
res = ipa_rm_add_dependency(IPA_RM_RESOURCE_BRIDGE_PROD,
IPA_RM_RESOURCE_A2_CONS);
- if (res) {
+ if (res && res != -EEXIST) {
TETH_ERR("ipa_rm_add_dependency() failed\n");
goto fail_add_dependency_1;
}
res = ipa_rm_add_dependency(IPA_RM_RESOURCE_USB_PROD,
IPA_RM_RESOURCE_A2_CONS);
- if (res) {
+ if (res && res != -EEXIST) {
TETH_ERR("ipa_rm_add_dependency() failed\n");
goto fail_add_dependency_2;
}
res = ipa_rm_add_dependency(IPA_RM_RESOURCE_A2_PROD,
IPA_RM_RESOURCE_USB_CONS);
- if (res) {
+ if (res && res != -EEXIST) {
TETH_ERR("ipa_rm_add_dependency() failed\n");
goto fail_add_dependency_3;
}
- init_completion(&teth_ctx->is_bridge_prod_up);
- init_completion(&teth_ctx->is_bridge_prod_down);
-
- /* The default link protocol is Ethernet */
- teth_ctx->link_protocol = TETH_LINK_PROTOCOL_ETHERNET;
goto bail;
fail_add_dependency_3:
@@ -1001,6 +982,20 @@
if (res == -EINPROGRESS)
wait_for_completion(&teth_ctx->is_bridge_prod_down);
+ /* Initialize statistics */
+ memset(&teth_ctx->stats, 0, sizeof(teth_ctx->stats));
+
+ /* Delete IPA Resource manager dependency graph */
+ res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_BRIDGE_PROD,
+ IPA_RM_RESOURCE_USB_CONS);
+ res |= ipa_rm_delete_dependency(IPA_RM_RESOURCE_BRIDGE_PROD,
+ IPA_RM_RESOURCE_A2_CONS);
+ res |= ipa_rm_delete_dependency(IPA_RM_RESOURCE_USB_PROD,
+ IPA_RM_RESOURCE_A2_CONS);
+ res |= ipa_rm_delete_dependency(IPA_RM_RESOURCE_A2_PROD,
+ IPA_RM_RESOURCE_USB_CONS);
+ if (res)
+ TETH_ERR("Failed deleting ipa_rm dependency.\n");
bail:
TETH_DBG_FUNC_EXIT();
return res;
@@ -1084,9 +1079,11 @@
static void set_aggr_default_params(struct teth_aggr_params_link *params)
{
if (params->max_datagrams == 0)
- params->max_datagrams = 16;
+ params->max_datagrams =
+ TETH_AGGR_MAX_DATAGRAMS_DEFAULT;
if (params->max_transfer_size_byte == 0)
- params->max_transfer_size_byte = 16*1024;
+ params->max_transfer_size_byte =
+ TETH_AGGR_MAX_AGGR_PACKET_SIZE_DEFAULT;
}
static void teth_set_bridge_mode(enum teth_link_protocol_type link_protocol)
@@ -1096,11 +1093,38 @@
memset(&teth_ctx->mac_addresses, 0, sizeof(teth_ctx->mac_addresses));
}
+int teth_bridge_set_aggr_params(struct teth_aggr_params *aggr_params)
+{
+ int res;
+
+ if (!aggr_params) {
+ TETH_ERR("Invalid parameter\n");
+ return -EINVAL;
+ }
+
+ memcpy(&teth_ctx->aggr_params,
+ aggr_params,
+ sizeof(struct teth_aggr_params));
+ set_aggr_default_params(&teth_ctx->aggr_params.dl);
+ set_aggr_default_params(&teth_ctx->aggr_params.ul);
+
+ teth_ctx->aggr_params_known = true;
+ res = teth_set_aggregation();
+ if (res) {
+ TETH_ERR("Failed setting aggregation params\n");
+ res = -EFAULT;
+ }
+
+ return res;
+}
+EXPORT_SYMBOL(teth_bridge_set_aggr_params);
+
static long teth_bridge_ioctl(struct file *filp,
unsigned int cmd,
unsigned long arg)
{
int res = 0;
+ struct teth_aggr_params aggr_params;
TETH_DBG("cmd=%x nr=%d\n", cmd, _IOC_NR(cmd));
@@ -1119,7 +1143,7 @@
case TETH_BRIDGE_IOC_SET_AGGR_PARAMS:
TETH_DBG("TETH_BRIDGE_IOC_SET_AGGR_PARAMS ioctl called\n");
- res = copy_from_user(&teth_ctx->aggr_params,
+ res = copy_from_user(&aggr_params,
(struct teth_aggr_params *)arg,
sizeof(struct teth_aggr_params));
if (res) {
@@ -1127,9 +1151,8 @@
res = -EFAULT;
break;
}
- set_aggr_default_params(&teth_ctx->aggr_params.dl);
- set_aggr_default_params(&teth_ctx->aggr_params.ul);
- teth_ctx->aggr_params_known = true;
+
+ res = teth_bridge_set_aggr_params(&aggr_params);
break;
case TETH_BRIDGE_IOC_GET_AGGR_PARAMS:
@@ -1201,12 +1224,10 @@
teth_ctx->aggr_caps->num_protocols = NUM_PROTOCOLS;
teth_ctx->aggr_caps->prot_caps[0].aggr_prot = TETH_AGGR_PROTOCOL_MBIM;
- teth_ctx->aggr_caps->prot_caps[0].max_datagrams = 16;
- teth_ctx->aggr_caps->prot_caps[0].max_transfer_size_byte = 16*1024;
+ set_aggr_default_params(&teth_ctx->aggr_caps->prot_caps[0]);
teth_ctx->aggr_caps->prot_caps[1].aggr_prot = TETH_AGGR_PROTOCOL_TLP;
- teth_ctx->aggr_caps->prot_caps[1].max_datagrams = 16;
- teth_ctx->aggr_caps->prot_caps[1].max_transfer_size_byte = 16*1024;
+ set_aggr_default_params(&teth_ctx->aggr_caps->prot_caps[1]);
}
void teth_bridge_get_client_handles(u32 *producer_handle,
@@ -1287,7 +1308,7 @@
aggr_prot_to_str(teth_ctx->aggr_params.ul.aggr_prot,
aggr_str,
sizeof(aggr_str)-1);
- nbytes += scnprintf(&dbg_buff[nbytes], TETH_MAX_MSG_LEN,
+ nbytes += scnprintf(&dbg_buff[nbytes], TETH_MAX_MSG_LEN - nbytes,
"Aggregation parameters for uplink:\n");
nbytes += scnprintf(&dbg_buff[nbytes], TETH_MAX_MSG_LEN - nbytes,
" Aggregation protocol: %s\n",
@@ -1493,6 +1514,7 @@
int teth_bridge_driver_init(void)
{
int res;
+ struct ipa_rm_create_params bridge_prod_params;
TETH_DBG("Tethering bridge driver init\n");
teth_ctx = kzalloc(sizeof(*teth_ctx), GFP_KERNEL);
@@ -1535,6 +1557,22 @@
teth_ctx->comp_hw_bridge_in_progress = false;
teth_debugfs_init();
+
+ /* Create BRIDGE_PROD entity in IPA Resource Manager */
+ bridge_prod_params.name = IPA_RM_RESOURCE_BRIDGE_PROD;
+ bridge_prod_params.reg_params.user_data = NULL;
+ bridge_prod_params.reg_params.notify_cb = bridge_prod_notify_cb;
+ res = ipa_rm_create_resource(&bridge_prod_params);
+ if (res) {
+ TETH_ERR("ipa_rm_create_resource() failed\n");
+ goto fail_cdev_add;
+ }
+ init_completion(&teth_ctx->is_bridge_prod_up);
+ init_completion(&teth_ctx->is_bridge_prod_down);
+
+ /* The default link protocol is Ethernet */
+ teth_ctx->link_protocol = TETH_LINK_PROTOCOL_ETHERNET;
+
TETH_DBG("Tethering bridge driver init OK\n");
return 0;
diff --git a/drivers/platform/msm/ssm.c b/drivers/platform/msm/ssm.c
index c57bb91..3afb954 100644
--- a/drivers/platform/msm/ssm.c
+++ b/drivers/platform/msm/ssm.c
@@ -66,7 +66,7 @@
struct device *dev;
smd_channel_t *ch;
ion_phys_addr_t buff_phys;
- ion_virt_addr_t buff_virt;
+ void *buff_virt;
dev_t ssm_device_no;
struct work_struct ipc_work;
struct mutex mutex;
@@ -401,7 +401,7 @@
const struct elf32_phdr *phdr;
struct ion_handle *ion_handle;
ion_phys_addr_t buff_phys;
- ion_virt_addr_t buff_virt;
+ void *buff_virt;
/* Check if TZ app already loaded */
app_req.cmd_id = APP_LOOKUP_COMMAND;
@@ -509,8 +509,7 @@
goto ion_free;
}
- buff_virt =
- (ion_virt_addr_t)ion_map_kernel(ssm_drv->ssm_ion_client,
+ buff_virt = ion_map_kernel(ssm_drv->ssm_ion_client,
ion_handle);
if (IS_ERR_OR_NULL((void *)buff_virt)) {
rc = PTR_ERR((void *)buff_virt);
@@ -605,8 +604,7 @@
goto ion_free;
}
- ssm->buff_virt =
- (ion_virt_addr_t)ion_map_kernel(ssm->ssm_ion_client,
+ ssm->buff_virt = ion_map_kernel(ssm->ssm_ion_client,
ssm->ssm_ion_handle);
if (IS_ERR_OR_NULL((void *)ssm->buff_virt)) {
rc = PTR_ERR((void *)ssm->buff_virt);
diff --git a/drivers/platform/msm/usb_bam.c b/drivers/platform/msm/usb_bam.c
index a9a850c..f9ae3c2 100644
--- a/drivers/platform/msm/usb_bam.c
+++ b/drivers/platform/msm/usb_bam.c
@@ -28,34 +28,8 @@
#include <linux/dma-mapping.h>
#include <mach/msm_smsm.h>
-#define USB_SUMMING_THRESHOLD 512
-#define CONNECTIONS_NUM 8
-
-static struct sps_bam_props usb_props;
-static struct sps_pipe *sps_pipes[CONNECTIONS_NUM][2];
-static struct sps_connect sps_connections[CONNECTIONS_NUM][2];
-static struct sps_mem_buffer data_mem_buf[CONNECTIONS_NUM][2];
-static struct sps_mem_buffer desc_mem_buf[CONNECTIONS_NUM][2];
-static struct platform_device *usb_bam_pdev;
-static struct workqueue_struct *usb_bam_wq;
-static u32 h_bam;
-static spinlock_t usb_bam_lock;
-
-struct usb_bam_event_info {
- struct sps_register_event event;
- int (*callback)(void *);
- void *param;
- struct work_struct event_w;
-};
-
-struct usb_bam_connect_info {
- u8 idx;
- u32 *src_pipe;
- u32 *dst_pipe;
- struct usb_bam_event_info wake_event;
- bool src_enabled;
- bool dst_enabled;
-};
+#define USB_THRESHOLD 512
+#define USB_BAM_MAX_STR_LEN 50
enum usb_bam_sm {
USB_BAM_SM_INIT = 0,
@@ -64,7 +38,7 @@
USB_BAM_SM_UNPLUG_NOTIFIED,
};
-struct usb_bam_peer_handhskae_info {
+struct usb_bam_peer_handshake_info {
enum usb_bam_sm state;
bool client_ready;
bool ack_received;
@@ -72,26 +46,79 @@
struct usb_bam_event_info reset_event;
};
-static struct usb_bam_connect_info usb_bam_connections[CONNECTIONS_NUM];
-static struct usb_bam_pipe_connect ***msm_usb_bam_connections_info;
-static struct usb_bam_pipe_connect *bam_connection_arr;
-void __iomem *qscratch_ram1_reg;
-struct clk *mem_clk;
-struct clk *mem_iface_clk;
-struct usb_bam_peer_handhskae_info peer_handhskae_info;
+struct usb_bam_sps_type {
+ struct sps_bam_props usb_props;
+ struct sps_pipe **sps_pipes;
+ struct sps_connect *sps_connections;
+};
-static int connect_pipe(u8 conn_idx, enum usb_bam_pipe_dir pipe_dir,
- u32 *usb_pipe_idx)
+struct usb_bam_ctx_type {
+ struct usb_bam_sps_type usb_bam_sps;
+ struct platform_device *usb_bam_pdev;
+ struct workqueue_struct *usb_bam_wq;
+ void __iomem *qscratch_ram1_reg;
+ u8 max_connections;
+ struct clk *mem_clk;
+ struct clk *mem_iface_clk;
+ char qdss_core_name[USB_BAM_MAX_STR_LEN];
+ char bam_enabled_list[USB_BAM_MAX_STR_LEN];
+ u32 h_bam[MAX_BAMS];
+};
+
+static char *bam_enable_strings[3] = {
+ [SSUSB_BAM] = "ssusb",
+ [HSUSB_BAM] = "hsusb",
+ [HSIC_BAM] = "hsic",
+};
+
+static spinlock_t usb_bam_lock;
+static struct usb_bam_peer_handshake_info peer_handshake_info;
+static struct usb_bam_pipe_connect *usb_bam_connections;
+static struct usb_bam_ctx_type ctx;
+
+static int get_bam_type_from_core_name(const char *name)
+{
+ if (strnstr(name, bam_enable_strings[SSUSB_BAM],
+ USB_BAM_MAX_STR_LEN) ||
+ strnstr(name, "dwc3", USB_BAM_MAX_STR_LEN))
+ return SSUSB_BAM;
+ else if (strnstr(name, bam_enable_strings[HSIC_BAM],
+ USB_BAM_MAX_STR_LEN))
+ return HSIC_BAM;
+ else if (strnstr(name, bam_enable_strings[HSUSB_BAM],
+ USB_BAM_MAX_STR_LEN) ||
+ strnstr(name, "ci", USB_BAM_MAX_STR_LEN))
+ return HSUSB_BAM;
+
+ pr_err("%s: invalid BAM name(%s)\n", __func__, name);
+ return -EINVAL;
+}
+
+static bool bam_use_private_mem(enum usb_bam bam)
+{
+ int i;
+
+ for (i = 0; i < ctx.max_connections; i++)
+ if (usb_bam_connections[i].bam_type == bam &&
+ usb_bam_connections[i].mem_type == USB_PRIVATE_MEM)
+ return true;
+
+ return false;
+}
+
+static int connect_pipe(u8 idx, u32 *usb_pipe_idx)
{
int ret, ram1_value;
- struct sps_pipe **pipe = &sps_pipes[conn_idx][pipe_dir];
- struct sps_connect *connection =
- &sps_connections[conn_idx][pipe_dir];
+ enum usb_bam bam;
+ struct usb_bam_sps_type usb_bam_sps = ctx.usb_bam_sps;
+ struct sps_pipe **pipe = &(usb_bam_sps.sps_pipes[idx]);
+ struct sps_connect *sps_connection = &usb_bam_sps.sps_connections[idx];
struct msm_usb_bam_platform_data *pdata =
- usb_bam_pdev->dev.platform_data;
- struct usb_bam_pipe_connect *pipe_connection =
- &msm_usb_bam_connections_info
- [pdata->usb_active_bam][conn_idx][pipe_dir];
+ ctx.usb_bam_pdev->dev.platform_data;
+ struct usb_bam_pipe_connect *pipe_connect = &usb_bam_connections[idx];
+ enum usb_bam_pipe_dir dir = pipe_connect->dir;
+ struct sps_mem_buffer *data_buf = &(pipe_connect->data_mem_buf);
+ struct sps_mem_buffer *desc_buf = &(pipe_connect->desc_mem_buf);
*pipe = sps_alloc_endpoint();
if (*pipe == NULL) {
@@ -99,42 +126,42 @@
return -ENOMEM;
}
- ret = sps_get_config(*pipe, connection);
+ ret = sps_get_config(*pipe, sps_connection);
if (ret) {
pr_err("%s: tx get config failed %d\n", __func__, ret);
goto free_sps_endpoint;
}
- ret = sps_phy2h(pipe_connection->src_phy_addr, &(connection->source));
+ ret = sps_phy2h(pipe_connect->src_phy_addr, &(sps_connection->source));
if (ret) {
pr_err("%s: sps_phy2h failed (src BAM) %d\n", __func__, ret);
goto free_sps_endpoint;
}
- connection->src_pipe_index = pipe_connection->src_pipe_index;
- ret = sps_phy2h(pipe_connection->dst_phy_addr,
- &(connection->destination));
+ sps_connection->src_pipe_index = pipe_connect->src_pipe_index;
+ ret = sps_phy2h(pipe_connect->dst_phy_addr,
+ &(sps_connection->destination));
if (ret) {
pr_err("%s: sps_phy2h failed (dst BAM) %d\n", __func__, ret);
goto free_sps_endpoint;
}
- connection->dest_pipe_index = pipe_connection->dst_pipe_index;
+ sps_connection->dest_pipe_index = pipe_connect->dst_pipe_index;
- if (pipe_dir == USB_TO_PEER_PERIPHERAL) {
- connection->mode = SPS_MODE_SRC;
- *usb_pipe_idx = connection->src_pipe_index;
+ if (dir == USB_TO_PEER_PERIPHERAL) {
+ sps_connection->mode = SPS_MODE_SRC;
+ *usb_pipe_idx = pipe_connect->src_pipe_index;
} else {
- connection->mode = SPS_MODE_DEST;
- *usb_pipe_idx = connection->dest_pipe_index;
+ sps_connection->mode = SPS_MODE_DEST;
+ *usb_pipe_idx = pipe_connect->dst_pipe_index;
}
/* If BAM is using dedicated SPS pipe memory, get it */
- if (pipe_connection->mem_type == SPS_PIPE_MEM) {
+ if (pipe_connect->mem_type == SPS_PIPE_MEM) {
pr_debug("%s: USB BAM using SPS pipe memory\n", __func__);
ret = sps_setup_bam2bam_fifo(
- &data_mem_buf[conn_idx][pipe_dir],
- pipe_connection->data_fifo_base_offset,
- pipe_connection->data_fifo_size, 1);
+ data_buf,
+ pipe_connect->data_fifo_base_offset,
+ pipe_connect->data_fifo_size, 1);
if (ret) {
pr_err("%s: data fifo setup failure %d\n", __func__,
ret);
@@ -142,90 +169,84 @@
}
ret = sps_setup_bam2bam_fifo(
- &desc_mem_buf[conn_idx][pipe_dir],
- pipe_connection->desc_fifo_base_offset,
- pipe_connection->desc_fifo_size, 1);
+ desc_buf,
+ pipe_connect->desc_fifo_base_offset,
+ pipe_connect->desc_fifo_size, 1);
if (ret) {
pr_err("%s: desc. fifo setup failure %d\n", __func__,
ret);
goto free_sps_endpoint;
}
- } else if (pipe_connection->mem_type == USB_PRIVATE_MEM) {
+ } else if (pipe_connect->mem_type == USB_PRIVATE_MEM) {
pr_debug("%s: USB BAM using private memory\n", __func__);
- if (IS_ERR(mem_clk) || IS_ERR(mem_iface_clk)) {
+ if (IS_ERR(ctx.mem_clk) || IS_ERR(ctx.mem_iface_clk)) {
pr_err("%s: Failed to enable USB mem_clk\n", __func__);
- ret = IS_ERR(mem_clk);
+ ret = IS_ERR(ctx.mem_clk);
goto free_sps_endpoint;
}
- clk_prepare_enable(mem_clk);
- clk_prepare_enable(mem_iface_clk);
+ clk_prepare_enable(ctx.mem_clk);
+ clk_prepare_enable(ctx.mem_iface_clk);
/*
* Enable USB PRIVATE RAM to be used for BAM FIFOs
* HSUSB: Only RAM13 is used for BAM FIFOs
* SSUSB: RAM11, 12, 13 are used for BAM FIFOs
*/
- if (pdata->usb_active_bam == HSUSB_BAM)
+ bam = pipe_connect->bam_type;
+ if (bam < 0)
+ goto free_sps_endpoint;
+
+ if (bam == HSUSB_BAM)
ram1_value = 0x4;
else
ram1_value = 0x7;
pr_debug("Writing 0x%x to QSCRATCH_RAM1\n", ram1_value);
- writel_relaxed(ram1_value, qscratch_ram1_reg);
+ writel_relaxed(ram1_value, ctx.qscratch_ram1_reg);
- data_mem_buf[conn_idx][pipe_dir].phys_base =
- pipe_connection->data_fifo_base_offset +
+ data_buf->phys_base =
+ pipe_connect->data_fifo_base_offset +
pdata->usb_base_address;
- data_mem_buf[conn_idx][pipe_dir].size =
- pipe_connection->data_fifo_size;
- data_mem_buf[conn_idx][pipe_dir].base =
- ioremap(data_mem_buf[conn_idx][pipe_dir].phys_base,
- data_mem_buf[conn_idx][pipe_dir].size);
- memset(data_mem_buf[conn_idx][pipe_dir].base, 0,
- data_mem_buf[conn_idx][pipe_dir].size);
+ data_buf->size = pipe_connect->data_fifo_size;
+ data_buf->base =
+ ioremap(data_buf->phys_base, data_buf->size);
+ memset(data_buf->base, 0, data_buf->size);
- desc_mem_buf[conn_idx][pipe_dir].phys_base =
- pipe_connection->desc_fifo_base_offset +
+ desc_buf->phys_base =
+ pipe_connect->desc_fifo_base_offset +
pdata->usb_base_address;
- desc_mem_buf[conn_idx][pipe_dir].size =
- pipe_connection->desc_fifo_size;
- desc_mem_buf[conn_idx][pipe_dir].base =
- ioremap(desc_mem_buf[conn_idx][pipe_dir].phys_base,
- desc_mem_buf[conn_idx][pipe_dir].size);
- memset(desc_mem_buf[conn_idx][pipe_dir].base, 0,
- desc_mem_buf[conn_idx][pipe_dir].size);
+ desc_buf->size = pipe_connect->desc_fifo_size;
+ desc_buf->base =
+ ioremap(desc_buf->phys_base, desc_buf->size);
+ memset(desc_buf->base, 0, desc_buf->size);
} else {
pr_debug("%s: USB BAM using system memory\n", __func__);
/* BAM would use system memory, allocate FIFOs */
- data_mem_buf[conn_idx][pipe_dir].size =
- pipe_connection->data_fifo_size;
- data_mem_buf[conn_idx][pipe_dir].base =
- dma_alloc_coherent(&usb_bam_pdev->dev,
- pipe_connection->data_fifo_size,
- &data_mem_buf[conn_idx][pipe_dir].phys_base,
- 0);
- memset(data_mem_buf[conn_idx][pipe_dir].base, 0,
- pipe_connection->data_fifo_size);
+ data_buf->size = pipe_connect->data_fifo_size;
+ data_buf->base =
+ dma_alloc_coherent(&ctx.usb_bam_pdev->dev,
+ pipe_connect->data_fifo_size,
+ &(data_buf->phys_base),
+ 0);
+ memset(data_buf->base, 0, pipe_connect->data_fifo_size);
- desc_mem_buf[conn_idx][pipe_dir].size =
- pipe_connection->desc_fifo_size;
- desc_mem_buf[conn_idx][pipe_dir].base =
- dma_alloc_coherent(&usb_bam_pdev->dev,
- pipe_connection->desc_fifo_size,
- &desc_mem_buf[conn_idx][pipe_dir].phys_base,
- 0);
- memset(desc_mem_buf[conn_idx][pipe_dir].base, 0,
- pipe_connection->desc_fifo_size);
+ desc_buf->size = pipe_connect->desc_fifo_size;
+ desc_buf->base =
+ dma_alloc_coherent(&ctx.usb_bam_pdev->dev,
+ pipe_connect->desc_fifo_size,
+ &(desc_buf->phys_base),
+ 0);
+ memset(desc_buf->base, 0, pipe_connect->desc_fifo_size);
}
- connection->data = data_mem_buf[conn_idx][pipe_dir];
- connection->desc = desc_mem_buf[conn_idx][pipe_dir];
- connection->event_thresh = 16;
- connection->options = SPS_O_AUTO_ENABLE;
+ sps_connection->data = *data_buf;
+ sps_connection->desc = *desc_buf;
+ sps_connection->event_thresh = 16;
+ sps_connection->options = SPS_O_AUTO_ENABLE;
- ret = sps_connect(*pipe, connection);
+ ret = sps_connect(*pipe, sps_connection);
if (ret < 0) {
pr_err("%s: sps_connect failed %d\n", __func__, ret);
goto error;
@@ -239,20 +260,15 @@
return ret;
}
-static int connect_pipe_ipa(
- struct usb_bam_connect_ipa_params *connection_params)
+static int connect_pipe_ipa(u8 idx,
+ struct usb_bam_connect_ipa_params *ipa_params)
{
int ret;
- u8 conn_idx = connection_params->idx;
- enum usb_bam_pipe_dir pipe_dir = connection_params->dir;
- struct sps_pipe **pipe = &sps_pipes[conn_idx][pipe_dir];
- struct sps_connect *connection =
- &sps_connections[conn_idx][pipe_dir];
- struct msm_usb_bam_platform_data *pdata =
- usb_bam_pdev->dev.platform_data;
- struct usb_bam_pipe_connect *pipe_connection =
- &msm_usb_bam_connections_info
- [pdata->usb_active_bam][conn_idx][pipe_dir];
+ struct usb_bam_sps_type usb_bam_sps = ctx.usb_bam_sps;
+ enum usb_bam_pipe_dir dir = ipa_params->dir;
+ struct sps_pipe **pipe = &(usb_bam_sps.sps_pipes[idx]);
+ struct sps_connect *sps_connection = &usb_bam_sps.sps_connections[idx];
+ struct usb_bam_pipe_connect *pipe_connect = &usb_bam_connections[idx];
struct ipa_connect_params ipa_in_params;
struct ipa_sps_params sps_out_params;
@@ -262,12 +278,12 @@
memset(&ipa_in_params, 0, sizeof(ipa_in_params));
memset(&sps_out_params, 0, sizeof(sps_out_params));
- if (pipe_dir == USB_TO_PEER_PERIPHERAL) {
- usb_phy_addr = pipe_connection->src_phy_addr;
- ipa_in_params.client_ep_idx = pipe_connection->src_pipe_index;
+ if (dir == USB_TO_PEER_PERIPHERAL) {
+ usb_phy_addr = pipe_connect->src_phy_addr;
+ ipa_in_params.client_ep_idx = pipe_connect->src_pipe_index;
} else {
- usb_phy_addr = pipe_connection->dst_phy_addr;
- ipa_in_params.client_ep_idx = pipe_connection->dst_pipe_index;
+ usb_phy_addr = pipe_connect->dst_phy_addr;
+ ipa_in_params.client_ep_idx = pipe_connect->dst_pipe_index;
}
/* Get HSUSB / HSIC bam handle */
ret = sps_phy2h(usb_phy_addr, &usb_handle);
@@ -279,46 +295,41 @@
/* IPA input parameters */
ipa_in_params.client_bam_hdl = usb_handle;
- ipa_in_params.desc_fifo_sz = pipe_connection->desc_fifo_size;
- ipa_in_params.data_fifo_sz = pipe_connection->data_fifo_size;
- ipa_in_params.notify = connection_params->notify;
- ipa_in_params.priv = connection_params->priv;
- ipa_in_params.client = connection_params->client;
+ ipa_in_params.desc_fifo_sz = pipe_connect->desc_fifo_size;
+ ipa_in_params.data_fifo_sz = pipe_connect->data_fifo_size;
+ ipa_in_params.notify = ipa_params->notify;
+ ipa_in_params.priv = ipa_params->priv;
+ ipa_in_params.client = ipa_params->client;
/* If BAM is using dedicated SPS pipe memory, get it */
- if (pipe_connection->mem_type == SPS_PIPE_MEM) {
+ if (pipe_connect->mem_type == SPS_PIPE_MEM) {
pr_debug("%s: USB BAM using SPS pipe memory\n", __func__);
ret = sps_setup_bam2bam_fifo(
- &data_mem_buf[conn_idx][pipe_dir],
- pipe_connection->data_fifo_base_offset,
- pipe_connection->data_fifo_size, 1);
+ &pipe_connect->data_mem_buf,
+ pipe_connect->data_fifo_base_offset,
+ pipe_connect->data_fifo_size, 1);
if (ret) {
- pr_err("%s: data fifo setup failure %d\n", __func__,
- ret);
+ pr_err("%s: data fifo setup failure %d\n",
+ __func__, ret);
return ret;
}
ret = sps_setup_bam2bam_fifo(
- &desc_mem_buf[conn_idx][pipe_dir],
- pipe_connection->desc_fifo_base_offset,
- pipe_connection->desc_fifo_size, 1);
+ &pipe_connect->desc_mem_buf,
+ pipe_connect->desc_fifo_base_offset,
+ pipe_connect->desc_fifo_size, 1);
if (ret) {
- pr_err("%s: desc. fifo setup failure %d\n", __func__,
- ret);
+ pr_err("%s: desc. fifo setup failure %d\n",
+ __func__, ret);
return ret;
}
- } else {
- pr_err("%s: unsupported memory type(%d)\n",
- __func__, pipe_connection->mem_type);
- return -EINVAL;
+ ipa_in_params.desc = pipe_connect->desc_mem_buf;
+ ipa_in_params.data = pipe_connect->data_mem_buf;
}
- ipa_in_params.desc = desc_mem_buf[conn_idx][pipe_dir];
- ipa_in_params.data = data_mem_buf[conn_idx][pipe_dir];
-
- memcpy(&ipa_in_params.ipa_ep_cfg, &connection_params->ipa_ep_cfg,
+ memcpy(&ipa_in_params.ipa_ep_cfg, &ipa_params->ipa_ep_cfg,
sizeof(struct ipa_ep_cfg));
ret = ipa_connect(&ipa_in_params, &sps_out_params, &clnt_hdl);
@@ -334,38 +345,48 @@
goto disconnect_ipa;
}
- ret = sps_get_config(*pipe, connection);
+ ret = sps_get_config(*pipe, sps_connection);
if (ret) {
pr_err("%s: tx get config failed %d\n", __func__, ret);
goto free_sps_endpoints;
}
- if (pipe_dir == USB_TO_PEER_PERIPHERAL) {
+ if (dir == USB_TO_PEER_PERIPHERAL) {
/* USB src IPA dest */
- connection->mode = SPS_MODE_SRC;
- connection_params->cons_clnt_hdl = clnt_hdl;
- connection->source = usb_handle;
- connection->destination = sps_out_params.ipa_bam_hdl;
- connection->src_pipe_index = pipe_connection->src_pipe_index;
- connection->dest_pipe_index = sps_out_params.ipa_ep_idx;
- *(connection_params->src_pipe) = connection->src_pipe_index;
+ sps_connection->mode = SPS_MODE_SRC;
+ ipa_params->cons_clnt_hdl = clnt_hdl;
+ sps_connection->source = usb_handle;
+ sps_connection->destination = sps_out_params.ipa_bam_hdl;
+ sps_connection->src_pipe_index = pipe_connect->src_pipe_index;
+ sps_connection->dest_pipe_index = sps_out_params.ipa_ep_idx;
+ *(ipa_params->src_pipe) = sps_connection->src_pipe_index;
+ pipe_connect->dst_pipe_index = sps_out_params.ipa_ep_idx;
+ pr_debug("%s: BAM pipe usb[%x]->ipa[%x] connection\n",
+ __func__,
+ pipe_connect->src_pipe_index,
+ pipe_connect->dst_pipe_index);
} else {
/* IPA src, USB dest */
- connection->mode = SPS_MODE_DEST;
- connection_params->prod_clnt_hdl = clnt_hdl;
- connection->source = sps_out_params.ipa_bam_hdl;
- connection->destination = usb_handle;
- connection->src_pipe_index = sps_out_params.ipa_ep_idx;
- connection->dest_pipe_index = pipe_connection->dst_pipe_index;
- *(connection_params->dst_pipe) = connection->dest_pipe_index;
+ sps_connection->mode = SPS_MODE_DEST;
+ ipa_params->prod_clnt_hdl = clnt_hdl;
+ sps_connection->source = sps_out_params.ipa_bam_hdl;
+ sps_connection->destination = usb_handle;
+ sps_connection->src_pipe_index = sps_out_params.ipa_ep_idx;
+ sps_connection->dest_pipe_index = pipe_connect->dst_pipe_index;
+ *(ipa_params->dst_pipe) = sps_connection->dest_pipe_index;
+ pipe_connect->src_pipe_index = sps_out_params.ipa_ep_idx;
+ pr_debug("%s: BAM pipe ipa[%x]->usb[%x] connection\n",
+ __func__,
+ pipe_connect->src_pipe_index,
+ pipe_connect->dst_pipe_index);
}
- connection->data = sps_out_params.data;
- connection->desc = sps_out_params.desc;
- connection->event_thresh = 16;
- connection->options = SPS_O_AUTO_ENABLE;
+ sps_connection->data = sps_out_params.data;
+ sps_connection->desc = sps_out_params.desc;
+ sps_connection->event_thresh = 16;
+ sps_connection->options = SPS_O_AUTO_ENABLE;
- ret = sps_connect(*pipe, connection);
+ ret = sps_connect(*pipe, sps_connection);
if (ret < 0) {
pr_err("%s: sps_connect failed %d\n", __func__, ret);
goto error;
@@ -382,92 +403,85 @@
return ret;
}
-static int disconnect_pipe(u8 connection_idx, enum usb_bam_pipe_dir pipe_dir)
+static int disconnect_pipe(u8 idx)
{
- struct msm_usb_bam_platform_data *pdata =
- usb_bam_pdev->dev.platform_data;
- struct usb_bam_pipe_connect *pipe_connection =
- &msm_usb_bam_connections_info
- [pdata->usb_active_bam][connection_idx][pipe_dir];
- struct sps_pipe *pipe = sps_pipes[connection_idx][pipe_dir];
- struct sps_connect *connection =
- &sps_connections[connection_idx][pipe_dir];
+ struct usb_bam_pipe_connect *pipe_connect =
+ &usb_bam_connections[idx];
+ struct sps_pipe *pipe = ctx.usb_bam_sps.sps_pipes[idx];
+ struct sps_connect *sps_connection =
+ &ctx.usb_bam_sps.sps_connections[idx];
sps_disconnect(pipe);
sps_free_endpoint(pipe);
- if (pipe_connection->mem_type == SYSTEM_MEM) {
+ if (pipe_connect->mem_type == SYSTEM_MEM) {
pr_debug("%s: Freeing system memory used by PIPE\n", __func__);
- dma_free_coherent(&usb_bam_pdev->dev, connection->data.size,
- connection->data.base, connection->data.phys_base);
- dma_free_coherent(&usb_bam_pdev->dev, connection->desc.size,
- connection->desc.base, connection->desc.phys_base);
- } else if (pipe_connection->mem_type == USB_PRIVATE_MEM) {
+ if (sps_connection->data.phys_base)
+ dma_free_coherent(&ctx.usb_bam_pdev->dev,
+ sps_connection->data.size,
+ sps_connection->data.base,
+ sps_connection->data.phys_base);
+ if (sps_connection->desc.phys_base)
+ dma_free_coherent(&ctx.usb_bam_pdev->dev,
+ sps_connection->desc.size,
+ sps_connection->desc.base,
+ sps_connection->desc.phys_base);
+ } else if (pipe_connect->mem_type == USB_PRIVATE_MEM) {
pr_debug("Freeing USB private memory used by BAM PIPE\n");
- writel_relaxed(0x0, qscratch_ram1_reg);
- iounmap(connection->data.base);
- iounmap(connection->desc.base);
- clk_disable_unprepare(mem_clk);
- clk_disable_unprepare(mem_iface_clk);
+ writel_relaxed(0x0, ctx.qscratch_ram1_reg);
+ iounmap(sps_connection->data.base);
+ iounmap(sps_connection->desc.base);
+ clk_disable_unprepare(ctx.mem_clk);
+ clk_disable_unprepare(ctx.mem_iface_clk);
}
- connection->options &= ~SPS_O_AUTO_ENABLE;
+ sps_connection->options &= ~SPS_O_AUTO_ENABLE;
return 0;
}
-int usb_bam_connect(u8 idx, u32 *src_pipe_idx, u32 *dst_pipe_idx)
+int usb_bam_connect(u8 idx, u32 *bam_pipe_idx)
{
- struct usb_bam_connect_info *connection = &usb_bam_connections[idx];
- struct msm_usb_bam_platform_data *pdata =
- usb_bam_pdev->dev.platform_data;
- int usb_active_bam = pdata->usb_active_bam;
int ret;
+ enum usb_bam bam;
+ struct usb_bam_pipe_connect *pipe_connect = &usb_bam_connections[idx];
+ struct msm_usb_bam_platform_data *pdata;
- if (!usb_bam_pdev) {
+ if (!ctx.usb_bam_pdev) {
pr_err("%s: usb_bam device not found\n", __func__);
return -ENODEV;
}
- if (idx >= CONNECTIONS_NUM) {
- pr_err("%s: Invalid connection index\n",
- __func__);
- return -EINVAL;
- }
+ pdata = ctx.usb_bam_pdev->dev.platform_data;
- if (connection->src_enabled && connection->dst_enabled) {
+ if (pipe_connect->enabled) {
pr_debug("%s: connection %d was already established\n",
__func__, idx);
return 0;
}
- connection->src_pipe = src_pipe_idx;
- connection->dst_pipe = dst_pipe_idx;
- connection->idx = idx;
+
+ if (!bam_pipe_idx) {
+ pr_err("%s: invalid bam_pipe_idx\n", __func__);
+ return -EINVAL;
+ }
+ if (idx < 0 || idx > ctx.max_connections) {
+ pr_err("idx is wrong %d", idx);
+ return -EINVAL;
+ }
+ bam = pipe_connect->bam_type;
+ if (bam < 0)
+ return -EINVAL;
/* Check if BAM requires RESET before connect */
- if (pdata->reset_on_connect[usb_active_bam] == true)
- sps_device_reset(h_bam);
+ if (pdata->reset_on_connect[bam] == true)
+ sps_device_reset(ctx.h_bam[bam]);
- if (src_pipe_idx) {
- /* open USB -> Peripheral pipe */
- ret = connect_pipe(connection->idx, USB_TO_PEER_PERIPHERAL,
- connection->src_pipe);
- if (ret) {
- pr_err("%s: src pipe connection failure\n", __func__);
- return ret;
- }
- connection->src_enabled = 1;
+ ret = connect_pipe(idx, bam_pipe_idx);
+ if (ret) {
+ pr_err("%s: pipe connection[%d] failure\n", __func__, idx);
+ return ret;
}
- if (dst_pipe_idx) {
- /* open Peripheral -> USB pipe */
- ret = connect_pipe(connection->idx, PEER_PERIPHERAL_TO_USB,
- connection->dst_pipe);
- if (ret) {
- pr_err("%s: dst pipe connection failure\n", __func__);
- return ret;
- }
- connection->dst_enabled = 1;
- }
+ pipe_connect->enabled = 1;
return 0;
}
@@ -531,64 +545,65 @@
int usb_bam_connect_ipa(struct usb_bam_connect_ipa_params *ipa_params)
{
- u8 idx = ipa_params->idx;
- struct usb_bam_connect_info *connection = &usb_bam_connections[idx];
+ u8 idx;
+ struct usb_bam_pipe_connect *pipe_connect;
int ret;
- if (idx >= CONNECTIONS_NUM) {
- pr_err("%s: Invalid connection index\n",
+ if (!ipa_params) {
+ pr_err("%s: Invalid ipa params\n",
__func__);
return -EINVAL;
}
- if ((connection->src_enabled &&
- ipa_params->dir == USB_TO_PEER_PERIPHERAL) ||
- (connection->dst_enabled &&
- ipa_params->dir == PEER_PERIPHERAL_TO_USB)) {
+ if (ipa_params->dir == USB_TO_PEER_PERIPHERAL)
+ idx = ipa_params->src_idx;
+ else
+ idx = ipa_params->dst_idx;
+
+ if (idx >= ctx.max_connections) {
+ pr_err("%s: Invalid connection index\n",
+ __func__);
+ return -EINVAL;
+ }
+ pipe_connect = &usb_bam_connections[idx];
+
+ if (pipe_connect->enabled) {
pr_debug("%s: connection %d was already established\n",
__func__, idx);
return 0;
}
- if (ipa_params->dir == USB_TO_PEER_PERIPHERAL)
- connection->src_pipe = ipa_params->src_pipe;
- else
- connection->dst_pipe = ipa_params->dst_pipe;
-
- connection->idx = idx;
-
+ ret = connect_pipe_ipa(idx, ipa_params);
ipa_rm_request_resource(IPA_CLIENT_USB_PROD);
- ret = connect_pipe_ipa(ipa_params);
if (ret) {
pr_err("%s: dst pipe connection failure\n", __func__);
return ret;
}
- if (ipa_params->dir == USB_TO_PEER_PERIPHERAL)
- connection->src_enabled = 1;
- else
- connection->dst_enabled = 1;
+ pipe_connect->enabled = 1;
return 0;
}
+EXPORT_SYMBOL(usb_bam_connect_ipa);
int usb_bam_client_ready(bool ready)
{
spin_lock(&usb_bam_lock);
- if (peer_handhskae_info.client_ready == ready) {
+ if (peer_handshake_info.client_ready == ready) {
pr_debug("%s: client state is already %d\n",
__func__, ready);
spin_unlock(&usb_bam_lock);
return 0;
}
- peer_handhskae_info.client_ready = ready;
+ peer_handshake_info.client_ready = ready;
spin_unlock(&usb_bam_lock);
- if (!queue_work(usb_bam_wq, &peer_handhskae_info.reset_event.event_w)) {
+ if (!queue_work(ctx.usb_bam_wq,
+ &peer_handshake_info.reset_event.event_w)) {
spin_lock(&usb_bam_lock);
- peer_handhskae_info.pending_work++;
+ peer_handshake_info.pending_work++;
spin_unlock(&usb_bam_lock);
}
@@ -608,65 +623,65 @@
struct usb_bam_event_info *wake_event_info =
(struct usb_bam_event_info *)notify->user;
- queue_work(usb_bam_wq, &wake_event_info->event_w);
+ queue_work(ctx.usb_bam_wq, &wake_event_info->event_w);
}
static void usb_bam_sm_work(struct work_struct *w)
{
pr_debug("%s: current state: %d\n", __func__,
- peer_handhskae_info.state);
+ peer_handshake_info.state);
spin_lock(&usb_bam_lock);
- switch (peer_handhskae_info.state) {
+ switch (peer_handshake_info.state) {
case USB_BAM_SM_INIT:
- if (peer_handhskae_info.client_ready) {
+ if (peer_handshake_info.client_ready) {
spin_unlock(&usb_bam_lock);
smsm_change_state(SMSM_APPS_STATE, 0,
SMSM_USB_PLUG_UNPLUG);
spin_lock(&usb_bam_lock);
- peer_handhskae_info.state = USB_BAM_SM_PLUG_NOTIFIED;
+ peer_handshake_info.state = USB_BAM_SM_PLUG_NOTIFIED;
}
break;
case USB_BAM_SM_PLUG_NOTIFIED:
- if (peer_handhskae_info.ack_received) {
- peer_handhskae_info.state = USB_BAM_SM_PLUG_ACKED;
- peer_handhskae_info.ack_received = 0;
+ if (peer_handshake_info.ack_received) {
+ peer_handshake_info.state = USB_BAM_SM_PLUG_ACKED;
+ peer_handshake_info.ack_received = 0;
}
break;
case USB_BAM_SM_PLUG_ACKED:
- if (!peer_handhskae_info.client_ready) {
+ if (!peer_handshake_info.client_ready) {
spin_unlock(&usb_bam_lock);
smsm_change_state(SMSM_APPS_STATE,
SMSM_USB_PLUG_UNPLUG, 0);
spin_lock(&usb_bam_lock);
- peer_handhskae_info.state = USB_BAM_SM_UNPLUG_NOTIFIED;
+ peer_handshake_info.state = USB_BAM_SM_UNPLUG_NOTIFIED;
}
break;
case USB_BAM_SM_UNPLUG_NOTIFIED:
- if (peer_handhskae_info.ack_received) {
+ if (peer_handshake_info.ack_received) {
spin_unlock(&usb_bam_lock);
- peer_handhskae_info.reset_event.
- callback(peer_handhskae_info.reset_event.param);
+ peer_handshake_info.reset_event.
+ callback(peer_handshake_info.reset_event.param);
spin_lock(&usb_bam_lock);
- peer_handhskae_info.state = USB_BAM_SM_INIT;
- peer_handhskae_info.ack_received = 0;
+ peer_handshake_info.state = USB_BAM_SM_INIT;
+ peer_handshake_info.ack_received = 0;
}
break;
}
- if (peer_handhskae_info.pending_work) {
- peer_handhskae_info.pending_work--;
+ if (peer_handshake_info.pending_work) {
+ peer_handshake_info.pending_work--;
spin_unlock(&usb_bam_lock);
- queue_work(usb_bam_wq,
- &peer_handhskae_info.reset_event.event_w);
+ queue_work(ctx.usb_bam_wq,
+ &peer_handshake_info.reset_event.event_w);
spin_lock(&usb_bam_lock);
}
spin_unlock(&usb_bam_lock);
}
-static void usb_bam_ack_toggle_cb(void *priv, uint32_t old_state,
- uint32_t new_state)
+static void usb_bam_ack_toggle_cb(void *priv,
+ uint32_t old_state, uint32_t new_state)
{
static int last_processed_state;
int current_state;
@@ -681,27 +696,35 @@
}
last_processed_state = current_state;
- peer_handhskae_info.ack_received = true;
+ peer_handshake_info.ack_received = true;
spin_unlock(&usb_bam_lock);
- if (!queue_work(usb_bam_wq, &peer_handhskae_info.reset_event.event_w)) {
+ if (!queue_work(ctx.usb_bam_wq,
+ &peer_handshake_info.reset_event.event_w)) {
spin_lock(&usb_bam_lock);
- peer_handhskae_info.pending_work++;
+ peer_handshake_info.pending_work++;
spin_unlock(&usb_bam_lock);
}
}
-int usb_bam_register_wake_cb(u8 idx,
- int (*callback)(void *user), void* param)
+int usb_bam_register_wake_cb(u8 idx, int (*callback)(void *user),
+ void *param)
{
- struct sps_pipe *pipe = sps_pipes[idx][PEER_PERIPHERAL_TO_USB];
- struct sps_connect *sps_connection =
- &sps_connections[idx][PEER_PERIPHERAL_TO_USB];
- struct usb_bam_connect_info *connection = &usb_bam_connections[idx];
- struct usb_bam_event_info *wake_event_info =
- &connection->wake_event;
+ struct sps_pipe *pipe = ctx.usb_bam_sps.sps_pipes[idx];
+ struct sps_connect *sps_connection;
+ struct usb_bam_pipe_connect *pipe_connect;
+ struct usb_bam_event_info *wake_event_info;
int ret;
+ if (idx < 0 || idx > ctx.max_connections) {
+ pr_err("%s:idx is wrong %d", __func__, idx);
+ return -EINVAL;
+ }
+ pipe = ctx.usb_bam_sps.sps_pipes[idx];
+ sps_connection = &ctx.usb_bam_sps.sps_connections[idx];
+ pipe_connect = &usb_bam_connections[idx];
+ wake_event_info = &pipe_connect->wake_event;
+
wake_event_info->param = param;
wake_event_info->callback = callback;
wake_event_info->event.mode = SPS_TRIGGER_CALLBACK;
@@ -717,7 +740,7 @@
sps_connection->options = callback ?
(SPS_O_AUTO_ENABLE | SPS_O_WAKEUP | SPS_O_WAKEUP_IS_ONESHOT) :
- SPS_O_AUTO_ENABLE;
+ SPS_O_AUTO_ENABLE;
ret = sps_set_config(pipe, sps_connection);
if (ret) {
pr_err("%s: sps_set_config() failed %d\n", __func__, ret);
@@ -727,14 +750,13 @@
return 0;
}
-int usb_bam_register_peer_reset_cb(u8 idx,
- int (*callback)(void *), void *param)
+int usb_bam_register_peer_reset_cb(int (*callback)(void *), void *param)
{
u32 ret = 0;
if (callback) {
- peer_handhskae_info.reset_event.param = param;
- peer_handhskae_info.reset_event.callback = callback;
+ peer_handshake_info.reset_event.param = param;
+ peer_handshake_info.reset_event.callback = callback;
ret = smsm_state_cb_register(SMSM_MODEM_STATE,
SMSM_USB_PLUG_UNPLUG, usb_bam_ack_toggle_cb, NULL);
@@ -748,8 +770,8 @@
SMSM_USB_PLUG_UNPLUG);
}
} else {
- peer_handhskae_info.reset_event.param = NULL;
- peer_handhskae_info.reset_event.callback = NULL;
+ peer_handshake_info.reset_event.param = NULL;
+ peer_handshake_info.reset_event.callback = NULL;
smsm_state_cb_deregister(SMSM_MODEM_STATE,
SMSM_USB_PLUG_UNPLUG, usb_bam_ack_toggle_cb, NULL);
}
@@ -759,126 +781,129 @@
int usb_bam_disconnect_pipe(u8 idx)
{
- struct usb_bam_connect_info *connection = &usb_bam_connections[idx];
+ struct usb_bam_pipe_connect *pipe_connect;
int ret;
- if (idx >= CONNECTIONS_NUM) {
- pr_err("%s: Invalid connection index\n",
- __func__);
- return -EINVAL;
- }
+ pipe_connect = &usb_bam_connections[idx];
- if (!connection->src_enabled && !connection->dst_enabled) {
+ if (!pipe_connect->enabled) {
pr_debug("%s: connection %d isn't enabled\n",
__func__, idx);
return 0;
}
- if (connection->src_enabled) {
- /* close USB -> Peripheral pipe */
- ret = disconnect_pipe(connection->idx, USB_TO_PEER_PERIPHERAL);
- if (ret) {
- pr_err("%s: src pipe connection failure\n", __func__);
- return ret;
- }
- connection->src_enabled = 0;
- }
- if (connection->dst_enabled) {
- /* close Peripheral -> USB pipe */
- ret = disconnect_pipe(connection->idx, PEER_PERIPHERAL_TO_USB);
- if (ret) {
- pr_err("%s: dst pipe connection failure\n", __func__);
- return ret;
- }
- connection->dst_enabled = 0;
+ ret = disconnect_pipe(idx);
+ if (ret) {
+ pr_err("%s: src pipe connection failure\n", __func__);
+ return ret;
}
- connection->src_pipe = 0;
- connection->dst_pipe = 0;
+ pipe_connect->enabled = 0;
return 0;
}
-int usb_bam_disconnect_ipa(u8 idx,
- struct usb_bam_connect_ipa_params *ipa_params)
+int usb_bam_disconnect_ipa(struct usb_bam_connect_ipa_params *ipa_params)
{
- struct usb_bam_connect_info *connection = &usb_bam_connections[idx];
int ret;
+ u8 idx;
+ struct usb_bam_pipe_connect *pipe_connect;
+ struct sps_connect *sps_connection;
- if (!usb_bam_pdev) {
- pr_err("%s: usb_bam device not found\n", __func__);
- return -ENODEV;
- }
-
- if (idx >= CONNECTIONS_NUM) {
- pr_err("%s: Invalid connection index\n",
- __func__);
- return -EINVAL;
- }
-
- /* Currently just calls ipa_disconnect, no sps pipes
- disconenction support */
-
- /* close IPA -> USB pipe */
- if (connection->dst_pipe) {
+ if (ipa_params->prod_clnt_hdl) {
+ /* close USB -> IPA pipe */
+ idx = ipa_params->dst_idx;
ret = ipa_disconnect(ipa_params->prod_clnt_hdl);
if (ret) {
pr_err("%s: dst pipe disconnection failure\n",
__func__);
return ret;
}
+ pipe_connect = &usb_bam_connections[idx];
+ sps_connection = &ctx.usb_bam_sps.sps_connections[idx];
+ sps_connection->data.phys_base = 0;
+ sps_connection->desc.phys_base = 0;
+
+ ret = usb_bam_disconnect_pipe(idx);
+ if (ret) {
+ pr_err("%s: failure to disconnect pipe %d\n",
+ __func__, idx);
+ return ret;
+ }
}
- /* close USB -> IPA pipe */
- if (connection->src_pipe) {
+ if (ipa_params->cons_clnt_hdl) {
+ /* close IPA -> USB pipe */
+ idx = ipa_params->src_idx;
ret = ipa_disconnect(ipa_params->cons_clnt_hdl);
if (ret) {
pr_err("%s: src pipe disconnection failure\n",
__func__);
return ret;
}
+ pipe_connect = &usb_bam_connections[idx];
+ sps_connection = &ctx.usb_bam_sps.sps_connections[idx];
+ sps_connection->data.phys_base = 0;
+ sps_connection->desc.phys_base = 0;
+
+ ret = usb_bam_disconnect_pipe(idx);
+ if (ret) {
+ pr_err("%s: failure to disconnect pipe %d\n",
+ __func__, idx);
+ return ret;
+ }
}
ipa_rm_release_resource(IPA_CLIENT_USB_PROD);
return 0;
-
}
+EXPORT_SYMBOL(usb_bam_disconnect_ipa);
-int usb_bam_reset(void)
+int usb_bam_a2_reset(void)
{
- struct usb_bam_connect_info *connection;
+ struct usb_bam_pipe_connect *pipe_connect;
int i;
int ret = 0, ret_int;
- bool reconnect[CONNECTIONS_NUM];
- u32 *reconnect_src_pipe[CONNECTIONS_NUM];
- u32 *reconnect_dst_pipe[CONNECTIONS_NUM];
+ u8 bam = -1;
+ int reconnect_pipe_idx[ctx.max_connections];
- /* Disconnect all pipes */
- for (i = 0; i < CONNECTIONS_NUM; i++) {
- connection = &usb_bam_connections[i];
- reconnect[i] = connection->src_enabled ||
- connection->dst_enabled;
- reconnect_src_pipe[i] = connection->src_pipe;
- reconnect_dst_pipe[i] = connection->dst_pipe;
+ for (i = 0; i < ctx.max_connections; i++)
+ reconnect_pipe_idx[i] = -1;
- ret_int = usb_bam_disconnect_pipe(i);
- if (ret_int) {
- pr_err("%s: failure to connect pipe %d\n",
- __func__, i);
- ret = ret_int;
- continue;
+ /* Disconnect a2 pipes */
+ for (i = 0; i < ctx.max_connections; i++) {
+ pipe_connect = &usb_bam_connections[i];
+ if (strnstr(pipe_connect->name, "a2", USB_BAM_MAX_STR_LEN) &&
+ pipe_connect->enabled) {
+ if (pipe_connect->dir == USB_TO_PEER_PERIPHERAL)
+ reconnect_pipe_idx[i] =
+ pipe_connect->src_pipe_index;
+ else
+ reconnect_pipe_idx[i] =
+ pipe_connect->dst_pipe_index;
+
+ bam = pipe_connect->bam_type;
+ if (bam < 0) {
+ ret = -EINVAL;
+ continue;
+ }
+ ret_int = usb_bam_disconnect_pipe(i);
+ if (ret_int) {
+ pr_err("%s: failure to connect pipe %d\n",
+ __func__, i);
+ ret = ret_int;
+ continue;
+ }
}
}
-
- /* Reset USB/HSIC BAM */
- if (sps_device_reset(h_bam))
+ /* Reset A2 (USB/HSIC) BAM */
+ if (bam != -1 && sps_device_reset(ctx.h_bam[bam]))
pr_err("%s: BAM reset failed\n", __func__);
- /* Reconnect all pipes */
- for (i = 0; i < CONNECTIONS_NUM; i++) {
- connection = &usb_bam_connections[i];
- if (reconnect[i]) {
- ret_int = usb_bam_connect(i, reconnect_src_pipe[i],
- reconnect_dst_pipe[i]);
+ /* Reconnect A2 pipes */
+ for (i = 0; i < ctx.max_connections; i++) {
+ pipe_connect = &usb_bam_connections[i];
+ if (reconnect_pipe_idx[i] != -1) {
+ ret_int = usb_bam_connect(i, &reconnect_pipe_idx[i]);
if (ret_int) {
pr_err("%s: failure to reconnect pipe %d\n",
__func__, i);
@@ -891,134 +916,23 @@
return ret;
}
-static int update_connections_info(struct device_node *node, int bam,
- int conn_num, int dir, enum usb_pipe_mem_type mem_type)
-{
- u32 rc;
- char *key = NULL;
- uint32_t val = 0;
-
- struct usb_bam_pipe_connect *pipe_connection;
-
- pipe_connection = &msm_usb_bam_connections_info[bam][conn_num][dir];
-
- pipe_connection->mem_type = mem_type;
-
- key = "qcom,src-bam-physical-address";
- rc = of_property_read_u32(node, key, &val);
- if (!rc)
- pipe_connection->src_phy_addr = val;
-
- key = "qcom,src-bam-pipe-index";
- rc = of_property_read_u32(node, key, &val);
- if (!rc)
- pipe_connection->src_pipe_index = val;
-
- key = "qcom,dst-bam-physical-address";
- rc = of_property_read_u32(node, key, &val);
- if (!rc)
- pipe_connection->dst_phy_addr = val;
-
- key = "qcom,dst-bam-pipe-index";
- rc = of_property_read_u32(node, key, &val);
- if (!rc)
- pipe_connection->dst_pipe_index = val;
-
- key = "qcom,data-fifo-offset";
- rc = of_property_read_u32(node, key, &val);
- if (!rc)
- pipe_connection->data_fifo_base_offset = val;
-
- key = "qcom,data-fifo-size";
- rc = of_property_read_u32(node, key, &val);
- if (rc)
- goto err;
- pipe_connection->data_fifo_size = val;
-
- key = "qcom,descriptor-fifo-offset";
- rc = of_property_read_u32(node, key, &val);
- if (!rc)
- pipe_connection->desc_fifo_base_offset = val;
-
- key = "qcom,descriptor-fifo-size";
- rc = of_property_read_u32(node, key, &val);
- if (rc)
- goto err;
- pipe_connection->desc_fifo_size = val;
-
- return 0;
-
-err:
- pr_err("%s: Error in name %s key %s\n", __func__,
- node->full_name, key);
- return -EFAULT;
-}
-
-static int usb_bam_update_conn_array_index(struct platform_device *pdev,
- void *buff, int bam_max, int conn_max, int pipe_dirs)
-{
- int bam_num, conn_num;
- struct usb_bam_pipe_connect *bam_connection_arr = buff;
-
- msm_usb_bam_connections_info = devm_kzalloc(&pdev->dev,
- bam_max * sizeof(struct usb_bam_pipe_connect **),
- GFP_KERNEL);
-
- if (!msm_usb_bam_connections_info)
- return -ENOMEM;
-
- for (bam_num = 0; bam_num < bam_max; bam_num++) {
- msm_usb_bam_connections_info[bam_num] =
- devm_kzalloc(&pdev->dev, conn_max *
- sizeof(struct usb_bam_pipe_connect *),
- GFP_KERNEL);
- if (!msm_usb_bam_connections_info[bam_num])
- return -ENOMEM;
-
- for (conn_num = 0; conn_num < conn_max; conn_num++)
- msm_usb_bam_connections_info[bam_num][conn_num] =
- bam_connection_arr +
- (bam_num * conn_max * pipe_dirs) +
- (conn_num * pipe_dirs);
- }
-
- return 0;
-}
-
static struct msm_usb_bam_platform_data *usb_bam_dt_to_pdata(
struct platform_device *pdev)
{
struct msm_usb_bam_platform_data *pdata;
struct device_node *node = pdev->dev.of_node;
- int conn_num, bam;
- u8 dir;
- u8 ncolumns = 2;
- int bam_amount, rc = 0;
- u32 pipe_entry = 0;
- char *key = NULL;
- enum usb_pipe_mem_type mem_type;
+ int rc = 0;
+ u8 i = 0;
bool reset_bam;
+ enum usb_bam bam;
+ ctx.max_connections = 0;
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata) {
pr_err("unable to allocate platform data\n");
return NULL;
}
- rc = of_property_read_u32(node, "qcom,usb-active-bam",
- &pdata->usb_active_bam);
- if (rc) {
- pr_err("Invalid usb active bam property\n");
- return NULL;
- }
-
- rc = of_property_read_u32(node, "qcom,usb-total-bam-num",
- &pdata->total_bam_num);
- if (rc) {
- pr_err("Invalid usb total bam num property\n");
- return NULL;
- }
-
rc = of_property_read_u32(node, "qcom,usb-bam-num-pipes",
&pdata->usb_bam_num_pipes);
if (rc) {
@@ -1032,91 +946,113 @@
pr_debug("%s: Invalid usb base address property\n", __func__);
pdata->ignore_core_reset_ack = of_property_read_bool(node,
- "qcom,ignore-core-reset-ack");
+ "qcom,ignore-core-reset-ack");
pdata->disable_clk_gating = of_property_read_bool(node,
- "qcom,disable-clk-gating");
+ "qcom,disable-clk-gating");
for_each_child_of_node(pdev->dev.of_node, node)
- pipe_entry++;
+ ctx.max_connections++;
- /*
- * we need to know the number of connection, so we will know
- * how much memory to allocate
- */
- conn_num = pipe_entry / 2;
- bam_amount = pdata->total_bam_num;
-
- if (conn_num <= 0 || conn_num >= pdata->usb_bam_num_pipes)
+ if (!ctx.max_connections) {
+ pr_err("%s: error: max_connections is zero\n", __func__);
goto err;
+ }
-
- /* alloc msm_usb_bam_connections_info */
- bam_connection_arr = devm_kzalloc(&pdev->dev, bam_amount *
- conn_num * ncolumns *
+ usb_bam_connections = devm_kzalloc(&pdev->dev, ctx.max_connections *
sizeof(struct usb_bam_pipe_connect), GFP_KERNEL);
- if (!bam_connection_arr)
- goto err;
-
- rc = usb_bam_update_conn_array_index(pdev, bam_connection_arr,
- bam_amount, conn_num, ncolumns);
- if (rc)
- goto err;
+ if (!usb_bam_connections) {
+ pr_err("%s: devm_kzalloc failed(%d)\n", __func__, __LINE__);
+ return NULL;
+ }
/* retrieve device tree parameters */
for_each_child_of_node(pdev->dev.of_node, node) {
- const char *str;
-
- key = "qcom,usb-bam-type";
- rc = of_property_read_u32(node, key, &bam);
+ rc = of_property_read_string(node, "label",
+ &usb_bam_connections[i].name);
if (rc)
goto err;
- key = "qcom,usb-bam-mem-type";
- rc = of_property_read_u32(node, key, &mem_type);
+ rc = of_property_read_u32(node, "qcom,usb-bam-mem-type",
+ &usb_bam_connections[i].mem_type);
if (rc)
goto err;
- if (mem_type == USB_PRIVATE_MEM &&
- !pdata->usb_base_address)
- goto err;
-
- rc = of_property_read_string(node, "label", &str);
- if (rc) {
- pr_err("Cannot read string\n");
+ if (usb_bam_connections[i].mem_type == USB_PRIVATE_MEM &&
+ !pdata->usb_base_address) {
+ pr_err("%s: base address is missing for private mem\n",
+ __func__);
goto err;
}
+
+ rc = of_property_read_u32(node, "qcom,bam-type",
+ &usb_bam_connections[i].bam_type);
+ if (rc) {
+ pr_err("%s: bam type is missing in device tree\n",
+ __func__);
+ goto err;
+ }
+
+ rc = of_property_read_u32(node, "qcom,peer-bam",
+ &usb_bam_connections[i].peer_bam);
+ if (rc) {
+ pr_err("%s: peer bam is missing in device tree\n",
+ __func__);
+ goto err;
+ }
+ rc = of_property_read_u32(node, "qcom,dir",
+ &usb_bam_connections[i].dir);
+ if (rc) {
+ pr_err("%s: direction is missing in device tree\n",
+ __func__);
+ goto err;
+ }
+
+ rc = of_property_read_u32(node, "qcom,pipe-num",
+ &usb_bam_connections[i].pipe_num);
+ if (rc) {
+ pr_err("%s: pipe num is missing in device tree\n",
+ __func__);
+ goto err;
+ }
+
reset_bam = of_property_read_bool(node,
- "qcom,reset-bam-on-connect");
+ "qcom,reset-bam-on-connect");
if (reset_bam)
pdata->reset_on_connect[bam] = true;
- if (strnstr(str, "usb-to", 30))
- dir = USB_TO_PEER_PERIPHERAL;
- else if (strnstr(str, "to-usb", 30))
- dir = PEER_PERIPHERAL_TO_USB;
- else
- goto err;
+ of_property_read_u32(node, "qcom,src-bam-physical-address",
+ &usb_bam_connections[i].src_phy_addr);
- /* Check if connection type is supported */
- if (!strcmp(str, "usb-to-peri-qdss-dwc3") ||
- !strcmp(str, "peri-to-usb-qdss-dwc3") ||
- !strcmp(str, "usb-to-ipa") ||
- !strcmp(str, "ipa-to-usb") ||
- !strcmp(str, "usb-to-peri-qdss-hsusb") ||
- !strcmp(str, "peri-to-usb-qdss-hsusb"))
- conn_num = 0;
- else
- goto err;
+ of_property_read_u32(node, "qcom,src-bam-pipe-index",
+ &usb_bam_connections[i].src_pipe_index);
- rc = update_connections_info(node, bam, conn_num,
- dir, mem_type);
+ of_property_read_u32(node, "qcom,dst-bam-physical-address",
+ &usb_bam_connections[i].dst_phy_addr);
+
+ of_property_read_u32(node, "qcom,dst-bam-pipe-index",
+ &usb_bam_connections[i].dst_pipe_index);
+
+ of_property_read_u32(node, "qcom,data-fifo-offset",
+ &usb_bam_connections[i].data_fifo_base_offset);
+
+ rc = of_property_read_u32(node, "qcom,data-fifo-size",
+ &usb_bam_connections[i].data_fifo_size);
if (rc)
goto err;
+
+ of_property_read_u32(node, "qcom,descriptor-fifo-offset",
+ &usb_bam_connections[i].desc_fifo_base_offset);
+
+ rc = of_property_read_u32(node, "qcom,descriptor-fifo-size",
+ &usb_bam_connections[i].desc_fifo_size);
+ if (rc)
+ goto err;
+ i++;
}
- pdata->connections = &msm_usb_bam_connections_info[0][0][0];
+ pdata->connections = usb_bam_connections;
return pdata;
err:
@@ -1124,83 +1060,78 @@
return NULL;
}
-static char *bam_enable_strings[3] = {
- [SSUSB_BAM] = "ssusb",
- [HSUSB_BAM] = "hsusb",
- [HSIC_BAM] = "hsic",
-};
-
-static int usb_bam_init(void)
+static int usb_bam_init(int bam_idx)
{
- int ret;
+ int ret, irq;
void *usb_virt_addr;
struct msm_usb_bam_platform_data *pdata =
- usb_bam_pdev->dev.platform_data;
- struct usb_bam_pipe_connect *pipe_connection =
- &msm_usb_bam_connections_info[pdata->usb_active_bam][0][0];
+ ctx.usb_bam_pdev->dev.platform_data;
struct resource *res, *ram_resource;
- int irq;
+ struct sps_bam_props props = ctx.usb_bam_sps.usb_props;
- res = platform_get_resource_byname(usb_bam_pdev, IORESOURCE_MEM,
- bam_enable_strings[pdata->usb_active_bam]);
+ pr_debug("%s: usb_bam_init - %s\n", __func__,
+ bam_enable_strings[bam_idx]);
+ res = platform_get_resource_byname(ctx.usb_bam_pdev, IORESOURCE_MEM,
+ bam_enable_strings[bam_idx]);
if (!res) {
- dev_err(&usb_bam_pdev->dev, "Unable to get memory resource\n");
- return -ENODEV;
+ dev_dbg(&ctx.usb_bam_pdev->dev, "bam not initialized\n");
+ return 0;
}
- irq = platform_get_irq_byname(usb_bam_pdev,
- bam_enable_strings[pdata->usb_active_bam]);
+ irq = platform_get_irq_byname(ctx.usb_bam_pdev,
+ bam_enable_strings[bam_idx]);
if (irq < 0) {
- dev_err(&usb_bam_pdev->dev, "Unable to get IRQ resource\n");
+ dev_err(&ctx.usb_bam_pdev->dev, "Unable to get IRQ resource\n");
return irq;
}
- usb_virt_addr = devm_ioremap(&usb_bam_pdev->dev, res->start,
- resource_size(res));
+ usb_virt_addr = devm_ioremap(&ctx.usb_bam_pdev->dev, res->start,
+ resource_size(res));
if (!usb_virt_addr) {
pr_err("%s: ioremap failed\n", __func__);
return -ENOMEM;
}
/* Check if USB3 pipe memory needs to be enabled */
- if (pipe_connection->mem_type == USB_PRIVATE_MEM) {
+ if (bam_idx == SSUSB_BAM && bam_use_private_mem(bam_idx)) {
pr_debug("%s: Enabling USB private memory for: %s\n", __func__,
- bam_enable_strings[pdata->usb_active_bam]);
+ bam_enable_strings[bam_idx]);
- ram_resource = platform_get_resource_byname(usb_bam_pdev,
- IORESOURCE_MEM, "qscratch_ram1_reg");
+ ram_resource = platform_get_resource_byname(ctx.usb_bam_pdev,
+ IORESOURCE_MEM, "qscratch_ram1_reg");
if (!res) {
- dev_err(&usb_bam_pdev->dev, "Unable to get qscratch\n");
+ dev_err(&ctx.usb_bam_pdev->dev, "Unable to get qscratch\n");
ret = -ENODEV;
goto free_bam_regs;
}
- qscratch_ram1_reg = devm_ioremap(&usb_bam_pdev->dev,
- ram_resource->start,
- resource_size(ram_resource));
- if (!qscratch_ram1_reg) {
+ ctx.qscratch_ram1_reg = devm_ioremap(&ctx.usb_bam_pdev->dev,
+ ram_resource->start,
+ resource_size(ram_resource));
+ if (!ctx.qscratch_ram1_reg) {
pr_err("%s: ioremap failed for qscratch\n", __func__);
ret = -ENOMEM;
goto free_bam_regs;
}
}
- usb_props.phys_addr = res->start;
- usb_props.virt_addr = usb_virt_addr;
- usb_props.virt_size = resource_size(res);
- usb_props.irq = irq;
- usb_props.summing_threshold = USB_SUMMING_THRESHOLD;
- usb_props.event_threshold = 512;
- usb_props.num_pipes = pdata->usb_bam_num_pipes;
+ props.phys_addr = res->start;
+ props.virt_addr = usb_virt_addr;
+ props.virt_size = resource_size(res);
+ props.irq = irq;
+ props.summing_threshold = USB_THRESHOLD;
+ props.event_threshold = USB_THRESHOLD;
+ props.num_pipes = pdata->usb_bam_num_pipes;
/*
- * HSUSB and HSIC Cores don't support RESET ACK signal to BAMs
- * Hence, let BAM to ignore acknowledge from USB while resetting PIPE
- */
- if (pdata->ignore_core_reset_ack && pdata->usb_active_bam != SSUSB_BAM)
- usb_props.options = SPS_BAM_NO_EXT_P_RST;
- if (pdata->disable_clk_gating)
- usb_props.options |= SPS_BAM_NO_LOCAL_CLK_GATING;
+ * HSUSB and HSIC Cores don't support RESET ACK signal to BAMs
+ * Hence, let BAM to ignore acknowledge from USB while resetting PIPE
+ */
+ if (pdata->ignore_core_reset_ack && bam_idx != SSUSB_BAM)
+ props.options = SPS_BAM_NO_EXT_P_RST;
- ret = sps_register_bam_device(&usb_props, &h_bam);
+ if (pdata->disable_clk_gating)
+ props.options |= SPS_BAM_NO_LOCAL_CLK_GATING;
+
+ ret = sps_register_bam_device(&props, &(ctx.h_bam[bam_idx]));
if (ret < 0) {
pr_err("%s: register bam error %d\n", __func__, ret);
ret = -EFAULT;
@@ -1210,61 +1141,46 @@
return 0;
free_qscratch_reg:
- iounmap(qscratch_ram1_reg);
+ iounmap(ctx.qscratch_ram1_reg);
free_bam_regs:
iounmap(usb_virt_addr);
return ret;
}
-static ssize_t
-usb_bam_show_enable(struct device *dev, struct device_attribute *attr,
- char *buf)
+static int enable_usb_bams(struct platform_device *pdev)
{
- struct msm_usb_bam_platform_data *pdata = dev->platform_data;
-
- if (!pdata)
- return 0;
- return scnprintf(buf, PAGE_SIZE, "%s\n",
- bam_enable_strings[pdata->usb_active_bam]);
-}
-
-static ssize_t usb_bam_store_enable(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct msm_usb_bam_platform_data *pdata = dev->platform_data;
- char str[10], *pstr;
int ret, i;
- if (!pdata) {
- dev_err(dev, "no usb_bam pdata found\n");
- return -ENODEV;
- }
-
- strlcpy(str, buf, sizeof(str));
- pstr = strim(str);
-
for (i = 0; i < ARRAY_SIZE(bam_enable_strings); i++) {
- if (!strncmp(pstr, bam_enable_strings[i], sizeof(str)))
- pdata->usb_active_bam = i;
+ ret = usb_bam_init(i);
+ if (ret) {
+ pr_err("failed to init usb bam %s\n",
+ bam_enable_strings[i]);
+ return ret;
+ }
}
- dev_dbg(dev, "active_bam=%s\n",
- bam_enable_strings[pdata->usb_active_bam]);
+ ctx.usb_bam_sps.sps_pipes = devm_kzalloc(&pdev->dev,
+ ctx.max_connections * sizeof(struct sps_pipe *),
+ GFP_KERNEL);
- ret = usb_bam_init();
- if (ret) {
- dev_err(dev, "failed to initialize usb bam\n");
- return ret;
+ if (!ctx.usb_bam_sps.sps_pipes) {
+ pr_err("%s: failed to allocate sps_pipes\n", __func__);
+ return -ENOMEM;
}
- return count;
+ ctx.usb_bam_sps.sps_connections = devm_kzalloc(&pdev->dev,
+ ctx.max_connections * sizeof(struct sps_connect),
+ GFP_KERNEL);
+ if (!ctx.usb_bam_sps.sps_connections) {
+ pr_err("%s: failed to allocate sps_connections\n", __func__);
+ return -ENOMEM;
+ }
+
+ return 0;
}
-static DEVICE_ATTR(enable, S_IWUSR | S_IRUSR, usb_bam_show_enable,
- usb_bam_store_enable);
-
static int usb_bam_probe(struct platform_device *pdev)
{
int ret, i;
@@ -1272,89 +1188,126 @@
dev_dbg(&pdev->dev, "usb_bam_probe\n");
- for (i = 0; i < CONNECTIONS_NUM; i++) {
- usb_bam_connections[i].src_enabled = 0;
- usb_bam_connections[i].dst_enabled = 0;
- INIT_WORK(&usb_bam_connections[i].wake_event.event_w,
- usb_bam_work);
- }
+ ctx.mem_clk = devm_clk_get(&pdev->dev, "mem_clk");
+ if (IS_ERR(ctx.mem_clk))
- spin_lock_init(&usb_bam_lock);
- INIT_WORK(&peer_handhskae_info.reset_event.event_w, usb_bam_sm_work);
- mem_clk = devm_clk_get(&pdev->dev, "mem_clk");
- if (IS_ERR(mem_clk))
dev_dbg(&pdev->dev, "failed to get mem_clock\n");
- mem_iface_clk = devm_clk_get(&pdev->dev, "mem_iface_clk");
- if (IS_ERR(mem_iface_clk))
+ ctx.mem_iface_clk = devm_clk_get(&pdev->dev, "mem_iface_clk");
+ if (IS_ERR(ctx.mem_iface_clk))
dev_dbg(&pdev->dev, "failed to get mem_iface_clock\n");
if (pdev->dev.of_node) {
dev_dbg(&pdev->dev, "device tree enabled\n");
pdata = usb_bam_dt_to_pdata(pdev);
if (!pdata)
- return -ENOMEM;
+ return -EINVAL;
pdev->dev.platform_data = pdata;
} else if (!pdev->dev.platform_data) {
dev_err(&pdev->dev, "missing platform_data\n");
return -ENODEV;
} else {
pdata = pdev->dev.platform_data;
- ret = usb_bam_update_conn_array_index(pdev, pdata->connections,
- MAX_BAMS, CONNECTIONS_NUM, 2);
- if (ret) {
- pr_err("usb_bam_update_conn_array_index failed\n");
- return ret;
- }
+ usb_bam_connections = pdata->connections;
+ ctx.max_connections = pdata->max_connections;
}
- usb_bam_pdev = pdev;
+ ctx.usb_bam_pdev = pdev;
- ret = device_create_file(&pdev->dev, &dev_attr_enable);
- if (ret)
- dev_err(&pdev->dev, "failed to create device file\n");
+ for (i = 0; i < ctx.max_connections; i++) {
+ usb_bam_connections[i].enabled = 0;
+ INIT_WORK(&usb_bam_connections[i].wake_event.event_w,
+ usb_bam_work);
+ }
- usb_bam_wq = alloc_workqueue("usb_bam_wq",
+ spin_lock_init(&usb_bam_lock);
+ INIT_WORK(&peer_handshake_info.reset_event.event_w, usb_bam_sm_work);
+
+ ctx.usb_bam_wq = alloc_workqueue("usb_bam_wq",
WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
- if (!usb_bam_wq) {
+ if (!ctx.usb_bam_wq) {
pr_err("unable to create workqueue usb_bam_wq\n");
return -ENOMEM;
}
+ ret = enable_usb_bams(pdev);
+ if (ret) {
+ destroy_workqueue(ctx.usb_bam_wq);
+ return ret;
+ }
usb_bam_ipa_create_resources();
return ret;
}
-void get_bam2bam_connection_info(u8 conn_idx, enum usb_bam_pipe_dir pipe_dir,
- u32 *usb_bam_handle, u32 *usb_bam_pipe_idx, u32 *peer_pipe_idx,
+int usb_bam_get_qdss_idx(u8 num)
+{
+ return usb_bam_get_connection_idx(ctx.qdss_core_name, QDSS_P_BAM,
+ PEER_PERIPHERAL_TO_USB, num);
+}
+EXPORT_SYMBOL(usb_bam_get_qdss_idx);
+
+void usb_bam_set_qdss_core(const char *qdss_core)
+{
+ strlcpy(ctx.qdss_core_name, qdss_core, USB_BAM_MAX_STR_LEN);
+}
+
+int get_bam2bam_connection_info(u8 idx, u32 *usb_bam_handle,
+ u32 *usb_bam_pipe_idx, u32 *peer_pipe_idx,
struct sps_mem_buffer *desc_fifo, struct sps_mem_buffer *data_fifo)
{
- struct sps_connect *connection =
- &sps_connections[conn_idx][pipe_dir];
+ struct usb_bam_pipe_connect *pipe_connect = &usb_bam_connections[idx];
+ enum usb_bam_pipe_dir dir = pipe_connect->dir;
+ struct sps_connect *sps_connection =
+ &ctx.usb_bam_sps.sps_connections[idx];
-
- if (pipe_dir == USB_TO_PEER_PERIPHERAL) {
- *usb_bam_handle = connection->source;
- *usb_bam_pipe_idx = connection->src_pipe_index;
- *peer_pipe_idx = connection->dest_pipe_index;
+ if (dir == USB_TO_PEER_PERIPHERAL) {
+ *usb_bam_handle = sps_connection->source;
+ *usb_bam_pipe_idx = sps_connection->src_pipe_index;
+ *peer_pipe_idx = sps_connection->dest_pipe_index;
} else {
- *usb_bam_handle = connection->destination;
- *usb_bam_pipe_idx = connection->dest_pipe_index;
- *peer_pipe_idx = connection->src_pipe_index;
+ *usb_bam_handle = sps_connection->destination;
+ *usb_bam_pipe_idx = sps_connection->dest_pipe_index;
+ *peer_pipe_idx = sps_connection->src_pipe_index;
}
if (data_fifo)
- memcpy(data_fifo, &data_mem_buf[conn_idx][pipe_dir],
- sizeof(struct sps_mem_buffer));
+ memcpy(data_fifo, &pipe_connect->data_mem_buf,
+ sizeof(struct sps_mem_buffer));
if (desc_fifo)
- memcpy(desc_fifo, &desc_mem_buf[conn_idx][pipe_dir],
- sizeof(struct sps_mem_buffer));
+ memcpy(desc_fifo, &pipe_connect->desc_mem_buf,
+ sizeof(struct sps_mem_buffer));
+ return 0;
}
EXPORT_SYMBOL(get_bam2bam_connection_info);
+
+int usb_bam_get_connection_idx(const char *core_name, enum peer_bam client,
+ enum usb_bam_pipe_dir dir, u32 num)
+{
+ u8 i;
+ int bam_type;
+
+ bam_type = get_bam_type_from_core_name(core_name);
+ if (bam_type < 0)
+ return -EINVAL;
+
+ for (i = 0; i < ctx.max_connections; i++)
+ if (usb_bam_connections[i].bam_type == bam_type &&
+ usb_bam_connections[i].peer_bam == client &&
+ usb_bam_connections[i].dir == dir &&
+ usb_bam_connections[i].pipe_num == num) {
+ pr_debug("%s: index %d was found\n", __func__, i);
+ return i;
+ }
+
+ pr_err("%s: failed for %s\n", __func__, core_name);
+ return -ENODEV;
+}
+EXPORT_SYMBOL(usb_bam_get_connection_idx);
+
static int usb_bam_remove(struct platform_device *pdev)
{
- destroy_workqueue(usb_bam_wq);
+ destroy_workqueue(ctx.usb_bam_wq);
return 0;
}
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 0d161b7..e42337f 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -294,6 +294,13 @@
help
Say Y to enable support for the battery in Qualcomm MSM.
+config BATTERY_MSM_FAKE
+ tristate "Fake MSM battery"
+ depends on ARCH_MSM && BATTERY_MSM
+ default n
+ help
+ Say Y to bypass actual battery queries.
+
config BATTERY_MSM8X60
tristate "MSM8X60 battery"
select PMIC8XXX_BATTALARM
@@ -365,13 +372,6 @@
The driver reports the charger status via the power supply framework.
A charger status change triggers an IRQ via the device STAT pin.
-config BATTERY_MSM_FAKE
- tristate "Fake MSM battery"
- depends on ARCH_MSM && BATTERY_MSM
- default n
- help
- Say Y to bypass actual battery queries.
-
config PM8058_FIX_USB
tristate "pmic8058 software workaround for usb removal"
depends on PMIC8058
@@ -396,13 +396,6 @@
help
Say Y here to enable support for batteries with BQ27520 (I2C) chips.
-config BATTERY_BQ27541
- tristate "BQ27541 battery driver"
- depends on I2C
- default n
- help
- Say Y here to enable support for batteries with BQ27541 (I2C) chips.
-
config BQ27520_TEST_ENABLE
bool "Enable BQ27520 Fuel Gauge Chip Test"
depends on BATTERY_BQ27520
@@ -410,6 +403,13 @@
help
Say Y here to enable Test sysfs Interface for BQ27520 Drivers.
+config BATTERY_BQ27541
+ tristate "BQ27541 battery driver"
+ depends on I2C
+ default n
+ help
+ Say Y here to enable support for batteries with BQ27541 (I2C) chips.
+
config BATTERY_BQ28400
tristate "BQ28400 battery driver"
depends on I2C
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
index 0fdadb9..bc6f289 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -115,8 +115,7 @@
u8 revision1;
u8 revision2;
- int charger_status;
- bool online;
+ int battery_present;
/* platform data */
int r_sense_uohm;
unsigned int v_cutoff_uv;
@@ -149,6 +148,9 @@
int shutdown_soc;
int shutdown_iavg_ma;
+ struct wake_lock low_voltage_wake_lock;
+ bool low_voltage_wake_lock_held;
+ int low_voltage_threshold;
int low_soc_calc_threshold;
int low_soc_calculate_soc_ms;
int calculate_soc_ms;
@@ -204,8 +206,7 @@
};
static enum power_supply_property msm_bms_power_props[] = {
- POWER_SUPPLY_PROP_STATUS,
- POWER_SUPPLY_PROP_ONLINE,
+ POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_CAPACITY,
POWER_SUPPLY_PROP_CURRENT_NOW,
POWER_SUPPLY_PROP_CURRENT_MAX,
@@ -1141,7 +1142,11 @@
pr_err("vadc read failed with rc: %d\n", rc);
return rc;
}
- *ibat_ua = (int)i_result.result_ua;
+ /*
+ * reverse the current read by the iadc, since the bms uses
+ * flipped battery current polarity.
+ */
+ *ibat_ua = -1 * (int)i_result.result_ua;
*vbat_uv = (int)v_result.physical;
return 0;
@@ -1285,6 +1290,25 @@
return chip->prev_chg_soc;
}
+static void very_low_voltage_check(struct qpnp_bms_chip *chip, int vbat_uv)
+{
+ /*
+ * if battery is very low (v_cutoff voltage + 20mv) hold
+ * a wakelock untill soc = 0%
+ */
+ if (vbat_uv <= chip->low_voltage_threshold
+ && !chip->low_voltage_wake_lock_held) {
+ pr_debug("voltage = %d low holding wakelock\n", vbat_uv);
+ wake_lock(&chip->low_voltage_wake_lock);
+ chip->low_voltage_wake_lock_held = 1;
+ } else if (vbat_uv > chip->low_voltage_threshold
+ && chip->low_voltage_wake_lock_held) {
+ pr_debug("voltage = %d releasing wakelock\n", vbat_uv);
+ chip->low_voltage_wake_lock_held = 0;
+ wake_unlock(&chip->low_voltage_wake_lock);
+ }
+}
+
static int adjust_soc(struct qpnp_bms_chip *chip, struct soc_params *params,
int soc, int batt_temp)
{
@@ -1305,6 +1329,8 @@
goto out;
}
+ very_low_voltage_check(chip, vbat_uv);
+
delta_ocv_uv_limit = DIV_ROUND_CLOSEST(ibat_ua, 1000);
ocv_est_uv = vbat_uv + (ibat_ua * params->rbatt_mohm)/1000;
@@ -1620,7 +1646,8 @@
calculate_soc_delayed_work.work);
int soc = recalculate_soc(chip);
- if (soc < chip->low_soc_calc_threshold)
+ if (soc < chip->low_soc_calc_threshold
+ || chip->low_voltage_wake_lock_held)
schedule_delayed_work(&chip->calculate_soc_delayed_work,
round_jiffies_relative(msecs_to_jiffies
(chip->low_soc_calculate_soc_ms)));
@@ -1838,24 +1865,15 @@
return chip->fcc;
}
-static bool get_prop_bms_online(struct qpnp_bms_chip *chip)
+static int get_prop_bms_present(struct qpnp_bms_chip *chip)
{
- return chip->online;
+ return chip->battery_present;
}
-static int get_prop_bms_status(struct qpnp_bms_chip *chip)
+static void set_prop_bms_present(struct qpnp_bms_chip *chip, int present)
{
- return chip->charger_status;
-}
-
-static void set_prop_bms_online(struct qpnp_bms_chip *chip, bool online)
-{
- chip->online = online;
-}
-
-static void set_prop_bms_status(struct qpnp_bms_chip *chip, int status)
-{
- chip->charger_status = status;
+ if (chip->battery_present != present)
+ chip->battery_present = present;
}
static void qpnp_bms_external_power_changed(struct power_supply *psy)
@@ -1882,11 +1900,8 @@
case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
val->intval = get_prop_bms_charge_full_design(chip);
break;
- case POWER_SUPPLY_PROP_STATUS:
- val->intval = get_prop_bms_status(chip);
- break;
- case POWER_SUPPLY_PROP_ONLINE:
- val->intval = get_prop_bms_online(chip);
+ case POWER_SUPPLY_PROP_PRESENT:
+ val->intval = get_prop_bms_present(chip);
break;
default:
return -EINVAL;
@@ -1902,11 +1917,8 @@
bms_psy);
switch (psp) {
- case POWER_SUPPLY_PROP_ONLINE:
- set_prop_bms_online(chip, val->intval);
- break;
- case POWER_SUPPLY_PROP_STATUS:
- set_prop_bms_status(chip, (bool)val->intval);
+ case POWER_SUPPLY_PROP_PRESENT:
+ set_prop_bms_present(chip, val->intval);
break;
default:
return -EINVAL;
@@ -2121,6 +2133,7 @@
"ocv-voltage-high-threshold-uv", rc);
SPMI_PROP_READ(ocv_low_threshold_uv,
"ocv-voltage-low-threshold-uv", rc);
+ SPMI_PROP_READ(low_voltage_threshold, "low-voltage-threshold", rc);
if (chip->adjust_soc_low_threshold >= 45)
chip->adjust_soc_low_threshold = 45;
@@ -2294,6 +2307,7 @@
static int __devinit qpnp_bms_probe(struct spmi_device *spmi)
{
struct qpnp_bms_chip *chip;
+ union power_supply_propval retval = {0,};
int rc, vbatt;
chip = kzalloc(sizeof *chip, GFP_KERNEL);
@@ -2373,6 +2387,8 @@
wake_lock_init(&chip->soc_wake_lock, WAKE_LOCK_SUSPEND,
"qpnp_soc_lock");
+ wake_lock_init(&chip->low_voltage_wake_lock, WAKE_LOCK_SUSPEND,
+ "qpnp_low_voltage_lock");
INIT_DELAYED_WORK(&chip->calculate_soc_delayed_work,
calculate_soc_work);
@@ -2381,6 +2397,14 @@
dev_set_drvdata(&spmi->dev, chip);
device_init_wakeup(&spmi->dev, 1);
+ if (!chip->batt_psy)
+ chip->batt_psy = power_supply_get_by_name("battery");
+ if (chip->batt_psy) {
+ chip->batt_psy->get_property(chip->batt_psy,
+ POWER_SUPPLY_PROP_PRESENT, &retval);
+ chip->battery_present = retval.intval;
+ }
+
calculate_soc_work(&(chip->calculate_soc_delayed_work.work));
/* setup & register the battery power supply */
@@ -2417,6 +2441,7 @@
unregister_dc:
wake_lock_destroy(&chip->soc_wake_lock);
+ wake_lock_destroy(&chip->low_voltage_wake_lock);
power_supply_unregister(&chip->bms_psy);
dev_set_drvdata(&spmi->dev, NULL);
error_resource:
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index 3d9e4b7..180ca0d 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, 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
@@ -525,6 +525,8 @@
if (chip->usb_present ^ usb_present) {
chip->usb_present = usb_present;
+ if (!usb_present)
+ qpnp_chg_iusbmax_set(chip, QPNP_CHG_I_MAX_MIN_100);
power_supply_set_present(chip->usb_psy,
chip->usb_present);
}
@@ -546,6 +548,9 @@
power_supply_changed(&chip->batt_psy);
}
+ if (chip->bms_psy)
+ power_supply_set_present(chip->bms_psy, batt_present);
+
return IRQ_HANDLED;
}
@@ -1012,17 +1017,15 @@
chip->usb_psy->get_property(chip->usb_psy,
POWER_SUPPLY_PROP_ONLINE, &ret);
- if (ret.intval && qpnp_chg_is_usb_chg_plugged_in(chip)) {
- chip->usb_psy->get_property(chip->usb_psy,
- POWER_SUPPLY_PROP_CURRENT_MAX, &ret);
- qpnp_chg_iusbmax_set(chip, ret.intval / 1000);
- if ((ret.intval / 1000) <= QPNP_CHG_I_MAX_MIN_MA)
+ /* Only honour requests while USB is present */
+ if (qpnp_chg_is_usb_chg_plugged_in(chip)) {
+ if (ret.intval <= 2) {
qpnp_chg_usb_suspend_enable(chip, 1);
- else
+ qpnp_chg_iusbmax_set(chip, QPNP_CHG_I_MAX_MIN_100);
+ } else {
+ qpnp_chg_iusbmax_set(chip, ret.intval / 1000);
qpnp_chg_usb_suspend_enable(chip, 0);
- } else {
- qpnp_chg_iusbmax_set(chip, QPNP_CHG_I_MAX_MIN_100);
- qpnp_chg_usb_suspend_enable(chip, 0);
+ }
}
pr_debug("end of power supply changed\n");
@@ -1638,6 +1641,7 @@
struct qpnp_chg_chip *chip;
struct resource *resource;
struct spmi_resource *spmi_resource;
+ bool present;
int rc = 0;
chip = kzalloc(sizeof *chip, GFP_KERNEL);
@@ -1936,6 +1940,14 @@
if (rc)
goto fail_chg_enable;
+ /* if bms exists, notify it of the presence of the battery */
+ if (!chip->bms_psy)
+ chip->bms_psy = power_supply_get_by_name("bms");
+ if (chip->bms_psy) {
+ present = get_prop_batt_present(chip);
+ power_supply_set_present(chip->bms_psy, present);
+ }
+
chip->batt_psy.name = "battery";
chip->batt_psy.type = POWER_SUPPLY_TYPE_BATTERY;
chip->batt_psy.properties = msm_batt_power_props;
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 8f924d6..fe5af3a 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -436,4 +436,6 @@
comply with QPNP. QPNP is a SPMI based PMIC implementation. These
chips provide several different varieties of LDO and switching
regulators. They also provide voltage switches and boost regulators.
+
endif
+
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 054ce42..eb07c97 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -45,7 +45,6 @@
obj-$(CONFIG_REGULATOR_TPS6524X) += tps6524x-regulator.o
obj-$(CONFIG_REGULATOR_TPS6586X) += tps6586x-regulator.o
obj-$(CONFIG_REGULATOR_TPS65910) += tps65910-regulator.o
-obj-$(CONFIG_REGULATOR_AAT2870) += aat2870-regulator.o
obj-$(CONFIG_REGULATOR_PMIC8058) += pmic8058-regulator.o
obj-$(CONFIG_REGULATOR_PMIC8901) += pmic8901-regulator.o
obj-$(CONFIG_REGULATOR_MSM_GPIO) += msm-gpio-regulator.o
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 1849118..7a559a6 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -123,24 +123,6 @@
clock several times per second, please enable this option
only if you know that you really need it.
-config RTC_INTF_ALARM
- bool "Android alarm driver"
- depends on RTC_CLASS
- default y
- help
- Provides non-wakeup and rtc backed wakeup alarms based on rtc or
- elapsed realtime, and a non-wakeup alarm on the monotonic clock.
- Also provides an interface to set the wall time which must be used
- for elapsed realtime to work.
-
-config RTC_INTF_ALARM_DEV
- bool "Android alarm device"
- depends on RTC_INTF_ALARM
- default y
- help
- Exports the alarm interface to user-space.
-
-
config RTC_DRV_TEST
tristate "Test driver/device"
help
@@ -804,13 +786,6 @@
This driver can also be built as a module. If so, the module
will be called rtc-davinci.
-config RTC_DRV_MSM7X00A
- tristate "MSM7X00A"
- depends on ARCH_MSM
- default y
- help
- RTC driver for Qualcomm MSM7K chipsets
-
config RTC_DRV_OMAP
tristate "TI OMAP1"
depends on ARCH_OMAP15XX || ARCH_OMAP16XX || ARCH_OMAP730 || ARCH_DAVINCI_DA8XX
@@ -1150,15 +1125,6 @@
This drive can also be built as a module. If so, the module
will be called rtc-puv3.
-config RTC_DRV_PM8XXX
- tristate "Qualcomm PMIC8XXX RTC"
- depends on MFD_PM8XXX
- help
- Say Y here if you want to support the Qualcomm PMIC8XXX RTC.
-
- To compile this driver as a module, choose M here: the
- module will be called rtc-pm8xxx.
-
config RTC_DRV_LOONGSON1
tristate "loongson1 RTC support"
depends on MACH_LOONGSON1
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 295f927..c6a0362 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -81,7 +81,6 @@
obj-$(CONFIG_RTC_DRV_PCF8583) += rtc-pcf8583.o
obj-$(CONFIG_RTC_DRV_PCF2123) += rtc-pcf2123.o
obj-$(CONFIG_RTC_DRV_PCF50633) += rtc-pcf50633.o
-obj-$(CONFIG_RTC_DRV_PM8XXX) += rtc-pm8xxx.o
obj-$(CONFIG_RTC_DRV_PL030) += rtc-pl030.o
obj-$(CONFIG_RTC_DRV_PL031) += rtc-pl031.o
obj-$(CONFIG_RTC_DRV_PM8XXX) += rtc-pm8xxx.o
diff --git a/drivers/slimbus/slimbus.c b/drivers/slimbus/slimbus.c
index bec0399..e9f056e 100644
--- a/drivers/slimbus/slimbus.c
+++ b/drivers/slimbus/slimbus.c
@@ -2568,11 +2568,12 @@
struct slim_pending_ch, pending);
struct slim_ich *slc = &ctrl->chans[pch->chan];
u32 sl = slc->seglen << slc->rootexp;
- if (revert) {
+ if (revert || slc->def > 0) {
if (slc->coeff == SLIM_COEFF_3)
sl *= 3;
ctrl->sched.usedslots += sl;
- slc->def = 1;
+ if (revert)
+ slc->def++;
slc->state = SLIM_CH_ACTIVE;
} else
slim_remove_ch(ctrl, slc);
@@ -2635,7 +2636,11 @@
/* Disconnect source port to free it up */
if (SLIM_HDL_TO_LA(slc->srch) == sb->laddr)
slc->srch = 0;
- if (slc->def != 0) {
+ /*
+ * If controller overrides BW allocation,
+ * delete this in remove channel itself
+ */
+ if (slc->def != 0 && !ctrl->allocbw) {
list_del(&pch->pending);
kfree(pch);
}
diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index 7f60128..b89f608 100644
--- a/drivers/spi/spi_qsd.c
+++ b/drivers/spi/spi_qsd.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-2013, 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
@@ -276,13 +276,12 @@
if (dd->input_block_size == 4 || dd->output_block_size == 4)
dd->use_dma = 0;
- /* DM mode is currently unsupported for different block sizes */
- if (dd->input_block_size != dd->output_block_size)
- dd->use_dma = 0;
-
- if (dd->use_dma)
- dd->burst_size = max(dd->input_block_size,
- DM_BURST_SIZE);
+ if (dd->use_dma) {
+ dd->input_burst_size = max(dd->input_block_size,
+ DM_BURST_SIZE);
+ dd->output_burst_size = max(dd->output_block_size,
+ DM_BURST_SIZE);
+ }
}
return;
@@ -646,7 +645,8 @@
static void msm_spi_setup_dm_transfer(struct msm_spi *dd)
{
dmov_box *box;
- int bytes_to_send, num_rows, bytes_sent;
+ int bytes_to_send, bytes_sent;
+ int tx_num_rows, rx_num_rows;
u32 num_transfers;
atomic_set(&dd->rx_irq_called, 0);
@@ -678,64 +678,80 @@
dd->max_trfr_len);
num_transfers = DIV_ROUND_UP(bytes_to_send, dd->bytes_per_word);
- dd->unaligned_len = bytes_to_send % dd->burst_size;
- num_rows = bytes_to_send / dd->burst_size;
+ dd->tx_unaligned_len = bytes_to_send % dd->output_burst_size;
+ dd->rx_unaligned_len = bytes_to_send % dd->input_burst_size;
+ tx_num_rows = bytes_to_send / dd->output_burst_size;
+ rx_num_rows = bytes_to_send / dd->input_burst_size;
dd->mode = SPI_DMOV_MODE;
- if (num_rows) {
+ if (tx_num_rows) {
/* src in 16 MSB, dst in 16 LSB */
box = &dd->tx_dmov_cmd->box;
box->src_row_addr = dd->cur_transfer->tx_dma + bytes_sent;
- box->src_dst_len = (dd->burst_size << 16) | dd->burst_size;
- box->num_rows = (num_rows << 16) | num_rows;
- box->row_offset = (dd->burst_size << 16) | 0;
+ box->src_dst_len
+ = (dd->output_burst_size << 16) | dd->output_burst_size;
+ box->num_rows = (tx_num_rows << 16) | tx_num_rows;
+ box->row_offset = (dd->output_burst_size << 16) | 0;
+ dd->tx_dmov_cmd->cmd_ptr = CMD_PTR_LP |
+ DMOV_CMD_ADDR(dd->tx_dmov_cmd_dma +
+ offsetof(struct spi_dmov_cmd, box));
+ } else {
+ dd->tx_dmov_cmd->cmd_ptr = CMD_PTR_LP |
+ DMOV_CMD_ADDR(dd->tx_dmov_cmd_dma +
+ offsetof(struct spi_dmov_cmd, single_pad));
+ }
+
+ if (rx_num_rows) {
+ /* src in 16 MSB, dst in 16 LSB */
box = &dd->rx_dmov_cmd->box;
box->dst_row_addr = dd->cur_transfer->rx_dma + bytes_sent;
- box->src_dst_len = (dd->burst_size << 16) | dd->burst_size;
- box->num_rows = (num_rows << 16) | num_rows;
- box->row_offset = (0 << 16) | dd->burst_size;
+ box->src_dst_len
+ = (dd->input_burst_size << 16) | dd->input_burst_size;
+ box->num_rows = (rx_num_rows << 16) | rx_num_rows;
+ box->row_offset = (0 << 16) | dd->input_burst_size;
- dd->tx_dmov_cmd->cmd_ptr = CMD_PTR_LP |
- DMOV_CMD_ADDR(dd->tx_dmov_cmd_dma +
- offsetof(struct spi_dmov_cmd, box));
dd->rx_dmov_cmd->cmd_ptr = CMD_PTR_LP |
DMOV_CMD_ADDR(dd->rx_dmov_cmd_dma +
offsetof(struct spi_dmov_cmd, box));
} else {
- dd->tx_dmov_cmd->cmd_ptr = CMD_PTR_LP |
- DMOV_CMD_ADDR(dd->tx_dmov_cmd_dma +
- offsetof(struct spi_dmov_cmd, single_pad));
dd->rx_dmov_cmd->cmd_ptr = CMD_PTR_LP |
DMOV_CMD_ADDR(dd->rx_dmov_cmd_dma +
offsetof(struct spi_dmov_cmd, single_pad));
}
- if (!dd->unaligned_len) {
+ if (!dd->tx_unaligned_len) {
dd->tx_dmov_cmd->box.cmd |= CMD_LC;
- dd->rx_dmov_cmd->box.cmd |= CMD_LC;
} else {
dmov_s *tx_cmd = &(dd->tx_dmov_cmd->single_pad);
- dmov_s *rx_cmd = &(dd->rx_dmov_cmd->single_pad);
- u32 offset = dd->cur_transfer->len - dd->unaligned_len;
+ u32 tx_offset = dd->cur_transfer->len - dd->tx_unaligned_len;
if ((dd->multi_xfr) && (dd->read_len <= 0))
- offset = dd->cur_msg_len - dd->unaligned_len;
+ tx_offset = dd->cur_msg_len - dd->tx_unaligned_len;
dd->tx_dmov_cmd->box.cmd &= ~CMD_LC;
- dd->rx_dmov_cmd->box.cmd &= ~CMD_LC;
- memset(dd->tx_padding, 0, dd->burst_size);
- memset(dd->rx_padding, 0, dd->burst_size);
+ memset(dd->tx_padding, 0, dd->output_burst_size);
if (dd->write_buf)
- memcpy(dd->tx_padding, dd->write_buf + offset,
- dd->unaligned_len);
+ memcpy(dd->tx_padding, dd->write_buf + tx_offset,
+ dd->tx_unaligned_len);
tx_cmd->src = dd->tx_padding_dma;
- rx_cmd->dst = dd->rx_padding_dma;
- tx_cmd->len = rx_cmd->len = dd->burst_size;
+ tx_cmd->len = dd->output_burst_size;
}
+
+ if (!dd->rx_unaligned_len) {
+ dd->rx_dmov_cmd->box.cmd |= CMD_LC;
+ } else {
+ dmov_s *rx_cmd = &(dd->rx_dmov_cmd->single_pad);
+ dd->rx_dmov_cmd->box.cmd &= ~CMD_LC;
+
+ memset(dd->rx_padding, 0, dd->input_burst_size);
+ rx_cmd->dst = dd->rx_padding_dma;
+ rx_cmd->len = dd->input_burst_size;
+ }
+
/* This also takes care of the padding dummy buf
Since this is set to the correct length, the
dummy bytes won't be actually sent */
@@ -893,7 +909,7 @@
if ((!dd->read_buf || op & SPI_OP_MAX_INPUT_DONE_FLAG) &&
(!dd->write_buf || op & SPI_OP_MAX_OUTPUT_DONE_FLAG)) {
msm_spi_ack_transfer(dd);
- if (dd->unaligned_len == 0) {
+ if (dd->rx_unaligned_len == 0) {
if (atomic_inc_return(&dd->rx_irq_called) == 1)
return IRQ_HANDLED;
}
@@ -1145,11 +1161,11 @@
prev_xfr->len,
DMA_TO_DEVICE);
}
- if (dd->unaligned_len && dd->read_buf) {
- offset = dd->cur_msg_len - dd->unaligned_len;
+ if (dd->rx_unaligned_len && dd->read_buf) {
+ offset = dd->cur_msg_len - dd->rx_unaligned_len;
dma_coherent_post_ops();
memcpy(dd->read_buf + offset, dd->rx_padding,
- dd->unaligned_len);
+ dd->rx_unaligned_len);
memcpy(dd->cur_transfer->rx_buf,
dd->read_buf + prev_xfr->len,
dd->cur_transfer->len);
@@ -1171,11 +1187,11 @@
unmap_end:
/* If we padded the transfer, we copy it from the padding buf */
- if (dd->unaligned_len && dd->read_buf) {
- offset = dd->cur_transfer->len - dd->unaligned_len;
+ if (dd->rx_unaligned_len && dd->read_buf) {
+ offset = dd->cur_transfer->len - dd->rx_unaligned_len;
dma_coherent_post_ops();
memcpy(dd->read_buf + offset, dd->rx_padding,
- dd->unaligned_len);
+ dd->rx_unaligned_len);
}
}
@@ -1960,7 +1976,8 @@
"use_dma ? %s\n"
"rx block size = %d bytes\n"
"tx block size = %d bytes\n"
- "burst size = %d bytes\n"
+ "input burst size = %d bytes\n"
+ "output burst size = %d bytes\n"
"DMA configuration:\n"
"tx_ch=%d, rx_ch=%d, tx_crci= %d, rx_crci=%d\n"
"--statistics--\n"
@@ -1975,7 +1992,8 @@
dd->use_dma ? "yes" : "no",
dd->input_block_size,
dd->output_block_size,
- dd->burst_size,
+ dd->input_burst_size,
+ dd->output_burst_size,
dd->tx_dma_chan,
dd->rx_dma_chan,
dd->tx_dma_crci,
@@ -2104,12 +2122,15 @@
}
}
-static inline u32 get_chunk_size(struct msm_spi *dd)
+static inline u32 get_chunk_size(struct msm_spi *dd, int input_burst_size,
+ int output_burst_size)
{
u32 cache_line = dma_get_cache_alignment();
+ int burst_size = (input_burst_size > output_burst_size) ?
+ input_burst_size : output_burst_size;
return (roundup(sizeof(struct spi_dmov_cmd), DM_BYTE_ALIGN) +
- roundup(dd->burst_size, cache_line))*2;
+ roundup(burst_size, cache_line))*2;
}
static void msm_spi_dmov_teardown(struct msm_spi *dd)
@@ -2125,8 +2146,10 @@
msleep(10);
}
- dma_free_coherent(NULL, get_chunk_size(dd), dd->tx_dmov_cmd,
- dd->tx_dmov_cmd_dma);
+ dma_free_coherent(NULL,
+ get_chunk_size(dd, dd->input_burst_size, dd->output_burst_size),
+ dd->tx_dmov_cmd,
+ dd->tx_dmov_cmd_dma);
dd->tx_dmov_cmd = dd->rx_dmov_cmd = NULL;
dd->tx_padding = dd->rx_padding = NULL;
}
@@ -2304,8 +2327,11 @@
/* We send NULL device, since it requires coherent_dma_mask id
device definition, we're okay with using system pool */
- dd->tx_dmov_cmd = dma_alloc_coherent(NULL, get_chunk_size(dd),
- &dd->tx_dmov_cmd_dma, GFP_KERNEL);
+ dd->tx_dmov_cmd
+ = dma_alloc_coherent(NULL,
+ get_chunk_size(dd, dd->input_burst_size,
+ dd->output_burst_size),
+ &dd->tx_dmov_cmd_dma, GFP_KERNEL);
if (dd->tx_dmov_cmd == NULL)
return -ENOMEM;
@@ -2319,9 +2345,9 @@
dd->tx_padding = (u8 *)ALIGN((size_t)&dd->rx_dmov_cmd[1], cache_line);
dd->tx_padding_dma = ALIGN(dd->rx_dmov_cmd_dma +
sizeof(struct spi_dmov_cmd), cache_line);
- dd->rx_padding = (u8 *)ALIGN((size_t)(dd->tx_padding + dd->burst_size),
- cache_line);
- dd->rx_padding_dma = ALIGN(dd->tx_padding_dma + dd->burst_size,
+ dd->rx_padding = (u8 *)ALIGN((size_t)(dd->tx_padding +
+ dd->output_burst_size), cache_line);
+ dd->rx_padding_dma = ALIGN(dd->tx_padding_dma + dd->output_burst_size,
cache_line);
/* Setup DM commands */
diff --git a/drivers/spi/spi_qsd.h b/drivers/spi/spi_qsd.h
index 7f5b726..b749cc0 100644
--- a/drivers/spi/spi_qsd.h
+++ b/drivers/spi/spi_qsd.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-2013, 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
@@ -318,7 +318,8 @@
struct msm_dmov_cmd rx_hdr;
int input_block_size;
int output_block_size;
- int burst_size;
+ int input_burst_size;
+ int output_burst_size;
atomic_t rx_irq_called;
atomic_t tx_irq_called;
/* Used to pad messages unaligned to block size */
@@ -326,7 +327,8 @@
dma_addr_t tx_padding_dma;
u8 *rx_padding;
dma_addr_t rx_padding_dma;
- u32 unaligned_len;
+ u32 tx_unaligned_len;
+ u32 rx_unaligned_len;
/* DMA statistics */
int stat_dmov_tx_err;
int stat_dmov_rx_err;
diff --git a/drivers/staging/ath6kl/os/linux/include/athendpack_linux.h b/drivers/staging/ath6kl/os/linux/include/athendpack_linux.h
deleted file mode 100644
index e69de29..0000000
--- a/drivers/staging/ath6kl/os/linux/include/athendpack_linux.h
+++ /dev/null
diff --git a/drivers/staging/ath6kl/os/linux/include/athstartpack_linux.h b/drivers/staging/ath6kl/os/linux/include/athstartpack_linux.h
deleted file mode 100644
index e69de29..0000000
--- a/drivers/staging/ath6kl/os/linux/include/athstartpack_linux.h
+++ /dev/null
diff --git a/drivers/staging/dream/Kconfig b/drivers/staging/dream/Kconfig
deleted file mode 100644
index 0c30b19..0000000
--- a/drivers/staging/dream/Kconfig
+++ /dev/null
@@ -1,13 +0,0 @@
-config DREAM
- tristate "HTC Dream support"
- depends on MACH_TROUT
-
-if DREAM
-
-source "drivers/staging/dream/camera/Kconfig"
-
-config INPUT_GPIO
- tristate "GPIO driver support"
- help
- Say Y here if you want to support gpio based keys, wheels etc...
-endif
diff --git a/drivers/staging/dream/Makefile b/drivers/staging/dream/Makefile
deleted file mode 100644
index fbea0ab..0000000
--- a/drivers/staging/dream/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-EXTRA_CFLAGS=-Idrivers/staging/dream/include
-obj-$(CONFIG_MSM_ADSP) += qdsp5/
-obj-$(CONFIG_MSM_CAMERA) += camera/
-obj-$(CONFIG_INPUT_GPIO) += gpio_axis.o gpio_event.o gpio_input.o gpio_matrix.o gpio_output.o
-
diff --git a/drivers/thermal/msm8974-tsens.c b/drivers/thermal/msm8974-tsens.c
index b04213c..7d3664a 100644
--- a/drivers/thermal/msm8974-tsens.c
+++ b/drivers/thermal/msm8974-tsens.c
@@ -54,6 +54,7 @@
#define TSENS_SW_RST BIT(1)
#define TSENS_ADC_CLK_SEL BIT(2)
#define TSENS_SENSOR0_SHIFT 3
+#define TSENS_62_5_MS_MEAS_PERIOD 1
#define TSENS_312_5_MS_MEAS_PERIOD 2
#define TSENS_MEAS_PERIOD_SHIFT 18
@@ -239,6 +240,7 @@
struct platform_device *pdev;
bool prev_reading_avail;
bool calibration_less_mode;
+ bool tsens_local_init;
int tsens_factor;
uint32_t tsens_num_sensor;
int tsens_irq;
@@ -570,24 +572,28 @@
unsigned int reg_cntl = 0;
unsigned int i;
- reg_cntl = readl_relaxed(TSENS_CTRL_ADDR(tmdev->tsens_addr));
- writel_relaxed(reg_cntl | TSENS_SW_RST,
+ if (tmdev->tsens_local_init) {
+ writel_relaxed(reg_cntl, TSENS_CTRL_ADDR(tmdev->tsens_addr));
+ writel_relaxed(reg_cntl | TSENS_SW_RST,
TSENS_CTRL_ADDR(tmdev->tsens_addr));
- reg_cntl |= ((TSENS_312_5_MS_MEAS_PERIOD << TSENS_MEAS_PERIOD_SHIFT) |
+ reg_cntl |= ((TSENS_62_5_MS_MEAS_PERIOD <<
+ TSENS_MEAS_PERIOD_SHIFT) |
(((1 << tmdev->tsens_num_sensor) - 1) << TSENS_SENSOR0_SHIFT) |
TSENS_EN);
- writel_relaxed(reg_cntl, TSENS_CTRL_ADDR(tmdev->tsens_addr));
- writel_relaxed(TSENS_GLOBAL_INIT_DATA,
+ writel_relaxed(reg_cntl, TSENS_CTRL_ADDR(tmdev->tsens_addr));
+ writel_relaxed(TSENS_GLOBAL_INIT_DATA,
TSENS_GLOBAL_CONFIG(tmdev->tsens_addr));
- writel_relaxed(TSENS_S0_MAIN_CFG_INIT_DATA,
+ writel_relaxed(TSENS_S0_MAIN_CFG_INIT_DATA,
TSENS_S0_MAIN_CONFIG(tmdev->tsens_addr));
- for (i = 0; i < tmdev->tsens_num_sensor; i++) {
- writel_relaxed(TSENS_SN_MIN_MAX_STATUS_CTRL_DATA,
+ for (i = 0; i < tmdev->tsens_num_sensor; i++) {
+ writel_relaxed(TSENS_SN_MIN_MAX_STATUS_CTRL_DATA,
TSENS_SN_MIN_MAX_STATUS_CTRL(tmdev->tsens_addr)
+ (i * TSENS_SN_ADDR_OFFSET));
- writel_relaxed(TSENS_SN_REMOTE_CFG_DATA,
+ writel_relaxed(TSENS_SN_REMOTE_CFG_DATA,
TSENS_SN_REMOTE_CONFIG(tmdev->tsens_addr)
+ (i * TSENS_SN_ADDR_OFFSET));
+ }
+ pr_debug("Local TSENS control initialization\n");
}
writel_relaxed(TSENS_INTERRUPT_EN,
TSENS_UPPER_LOWER_INTERRUPT_CTRL(tmdev->tsens_addr));
@@ -1156,6 +1162,8 @@
tmdev->calibration_less_mode = of_property_read_bool(of_node,
"qcom,calibration-less-mode");
tmdev->calib_mode = calib_type;
+ tmdev->tsens_local_init = of_property_read_bool(of_node,
+ "qcom,tsens_local_init");
tmdev->tsens_irq = platform_get_irq(pdev, 0);
if (tmdev->tsens_irq < 0) {
diff --git a/drivers/tty/n_smux.c b/drivers/tty/n_smux.c
index 0348145..8760603 100644
--- a/drivers/tty/n_smux.c
+++ b/drivers/tty/n_smux.c
@@ -1719,7 +1719,7 @@
*/
static int smux_handle_rx_power_cmd(struct smux_pkt_t *pkt)
{
- struct smux_pkt_t *ack_pkt = NULL;
+ struct smux_pkt_t *ack_pkt;
int power_down = 0;
unsigned long flags;
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 9274c17..5c8645a 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -988,14 +988,6 @@
Choose M here to compile it as a module. The module will be
called msm_serial_hs.
-config SERIAL_MSM_CLOCK_CONTROL
- bool "Allow tty clients to make clock requests to msm uarts."
- depends on SERIAL_MSM=y
- default y
- help
- Provides an interface for tty clients to request the msm uart clock
- to be turned on or off for power savings.
-
config SERIAL_MSM_RX_WAKEUP
bool "Wakeup the msm uart clock on GPIO activity."
depends on SERIAL_MSM_CLOCK_CONTROL
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index c982587..21a936e 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -200,7 +200,6 @@
struct work_struct clock_off_w; /* work for actual clock off */
struct workqueue_struct *hsuart_wq; /* hsuart workqueue */
struct mutex clk_mutex; /* mutex to guard against clock off/clock on */
- struct work_struct reset_bam_rx; /* work for reset bam rx endpoint */
struct work_struct disconnect_rx_endpoint; /* disconnect rx_endpoint */
bool tty_flush_receive;
enum uart_core_type uart_type;
@@ -218,6 +217,8 @@
u32 bus_perf_client;
/* BLSP UART required BUS Scaling data */
struct msm_bus_scale_pdata *bus_scale_table;
+ bool rx_discard_flush_issued;
+ int rx_count_callback;
};
#define MSM_UARTDM_BURST_SIZE 16 /* DM burst size (in bytes) */
@@ -229,6 +230,7 @@
#define BAM_PIPE_MAX 11
#define BUS_SCALING 1
#define BUS_RESET 0
+#define RX_FLUSH_COMPLETE_TIMEOUT 300 /* In jiffies */
static struct dentry *debug_base;
static struct msm_hs_port q_uart_port[UARTDM_NR];
@@ -821,22 +823,6 @@
}
-/* Reset BAM RX Endpoint Pipe Index from workqueue context*/
-
-static void hsuart_reset_bam_rx_work(struct work_struct *w)
-{
- struct msm_hs_port *msm_uport = container_of(w, struct msm_hs_port,
- reset_bam_rx);
- struct uart_port *uport = &msm_uport->uport;
- struct msm_hs_rx *rx = &msm_uport->rx;
- struct sps_pipe *sps_pipe_handle = rx->prod.pipe_handle;
-
- sps_disconnect(sps_pipe_handle);
- msm_hs_spsconnect_rx(uport);
-
- msm_serial_hs_rx_tlet((unsigned long) &rx->tlet);
-}
-
/*
* termios : new ktermios
* oldtermios: old ktermios previous setting
@@ -849,6 +835,7 @@
{
unsigned int bps;
unsigned long data;
+ int ret;
unsigned int c_cflag = termios->c_cflag;
struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
struct msm_hs_rx *rx = &msm_uport->rx;
@@ -969,8 +956,17 @@
msm_hs_spsconnect_rx(uport);
msm_serial_hs_rx_tlet((unsigned long) &rx->tlet);
} else {
+ msm_uport->rx_discard_flush_issued = true;
/* do discard flush */
msm_dmov_flush(msm_uport->dma_rx_channel, 0);
+ pr_debug("%s(): wainting for flush completion.\n",
+ __func__);
+ ret = wait_event_timeout(msm_uport->rx.wait,
+ msm_uport->rx_discard_flush_issued == false,
+ RX_FLUSH_COMPLETE_TIMEOUT);
+ if (!ret)
+ pr_err("%s(): Discard flush pending.\n",
+ __func__);
}
}
@@ -1061,13 +1057,6 @@
if (!is_blsp_uart(msm_uport) && msm_uport->rx.flush != FLUSH_SHUTDOWN)
msm_uport->rx.flush = FLUSH_STOP;
- /* During uart port close, due to spurious rx stale interrupt,
- * the rx state machine is causing BUG_ON to be hit in
- * msm_hs_shutdown causing kernel panic.
- * Hence fixing the same by handling the rx state machine.
- */
- if (is_blsp_uart(msm_uport) && msm_uport->rx.flush == FLUSH_DATA_READY)
- msm_uport->rx.flush = FLUSH_SHUTDOWN;
}
/* Transmit the next chunk of data */
@@ -1166,10 +1155,6 @@
printk(KERN_ERR "Error: rx started in buffer state = %x",
buffer_pending);
- if (is_blsp_uart(msm_uport)) {
- /* Issue RX BAM Start IFC command */
- msm_hs_write(uport, UARTDM_CR_ADDR, START_RX_BAM_IFC);
- }
msm_hs_write(uport, UARTDM_CR_ADDR, RESET_STALE_INT);
msm_hs_write(uport, UARTDM_DMRX_ADDR, UARTDM_RX_BUF_SIZE);
msm_hs_write(uport, UARTDM_CR_ADDR, STALE_EVENT_ENABLE);
@@ -1192,6 +1177,19 @@
/* Calling next DMOV API. Hence mb() here. */
mb();
+ if (is_blsp_uart(msm_uport)) {
+ /*
+ * RX-transfer will be automatically re-activated
+ * after last data of previous transfer was read.
+ */
+ data = (RX_STALE_AUTO_RE_EN | RX_TRANS_AUTO_RE_ACTIVATE |
+ RX_DMRX_CYCLIC_EN);
+ msm_hs_write(uport, UARTDM_RX_TRANS_CTRL_ADDR, data);
+ /* Issue RX BAM Start IFC command */
+ msm_hs_write(uport, UARTDM_CR_ADDR, START_RX_BAM_IFC);
+ mb();
+ }
+
msm_uport->rx.flush = FLUSH_NONE;
if (is_blsp_uart(msm_uport)) {
@@ -1264,7 +1262,6 @@
{
int retval;
int rx_count;
- static int remaining_rx_count, bytes_pending;
unsigned long status;
unsigned long flags;
unsigned int error_f = 0;
@@ -1272,17 +1269,24 @@
struct msm_hs_port *msm_uport;
unsigned int flush;
struct tty_struct *tty;
+ struct sps_event_notify *notify;
+ struct msm_hs_rx *rx;
+ struct sps_pipe *sps_pipe_handle;
+ u32 sps_flags = SPS_IOVEC_FLAG_EOT;
msm_uport = container_of((struct tasklet_struct *)tlet_ptr,
struct msm_hs_port, rx.tlet);
uport = &msm_uport->uport;
tty = uport->state->port.tty;
+ notify = &msm_uport->notify;
+ rx = &msm_uport->rx;
status = msm_hs_read(uport, UARTDM_SR_ADDR);
spin_lock_irqsave(&uport->lock, flags);
- msm_hs_write(uport, UARTDM_CR_ADDR, STALE_EVENT_DISABLE);
+ if (!is_blsp_uart(msm_uport))
+ msm_hs_write(uport, UARTDM_CR_ADDR, STALE_EVENT_DISABLE);
/* overflow is not connect to data in a FIFO */
if (unlikely((status & UARTDM_SR_OVERRUN_BMSK) &&
@@ -1339,24 +1343,13 @@
if (flush >= FLUSH_DATA_INVALID)
goto out;
- rx_count = msm_hs_read(uport, UARTDM_RX_TOTAL_SNAP_ADDR);
-
if (is_blsp_uart(msm_uport)) {
- if (rx_count > UARTDM_RX_BUF_SIZE) {
- if (bytes_pending) {
- rx_count = remaining_rx_count;
- bytes_pending = 0;
- } else {
- remaining_rx_count = rx_count -
- UARTDM_RX_BUF_SIZE;
- if (remaining_rx_count)
- bytes_pending = 1;
- rx_count = UARTDM_RX_BUF_SIZE;
- }
- }
+ rx_count = msm_uport->rx_count_callback;
+ } else {
+ rx_count = msm_hs_read(uport, UARTDM_RX_TOTAL_SNAP_ADDR);
+ /* order the read of rx.buffer */
+ rmb();
}
- /* order the read of rx.buffer */
- rmb();
if (0 != (uport->read_status_mask & CREAD)) {
retval = tty_insert_flip_string(tty, msm_uport->rx.buffer,
@@ -1370,9 +1363,17 @@
/* order the read of rx.buffer and the start of next rx xfer */
wmb();
- if (!msm_uport->rx.buffer_pending)
- msm_hs_start_rx_locked(uport);
-
+ if (!msm_uport->rx.buffer_pending) {
+ if (is_blsp_uart(msm_uport)) {
+ msm_uport->rx.flush = FLUSH_NONE;
+ sps_pipe_handle = rx->prod.pipe_handle;
+ /* Queue transfer request to SPS */
+ sps_transfer_one(sps_pipe_handle, rx->rbuffer,
+ UARTDM_RX_BUF_SIZE, msm_uport, sps_flags);
+ } else {
+ msm_hs_start_rx_locked(uport);
+ }
+ }
out:
if (msm_uport->rx.buffer_pending) {
if (hs_serial_debug_mask)
@@ -1490,7 +1491,10 @@
struct msm_hs_port *msm_uport =
(struct msm_hs_port *)
((struct sps_event_notify *)notify)->user;
+ struct uart_port *uport;
+ unsigned long flags;
+ uport = &(msm_uport->uport);
msm_uport->notify = *notify;
pr_debug("%s: sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
__func__, notify->event_id,
@@ -1498,8 +1502,12 @@
notify->data.transfer.iovec.size,
notify->data.transfer.iovec.flags);
- if (msm_uport->rx.flush == FLUSH_NONE)
+ if (msm_uport->rx.flush == FLUSH_NONE) {
+ spin_lock_irqsave(&uport->lock, flags);
+ msm_uport->rx_count_callback = notify->data.transfer.iovec.size;
+ spin_unlock_irqrestore(&uport->lock, flags);
tasklet_schedule(&msm_uport->rx.tlet);
+ }
}
/*
@@ -1514,8 +1522,23 @@
struct msm_dmov_errdata *err)
{
struct msm_hs_port *msm_uport;
+ struct uart_port *uport;
+ unsigned long flags;
msm_uport = container_of(cmd_ptr, struct msm_hs_port, rx.xfer);
+ uport = &(msm_uport->uport);
+
+ pr_debug("%s(): called result:%x\n", __func__, result);
+ if (!(result & DMOV_RSLT_ERROR)) {
+ if (result & DMOV_RSLT_FLUSH) {
+ if (msm_uport->rx_discard_flush_issued) {
+ spin_lock_irqsave(&uport->lock, flags);
+ msm_uport->rx_discard_flush_issued = false;
+ spin_unlock_irqrestore(&uport->lock, flags);
+ wake_up(&msm_uport->rx.wait);
+ }
+ }
+ }
tasklet_schedule(&msm_uport->rx.tlet);
}
@@ -1661,8 +1684,11 @@
{
unsigned long sr_status;
unsigned long flags;
+ int ret;
struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
struct circ_buf *tx_buf = &uport->state->xmit;
+ struct msm_hs_rx *rx = &msm_uport->rx;
+ struct sps_pipe *sps_pipe_handle = rx->prod.pipe_handle;
mutex_lock(&msm_uport->clk_mutex);
spin_lock_irqsave(&uport->lock, flags);
@@ -1689,26 +1715,26 @@
switch (msm_uport->clk_req_off_state) {
case CLK_REQ_OFF_START:
msm_uport->clk_req_off_state = CLK_REQ_OFF_RXSTALE_ISSUED;
- if (is_blsp_uart(msm_uport)) {
- /* Stale interrupt when RX-FIFO is empty
- * will fire if STALE_IRQ_EMPTY bit is set
- * for UART Core v1.4
- */
- msm_hs_write(uport, UARTDM_BCR_ADDR,
- UARTDM_BCR_STALE_IRQ_EMPTY);
+
+ if (!is_blsp_uart(msm_uport)) {
+ msm_hs_write(uport, UARTDM_CR_ADDR, FORCE_STALE_EVENT);
+ /*
+ * Before returning make sure that device writel
+ * completed. Hence mb() requires here.
+ */
+ mb();
}
- msm_hs_write(uport, UARTDM_CR_ADDR, FORCE_STALE_EVENT);
- /*
- * Before returning make sure that device writel completed.
- * Hence mb() requires here.
- */
- mb();
spin_unlock_irqrestore(&uport->lock, flags);
mutex_unlock(&msm_uport->clk_mutex);
return 0; /* RXSTALE flush not complete - retry */
case CLK_REQ_OFF_RXSTALE_ISSUED:
case CLK_REQ_OFF_FLUSH_ISSUED:
spin_unlock_irqrestore(&uport->lock, flags);
+ if (is_blsp_uart(msm_uport)) {
+ msm_uport->clk_req_off_state =
+ CLK_REQ_OFF_RXSTALE_FLUSHED;
+ sps_disconnect(sps_pipe_handle);
+ }
mutex_unlock(&msm_uport->clk_mutex);
return 0; /* RXSTALE flush not complete - retry */
case CLK_REQ_OFF_RXSTALE_FLUSHED:
@@ -1716,10 +1742,24 @@
}
if (msm_uport->rx.flush != FLUSH_SHUTDOWN) {
- if (msm_uport->rx.flush == FLUSH_NONE)
+ if (msm_uport->rx.flush == FLUSH_NONE) {
msm_hs_stop_rx_locked(uport);
+ if (!is_blsp_uart(msm_uport))
+ msm_uport->rx_discard_flush_issued = true;
+ }
spin_unlock_irqrestore(&uport->lock, flags);
+ if (msm_uport->rx_discard_flush_issued) {
+ pr_debug("%s(): wainting for flush completion.\n",
+ __func__);
+ ret = wait_event_timeout(msm_uport->rx.wait,
+ msm_uport->rx_discard_flush_issued == false,
+ RX_FLUSH_COMPLETE_TIMEOUT);
+ if (!ret)
+ pr_err("%s(): Flush complete pending.\n",
+ __func__);
+ }
+
mutex_unlock(&msm_uport->clk_mutex);
return 0; /* come back later to really clock off */
}
@@ -1804,24 +1844,13 @@
mb();
if (msm_uport->clk_req_off_state ==
- CLK_REQ_OFF_RXSTALE_ISSUED) {
+ CLK_REQ_OFF_RXSTALE_ISSUED)
msm_uport->clk_req_off_state =
- CLK_REQ_OFF_FLUSH_ISSUED;
+ CLK_REQ_OFF_FLUSH_ISSUED;
- if (is_blsp_uart(msm_uport)) {
- /* Reset BCR Register for UARTDM Core v14*/
- msm_hs_write(uport, UARTDM_BCR_ADDR, 0x0);
- }
- }
-
- if (rx->flush == FLUSH_NONE) {
+ if (!is_blsp_uart(msm_uport) && (rx->flush == FLUSH_NONE)) {
rx->flush = FLUSH_DATA_READY;
- if (is_blsp_uart(msm_uport)) {
- queue_work(msm_uport->hsuart_wq,
- &msm_uport->reset_bam_rx);
- } else {
- msm_dmov_flush(msm_uport->dma_rx_channel, 1);
- }
+ msm_dmov_flush(msm_uport->dma_rx_channel, 1);
}
}
/* tx ready interrupt */
@@ -1951,8 +1980,14 @@
mb();
}
hrtimer_try_to_cancel(&msm_uport->clk_off_timer);
- if (msm_uport->rx.flush == FLUSH_SHUTDOWN)
+ if (msm_uport->rx.flush == FLUSH_SHUTDOWN) {
+ if (is_blsp_uart(msm_uport)) {
+ spin_unlock_irqrestore(&uport->lock, flags);
+ msm_hs_spsconnect_rx(uport);
+ spin_lock_irqsave(&uport->lock, flags);
+ }
msm_hs_start_rx_locked(uport);
+ }
if (msm_uport->rx.flush == FLUSH_STOP)
msm_uport->rx.flush = FLUSH_IGNORE;
msm_uport->clk_state = MSM_HS_CLK_ON;
@@ -2223,9 +2258,10 @@
tx->command_ptr->dst_row_addr =
msm_uport->uport.mapbase + UARTDM_TF_ADDR;
+
+ msm_uport->imr_reg |= UARTDM_ISR_RXSTALE_BMSK;
}
- msm_uport->imr_reg |= UARTDM_ISR_RXSTALE_BMSK;
/* Enable reading the current CTS, no harm even if CTS is ignored */
msm_uport->imr_reg |= UARTDM_ISR_CURRENT_CTS_BMSK;
@@ -2336,7 +2372,10 @@
}
/* Set up Uart Receive */
- msm_hs_write(uport, UARTDM_RFWR_ADDR, 0);
+ if (is_blsp_uart(msm_uport))
+ msm_hs_write(uport, UARTDM_RFWR_ADDR, 32);
+ else
+ msm_hs_write(uport, UARTDM_RFWR_ADDR, 0);
INIT_DELAYED_WORK(&rx->flip_insert_work, flip_insert_work);
@@ -2933,9 +2972,6 @@
INIT_WORK(&msm_uport->clock_off_w, hsuart_clock_off_work);
- /* Init work for Reset Rx bam endpoints */
- INIT_WORK(&msm_uport->reset_bam_rx, hsuart_reset_bam_rx_work);
-
/* Init work for sps_disconnect in stop_rx_locked */
INIT_WORK(&msm_uport->disconnect_rx_endpoint,
hsuart_disconnect_rx_endpoint_work);
diff --git a/drivers/tty/serial/msm_serial_hs_hwreg.h b/drivers/tty/serial/msm_serial_hs_hwreg.h
index 9fa4f55..cdd0450 100644
--- a/drivers/tty/serial/msm_serial_hs_hwreg.h
+++ b/drivers/tty/serial/msm_serial_hs_hwreg.h
@@ -68,6 +68,14 @@
*/
#define UARTDM_BCR_STALE_IRQ_EMPTY 0x2
+/* TRANSFER_CONTROL Register for UARTDM Core v1.4 */
+#define UARTDM_RX_TRANS_CTRL_ADDR 0xcc
+
+/* TRANSFER_CONTROL Register bits */
+#define RX_STALE_AUTO_RE_EN 0x1
+#define RX_TRANS_AUTO_RE_ACTIVATE 0x2
+#define RX_DMRX_CYCLIC_EN 0x4
+
/* write only register */
#define UARTDM_CSR_115200 0xFF
#define UARTDM_CSR_57600 0xEE
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 3e15ea7..fddb4fe 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -134,6 +134,8 @@
source "drivers/usb/musb/Kconfig"
+source "drivers/usb/renesas_usbhs/Kconfig"
+
source "drivers/usb/class/Kconfig"
source "drivers/usb/storage/Kconfig"
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index e5aca6f..b48785c 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -535,6 +535,7 @@
static int dwc3_msm_dbm_ep_unconfig(u8 usb_ep)
{
u8 dbm_ep;
+ u32 data;
dev_dbg(context->dev, "%s\n", __func__);
@@ -548,10 +549,18 @@
context->ep_num_mapping[dbm_ep] = 0;
- dwc3_msm_write_reg(context->base, DBM_EP_CFG(dbm_ep), 0);
+ data = dwc3_msm_read_reg(context->base, DBM_EP_CFG(dbm_ep));
+ data &= (~0x1);
+ dwc3_msm_write_reg(context->base, DBM_EP_CFG(dbm_ep), data);
/* Reset the dbm endpoint */
dwc3_msm_dbm_ep_soft_reset(dbm_ep, true);
+ /*
+ * 10 usec delay is required before deasserting DBM endpoint reset
+ * according to hardware programming guide.
+ */
+ udelay(10);
+ dwc3_msm_dbm_ep_soft_reset(dbm_ep, false);
return 0;
}
@@ -888,6 +897,8 @@
}
(*new_ep_ops) = (*ep->ops);
new_ep_ops->queue = dwc3_msm_ep_queue;
+ new_ep_ops->disable = ep->ops->disable;
+
ep->ops = new_ep_ops;
/*
@@ -1328,24 +1339,27 @@
dwc3_msm_write_readback(msm->base, SS_PHY_PARAM_CTRL_1, 0x07, 0x5);
}
-static void dwc3_msm_block_reset(void)
+static void dwc3_msm_block_reset(bool core_reset)
{
+
struct dwc3_msm *mdwc = context;
int ret = 0;
- ret = dwc3_msm_link_clk_reset(1);
- if (ret)
- return;
+ if (core_reset) {
+ ret = dwc3_msm_link_clk_reset(1);
+ if (ret)
+ return;
- usleep_range(1000, 1200);
- ret = dwc3_msm_link_clk_reset(0);
- if (ret)
- return;
+ usleep_range(1000, 1200);
+ ret = dwc3_msm_link_clk_reset(0);
+ if (ret)
+ return;
- usleep_range(10000, 12000);
+ usleep_range(10000, 12000);
- /* Reinitialize QSCRATCH registers after block reset */
- dwc3_msm_qscratch_reg_init(mdwc);
+ /* Reinitialize QSCRATCH registers after block reset */
+ dwc3_msm_qscratch_reg_init(mdwc);
+ }
/* Reset the DBM */
dwc3_msm_dbm_soft_reset(1);
diff --git a/drivers/usb/dwc3/dwc3_otg.c b/drivers/usb/dwc3/dwc3_otg.c
index 01fad76..282f49e 100644
--- a/drivers/usb/dwc3/dwc3_otg.c
+++ b/drivers/usb/dwc3/dwc3_otg.c
@@ -206,6 +206,20 @@
return ret;
}
dwc3_otg_notify_host_mode(otg, on);
+
+ /*
+ * Perform USB hardware RESET (both core reset and DBM reset)
+ * when moving from host to peripheral. This is required for
+ * peripheral mode to work.
+ */
+ if (ext_xceiv && ext_xceiv->otg_capability &&
+ ext_xceiv->ext_block_reset)
+ ext_xceiv->ext_block_reset(true);
+
+ /* re-init core and OTG registers as block reset clears these */
+ dwc3_post_host_reset_core_init(dwc);
+ if (ext_xceiv && !ext_xceiv->otg_capability)
+ dwc3_otg_reset(dotg);
}
return 0;
@@ -253,7 +267,6 @@
{
struct dwc3_otg *dotg = container_of(otg, struct dwc3_otg, otg);
struct dwc3_ext_xceiv *ext_xceiv = dotg->ext_xceiv;
- struct dwc3 *dwc = dotg->dwc;
if (!otg->gadget)
return -EINVAL;
@@ -262,20 +275,11 @@
dev_dbg(otg->phy->dev, "%s: turn on gadget %s\n",
__func__, otg->gadget->name);
- /*
- * Hardware reset is required to support below scenarios:
- * 1. Host <-> peripheral switching
- * 2. Once an endpoint is configured in DBM (BAM) mode, it
- * can be unconfigured only after RESET
- */
+ /* Core reset is not required during start peripheral. Only
+ * DBM reset is required, hence perform only DBM reset here */
if (ext_xceiv && ext_xceiv->otg_capability &&
ext_xceiv->ext_block_reset)
- ext_xceiv->ext_block_reset();
-
- /* re-init core and OTG registers as block reset clears these */
- dwc3_post_host_reset_core_init(dwc);
- if (ext_xceiv && !ext_xceiv->otg_capability)
- dwc3_otg_reset(dotg);
+ ext_xceiv->ext_block_reset(false);
dwc3_otg_set_peripheral_regs(dotg);
usb_gadget_vbus_connect(otg->gadget);
diff --git a/drivers/usb/dwc3/dwc3_otg.h b/drivers/usb/dwc3/dwc3_otg.h
index d3b1b4a..c2fab53 100644
--- a/drivers/usb/dwc3/dwc3_otg.h
+++ b/drivers/usb/dwc3/dwc3_otg.h
@@ -109,7 +109,7 @@
void (*notify_ext_events)(struct usb_otg *otg,
enum dwc3_ext_events ext_event);
/* for block reset USB core */
- void (*ext_block_reset)(void);
+ void (*ext_block_reset)(bool core_reset);
};
/* for external transceiver driver */
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index 87a0078..d4bdf99 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -77,8 +77,8 @@
#include "f_rndis.c"
#include "rndis.c"
#include "f_qc_ecm.c"
-#include "u_bam_data.c"
#include "f_mbim.c"
+#include "u_bam_data.c"
#include "f_ecm.c"
#include "f_qc_rndis.c"
#include "u_ether.c"
@@ -865,10 +865,18 @@
fmbim_cleanup();
}
+
+/* mbim transport string */
+static char mbim_transports[MAX_XPORT_STR_LEN];
+
static int mbim_function_bind_config(struct android_usb_function *f,
struct usb_configuration *c)
{
- return mbim_bind_config(c, 0);
+ char *trans;
+
+ pr_debug("%s: mbim transport is %s", __func__, mbim_transports);
+ trans = strim(mbim_transports);
+ return mbim_bind_config(c, 0, trans);
}
static int mbim_function_ctrlrequest(struct android_usb_function *f,
@@ -878,12 +886,34 @@
return mbim_ctrlrequest(cdev, c);
}
+static ssize_t mbim_transports_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%s\n", mbim_transports);
+}
+
+static ssize_t mbim_transports_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ strlcpy(mbim_transports, buf, sizeof(mbim_transports));
+ return size;
+}
+
+static DEVICE_ATTR(mbim_transports, S_IRUGO | S_IWUSR, mbim_transports_show,
+ mbim_transports_store);
+
+static struct device_attribute *mbim_function_attributes[] = {
+ &dev_attr_mbim_transports,
+ NULL
+};
+
static struct android_usb_function mbim_function = {
.name = "usb_mbim",
.cleanup = mbim_function_cleanup,
.bind_config = mbim_function_bind_config,
.init = mbim_function_init,
.ctrlrequest = mbim_function_ctrlrequest,
+ .attributes = mbim_function_attributes,
};
#ifdef CONFIG_SND_PCM
@@ -2093,6 +2123,7 @@
bool audio_enabled = false;
static DEFINE_RATELIMIT_STATE(rl, 10*HZ, 1);
+
if (!cdev)
return -ENODEV;
diff --git a/drivers/usb/gadget/ci13xxx_msm.c b/drivers/usb/gadget/ci13xxx_msm.c
index ccede0c..569f200 100644
--- a/drivers/usb/gadget/ci13xxx_msm.c
+++ b/drivers/usb/gadget/ci13xxx_msm.c
@@ -3,12 +3,6 @@
* 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>
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index 81fc1cc..e0255ce 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -3280,6 +3280,7 @@
static int ci13xxx_start(struct usb_gadget_driver *driver,
int (*bind)(struct usb_gadget *));
static int ci13xxx_stop(struct usb_gadget_driver *driver);
+
/**
* Device operations part of the API to the USB controller hardware,
* which don't involve endpoints (or i/o)
diff --git a/drivers/usb/gadget/ci13xxx_udc.h b/drivers/usb/gadget/ci13xxx_udc.h
index 76028b2..3145418 100644
--- a/drivers/usb/gadget/ci13xxx_udc.h
+++ b/drivers/usb/gadget/ci13xxx_udc.h
@@ -137,10 +137,10 @@
#define CI13XXX_CONTROLLER_RESET_EVENT 0
#define CI13XXX_CONTROLLER_CONNECT_EVENT 1
#define CI13XXX_CONTROLLER_SUSPEND_EVENT 2
-#define CI13XXX_CONTROLLER_REMOTE_WAKEUP_EVENT 3
-#define CI13XXX_CONTROLLER_RESUME_EVENT 4
-#define CI13XXX_CONTROLLER_DISCONNECT_EVENT 5
-#define CI13XXX_CONTROLLER_UDC_STARTED_EVENT 6
+#define CI13XXX_CONTROLLER_REMOTE_WAKEUP_EVENT 3
+#define CI13XXX_CONTROLLER_RESUME_EVENT 4
+#define CI13XXX_CONTROLLER_DISCONNECT_EVENT 5
+#define CI13XXX_CONTROLLER_UDC_STARTED_EVENT 6
void (*notify_event) (struct ci13xxx *udc, unsigned event);
};
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 4bc0da2..de4a233 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -176,13 +176,12 @@
_ep->comp_desc = comp_desc;
if (g->speed == USB_SPEED_SUPER) {
switch (usb_endpoint_type(_ep->desc)) {
- case USB_ENDPOINT_XFER_BULK:
- case USB_ENDPOINT_XFER_INT:
- _ep->maxburst = comp_desc->bMaxBurst + 1;
- break;
case USB_ENDPOINT_XFER_ISOC:
/* mult: bits 1:0 of bmAttributes */
_ep->mult = comp_desc->bmAttributes & 0x3;
+ case USB_ENDPOINT_XFER_BULK:
+ case USB_ENDPOINT_XFER_INT:
+ _ep->maxburst = comp_desc->bMaxBurst + 1;
break;
default:
if (comp_desc->bMaxBurst != 0)
@@ -693,7 +692,6 @@
CONFIG_USB_GADGET_VBUS_DRAW;
done:
usb_gadget_vbus_draw(gadget, power);
-
if (result >= 0 && cdev->delayed_status)
result = USB_GADGET_DELAYED_STATUS;
return result;
diff --git a/drivers/usb/gadget/f_mbim.c b/drivers/usb/gadget/f_mbim.c
index a32dd15..52e3126 100644
--- a/drivers/usb/gadget/f_mbim.c
+++ b/drivers/usb/gadget/f_mbim.c
@@ -84,6 +84,7 @@
wait_queue_head_t read_wq;
wait_queue_head_t write_wq;
+ enum transport_type xport;
u8 port_num;
struct data_port bam_port;
struct mbim_notify_port not_port;
@@ -143,6 +144,9 @@
#define NTB_OUT_SIZE (0x1000)
#define NDP_IN_DIVISOR (0x4)
+#define NTB_DEFAULT_IN_SIZE_IPA (0x2000)
+#define NTB_OUT_SIZE_IPA (0x2000)
+
#define FORMATS_SUPPORTED USB_CDC_NCM_NTB16_SUPPORTED
static struct usb_cdc_ncm_ntb_parameters ntb_parameters = {
@@ -659,22 +663,56 @@
return 0;
}
+int mbim_configure_params(void)
+{
+ struct teth_aggr_params aggr_params;
+ int ret = 0;
+
+ aggr_params.dl.aggr_prot = TETH_AGGR_PROTOCOL_MBIM;
+ aggr_params.dl.max_datagrams = ntb_parameters.wNtbOutMaxDatagrams;
+ aggr_params.dl.max_transfer_size_byte = ntb_parameters.dwNtbInMaxSize;
+
+ aggr_params.ul.aggr_prot = TETH_AGGR_PROTOCOL_MBIM;
+ aggr_params.ul.max_datagrams = ntb_parameters.wNtbOutMaxDatagrams;
+ aggr_params.ul.max_transfer_size_byte = ntb_parameters.dwNtbOutMaxSize;
+
+ ret = teth_bridge_set_aggr_params(&aggr_params);
+ if (ret)
+ pr_err("%s: teth_bridge_set_aggr_params failed\n", __func__);
+
+ return ret;
+}
+
static int mbim_bam_connect(struct f_mbim *dev)
{
int ret;
+ u8 src_connection_idx, dst_connection_idx;
+ struct usb_gadget *gadget = dev->cdev->gadget;
+ enum peer_bam bam_name = (dev->xport == USB_GADGET_XPORT_BAM2BAM_IPA) ?
+ IPA_P_BAM : A2_P_BAM;
pr_info("dev:%p portno:%d\n", dev, dev->port_num);
+ src_connection_idx = usb_bam_get_connection_idx(gadget->name, bam_name,
+ USB_TO_PEER_PERIPHERAL, dev->port_num);
+ dst_connection_idx = usb_bam_get_connection_idx(gadget->name, bam_name,
+ PEER_PERIPHERAL_TO_USB, dev->port_num);
+ if (src_connection_idx < 0 || dst_connection_idx < 0) {
+ pr_err("%s: usb_bam_get_connection_idx failed\n", __func__);
+ return ret;
+ }
+
ret = bam_data_connect(&dev->bam_port, dev->port_num,
- USB_GADGET_XPORT_BAM2BAM, dev->port_num, USB_FUNC_MBIM);
+ dev->xport, src_connection_idx, dst_connection_idx,
+ USB_FUNC_MBIM);
+
if (ret) {
pr_err("bam_data_setup failed: err:%d\n",
ret);
return ret;
- } else {
- pr_info("mbim bam connected\n");
}
+ pr_info("mbim bam connected\n");
return 0;
}
@@ -1592,7 +1630,8 @@
* Context: single threaded during gadget setup
* Returns zero on success, else negative errno.
*/
-int mbim_bind_config(struct usb_configuration *c, unsigned portno)
+int mbim_bind_config(struct usb_configuration *c, unsigned portno,
+ char *xport_name)
{
struct f_mbim *mbim = NULL;
int status = 0;
@@ -1651,6 +1690,19 @@
mbim->function.disable = mbim_disable;
mbim->function.suspend = mbim_suspend;
mbim->function.resume = mbim_resume;
+ mbim->xport = str_to_xport(xport_name);
+
+ if (mbim->xport != USB_GADGET_XPORT_BAM2BAM_IPA) {
+ /* Use BAM2BAM by default if not IPA */
+ mbim->xport = USB_GADGET_XPORT_BAM2BAM;
+ } else {
+ /* For IPA we use limit of 16 */
+ ntb_parameters.wNtbOutMaxDatagrams = 16;
+ /* For IPA this is proven to give maximum throughput */
+ ntb_parameters.dwNtbInMaxSize =
+ cpu_to_le32(NTB_DEFAULT_IN_SIZE_IPA);
+ ntb_parameters.dwNtbOutMaxSize = cpu_to_le32(NTB_OUT_SIZE_IPA);
+ }
INIT_LIST_HEAD(&mbim->cpkt_req_q);
INIT_LIST_HEAD(&mbim->cpkt_resp_q);
diff --git a/drivers/usb/gadget/f_qc_ecm.c b/drivers/usb/gadget/f_qc_ecm.c
index 559fd04..51f0e50 100644
--- a/drivers/usb/gadget/f_qc_ecm.c
+++ b/drivers/usb/gadget/f_qc_ecm.c
@@ -390,14 +390,27 @@
static int ecm_qc_bam_connect(struct f_ecm_qc *dev)
{
int ret;
+ u8 src_connection_idx, dst_connection_idx;
+ struct usb_composite_dev *cdev = dev->port.func.config->cdev;
+ struct usb_gadget *gadget = cdev->gadget;
+ enum peer_bam peer_bam = (dev->xport == USB_GADGET_XPORT_BAM2BAM_IPA) ?
+ IPA_P_BAM : A2_P_BAM;
- ecm_qc_bam_port.cdev = dev->port.func.config->cdev;
+ ecm_qc_bam_port.cdev = cdev;
ecm_qc_bam_port.in = dev->port.in_ep;
ecm_qc_bam_port.out = dev->port.out_ep;
/* currently we use the first connection */
+ src_connection_idx = usb_bam_get_connection_idx(gadget->name, peer_bam,
+ USB_TO_PEER_PERIPHERAL, 0);
+ dst_connection_idx = usb_bam_get_connection_idx(gadget->name, peer_bam,
+ PEER_PERIPHERAL_TO_USB, 0);
+ if (src_connection_idx < 0 || dst_connection_idx < 0) {
+ pr_err("%s: usb_bam_get_connection_idx failed\n", __func__);
+ return ret;
+ }
ret = bam_data_connect(&ecm_qc_bam_port, 0, dev->xport,
- 0, USB_FUNC_ECM);
+ src_connection_idx, dst_connection_idx, USB_FUNC_ECM);
if (ret) {
pr_err("bam_data_connect failed: err:%d\n", ret);
return ret;
diff --git a/drivers/usb/gadget/f_qc_rndis.c b/drivers/usb/gadget/f_qc_rndis.c
index 51d7bc1..8b01176 100644
--- a/drivers/usb/gadget/f_qc_rndis.c
+++ b/drivers/usb/gadget/f_qc_rndis.c
@@ -421,22 +421,33 @@
static int rndis_qc_bam_connect(struct f_rndis_qc *dev)
{
int ret;
+ u8 src_connection_idx, dst_connection_idx;
+ struct usb_composite_dev *cdev = dev->port.func.config->cdev;
+ struct usb_gadget *gadget = cdev->gadget;
- dev->bam_port.cdev = dev->port.func.config->cdev;
+ dev->bam_port.cdev = cdev;
dev->bam_port.in = dev->port.in_ep;
dev->bam_port.out = dev->port.out_ep;
/* currently we use the first connection */
+ src_connection_idx = usb_bam_get_connection_idx(gadget->name, A2_P_BAM,
+ USB_TO_PEER_PERIPHERAL, 0);
+ dst_connection_idx = usb_bam_get_connection_idx(gadget->name, A2_P_BAM,
+ PEER_PERIPHERAL_TO_USB, 0);
+ if (src_connection_idx < 0 || dst_connection_idx < 0) {
+ pr_err("%s: usb_bam_get_connection_idx failed\n", __func__);
+ return ret;
+ }
ret = bam_data_connect(&dev->bam_port, 0, USB_GADGET_XPORT_BAM2BAM,
- 0, USB_FUNC_RNDIS);
+ src_connection_idx, dst_connection_idx, USB_FUNC_RNDIS);
if (ret) {
pr_err("bam_data_connect failed: err:%d\n",
ret);
return ret;
- } else {
- pr_info("rndis bam connected\n");
}
+ pr_info("rndis bam connected\n");
+
return 0;
}
diff --git a/drivers/usb/gadget/f_qdss.c b/drivers/usb/gadget/f_qdss.c
index 3069bcb..cece500 100644
--- a/drivers/usb/gadget/f_qdss.c
+++ b/drivers/usb/gadget/f_qdss.c
@@ -1,7 +1,7 @@
/*
* f_qdss.c -- QDSS function Driver
*
- * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2013, 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
@@ -410,7 +410,6 @@
clear_eps(f);
clear_desc(c->cdev->gadget, f);
- msm_dwc3_restart_usb_session();
}
static void qdss_eps_disable(struct usb_function *f)
@@ -447,8 +446,8 @@
qdss->ch.notify(qdss->ch.priv, USB_QDSS_DISCONNECT, NULL,
NULL);
/* If the app was never started, we can skip USB BAM reset */
- status = set_qdss_data_connection(qdss->data,
- qdss->data->address, 0);
+ status = set_qdss_data_connection(qdss->cdev->gadget,
+ qdss->data, qdss->data->address, 0);
if (status)
pr_err("qdss_disconnect error");
}
@@ -467,13 +466,13 @@
qdss->usb_connected = 0;
spin_unlock_irqrestore(&qdss->lock, flags);
+ /*cancell all active xfers*/
+ qdss_eps_disable(f);
+
status = uninit_data(qdss->data);
if (status)
pr_err("%s: uninit_data error\n", __func__);
- /*cancell all active xfers*/
- qdss_eps_disable(f);
-
schedule_work(&qdss->disconnect_w);
}
@@ -490,7 +489,7 @@
return;
}
- status = set_qdss_data_connection(qdss->data,
+ status = set_qdss_data_connection(qdss->cdev->gadget, qdss->data,
qdss->data->address, 1);
if (status) {
pr_err("set_qdss_data_connection error");
diff --git a/drivers/usb/gadget/f_rmnet.c b/drivers/usb/gadget/f_rmnet.c
index af68827..4b9dfbf 100644
--- a/drivers/usb/gadget/f_rmnet.c
+++ b/drivers/usb/gadget/f_rmnet.c
@@ -387,6 +387,8 @@
unsigned port_num;
enum transport_type cxport = rmnet_ports[dev->port_num].ctrl_xport;
enum transport_type dxport = rmnet_ports[dev->port_num].data_xport;
+ u8 src_connection_idx, dst_connection_idx;
+ struct usb_gadget *gadget = dev->cdev->gadget;
pr_debug("%s: ctrl xport: %s data xport: %s dev: %p portno: %d\n",
__func__, xport_to_str(cxport), xport_to_str(dxport),
@@ -435,12 +437,42 @@
}
port_num = rmnet_ports[dev->port_num].data_xport_num;
+
switch (dxport) {
case USB_GADGET_XPORT_BAM:
case USB_GADGET_XPORT_BAM2BAM:
- case USB_GADGET_XPORT_BAM2BAM_IPA:
+ src_connection_idx = usb_bam_get_connection_idx(gadget->name,
+ A2_P_BAM, USB_TO_PEER_PERIPHERAL, port_num);
+ dst_connection_idx = usb_bam_get_connection_idx(gadget->name,
+ A2_P_BAM, PEER_PERIPHERAL_TO_USB, port_num);
+ if (dst_connection_idx < 0 || src_connection_idx < 0) {
+ pr_err("%s: usb_bam_get_connection_idx failed\n",
+ __func__);
+ gsmd_ctrl_disconnect(&dev->port, port_num);
+ return ret;
+ }
ret = gbam_connect(&dev->port, port_num,
- dxport, port_num);
+ dxport, src_connection_idx, dst_connection_idx);
+ if (ret) {
+ pr_err("%s: gbam_connect failed: err:%d\n",
+ __func__, ret);
+ gsmd_ctrl_disconnect(&dev->port, port_num);
+ return ret;
+ }
+ break;
+ case USB_GADGET_XPORT_BAM2BAM_IPA:
+ src_connection_idx = usb_bam_get_connection_idx(gadget->name,
+ IPA_P_BAM, USB_TO_PEER_PERIPHERAL, port_num);
+ dst_connection_idx = usb_bam_get_connection_idx(gadget->name,
+ IPA_P_BAM, PEER_PERIPHERAL_TO_USB, port_num);
+ if (dst_connection_idx < 0 || src_connection_idx < 0) {
+ pr_err("%s: usb_bam_get_connection_idx failed\n",
+ __func__);
+ gsmd_ctrl_disconnect(&dev->port, port_num);
+ return ret;
+ }
+ ret = gbam_connect(&dev->port, port_num,
+ dxport, src_connection_idx, dst_connection_idx);
if (ret) {
pr_err("%s: gbam_connect failed: err:%d\n",
__func__, ret);
diff --git a/drivers/usb/gadget/qcom_maemo.c b/drivers/usb/gadget/qcom_maemo.c
deleted file mode 100644
index 2fb8be0..0000000
--- a/drivers/usb/gadget/qcom_maemo.c
+++ /dev/null
@@ -1,304 +0,0 @@
-/*
- * Qualcomm Maemo Composite driver
- *
- * Copyright (C) 2008 David Brownell
- * Copyright (C) 2008 Nokia Corporation
- * Copyright (C) 2009 Samsung Electronics
- * Copyright (c) 2010, The Linux Foundation. All rights reserved.
- *
- * This program from The Linux Foundation is free software; you can
- * redistribute it and/or modify it under the GNU General Public License
- * version 2 and only version 2 as published by the Free Software Foundation.
- * The original work available from [git.kernel.org ] is subject to the
- * notice below.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <linux/kernel.h>
-#include <linux/utsname.h>
-#include <linux/kdev_t.h>
-#include <linux/delay.h>
-
-
-#define DRIVER_DESC "Qcom Maemo Composite Gadget"
-#define VENDOR_ID 0x05c6
-#define PRODUCT_ID 0x902E
-
-/*
- * kbuild is not very cooperative with respect to linking separately
- * compiled library objects into one module. So for now we won't use
- * separate compilation ... ensuring init/exit sections work to shrink
- * the runtime footprint, and giving us at least some parts of what
- * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
- */
-
-#include "composite.c"
-#include "usbstring.c"
-#include "config.c"
-#include "epautoconf.c"
-
-#define USB_ETH
-
-#define USB_ETH_RNDIS
-#ifdef USB_ETH_RNDIS
-# include "f_rndis.c"
-# include "rndis.c"
-#endif
-
-
-#include "u_serial.c"
-#include "f_serial.c"
-
-#include "u_ether.c"
-
-#undef DBG /* u_ether.c has broken idea about macros */
-#undef VDBG /* so clean up after it */
-#undef ERROR
-#undef INFO
-
-#include "f_mass_storage.c"
-#include "f_diag.c"
-#include "f_rmnet.c"
-
-/*-------------------------------------------------------------------------*/
-/* string IDs are assigned dynamically */
-
-#define STRING_MANUFACTURER_IDX 0
-#define STRING_PRODUCT_IDX 1
-#define STRING_SERIAL_IDX 2
-
-/* String Table */
-static struct usb_string strings_dev[] = {
- /* These dummy values should be overridden by platform data */
- [STRING_MANUFACTURER_IDX].s = "Qualcomm Incorporated",
- [STRING_PRODUCT_IDX].s = "Usb composition",
- [STRING_SERIAL_IDX].s = "0123456789ABCDEF",
- { } /* end of list */
-};
-
-static struct usb_gadget_strings stringtab_dev = {
- .language = 0x0409, /* en-us */
- .strings = strings_dev,
-};
-
-static struct usb_gadget_strings *dev_strings[] = {
- &stringtab_dev,
- NULL,
-};
-
-static struct usb_device_descriptor device_desc = {
- .bLength = sizeof(device_desc),
- .bDescriptorType = USB_DT_DEVICE,
- .bcdUSB = __constant_cpu_to_le16(0x0200),
- .bDeviceClass = USB_CLASS_PER_INTERFACE,
- .bDeviceSubClass = 0,
- .bDeviceProtocol = 0,
- .idVendor = __constant_cpu_to_le16(VENDOR_ID),
- .idProduct = __constant_cpu_to_le16(PRODUCT_ID),
- .bcdDevice = __constant_cpu_to_le16(0xffff),
- .bNumConfigurations = 1,
-};
-
-static u8 hostaddr[ETH_ALEN];
-static struct usb_diag_ch *diag_ch;
-static struct usb_diag_platform_data usb_diag_pdata = {
- .ch_name = DIAG_LEGACY,
-};
-
-/****************************** Configurations ******************************/
-static struct fsg_module_parameters mod_data = {
- .stall = 0
-};
-FSG_MODULE_PARAMETERS(/* no prefix */, mod_data);
-
-static struct fsg_common *fsg_common;
-static int maemo_setup_config(struct usb_configuration *c,
- const struct usb_ctrlrequest *ctrl);
-
-static int maemo_do_config(struct usb_configuration *c)
-{
- int ret;
-
- ret = rndis_bind_config(c, hostaddr);
- if (ret < 0)
- return ret;
-
- ret = diag_function_add(c);
- if (ret < 0)
- return ret;
-
- ret = gser_bind_config(c, 0);
- if (ret < 0)
- return ret;
-
- ret = gser_bind_config(c, 1);
- if (ret < 0)
- return ret;
-
- ret = rmnet_function_add(c);
- if (ret < 0)
- return ret;
-
- ret = fsg_add(c->cdev, c, fsg_common);
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-static struct usb_configuration maemo_config_driver = {
- .label = "Qcom Maemo Gadget",
- .bind = maemo_do_config,
- .setup = maemo_setup_config,
- .bConfigurationValue = 1,
- .bMaxPower = 0xFA,
-};
-static int maemo_setup_config(struct usb_configuration *c,
- const struct usb_ctrlrequest *ctrl)
-{
- int i;
- int ret = -EOPNOTSUPP;
-
- for (i = 0; i < maemo_config_driver.next_interface_id; i++) {
- if (maemo_config_driver.interface[i]->setup) {
- ret = maemo_config_driver.interface[i]->setup(
- maemo_config_driver.interface[i], ctrl);
- if (ret >= 0)
- return ret;
- }
- }
-
- return ret;
-}
-
-static int maemo_bind(struct usb_composite_dev *cdev)
-{
- struct usb_gadget *gadget = cdev->gadget;
- int status, gcnum;
-
- /* set up diag channel */
- diag_ch = diag_setup(&usb_diag_pdata);
- if (IS_ERR(diag_ch))
- return PTR_ERR(diag_ch);
-
- /* set up network link layer */
- status = gether_setup(cdev->gadget, hostaddr);
- if (status < 0)
- goto diag_clean;
-
- /* set up serial link layer */
- status = gserial_setup(cdev->gadget, 2);
- if (status < 0)
- goto fail0;
-
- /* set up mass storage function */
- fsg_common = fsg_common_from_params(0, cdev, &mod_data);
- if (IS_ERR(fsg_common)) {
- status = PTR_ERR(fsg_common);
- goto fail1;
- }
-
- gcnum = usb_gadget_controller_number(gadget);
- if (gcnum >= 0)
- device_desc.bcdDevice = cpu_to_le16(0x0300 | gcnum);
- else {
- /* gadget zero is so simple (for now, no altsettings) that
- * it SHOULD NOT have problems with bulk-capable hardware.
- * so just warn about unrcognized controllers -- don't panic.
- *
- * things like configuration and altsetting numbering
- * can need hardware-specific attention though.
- */
- WARNING(cdev, "controller '%s' not recognized\n",
- gadget->name);
- device_desc.bcdDevice = __constant_cpu_to_le16(0x9999);
- }
-
- /* Allocate string descriptor numbers ... note that string
- * contents can be overridden by the composite_dev glue.
- */
-
- status = usb_string_id(cdev);
- if (status < 0)
- goto fail2;
- strings_dev[STRING_MANUFACTURER_IDX].id = status;
- device_desc.iManufacturer = status;
-
- status = usb_string_id(cdev);
- if (status < 0)
- goto fail2;
- strings_dev[STRING_PRODUCT_IDX].id = status;
- device_desc.iProduct = status;
-
- if (!usb_gadget_set_selfpowered(gadget))
- maemo_config_driver.bmAttributes |= USB_CONFIG_ATT_SELFPOWER;
-
- if (gadget->ops->wakeup)
- maemo_config_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
-
- /* register our first configuration */
- status = usb_add_config(cdev, &maemo_config_driver);
- if (status < 0)
- goto fail2;
-
- usb_gadget_set_selfpowered(gadget);
- dev_info(&gadget->dev, DRIVER_DESC "\n");
- fsg_common_put(fsg_common);
- return 0;
-
-fail2:
- fsg_common_put(fsg_common);
-fail1:
- gserial_cleanup();
-fail0:
- gether_cleanup();
-diag_clean:
- diag_cleanup(diag_ch);
-
- return status;
-}
-
-static int __exit maemo_unbind(struct usb_composite_dev *cdev)
-{
- gserial_cleanup();
- gether_cleanup();
- diag_cleanup(diag_ch);
- return 0;
-}
-
-static struct usb_composite_driver qcom_maemo_driver = {
- .name = "Qcom Maemo Gadget",
- .dev = &device_desc,
- .strings = dev_strings,
- .bind = maemo_bind,
- .unbind = __exit_p(maemo_unbind),
-};
-
-static int __init qcom_maemo_usb_init(void)
-{
- return usb_composite_register(&qcom_maemo_driver);
-}
-module_init(qcom_maemo_usb_init);
-
-static void __exit qcom_maemo_usb_cleanup(void)
-{
- usb_composite_unregister(&qcom_maemo_driver);
-}
-module_exit(qcom_maemo_usb_cleanup);
-
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL v2");
-MODULE_VERSION("1.0");
diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c
index 801d24d..7ac5b64 100644
--- a/drivers/usb/gadget/rndis.c
+++ b/drivers/usb/gadget/rndis.c
@@ -687,6 +687,12 @@
rndis_reset_cmplt_type *resp;
rndis_resp_t *r;
struct rndis_params *params = rndis_per_dev_params + configNr;
+ u32 length;
+ u8 *xbuf;
+
+ /* drain the response queue */
+ while ((xbuf = rndis_get_next_response(configNr, &length)))
+ rndis_free_response(configNr, xbuf);
r = rndis_add_response(configNr, sizeof(rndis_reset_cmplt_type));
if (!r)
diff --git a/drivers/usb/gadget/u_bam.c b/drivers/usb/gadget/u_bam.c
index 5a6faf2..3c3fbca 100644
--- a/drivers/usb/gadget/u_bam.c
+++ b/drivers/usb/gadget/u_bam.c
@@ -100,7 +100,8 @@
u32 src_pipe_idx;
u32 dst_pipe_idx;
- u8 connection_idx;
+ u8 src_connection_idx;
+ u8 dst_connection_idx;
enum transport_type trans;
struct usb_bam_connect_ipa_params ipa_params;
@@ -663,7 +664,7 @@
int ret;
if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
- ret = usb_bam_disconnect_ipa(d->connection_idx, &d->ipa_params);
+ ret = usb_bam_disconnect_ipa(&d->ipa_params);
if (ret)
pr_err("%s: usb_bam_disconnect_ipa failed: err:%d\n",
__func__, ret);
@@ -715,10 +716,15 @@
int ret;
if (d->trans == USB_GADGET_XPORT_BAM2BAM) {
- ret = usb_bam_connect(d->connection_idx, &d->src_pipe_idx,
- &d->dst_pipe_idx);
+ ret = usb_bam_connect(d->src_connection_idx, &d->src_pipe_idx);
if (ret) {
- pr_err("%s: usb_bam_connect failed: err:%d\n",
+ pr_err("%s: usb_bam_connect (src) failed: err:%d\n",
+ __func__, ret);
+ return;
+ }
+ ret = usb_bam_connect(d->dst_connection_idx, &d->dst_pipe_idx);
+ if (ret) {
+ pr_err("%s: usb_bam_connect (dst) failed: err:%d\n",
__func__, ret);
return;
}
@@ -787,8 +793,7 @@
if (d->trans == USB_GADGET_XPORT_BAM2BAM && port->port_num == 0) {
/* Register for peer reset callback */
- usb_bam_register_peer_reset_cb(d->connection_idx,
- gbam_peer_reset_cb, port);
+ usb_bam_register_peer_reset_cb(gbam_peer_reset_cb, port);
ret = usb_bam_client_ready(true);
if (ret) {
@@ -832,7 +837,7 @@
msm_hw_bam_disable(1);
/* Reset BAM */
- ret = usb_bam_reset();
+ ret = usb_bam_a2_reset();
if (ret) {
pr_err("%s: BAM reset failed %d\n", __func__, ret);
goto reenable_eps;
@@ -867,7 +872,7 @@
/* Unregister the peer reset callback */
if (d->trans == USB_GADGET_XPORT_BAM2BAM && port->port_num == 0)
- usb_bam_register_peer_reset_cb(d->connection_idx, NULL, NULL);
+ usb_bam_register_peer_reset_cb(NULL, NULL);
return 0;
}
@@ -1216,7 +1221,8 @@
}
int gbam_connect(struct grmnet *gr, u8 port_num,
- enum transport_type trans, u8 connection_idx)
+ enum transport_type trans, u8 src_connection_idx,
+ u8 dst_connection_idx)
{
struct gbam_port *port;
struct bam_ch_info *d;
@@ -1283,12 +1289,14 @@
if (trans == USB_GADGET_XPORT_BAM2BAM) {
port->gr = gr;
- d->connection_idx = connection_idx;
+ d->src_connection_idx = src_connection_idx;
+ d->dst_connection_idx = dst_connection_idx;
} else if (trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
port->gr = gr;
d->ipa_params.src_pipe = &(d->src_pipe_idx);
d->ipa_params.dst_pipe = &(d->dst_pipe_idx);
- d->ipa_params.idx = connection_idx;
+ d->ipa_params.src_idx = src_connection_idx;
+ d->ipa_params.dst_idx = dst_connection_idx;
}
d->trans = trans;
@@ -1379,7 +1387,7 @@
pr_debug("%s: suspended port %d\n", __func__, port_num);
- usb_bam_register_wake_cb(d->connection_idx, gbam_wake_cb, port);
+ usb_bam_register_wake_cb(d->dst_connection_idx, gbam_wake_cb, port);
}
void gbam_resume(struct grmnet *gr, u8 port_num, enum transport_type trans)
@@ -1396,5 +1404,5 @@
pr_debug("%s: resumed port %d\n", __func__, port_num);
- usb_bam_register_wake_cb(d->connection_idx, NULL, NULL);
+ usb_bam_register_wake_cb(d->dst_connection_idx, NULL, NULL);
}
diff --git a/drivers/usb/gadget/u_bam_data.c b/drivers/usb/gadget/u_bam_data.c
index 700d07f..eec9e37 100644
--- a/drivers/usb/gadget/u_bam_data.c
+++ b/drivers/usb/gadget/u_bam_data.c
@@ -47,7 +47,8 @@
u32 src_pipe_idx;
u32 dst_pipe_idx;
- u8 connection_idx;
+ u8 src_connection_idx;
+ u8 dst_connection_idx;
enum function_type func_type;
enum transport_type trans;
@@ -135,7 +136,7 @@
msm_hw_bam_disable(1);
/* Reset BAM */
- ret = usb_bam_reset();
+ ret = usb_bam_a2_reset();
if (ret) {
pr_err("%s: BAM reset failed %d\n", __func__, ret);
goto reenable_eps;
@@ -169,7 +170,7 @@
}
/* Unregister the peer reset callback */
- usb_bam_register_peer_reset_cb(d->connection_idx, NULL, NULL);
+ usb_bam_register_peer_reset_cb(NULL, NULL);
return 0;
}
@@ -182,9 +183,11 @@
int ret;
if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
+ if (d->func_type == USB_FUNC_MBIM)
+ teth_bridge_disconnect();
if (d->func_type == USB_FUNC_ECM)
ecm_ipa_disconnect(d->ipa_params.priv);
- ret = usb_bam_disconnect_ipa(d->connection_idx, &d->ipa_params);
+ ret = usb_bam_disconnect_ipa(&d->ipa_params);
if (ret)
pr_err("usb_bam_disconnect_ipa failed: err:%d\n", ret);
}
@@ -194,13 +197,28 @@
{
struct bam_data_port *port = container_of(w, struct bam_data_port,
connect_w);
+ struct teth_bridge_connect_params connect_params;
struct bam_data_ch_info *d = &port->data_ch;
+ ipa_notify_cb usb_notify_cb;
+ void *priv;
u32 sps_params;
int ret;
pr_debug("%s: Connect workqueue started", __func__);
if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
+ if (d->func_type == USB_FUNC_MBIM) {
+ ret = teth_bridge_init(&usb_notify_cb, &priv);
+ if (ret) {
+ pr_err("%s:teth_bridge_init() failed\n",
+ __func__);
+ return;
+ }
+ d->ipa_params.notify = usb_notify_cb;
+ d->ipa_params.priv = priv;
+ d->ipa_params.ipa_ep_cfg.mode.mode = IPA_BASIC;
+ }
+
d->ipa_params.client = IPA_CLIENT_USB_CONS;
d->ipa_params.dir = PEER_PERIPHERAL_TO_USB;
if (d->func_type == USB_FUNC_ECM) {
@@ -226,6 +244,23 @@
__func__, ret);
return;
}
+
+ if (d->func_type == USB_FUNC_MBIM) {
+ connect_params.ipa_usb_pipe_hdl =
+ d->ipa_params.prod_clnt_hdl;
+ connect_params.usb_ipa_pipe_hdl =
+ d->ipa_params.cons_clnt_hdl;
+ connect_params.tethering_mode =
+ TETH_TETHERING_MODE_MBIM;
+ ret = teth_bridge_connect(&connect_params);
+ if (ret) {
+ pr_err("%s:teth_bridge_connect() failed\n",
+ __func__);
+ return;
+ }
+ mbim_configure_params();
+ }
+
if (d->func_type == USB_FUNC_ECM) {
ret = ecm_ipa_connect(d->ipa_params.cons_clnt_hdl,
d->ipa_params.prod_clnt_hdl,
@@ -237,13 +272,17 @@
}
}
} else { /* transport type is USB_GADGET_XPORT_BAM2BAM */
- ret = usb_bam_connect(d->connection_idx, &d->src_pipe_idx,
- &d->dst_pipe_idx);
- if (ret) {
- pr_err("usb_bam_connect failed: err:%d\n", ret);
- return;
- }
+ ret = usb_bam_connect(d->src_connection_idx, &d->src_pipe_idx);
+ if (ret) {
+ pr_err("usb_bam_connect (src) failed: err:%d\n", ret);
+ return;
}
+ ret = usb_bam_connect(d->dst_connection_idx, &d->dst_pipe_idx);
+ if (ret) {
+ pr_err("usb_bam_connect (dst) failed: err:%d\n", ret);
+ return;
+ }
+}
if (!port->port_usb) {
pr_err("port_usb is NULL");
@@ -282,8 +321,7 @@
/* Register for peer reset callback if USB_GADGET_XPORT_BAM2BAM */
if (d->trans != USB_GADGET_XPORT_BAM2BAM_IPA) {
- usb_bam_register_peer_reset_cb(d->connection_idx,
- bam_data_peer_reset_cb, port);
+ usb_bam_register_peer_reset_cb(bam_data_peer_reset_cb, port);
ret = usb_bam_client_ready(true);
if (ret) {
@@ -369,7 +407,8 @@
}
int bam_data_connect(struct data_port *gr, u8 port_num,
- enum transport_type trans, u8 connection_idx, enum function_type func)
+ enum transport_type trans, u8 src_connection_idx,
+ u8 dst_connection_idx, enum function_type func)
{
struct bam_data_port *port;
struct bam_data_ch_info *d;
@@ -408,18 +447,19 @@
port->port_usb = gr;
- d->connection_idx = connection_idx;
+ d->src_connection_idx = src_connection_idx;
+ d->dst_connection_idx = dst_connection_idx;
d->trans = trans;
+ d->func_type = func;
if (trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
d->ipa_params.src_pipe = &(d->src_pipe_idx);
d->ipa_params.dst_pipe = &(d->dst_pipe_idx);
- d->ipa_params.idx = connection_idx;
+ d->ipa_params.src_idx = src_connection_idx;
+ d->ipa_params.dst_idx = dst_connection_idx;
}
- d->func_type = func;
-
queue_work(bam_data_wq, &port->connect_w);
return 0;
@@ -499,7 +539,7 @@
d = &port->data_ch;
pr_debug("%s: suspended port %d\n", __func__, port_num);
- usb_bam_register_wake_cb(d->connection_idx, bam_data_wake_cb, port);
+ usb_bam_register_wake_cb(d->dst_connection_idx, bam_data_wake_cb, port);
}
void bam_data_resume(u8 port_num)
@@ -512,6 +552,6 @@
d = &port->data_ch;
pr_debug("%s: resumed port %d\n", __func__, port_num);
- usb_bam_register_wake_cb(d->connection_idx, NULL, NULL);
+ usb_bam_register_wake_cb(d->dst_connection_idx, NULL, NULL);
}
diff --git a/drivers/usb/gadget/u_bam_data.h b/drivers/usb/gadget/u_bam_data.h
index 71a01b9..486191b5 100644
--- a/drivers/usb/gadget/u_bam_data.h
+++ b/drivers/usb/gadget/u_bam_data.h
@@ -30,7 +30,8 @@
void bam_data_disconnect(struct data_port *gr, u8 port_num);
int bam_data_connect(struct data_port *gr, u8 port_num,
- enum transport_type trans, u8 connection_idx, enum function_type func);
+ enum transport_type trans, u8 src_connection_idx,
+ u8 dst_connection_idx, enum function_type func);
int bam_data_setup(unsigned int no_bam2bam_port);
diff --git a/drivers/usb/gadget/u_qdss.c b/drivers/usb/gadget/u_qdss.c
index 028d5e6..e241e29 100644
--- a/drivers/usb/gadget/u_qdss.c
+++ b/drivers/usb/gadget/u_qdss.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012-2013, 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
@@ -15,8 +15,6 @@
#include <linux/usb/msm_hsusb.h>
#include <mach/usb_bam.h>
-#define BAM_CONNC_IDX 0 /* USB bam connection index */
-
struct usb_qdss_bam_connect_info {
u32 usb_bam_pipe_idx;
u32 peer_pipe_idx;
@@ -60,28 +58,33 @@
return 0;
}
-int set_qdss_data_connection(struct usb_ep *data_ep, u8 data_addr, int enable)
+static int set_qdss_data_connection(struct usb_gadget *gadget,
+ struct usb_ep *data_ep, u8 data_addr, int enable)
{
int res = 0;
+ u8 idx;
pr_debug("set_qdss_data_connection\n");
- if (enable) {
- res = usb_bam_connect(BAM_CONNC_IDX, NULL,
- &(bam_info.usb_bam_pipe_idx));
- if (res) {
- pr_err("usb_bam_connection error\n");
- return res;
- }
+ /* There is only one qdss pipe, so the pipe number can be set to 0 */
+ idx = usb_bam_get_connection_idx(gadget->name, QDSS_P_BAM,
+ PEER_PERIPHERAL_TO_USB, 0);
+ if (idx < 0) {
+ pr_err("%s: usb_bam_get_connection_idx failed\n", __func__);
+ return idx;
+ }
+ if (enable) {
+ res = usb_bam_connect(idx, &(bam_info.usb_bam_pipe_idx));
bam_info.data_fifo =
kzalloc(sizeof(struct sps_mem_buffer *), GFP_KERNEL);
if (!bam_info.data_fifo) {
pr_err("qdss_data_connection: memory alloc failed\n");
return -ENOMEM;
}
- get_bam2bam_connection_info(BAM_CONNC_IDX,
- PEER_PERIPHERAL_TO_USB, &bam_info.usb_bam_handle,
+ usb_bam_set_qdss_core(gadget->name);
+ get_bam2bam_connection_info(idx,
+ &bam_info.usb_bam_handle,
&bam_info.usb_bam_pipe_idx, &bam_info.peer_pipe_idx,
NULL, bam_info.data_fifo);
@@ -89,13 +92,13 @@
bam_info.data_fifo->size, bam_info.usb_bam_pipe_idx);
} else {
kfree(bam_info.data_fifo);
- res = usb_bam_disconnect_pipe(BAM_CONNC_IDX);
+ res = usb_bam_disconnect_pipe(idx);
if (res) {
pr_err("usb_bam_disconnection error\n");
return res;
}
-
}
+
return res;
}
diff --git a/drivers/usb/gadget/u_rmnet.h b/drivers/usb/gadget/u_rmnet.h
index cea9369..a9cca50 100644
--- a/drivers/usb/gadget/u_rmnet.h
+++ b/drivers/usb/gadget/u_rmnet.h
@@ -48,8 +48,10 @@
int gbam_setup(unsigned int no_bam_port, unsigned int no_bam2bam_port);
int gbam_connect(struct grmnet *gr, u8 port_num,
- enum transport_type trans, u8 connection_idx);
-void gbam_disconnect(struct grmnet *gr, u8 port_num, enum transport_type trans);
+ enum transport_type trans, u8 src_connection_idx,
+ u8 dst_connection_idx);
+void gbam_disconnect(struct grmnet *gr, u8 port_num,
+ enum transport_type trans);
void gbam_suspend(struct grmnet *gr, u8 port_num, enum transport_type trans);
void gbam_resume(struct grmnet *gr, u8 port_num, enum transport_type trans);
int gsmd_ctrl_connect(struct grmnet *gr, int port_num);
diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c
index 502c33a..350e723 100644
--- a/drivers/usb/gadget/u_serial.c
+++ b/drivers/usb/gadget/u_serial.c
@@ -1048,6 +1048,13 @@
struct gs_port *port = tty->driver_data;
unsigned long flags;
+ /*
+ * tty's driver data is set to NULL during port close. Nothing
+ * to do here.
+ */
+ if (!port)
+ return;
+
spin_lock_irqsave(&port->port_lock, flags);
if (port->port_usb) {
/* Kickstart read queue processing. We don't do xon/xoff,
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index 8c0894c..9879122 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -624,6 +624,15 @@
int ret;
void __iomem *reg;
+ if (pdata && pdata->resume_gpio) {
+ ret = gpio_request(pdata->resume_gpio, "HSIC_RESUME_GPIO");
+ if (ret < 0) {
+ dev_err(mehci->dev,
+ "gpio req failed for hsic resume:%d\n", ret);
+ pdata->resume_gpio = 0;
+ }
+ }
+
/* HSIC init sequence when HSIC signals (Strobe/Data) are
routed via GPIOs */
if (pdata && pdata->strobe && pdata->data) {
@@ -645,7 +654,7 @@
ret = msm_hsic_config_gpios(mehci, 1);
if (ret) {
dev_err(mehci->dev, " gpio configuarion failed\n");
- return ret;
+ goto free_resume_gpio;
}
if (pdata->strobe_pad_offset) {
/* Set CORE_CTL_EN in STROBE GPIO PAD_CTL register */
@@ -694,6 +703,12 @@
ulpi_write(mehci, ULPI_IFC_CTRL_AUTORESUME, ULPI_CLR(ULPI_IFC_CTRL));
return 0;
+
+free_resume_gpio:
+ if (pdata && pdata->resume_gpio)
+ gpio_free(pdata->resume_gpio);
+
+ return ret;
}
#define PHY_SUSPEND_TIMEOUT_USEC (500 * 1000)
@@ -1312,6 +1327,10 @@
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
u32 temp;
struct task_struct *resume_thread = NULL;
+ struct msm_hsic_host_platform_data *pdata = mehci->dev->platform_data;
+
+ if (pdata->resume_gpio)
+ gpio_direction_output(pdata->resume_gpio, 1);
mehci->resume_status = 0;
resume_thread = kthread_run(msm_hsic_resume_thread,
@@ -1351,6 +1370,9 @@
spin_unlock_irq(&ehci->lock);
+ if (pdata->resume_gpio)
+ gpio_direction_output(pdata->resume_gpio, 0);
+
return 0;
}
@@ -1781,6 +1803,11 @@
res_gpio = 0;
pdata->data = res_gpio;
+ res_gpio = of_get_named_gpio(node, "hsic,resume-gpio", 0);
+ if (res_gpio < 0)
+ res_gpio = 0;
+ pdata->resume_gpio = res_gpio;
+
pdata->ignore_cal_pad_config = of_property_read_bool(node,
"hsic,ignore-cal-pad-config");
of_property_read_u32(node, "hsic,strobe-pad-offset",
@@ -2079,7 +2106,9 @@
}
if (mehci->async_irq) {
- disable_irq_wake(mehci->async_irq);
+ /* Async IRQ is used only in absence of dedicated wakeup irq */
+ if (!mehci->wakeup_irq)
+ disable_irq_wake(mehci->async_irq);
free_irq(mehci->async_irq, mehci);
}
/*
@@ -2099,6 +2128,10 @@
destroy_workqueue(ehci_wq);
msm_hsic_config_gpios(mehci, 0);
+
+ if (pdata && pdata->resume_gpio)
+ gpio_free(pdata->resume_gpio);
+
msm_hsic_init_vddcx(mehci, 0);
msm_hsic_init_gdsc(mehci, 0);
diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c
index 66363eb..521ace0 100644
--- a/drivers/usb/host/ehci-msm.c
+++ b/drivers/usb/host/ehci-msm.c
@@ -117,6 +117,8 @@
return -ENOMEM;
}
+ hcd_to_bus(hcd)->skip_resume = true;
+
hcd->irq = platform_get_irq(pdev, 0);
if (hcd->irq < 0) {
dev_err(&pdev->dev, "Unable to get IRQ resource\n");
diff --git a/drivers/usb/host/ehci-msm2.c b/drivers/usb/host/ehci-msm2.c
index faa5625..6727996 100644
--- a/drivers/usb/host/ehci-msm2.c
+++ b/drivers/usb/host/ehci-msm2.c
@@ -1057,6 +1057,8 @@
return -ENOMEM;
}
+ hcd_to_bus(hcd)->skip_resume = true;
+
hcd->irq = platform_get_irq(pdev, 0);
if (hcd->irq < 0) {
dev_err(&pdev->dev, "Unable to get IRQ resource\n");
diff --git a/drivers/usb/host/ehci-msm72k.c b/drivers/usb/host/ehci-msm72k.c
index 76cd977..bab330c 100644
--- a/drivers/usb/host/ehci-msm72k.c
+++ b/drivers/usb/host/ehci-msm72k.c
@@ -681,6 +681,8 @@
if (!hcd)
return -ENOMEM;
+ hcd_to_bus(hcd)->skip_resume = true;
+
hcd->irq = platform_get_irq(pdev, 0);
if (hcd->irq < 0) {
usb_put_hcd(hcd);
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index cd17421..edf2a73 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -754,23 +754,6 @@
#endif
-/*
- * Writing to dma coherent memory on ARM may be delayed via L2
- * writing buffer, so introduce the helper which can flush L2 writing
- * buffer into memory immediately, especially used to flush ehci
- * descriptor to memory.
- * */
-#ifdef CONFIG_ARM_DMA_MEM_BUFFERABLE
-static inline void ehci_sync_mem(void)
-{
- mb();
-}
-#else
-static inline void ehci_sync_mem(void)
-{
-}
-#endif
-
/*-------------------------------------------------------------------------*/
#ifdef CONFIG_PCI
diff --git a/drivers/usb/host/hbm.c b/drivers/usb/host/hbm.c
index d48a631..1a0c0aa 100644
--- a/drivers/usb/host/hbm.c
+++ b/drivers/usb/host/hbm.c
@@ -39,6 +39,7 @@
#define PIPE_PRODUCER 1
#define MAX_PIPE_NUM 16
#define HBM_QH_MAP_PIPE 0xffffffc0
+#define QTD_CERR_MASK 0xfffff3ff
struct hbm_msm {
u32 *base;
@@ -257,6 +258,7 @@
{
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
struct list_head qtd_list;
+ struct ehci_qtd *qtd;
INIT_LIST_HEAD(&qtd_list);
@@ -272,5 +274,11 @@
if (!qh_urb_transaction(ehci, urb, &qtd_list, mem_flags))
return -ENOMEM;
+
+ /* set err counter in qTD token to zero */
+ qtd = list_entry(qtd_list.next, struct ehci_qtd, qtd_list);
+ if (qtd != NULL)
+ qtd->hw_token &= QTD_CERR_MASK;
+
return hbm_submit_async(ehci, urb, &qtd_list, mem_flags);
}
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 7760d28..5750e0d 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -3651,7 +3651,7 @@
cmd_buf.vmid_idx = MSM_OTG_VMID_IDX;
cmd_buf.mem_type = MSM_OTG_MEM_TYPE;
- ret = scm_call(SCM_SVC_CP, MSM_OTG_CMD_ID, &cmd_buf,
+ ret = scm_call(SCM_SVC_MP, MSM_OTG_CMD_ID, &cmd_buf,
sizeof(cmd_buf), NULL, 0);
if (ret)
diff --git a/drivers/usb/otg/otg_id.c b/drivers/usb/otg/otg_id.c
deleted file mode 100644
index 7c38390..0000000
--- a/drivers/usb/otg/otg_id.c
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Copyright (C) 2011 Google, Inc.
- *
- * Author:
- * Colin Cross <ccross@android.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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/kernel.h>
-#include <linux/mutex.h>
-#include <linux/notifier.h>
-#include <linux/usb/otg_id.h>
-
-static DEFINE_MUTEX(otg_id_lock);
-static struct plist_head otg_id_plist =
- PLIST_HEAD_INIT(otg_id_plist);
-static struct otg_id_notifier_block *otg_id_active;
-static bool otg_id_cancelling;
-static bool otg_id_inited;
-static int otg_id_suspended;
-static bool otg_id_pending;
-
-static void otg_id_cancel(void)
-{
- if (otg_id_active) {
- otg_id_cancelling = true;
- mutex_unlock(&otg_id_lock);
-
- otg_id_active->cancel(otg_id_active);
-
- mutex_lock(&otg_id_lock);
- otg_id_cancelling = false;
- }
-}
-
-static void __otg_id_notify(void)
-{
- int ret = 0;
- struct otg_id_notifier_block *otg_id_nb;
- bool proxy_wait = false;
- if (plist_head_empty(&otg_id_plist))
- return;
-
- plist_for_each_entry(otg_id_nb, &otg_id_plist, p) {
- if (proxy_wait) {
- if (otg_id_nb->proxy_wait)
- ret = otg_id_nb->proxy_wait(otg_id_nb);
- } else {
- ret = otg_id_nb->detect(otg_id_nb);
- }
- if (ret == OTG_ID_HANDLED) {
- otg_id_active = otg_id_nb;
- return;
- }
- if (ret == OTG_ID_PROXY_WAIT)
- proxy_wait = true;
-
- }
-
- WARN(1, "otg id event not handled");
- otg_id_active = NULL;
-}
-
-int otg_id_init(void)
-{
- mutex_lock(&otg_id_lock);
-
- otg_id_inited = true;
- __otg_id_notify();
-
- mutex_unlock(&otg_id_lock);
- return 0;
-}
-late_initcall(otg_id_init);
-
-/**
- * otg_id_register_notifier
- * @otg_id_nb: notifier block containing priority and callback function
- *
- * Register a notifier that will be called on any USB cable state change.
- * The priority determines the order the callback will be called in, a higher
- * number will be called first. A callback function needs to determine the
- * type of USB cable that is connected. If it can determine the type, it
- * should notify the appropriate drivers (for example, call an otg notifier
- * with USB_EVENT_VBUS), and return OTG_ID_HANDLED. Once a callback has
- * returned OTG_ID_HANDLED, it is responsible for calling otg_id_notify() when
- * the detected USB cable is disconnected.
- */
-int otg_id_register_notifier(struct otg_id_notifier_block *otg_id_nb)
-{
- plist_node_init(&otg_id_nb->p, otg_id_nb->priority);
-
- mutex_lock(&otg_id_lock);
- plist_add(&otg_id_nb->p, &otg_id_plist);
-
- if (otg_id_inited) {
- otg_id_cancel();
- __otg_id_notify();
- }
-
- mutex_unlock(&otg_id_lock);
-
- return 0;
-}
-
-void otg_id_unregister_notifier(struct otg_id_notifier_block *otg_id_nb)
-{
- mutex_lock(&otg_id_lock);
-
- plist_del(&otg_id_nb->p, &otg_id_plist);
-
- if (otg_id_inited && (otg_id_active == otg_id_nb)) {
- otg_id_cancel();
- __otg_id_notify();
- }
-
- mutex_unlock(&otg_id_lock);
-}
-
-/**
- * otg_id_notify
- *
- * Notify listeners on any USB cable state change.
- *
- * A driver may only call otg_id_notify if it returned OTG_ID_HANDLED the last
- * time it's notifier was called, and it's cancel function has not been called.
- */
-void otg_id_notify(void)
-{
- mutex_lock(&otg_id_lock);
-
- if (otg_id_cancelling)
- goto out;
-
- if (otg_id_suspended != 0) {
- otg_id_pending = true;
- goto out;
- }
-
- __otg_id_notify();
-out:
- mutex_unlock(&otg_id_lock);
-}
-
-/**
- * otg_id_suspend
- *
- * Mark the otg_id subsystem as going into suspend. From here on out,
- * any notifications will be deferred until the last otg_id client resumes.
- * If there is a pending notification when calling this function, it will
- * return a negative errno and expects that the caller will abort suspend.
- * Returs 0 on success.
- */
-int otg_id_suspend(void)
-{
- int ret = 0;
-
- mutex_lock(&otg_id_lock);
-
- /*
- * if there's a pending notification, tell the caller to abort suspend
- */
- if (otg_id_suspended != 0 && otg_id_pending) {
- pr_info("otg_id: pending notification, should abort suspend\n");
- ret = -EBUSY;
- goto out;
- }
-
- otg_id_suspended++;
-out:
- mutex_unlock(&otg_id_lock);
- return ret;
-}
-
-/**
- * otg_id_resume
- *
- * Inform the otg_id subsystem that a client is resuming. If this is the
- * last client to be resumed and there's a pending notification,
- * otg_id_notify() is called.
- */
-void otg_id_resume(void)
-{
- mutex_lock(&otg_id_lock);
- if (WARN(!otg_id_suspended, "unbalanced otg_id_resume\n"))
- goto out;
- if (--otg_id_suspended == 0) {
- if (otg_id_pending) {
- pr_info("otg_id: had pending notification\n");
- otg_id_pending = false;
- __otg_id_notify();
- }
- }
-out:
- mutex_unlock(&otg_id_lock);
-}
diff --git a/drivers/video/msm/Kconfig b/drivers/video/msm/Kconfig
index ed4c25d..88f8be5 100644
--- a/drivers/video/msm/Kconfig
+++ b/drivers/video/msm/Kconfig
@@ -10,6 +10,8 @@
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
+ select SYNC
+ select SW_SYNC
---help---
Support for MSM Framebuffer.
@@ -39,6 +41,9 @@
bool
default n
+config FB_MSM_MDSS_COMMON
+ bool
+
choice
prompt "MDP HW version"
default FB_MSM_MDP22
@@ -86,6 +91,7 @@
config FB_MSM_MDSS
bool "MDSS HW"
+ select FB_MSM_MDSS_COMMON
---help---
The Mobile Display Sub System (MDSS) driver supports devices which
contain MDSS hardware block.
@@ -101,6 +107,10 @@
endchoice
+config FB_MSM_QPIC
+ bool
+ select FB_MSM_MDSS_COMMON
+
config FB_MSM_EBI2
bool
default n
@@ -948,6 +958,21 @@
---help---
Support for EBI2 panel auto detect
+config FB_MSM_QPIC_ILI_QVGA_PANEL
+ bool "Qpic MIPI ILI QVGA Panel"
+ select FB_MSM_QPIC
+ ---help---
+ Support for MIPI ILI QVGA (240x320) panel
+ ILI TECHNOLOGY 9341
+ with on-chip full display RAM
+ use parallel interface
+
+config FB_MSM_QPIC_PANEL_DETECT
+ bool "Qpic Panel Detect"
+ select FB_MSM_QPIC_ILI_QVGA_PANEL
+ ---help---
+ Support for Qpic panel auto detect
+
if FB_MSM_MDSS
source "drivers/video/msm/mdss/Kconfig"
endif
diff --git a/drivers/video/msm/Makefile b/drivers/video/msm/Makefile
index e49e2ba..67c6b48 100644
--- a/drivers/video/msm/Makefile
+++ b/drivers/video/msm/Makefile
@@ -1,4 +1,4 @@
-ifeq ($(CONFIG_FB_MSM_MDSS),y)
+ifeq ($(CONFIG_FB_MSM_MDSS_COMMON),y)
obj-y += mdss/
else
obj-y := msm_fb.o
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index 77eb9c2..63a842d 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -1609,7 +1609,6 @@
outpdw(MDP_BASE + 0x0014, 0x0); /* start DMA */
} else if (term == MDP_OVERLAY0_TERM) {
mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
- mdp_lut_enable();
outpdw(MDP_BASE + 0x0004, 0);
} else if (term == MDP_OVERLAY1_TERM) {
mdp_pipe_ctrl(MDP_OVERLAY1_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index bfd8238..e50055f 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -3682,6 +3682,8 @@
mdp4_overlay_mdp_perf_upd(mfd, 1);
+ msm_fb_wait_for_fence(mfd);
+
switch (mfd->panel.type) {
case MIPI_CMD_PANEL:
mdp4_dsi_cmd_pipe_commit(0, 1);
@@ -3703,6 +3705,7 @@
ret = -EINVAL;
break;
}
+ msm_fb_signal_timeline(mfd);
mdp4_overlay_mdp_perf_upd(mfd, 0);
diff --git a/drivers/video/msm/mdss/Makefile b/drivers/video/msm/mdss/Makefile
index 17987d4..a710fef 100644
--- a/drivers/video/msm/mdss/Makefile
+++ b/drivers/video/msm/mdss/Makefile
@@ -7,7 +7,10 @@
mdss-mdp-objs += mdss_mdp_wb.o
obj-$(CONFIG_FB_MSM_MDSS) += mdss-mdp.o
obj-$(CONFIG_FB_MSM_MDSS) += mdss_fb.o
+
+ifeq ($(CONFIG_FB_MSM_MDSS),y)
obj-$(CONFIG_DEBUG_FS) += mdss_debug.o
+endif
mdss-dsi-objs := mdss_dsi.o mdss_dsi_host.o
mdss-dsi-objs += mdss_dsi_panel.o
@@ -23,3 +26,7 @@
obj-$(CONFIG_FB_MSM_MDSS_HDMI_PANEL) += mdss_hdmi_hdcp.o
obj-$(CONFIG_FB_MSM_MDSS_WRITEBACK) += mdss_wb.o
+
+mdss-qpic-objs := mdss_qpic.o mdss_fb.o mdss_qpic_panel.o
+obj-$(CONFIG_FB_MSM_QPIC) += mdss-qpic.o
+obj-$(CONFIG_FB_MSM_QPIC_ILI_QVGA_PANEL) += qpic_panel_ili_qvga.o
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
index 99eea82..bfcd7ec 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -28,48 +28,73 @@
static unsigned char *mdss_dsi_base;
-static int mdss_dsi_regulator_init(struct platform_device *pdev,
- struct dsi_drv_cm_data *dsi_drv)
+static int mdss_dsi_regulator_init(struct platform_device *pdev)
{
- int ret;
+ int ret = 0;
+ struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+ struct dsi_drv_cm_data *dsi_drv = NULL;
- dsi_drv->vdd_vreg = devm_regulator_get(&pdev->dev, "vdd");
- if (IS_ERR(dsi_drv->vdd_vreg)) {
- pr_err("could not get 8941_l22, rc = %ld\n",
- PTR_ERR(dsi_drv->vdd_vreg));
- return -ENODEV;
- }
-
- ret = regulator_set_voltage(dsi_drv->vdd_vreg, 3000000, 3000000);
- if (ret) {
- pr_err("vdd_vreg->set_voltage failed, rc=%d\n", ret);
+ if (!pdev) {
+ pr_err("%s: invalid input\n", __func__);
return -EINVAL;
}
- dsi_drv->vdd_io_vreg = devm_regulator_get(&pdev->dev, "vdd_io");
- if (IS_ERR(dsi_drv->vdd_io_vreg)) {
- pr_err("could not get 8941_l12, rc = %ld\n",
- PTR_ERR(dsi_drv->vdd_io_vreg));
- return -ENODEV;
- }
-
- ret = regulator_set_voltage(dsi_drv->vdd_io_vreg, 1800000, 1800000);
- if (ret) {
- pr_err("vdd_io_vreg->set_voltage failed, rc=%d\n", ret);
+ ctrl_pdata = platform_get_drvdata(pdev);
+ if (!ctrl_pdata) {
+ pr_err("%s: invalid driver data\n", __func__);
return -EINVAL;
}
- dsi_drv->dsi_vreg = devm_regulator_get(&pdev->dev, "vreg");
- if (IS_ERR(dsi_drv->dsi_vreg)) {
- pr_err("could not get 8941_l2, rc = %ld\n",
- PTR_ERR(dsi_drv->dsi_vreg));
- return -ENODEV;
- }
+ dsi_drv = &(ctrl_pdata->shared_pdata);
+ if (ctrl_pdata->power_data.num_vreg > 0) {
+ ret = msm_dss_config_vreg(&pdev->dev,
+ ctrl_pdata->power_data.vreg_config,
+ ctrl_pdata->power_data.num_vreg, 1);
+ } else {
+ dsi_drv->vdd_vreg = devm_regulator_get(&pdev->dev, "vdd");
+ if (IS_ERR(dsi_drv->vdd_vreg)) {
+ pr_err("%s: could not get vdda vreg, rc=%ld\n",
+ __func__, PTR_ERR(dsi_drv->vdd_vreg));
+ return PTR_ERR(dsi_drv->vdd_vreg);
+ }
- ret = regulator_set_voltage(dsi_drv->dsi_vreg, 1200000, 1200000);
- if (ret) {
- pr_err("dsi_vreg->set_voltage failed, rc=%d\n", ret);
- return -EINVAL;
+ ret = regulator_set_voltage(dsi_drv->vdd_vreg, 3000000,
+ 3000000);
+ if (ret) {
+ pr_err("%s: set voltage failed on vdda vreg, rc=%d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ dsi_drv->vdd_io_vreg = devm_regulator_get(&pdev->dev, "vddio");
+ if (IS_ERR(dsi_drv->vdd_io_vreg)) {
+ pr_err("%s: could not get vddio reg, rc=%ld\n",
+ __func__, PTR_ERR(dsi_drv->vdd_io_vreg));
+ return PTR_ERR(dsi_drv->vdd_io_vreg);
+ }
+
+ ret = regulator_set_voltage(dsi_drv->vdd_io_vreg, 1800000,
+ 1800000);
+ if (ret) {
+ pr_err("%s: set voltage failed on vddio vreg, rc=%d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ dsi_drv->vdda_vreg = devm_regulator_get(&pdev->dev, "vdda");
+ if (IS_ERR(dsi_drv->vdda_vreg)) {
+ pr_err("%s: could not get vdda vreg, rc=%ld\n",
+ __func__, PTR_ERR(dsi_drv->vdda_vreg));
+ return PTR_ERR(dsi_drv->vdda_vreg);
+ }
+
+ ret = regulator_set_voltage(dsi_drv->vdda_vreg, 1200000,
+ 1200000);
+ if (ret) {
+ pr_err("%s: set voltage failed on vdda vreg, rc=%d\n",
+ __func__, ret);
+ return ret;
+ }
}
return 0;
@@ -90,51 +115,73 @@
pr_debug("%s: enable=%d\n", __func__, enable);
if (enable) {
- ret = regulator_set_optimum_mode
- ((ctrl_pdata->shared_pdata).vdd_vreg, 100000);
- if (ret < 0) {
- pr_err("%s: vdd_vreg set regulator mode failed.\n",
- __func__);
- return ret;
+ if (ctrl_pdata->power_data.num_vreg > 0) {
+ ret = msm_dss_enable_vreg(
+ ctrl_pdata->power_data.vreg_config,
+ ctrl_pdata->power_data.num_vreg, 1);
+ if (ret) {
+ pr_err("%s:Failed to enable regulators.rc=%d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ /*
+ * A small delay is needed here after enabling
+ * all regulators and before issuing panel reset
+ */
+ msleep(20);
+ } else {
+ ret = regulator_set_optimum_mode(
+ (ctrl_pdata->shared_pdata).vdd_vreg, 100000);
+ if (ret < 0) {
+ pr_err("%s: vdd_vreg set opt mode failed.\n",
+ __func__);
+ return ret;
+ }
+
+ ret = regulator_set_optimum_mode(
+ (ctrl_pdata->shared_pdata).vdd_io_vreg, 100000);
+ if (ret < 0) {
+ pr_err("%s: vdd_io_vreg set opt mode failed.\n",
+ __func__);
+ return ret;
+ }
+
+ ret = regulator_set_optimum_mode
+ ((ctrl_pdata->shared_pdata).vdda_vreg, 100000);
+ if (ret < 0) {
+ pr_err("%s: vdda_vreg set opt mode failed.\n",
+ __func__);
+ return ret;
+ }
+
+ ret = regulator_enable(
+ (ctrl_pdata->shared_pdata).vdd_io_vreg);
+ if (ret) {
+ pr_err("%s: Failed to enable regulator.\n",
+ __func__);
+ return ret;
+ }
+ msleep(20);
+
+ ret = regulator_enable(
+ (ctrl_pdata->shared_pdata).vdd_vreg);
+ if (ret) {
+ pr_err("%s: Failed to enable regulator.\n",
+ __func__);
+ return ret;
+ }
+ msleep(20);
+
+ ret = regulator_enable(
+ (ctrl_pdata->shared_pdata).vdda_vreg);
+ if (ret) {
+ pr_err("%s: Failed to enable regulator.\n",
+ __func__);
+ return ret;
+ }
}
- ret = regulator_set_optimum_mode
- ((ctrl_pdata->shared_pdata).vdd_io_vreg, 100000);
- if (ret < 0) {
- pr_err("%s: vdd_io_vreg set regulator mode failed.\n",
- __func__);
- return ret;
- }
-
- ret = regulator_set_optimum_mode
- ((ctrl_pdata->shared_pdata).dsi_vreg, 100000);
- if (ret < 0) {
- pr_err("%s: dsi_vreg set regulator mode failed.\n",
- __func__);
- return ret;
- }
-
- ret = regulator_enable((ctrl_pdata->shared_pdata).vdd_io_vreg);
- if (ret) {
- pr_err("%s: Failed to enable regulator.\n", __func__);
- return ret;
- }
- msleep(20);
- wmb();
-
- ret = regulator_enable((ctrl_pdata->shared_pdata).vdd_vreg);
- if (ret) {
- pr_err("%s: Failed to enable regulator.\n", __func__);
- return ret;
- }
- msleep(20);
- wmb();
-
- ret = regulator_enable((ctrl_pdata->shared_pdata).dsi_vreg);
- if (ret) {
- pr_err("%s: Failed to enable regulator.\n", __func__);
- return ret;
- }
if (pdata->panel_info.panel_power_on == 0)
mdss_dsi_panel_reset(pdata, 1);
@@ -142,45 +189,62 @@
mdss_dsi_panel_reset(pdata, 0);
- ret = regulator_disable((ctrl_pdata->shared_pdata).vdd_vreg);
- if (ret) {
- pr_err("%s: Failed to disable regulator.\n", __func__);
- return ret;
- }
+ if (ctrl_pdata->power_data.num_vreg > 0) {
+ ret = msm_dss_enable_vreg(
+ ctrl_pdata->power_data.vreg_config,
+ ctrl_pdata->power_data.num_vreg, 0);
+ if (ret) {
+ pr_err("%s: Failed to disable regs.rc=%d\n",
+ __func__, ret);
+ return ret;
+ }
+ } else {
+ ret = regulator_disable(
+ (ctrl_pdata->shared_pdata).vdd_vreg);
+ if (ret) {
+ pr_err("%s: Failed to disable regulator.\n",
+ __func__);
+ return ret;
+ }
- ret = regulator_disable((ctrl_pdata->shared_pdata).dsi_vreg);
- if (ret) {
- pr_err("%s: Failed to disable regulator.\n", __func__);
- return ret;
- }
+ ret = regulator_disable(
+ (ctrl_pdata->shared_pdata).vdda_vreg);
+ if (ret) {
+ pr_err("%s: Failed to disable regulator.\n",
+ __func__);
+ return ret;
+ }
- ret = regulator_disable((ctrl_pdata->shared_pdata).vdd_io_vreg);
- if (ret) {
- pr_err("%s: Failed to disable regulator.\n", __func__);
- return ret;
- }
+ ret = regulator_disable(
+ (ctrl_pdata->shared_pdata).vdd_io_vreg);
+ if (ret) {
+ pr_err("%s: Failed to disable regulator.\n",
+ __func__);
+ return ret;
+ }
- ret = regulator_set_optimum_mode
- ((ctrl_pdata->shared_pdata).vdd_vreg, 100);
- if (ret < 0) {
- pr_err("%s: vdd_vreg set regulator mode failed.\n",
- __func__);
- return ret;
- }
+ ret = regulator_set_optimum_mode(
+ (ctrl_pdata->shared_pdata).vdd_vreg, 100);
+ if (ret < 0) {
+ pr_err("%s: vdd_vreg set opt mode failed.\n",
+ __func__);
+ return ret;
+ }
- ret = regulator_set_optimum_mode
- ((ctrl_pdata->shared_pdata).vdd_io_vreg, 100);
- if (ret < 0) {
- pr_err("%s: vdd_io_vreg set regulator mode failed.\n",
- __func__);
- return ret;
- }
- ret = regulator_set_optimum_mode
- ((ctrl_pdata->shared_pdata).dsi_vreg, 100);
- if (ret < 0) {
- pr_err("%s: dsi_vreg set regulator mode failed.\n",
- __func__);
- return ret;
+ ret = regulator_set_optimum_mode(
+ (ctrl_pdata->shared_pdata).vdd_io_vreg, 100);
+ if (ret < 0) {
+ pr_err("%s: vdd_io_vreg set opt mode failed.\n",
+ __func__);
+ return ret;
+ }
+ ret = regulator_set_optimum_mode(
+ (ctrl_pdata->shared_pdata).vdda_vreg, 100);
+ if (ret < 0) {
+ pr_err("%s: vdda_vreg set opt mode failed.\n",
+ __func__);
+ return ret;
+ }
}
}
return 0;
@@ -212,6 +276,154 @@
return ret;
}
+static void mdss_dsi_put_dt_vreg_data(struct device *dev,
+ struct dss_module_power *module_power)
+{
+ if (!module_power) {
+ pr_err("%s: invalid input\n", __func__);
+ return;
+ }
+
+ if (module_power->vreg_config) {
+ devm_kfree(dev, module_power->vreg_config);
+ module_power->vreg_config = NULL;
+ }
+ module_power->num_vreg = 0;
+}
+
+static int mdss_dsi_get_dt_vreg_data(struct device *dev,
+ struct dss_module_power *mp)
+{
+ int i, rc = 0;
+ int dt_vreg_total = 0;
+ u32 *val_array = NULL;
+ struct device_node *of_node = NULL;
+
+ if (!dev || !mp) {
+ pr_err("%s: invalid input\n", __func__);
+ rc = -EINVAL;
+ goto error;
+ }
+
+ of_node = dev->of_node;
+
+ mp->num_vreg = 0;
+ dt_vreg_total = of_property_count_strings(of_node, "qcom,supply-names");
+ if (dt_vreg_total < 0) {
+ pr_debug("%s: vreg not found. rc=%d\n", __func__,
+ dt_vreg_total);
+ rc = 0;
+ goto error;
+ } else {
+ pr_debug("%s: vreg found. count=%d\n", __func__, dt_vreg_total);
+ }
+
+ if (dt_vreg_total > 0) {
+ mp->num_vreg = dt_vreg_total;
+ mp->vreg_config = devm_kzalloc(dev, sizeof(struct dss_vreg) *
+ dt_vreg_total, GFP_KERNEL);
+ if (!mp->vreg_config) {
+ pr_err("%s: can't alloc vreg mem\n", __func__);
+ goto error;
+ }
+ } else {
+ pr_debug("%s: no vreg\n", __func__);
+ return 0;
+ }
+
+ val_array = devm_kzalloc(dev, sizeof(u32) * dt_vreg_total, GFP_KERNEL);
+ if (!val_array) {
+ pr_err("%s: can't allocate vreg scratch mem\n", __func__);
+ rc = -ENOMEM;
+ goto error;
+ }
+
+ for (i = 0; i < dt_vreg_total; i++) {
+ const char *st = NULL;
+ /* vreg-name */
+ rc = of_property_read_string_index(of_node, "qcom,supply-names",
+ i, &st);
+ if (rc) {
+ pr_err("%s: error reading name. i=%d, rc=%d\n",
+ __func__, i, rc);
+ goto error;
+ }
+ snprintf(mp->vreg_config[i].vreg_name,
+ ARRAY_SIZE((mp->vreg_config[i].vreg_name)), "%s", st);
+
+ /* vreg-type */
+ rc = of_property_read_string_index(of_node, "qcom,supply-type",
+ i, &st);
+ if (rc) {
+ pr_err("%s: error reading vreg type. rc=%d\n",
+ __func__, rc);
+ goto error;
+ }
+ if (!strncmp(st, "regulator", 9))
+ mp->vreg_config[i].type = 0;
+ else if (!strncmp(st, "switch", 6))
+ mp->vreg_config[i].type = 1;
+
+ /* vreg-min-voltage */
+ memset(val_array, 0, sizeof(u32) * dt_vreg_total);
+ rc = of_property_read_u32_array(of_node,
+ "qcom,supply-min-voltage-level", val_array,
+ dt_vreg_total);
+ if (rc) {
+ pr_err("%s: error reading min volt. rc=%d\n",
+ __func__, rc);
+ goto error;
+ }
+ mp->vreg_config[i].min_voltage = val_array[i];
+
+ /* vreg-max-voltage */
+ memset(val_array, 0, sizeof(u32) * dt_vreg_total);
+ rc = of_property_read_u32_array(of_node,
+ "qcom,supply-max-voltage-level", val_array,
+ dt_vreg_total);
+ if (rc) {
+ pr_err("%s: error reading max volt. rc=%d\n",
+ __func__, rc);
+ goto error;
+ }
+ mp->vreg_config[i].max_voltage = val_array[i];
+
+ /* vreg-peak-current*/
+ memset(val_array, 0, sizeof(u32) * dt_vreg_total);
+ rc = of_property_read_u32_array(of_node,
+ "qcom,supply-peak-current", val_array,
+ dt_vreg_total);
+ if (rc) {
+ pr_err("%s: error reading peak current. rc=%d\n",
+ __func__, rc);
+ goto error;
+ }
+ mp->vreg_config[i].optimum_voltage = val_array[i];
+
+ pr_debug("%s: %s type=%d, min=%d, max=%d, op=%d\n",
+ __func__, mp->vreg_config[i].vreg_name,
+ mp->vreg_config[i].type,
+ mp->vreg_config[i].min_voltage,
+ mp->vreg_config[i].max_voltage,
+ mp->vreg_config[i].optimum_voltage);
+ }
+
+ devm_kfree(dev, val_array);
+
+ return rc;
+
+error:
+ if (mp->vreg_config) {
+ devm_kfree(dev, mp->vreg_config);
+ mp->vreg_config = NULL;
+ }
+ mp->num_vreg = 0;
+
+ if (val_array)
+ devm_kfree(dev, val_array);
+ return rc;
+}
+
static int mdss_dsi_off(struct mdss_panel_data *pdata)
{
int ret = 0;
@@ -460,6 +672,7 @@
{
int rc = 0;
u32 index;
+ struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
pr_debug("%s\n", __func__);
@@ -467,6 +680,19 @@
struct resource *mdss_dsi_mres;
const char *ctrl_name;
+ ctrl_pdata = platform_get_drvdata(pdev);
+ if (!ctrl_pdata) {
+ ctrl_pdata = devm_kzalloc(&pdev->dev,
+ sizeof(struct mdss_dsi_ctrl_pdata), GFP_KERNEL);
+ if (!ctrl_pdata) {
+ pr_err("%s: FAILED: cannot alloc dsi ctrl\n",
+ __func__);
+ rc = -ENOMEM;
+ goto error_no_mem;
+ }
+ platform_set_drvdata(pdev, ctrl_pdata);
+ }
+
ctrl_name = of_get_property(pdev->dev.of_node, "label", NULL);
if (!ctrl_name)
pr_info("%s:%d, DSI Ctrl name not specified\n",
@@ -481,7 +707,7 @@
dev_err(&pdev->dev,
"%s: Cell-index not specified, rc=%d\n",
__func__, rc);
- return rc;
+ goto error_no_mem;
}
if (index == 0)
@@ -493,7 +719,8 @@
if (!mdss_dsi_mres) {
pr_err("%s:%d unable to get the MDSS resources",
__func__, __LINE__);
- return -ENOMEM;
+ rc = -ENOMEM;
+ goto error_no_mem;
}
if (mdss_dsi_mres) {
mdss_dsi_base = ioremap(mdss_dsi_mres->start,
@@ -501,7 +728,8 @@
if (!mdss_dsi_base) {
pr_err("%s:%d unable to remap dsi resources",
__func__, __LINE__);
- return -ENOMEM;
+ rc = -ENOMEM;
+ goto error_no_mem;
}
}
@@ -511,20 +739,48 @@
dev_err(&pdev->dev,
"%s: failed to add child nodes, rc=%d\n",
__func__, rc);
- iounmap(mdss_dsi_base);
- return rc;
+ goto error_ioremap;
+ }
+
+ /* Parse the regulator information */
+ rc = mdss_dsi_get_dt_vreg_data(&pdev->dev,
+ &ctrl_pdata->power_data);
+ if (rc) {
+ pr_err("%s: failed to get vreg data from dt. rc=%d\n",
+ __func__, rc);
+ goto error_vreg;
}
pr_debug("%s: Dsi Ctrl->%d initialized\n", __func__, index);
}
return 0;
+
+error_ioremap:
+ iounmap(mdss_dsi_base);
+error_no_mem:
+ devm_kfree(&pdev->dev, ctrl_pdata);
+error_vreg:
+ mdss_dsi_put_dt_vreg_data(&pdev->dev, &ctrl_pdata->power_data);
+
+ return rc;
}
static int __devexit mdss_dsi_ctrl_remove(struct platform_device *pdev)
{
struct msm_fb_data_type *mfd;
+ struct mdss_dsi_ctrl_pdata *ctrl_pdata = platform_get_drvdata(pdev);
+ if (!ctrl_pdata) {
+ pr_err("%s: no driver data\n", __func__);
+ return -ENODEV;
+ }
+
+ if (msm_dss_config_vreg(&pdev->dev,
+ ctrl_pdata->power_data.vreg_config,
+ ctrl_pdata->power_data.num_vreg, 1) < 0)
+ pr_err("%s: failed to de-init vregs\n", __func__);
+ mdss_dsi_put_dt_vreg_data(&pdev->dev, &ctrl_pdata->power_data);
mfd = platform_get_drvdata(pdev);
iounmap(mdss_dsi_base);
return 0;
@@ -592,7 +848,7 @@
int rc;
u8 lanes = 0, bpp;
u32 h_period, v_period, dsi_pclk_rate;
- struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+ struct mdss_dsi_ctrl_pdata *ctrl_pdata;
struct device_node *dsi_ctrl_np = NULL;
struct platform_device *ctrl_pdev = NULL;
unsigned char *ctrl_addr;
@@ -659,31 +915,29 @@
return rc;
}
- if ((dsi_pclk_rate < 3300000) || (dsi_pclk_rate > 103300000))
+ if ((dsi_pclk_rate < 3300000) || (dsi_pclk_rate > 250000000))
dsi_pclk_rate = 35000000;
mipi->dsi_pclk_rate = dsi_pclk_rate;
- ctrl_pdata = devm_kzalloc(&pdev->dev,
- sizeof(struct mdss_dsi_ctrl_pdata), GFP_KERNEL);
- if (!ctrl_pdata)
- return -ENOMEM;
-
dsi_ctrl_np = of_parse_phandle(pdev->dev.of_node,
"qcom,dsi-ctrl-phandle", 0);
if (!dsi_ctrl_np) {
pr_err("%s: Dsi controller node not initialized\n", __func__);
- devm_kfree(&pdev->dev, ctrl_pdata);
return -EPROBE_DEFER;
}
ctrl_pdev = of_find_device_by_node(dsi_ctrl_np);
+ ctrl_pdata = platform_get_drvdata(ctrl_pdev);
+ if (!ctrl_pdata) {
+ pr_err("%s: no dsi ctrl driver data\n", __func__);
+ return -EINVAL;
+ }
- rc = mdss_dsi_regulator_init(ctrl_pdev, &(ctrl_pdata->shared_pdata));
+ rc = mdss_dsi_regulator_init(ctrl_pdev);
if (rc) {
dev_err(&pdev->dev,
"%s: failed to init regulator, rc=%d\n",
__func__, rc);
- devm_kfree(&pdev->dev, ctrl_pdata);
return rc;
}
@@ -718,14 +972,14 @@
pr_err("request reset gpio failed, rc=%d\n",
rc);
gpio_free(ctrl_pdata->rst_gpio);
- gpio_free(ctrl_pdata->disp_en_gpio);
+ if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
+ gpio_free(ctrl_pdata->disp_en_gpio);
return -ENODEV;
}
}
if (mdss_dsi_clk_init(ctrl_pdev, ctrl_pdata)) {
pr_err("%s: unable to initialize Dsi ctrl clks\n", __func__);
- devm_kfree(&pdev->dev, ctrl_pdata);
return -EPERM;
}
@@ -733,7 +987,6 @@
panel_data->panel_info.pdest,
&ctrl_addr)) {
pr_err("%s: unable to get Dsi controller res\n", __func__);
- devm_kfree(&pdev->dev, ctrl_pdata);
return -EPERM;
}
@@ -779,10 +1032,9 @@
rc = mdss_register_panel(ctrl_pdev, &(ctrl_pdata->panel_data));
if (rc) {
dev_err(&pdev->dev, "unable to register MIPI DSI panel\n");
- devm_kfree(&pdev->dev, ctrl_pdata);
if (ctrl_pdata->rst_gpio)
gpio_free(ctrl_pdata->rst_gpio);
- if (ctrl_pdata->disp_en_gpio)
+ if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
gpio_free(ctrl_pdata->disp_en_gpio);
return rc;
}
@@ -790,6 +1042,11 @@
ctrl_pdata->on = panel_data->on;
ctrl_pdata->off = panel_data->off;
+ ctrl_pdata->pclk_rate = dsi_pclk_rate;
+ ctrl_pdata->byte_clk_rate = panel_data->panel_info.clk_rate / 8;
+ pr_debug("%s: pclk=%d, bclk=%d\n", __func__,
+ ctrl_pdata->pclk_rate, ctrl_pdata->byte_clk_rate);
+
pr_debug("%s: Panal data initialized\n", __func__);
return 0;
}
diff --git a/drivers/video/msm/mdss/mdss_dsi.h b/drivers/video/msm/mdss/mdss_dsi.h
index 06c2952..4a06be5 100644
--- a/drivers/video/msm/mdss/mdss_dsi.h
+++ b/drivers/video/msm/mdss/mdss_dsi.h
@@ -18,6 +18,7 @@
#include <mach/scm-io.h>
#include "mdss_panel.h"
+#include "mdss_io_util.h"
#define MMSS_SERDES_BASE_PHY 0x04f01000 /* mmss (De)Serializer CFG */
@@ -267,7 +268,7 @@
struct dsi_drv_cm_data {
struct regulator *vdd_vreg;
struct regulator *vdd_io_vreg;
- struct regulator *dsi_vreg;
+ struct regulator *vdda_vreg;
int broadcast_enable;
};
@@ -286,6 +287,9 @@
struct dsi_panel_cmds_list *on_cmds;
struct dsi_panel_cmds_list *off_cmds;
struct dsi_drv_cm_data shared_pdata;
+ u32 pclk_rate;
+ u32 byte_clk_rate;
+ struct dss_module_power power_data;
};
int dsi_panel_device_register(struct platform_device *pdev,
diff --git a/drivers/video/msm/mdss/mdss_dsi_panel.c b/drivers/video/msm/mdss/mdss_dsi_panel.c
index 4c30d18..8d38737 100644
--- a/drivers/video/msm/mdss/mdss_dsi_panel.c
+++ b/drivers/video/msm/mdss/mdss_dsi_panel.c
@@ -45,7 +45,6 @@
if (!gpio_is_valid(ctrl_pdata->disp_en_gpio)) {
pr_debug("%s:%d, reset line not configured\n",
__func__, __LINE__);
- return;
}
if (!gpio_is_valid(ctrl_pdata->rst_gpio)) {
@@ -59,18 +58,16 @@
if (enable) {
gpio_set_value((ctrl_pdata->rst_gpio), 1);
msleep(20);
- wmb();
gpio_set_value((ctrl_pdata->rst_gpio), 0);
udelay(200);
- wmb();
gpio_set_value((ctrl_pdata->rst_gpio), 1);
msleep(20);
- wmb();
- gpio_set_value((ctrl_pdata->disp_en_gpio), 1);
- wmb();
+ if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
+ gpio_set_value((ctrl_pdata->disp_en_gpio), 1);
} else {
gpio_set_value((ctrl_pdata->rst_gpio), 0);
- gpio_set_value((ctrl_pdata->disp_en_gpio), 0);
+ if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
+ gpio_set_value((ctrl_pdata->disp_en_gpio), 0);
}
}
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index 1e0de89..94261cc 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -730,19 +730,6 @@
.fb_mmap = mdss_fb_mmap,
};
-static u32 mdss_fb_line_length(u32 fb_index, u32 xres, int bpp)
-{
- /* The adreno GPU hardware requires that the pitch be aligned to
- 32 pixels for color buffers, so for the cases where the GPU
- is writing directly to fb0, the framebuffer pitch
- also needs to be 32 pixel aligned */
-
- if (fb_index == 0)
- return ALIGN(xres, 32) * bpp;
- else
- return xres * bpp;
-}
-
static int mdss_fb_alloc_fbmem(struct msm_fb_data_type *mfd)
{
void *virt = NULL;
@@ -753,16 +740,8 @@
size = PAGE_ALIGN(mfd->fbi->fix.line_length * yres);
if (mfd->index == 0) {
- int dom;
- virt = allocate_contiguous_memory(size, MEMTYPE_EBI1, SZ_1M, 0);
- if (!virt) {
- pr_err("unable to alloc fbmem size=%u\n", size);
- return -ENOMEM;
- }
- phys = memory_pool_node_paddr(virt);
- dom = mdss_get_iommu_domain(MDSS_IOMMU_DOMAIN_UNSECURE);
- msm_iommu_map_contig_buffer(phys, dom, 0, size, SZ_4K,
- 0, &(mfd->iova));
+ if (mdss_mdp_alloc_fb_mem(mfd, size, (u32 *)&phys, &virt))
+ return -ENOMEM;
pr_info("allocating %u bytes at %p (%lx phys) for fb %d\n",
size, virt, phys, mfd->index);
} else {
@@ -921,7 +900,7 @@
var->xres *= 2;
fix->type = panel_info->is_3d_panel;
- fix->line_length = mdss_fb_line_length(mfd->index, var->xres, bpp);
+ fix->line_length = mdss_mdp_fb_stride(mfd->index, var->xres, bpp);
var->yres = panel_info->yres;
var->xres_virtual = var->xres;
@@ -1425,7 +1404,7 @@
return -EINVAL;
}
- mfd->fbi->fix.line_length = mdss_fb_line_length(mfd->index, var->xres,
+ mfd->fbi->fix.line_length = mdss_mdp_fb_stride(mfd->index, var->xres,
var->bits_per_pixel / 8);
if (mfd->panel_reconfig || (mfd->fb_imgType != old_imgType)) {
@@ -1660,6 +1639,22 @@
return ret;
}
+static int mdss_fb_get_hw_caps(struct msm_fb_data_type *mfd,
+ struct mdss_hw_caps *caps)
+{
+ struct mdss_data_type *mdata = mfd->mdata;
+
+ if (!mdata)
+ return -ENODEV;
+
+ caps->mdp_rev = mdata->mdp_rev;
+ caps->vig_pipes = mdata->nvig_pipes;
+ caps->rgb_pipes = mdata->nrgb_pipes;
+ caps->dma_pipes = mdata->ndma_pipes;
+
+ return 0;
+}
+
static int mdss_fb_get_metadata(struct msm_fb_data_type *mfd,
struct msmfb_metadata *metadata)
{
@@ -1669,6 +1664,9 @@
metadata->data.panel_frame_rate =
mdss_get_panel_framerate(mfd);
break;
+ case metadata_op_get_caps:
+ ret = mdss_fb_get_hw_caps(mfd, &metadata->data.caps);
+ break;
default:
pr_warn("Unsupported request to MDP META IOCTL.\n");
ret = -EINVAL;
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
index 4f95aee..e8a3795 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -24,6 +24,7 @@
#define REG_DUMP 0
+#include "mdss_debug.h"
#include "mdss_fb.h"
#include "mdss_hdmi_tx.h"
#include "mdss_hdmi_edid.h"
@@ -448,6 +449,18 @@
hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID]) ? 0 : 1;
} /* hdmi_tx_is_dvi_mode */
+static inline void hdmi_tx_send_cable_notification(
+ struct hdmi_tx_ctrl *hdmi_ctrl, int val)
+{
+ if (!hdmi_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return;
+ }
+
+ if (!hdmi_ctrl->pdata.primary && (hdmi_ctrl->sdev.state != val))
+ switch_set_state(&hdmi_ctrl->sdev, val);
+} /* hdmi_tx_send_cable_notification */
+
static inline void hdmi_tx_set_audio_switch_node(struct hdmi_tx_ctrl *hdmi_ctrl,
int val, bool force)
{
@@ -694,11 +707,11 @@
if (hdmi_ctrl->hpd_state) {
hdmi_tx_read_sink_info(hdmi_ctrl);
- switch_set_state(&hdmi_ctrl->sdev, 1);
+ hdmi_tx_send_cable_notification(hdmi_ctrl, 1);
DEV_INFO("%s: sense cable CONNECTED: state switch to %d\n",
__func__, hdmi_ctrl->sdev.state);
} else {
- switch_set_state(&hdmi_ctrl->sdev, 0);
+ hdmi_tx_send_cable_notification(hdmi_ctrl, 0);
DEV_INFO("%s: sense cable DISCONNECTED: state switch to %d\n",
__func__, hdmi_ctrl->sdev.state);
}
@@ -1774,6 +1787,12 @@
return -ENODEV;
}
+ if (!hdmi_ctrl->audio_sdev.state) {
+ DEV_ERR("%s: failed. HDMI is not connected/ready for audio\n",
+ __func__);
+ return -EPERM;
+ }
+
return hdmi_edid_get_audio_blk(
hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID], blk);
} /* hdmi_tx_get_audio_edid_blk */
@@ -2090,6 +2109,7 @@
static int hdmi_tx_power_on(struct mdss_panel_data *panel_data)
{
+ u32 timeout;
int rc = 0;
struct dss_io_data *io = NULL;
struct hdmi_tx_ctrl *hdmi_ctrl =
@@ -2114,6 +2134,16 @@
/* If a power down is already underway, wait for it to finish */
flush_work_sync(&hdmi_ctrl->power_off_work);
+ if (hdmi_ctrl->pdata.primary) {
+ timeout = wait_for_completion_interruptible_timeout(
+ &hdmi_ctrl->hpd_done, HZ);
+ if (!timeout) {
+ DEV_ERR("%s: cable connection hasn't happened yet\n",
+ __func__);
+ return -ETIMEDOUT;
+ }
+ }
+
rc = hdmi_tx_set_video_fmt(hdmi_ctrl, &panel_data->panel_info);
if (rc) {
DEV_ERR("%s: cannot set video_fmt.rc=%d\n", __func__, rc);
@@ -2182,6 +2212,7 @@
DEV_INFO("%s: Failed to disable hpd power. Error=%d\n",
__func__, rc);
+ hdmi_ctrl->hpd_state = false;
hdmi_ctrl->hpd_initialized = false;
} /* hdmi_tx_hpd_off */
@@ -2257,7 +2288,7 @@
} else {
hdmi_ctrl->hpd_off_pending = true;
- switch_set_state(&hdmi_ctrl->sdev, 0);
+ hdmi_tx_send_cable_notification(hdmi_ctrl, 0);
DEV_DBG("%s: Hdmi state switch to %d\n", __func__,
hdmi_ctrl->sdev.state);
}
@@ -2433,6 +2464,20 @@
hdmi_tx_sysfs_remove(hdmi_ctrl);
return rc;
}
+
+ if (hdmi_ctrl->pdata.primary) {
+ INIT_COMPLETION(hdmi_ctrl->hpd_done);
+ rc = hdmi_tx_sysfs_enable_hpd(hdmi_ctrl, true);
+ if (rc) {
+ DEV_ERR("%s: hpd_enable failed. rc=%d\n",
+ __func__, rc);
+ hdmi_tx_sysfs_remove(hdmi_ctrl);
+ return rc;
+ } else {
+ hdmi_ctrl->hpd_feature_on = true;
+ }
+ }
+
break;
case MDSS_EVENT_CHECK_PARAMS:
@@ -2479,7 +2524,7 @@
if (!timeout & !hdmi_ctrl->hpd_state) {
DEV_INFO("%s: cable removed during suspend\n",
__func__);
- switch_set_state(&hdmi_ctrl->sdev, 0);
+ hdmi_tx_send_cable_notification(hdmi_ctrl, 0);
rc = -EPERM;
} else {
DEV_DBG("%s: cable present after resume\n",
@@ -3108,6 +3153,13 @@
}
}
+ if (of_find_property(pdev->dev.of_node, "qcom,primary_panel", NULL)) {
+ u32 tmp;
+ of_property_read_u32(pdev->dev.of_node, "qcom,primary_panel",
+ &tmp);
+ pdata->primary = tmp ? true : false;
+ }
+
return rc;
error:
@@ -3167,15 +3219,18 @@
if (rc) {
DEV_ERR("%s: Failed to add child devices. rc=%d\n",
__func__, rc);
- goto failed_init_features;
+ goto failed_reg_panel;
} else {
DEV_DBG("%s: Add child devices.\n", __func__);
}
+ if (mdss_debug_register_base("hdmi",
+ hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO].base,
+ hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO].len))
+ DEV_WARN("%s: hdmi_tx debugfs register failed\n", __func__);
+
return rc;
-failed_init_features:
- hdmi_tx_sysfs_remove(hdmi_ctrl);
failed_reg_panel:
hdmi_tx_dev_deinit(hdmi_ctrl);
failed_dev_init:
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.h b/drivers/video/msm/mdss/mdss_hdmi_tx.h
index 06ae427..8d9a477 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.h
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.h
@@ -30,8 +30,9 @@
HDMI_TX_MAX_PM
};
+/* Data filled from device tree */
struct hdmi_tx_platform_data {
- /* Data filled from device tree nodes */
+ bool primary;
struct dss_io_data io[HDMI_TX_MAX_IO];
struct dss_module_power power_data[HDMI_TX_MAX_PM];
};
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index 977fc63..f9b05fc 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -46,6 +46,8 @@
#include <mach/msm_bus_board.h>
#include <mach/iommu.h>
#include <mach/iommu_domains.h>
+#include <mach/memory.h>
+#include <mach/msm_memtypes.h>
#include "mdss.h"
#include "mdss_fb.h"
@@ -126,6 +128,39 @@
char *prop_name);
static int mdss_mdp_parse_dt_smp(struct platform_device *pdev);
+int mdss_mdp_alloc_fb_mem(struct msm_fb_data_type *mfd,
+ u32 size, u32 *phys, void **virt)
+{
+ int dom;
+ void *fb_virt;
+ u32 fb_phys;
+ fb_virt = allocate_contiguous_memory(size, MEMTYPE_EBI1, SZ_1M, 0);
+ if (!fb_virt) {
+ pr_err("unable to alloc fbmem size=%u\n", size);
+ return -ENOMEM;
+ }
+ fb_phys = memory_pool_node_paddr(fb_virt);
+ dom = mdss_get_iommu_domain(MDSS_IOMMU_DOMAIN_UNSECURE);
+ msm_iommu_map_contig_buffer(fb_phys, dom, 0, size, SZ_4K,
+ 0, &(mfd->iova));
+ *phys = fb_phys;
+ *virt = fb_virt;
+ return 0;
+}
+
+u32 mdss_mdp_fb_stride(u32 fb_index, u32 xres, int bpp)
+{
+ /* The adreno GPU hardware requires that the pitch be aligned to
+ 32 pixels for color buffers, so for the cases where the GPU
+ is writing directly to fb0, the framebuffer pitch
+ also needs to be 32 pixel aligned */
+
+ if (fb_index == 0)
+ return ALIGN(xres, 32) * bpp;
+ else
+ return xres * bpp;
+}
+
static inline int mdss_irq_dispatch(u32 hw_ndx, int irq, void *ptr)
{
struct mdss_hw *hw;
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index efd93c0..43456ca 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -420,4 +420,7 @@
int mdss_mdp_wb_ioctl_handler(struct msm_fb_data_type *mfd, u32 cmd, void *arg);
int mdss_mdp_get_ctl_mixers(u32 fb_num, u32 *mixer_id);
+int mdss_mdp_alloc_fb_mem(struct msm_fb_data_type *mfd,
+ u32 size, u32 *phys, void **virt);
+u32 mdss_mdp_fb_stride(u32 fb_index, u32 xres, int bpp);
#endif /* MDSS_MDP_H */
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index 8515782..e850321 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -71,7 +71,7 @@
}
}
if (flags & MDSS_MDP_PERF_UPDATE_BUS) {
- bus_ab_quota = bus_ab_quota << MDSS_MDP_BUS_FACTOR_SHIFT;
+ bus_ab_quota = bus_ib_quota << MDSS_MDP_BUS_FACTOR_SHIFT;
bus_ib_quota = MDSS_MDP_BUS_FUDGE_FACTOR(bus_ib_quota);
bus_ib_quota <<= MDSS_MDP_BUS_FACTOR_SHIFT;
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
index 97428cd..c6b6e3f 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
@@ -265,12 +265,12 @@
if (ctx->rot90) {
ctx->opmode |= BIT(5); /* ROT 90 */
swap(ctx->width, ctx->height);
+ ctx->format = mdss_mdp_get_rotator_dst_format(rot->format);
+ } else {
+ ctx->format = rot->format;
}
- if (mdss_mdp_writeback_format_setup(ctx))
- return -EINVAL;
-
- return 0;
+ return mdss_mdp_writeback_format_setup(ctx);
}
static int mdss_mdp_writeback_stop(struct mdss_mdp_ctl *ctl)
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index dcefc09..c6b3472 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -236,7 +236,7 @@
struct mdss_mdp_format_params *fmt;
struct mdss_mdp_pipe *pipe;
struct mdss_mdp_mixer *mixer = NULL;
- u32 pipe_type, mixer_mux, len;
+ u32 pipe_type, mixer_mux, len, src_format;
int ret;
if (mfd == NULL || mfd->ctl == NULL)
@@ -255,9 +255,13 @@
return -ENOTSUPP;
}
- fmt = mdss_mdp_get_format_params(req->src.format);
+ src_format = req->src.format;
+ if (req->flags & MDP_SOURCE_ROTATED_90)
+ src_format = mdss_mdp_get_rotator_dst_format(src_format);
+
+ fmt = mdss_mdp_get_format_params(src_format);
if (!fmt) {
- pr_err("invalid pipe format %d\n", req->src.format);
+ pr_err("invalid pipe format %d\n", src_format);
return -EINVAL;
}
@@ -539,9 +543,9 @@
virt = ion_map_kernel(iclient, ihdl);
ion_phys(iclient, ihdl, &phys, &size);
- pr_debug("%s %d Allocating %u bytes at 0x%lx (%lx phys)\n",
+ pr_debug("%s %d Allocating %u bytes at 0x%lx (%pa phys)\n",
__func__, __LINE__, size,
- (unsigned long int)virt, phys);
+ (unsigned long int)virt, &phys);
bl_fb_addr_va = (unsigned long *)ioremap(bl_fb_addr, size);
@@ -560,6 +564,8 @@
struct ion_client *iclient = mdss_get_ionclient();
struct mdss_panel_data *pdata;
int ret = 0, off;
+ int mdss_mdp_rev = MDSS_MDP_REG_READ(MDSS_MDP_REG_HW_VERSION);
+ int mdss_v2_intf_off = 0;
off = 0;
@@ -572,9 +578,13 @@
mdss_mdp_ctl_write(ctl, 0, MDSS_MDP_LM_BORDER_COLOR);
off = MDSS_MDP_REG_INTF_OFFSET(ctl->intf_num);
+ if (mdss_mdp_rev == MDSS_MDP_HW_REV_102)
+ mdss_v2_intf_off = 0xEC00;
+
/* wait for 1 VSYNC for the pipe to be unstaged */
msleep(20);
- MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_INTF_TIMING_ENGINE_EN, 0);
+ MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_INTF_TIMING_ENGINE_EN -
+ mdss_v2_intf_off, 0);
ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_CONT_SPLASH_FINISH,
NULL);
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
@@ -1148,7 +1158,7 @@
ret = wait_for_completion_interruptible_timeout(&mfd->vsync_comp,
timeout);
if (ret <= 0) {
- pr_warn("Sending current time as vsync timestamp for fb%d\n",
+ pr_debug("Sending current time as vsync timestamp for fb%d\n",
mfd->index);
mfd->vsync_time = ktime_get();
}
diff --git a/drivers/video/msm/mdss/mdss_mdp_rotator.h b/drivers/video/msm/mdss/mdss_mdp_rotator.h
index 70ef6bf..c46f271 100644
--- a/drivers/video/msm/mdss/mdss_mdp_rotator.h
+++ b/drivers/video/msm/mdss/mdss_mdp_rotator.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, 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
@@ -42,6 +42,18 @@
struct list_head head;
};
+static inline u32 mdss_mdp_get_rotator_dst_format(u32 in_format)
+{
+ switch (in_format) {
+ case MDP_Y_CBCR_H2V2_VENUS:
+ return MDP_Y_CBCR_H2V2;
+ case MDP_Y_CR_CB_GH2V2:
+ return MDP_Y_CR_CB_H2V2;
+ default:
+ return in_format;
+ }
+}
+
struct mdss_mdp_rotator_session *mdss_mdp_rotator_session_alloc(void);
struct mdss_mdp_rotator_session *mdss_mdp_rotator_session_get(u32 session_id);
diff --git a/drivers/video/msm/mdss/mdss_qpic.c b/drivers/video/msm/mdss/mdss_qpic.c
new file mode 100644
index 0000000..647504f
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_qpic.c
@@ -0,0 +1,708 @@
+/* Copyright (c) 2013, 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/kernel.h>
+#include <linux/sched.h>
+#include <linux/time.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/hrtimer.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/regulator/consumer.h>
+#include <linux/semaphore.h>
+#include <linux/uaccess.h>
+#include <linux/bootmem.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/system.h>
+#include <asm/mach-types.h>
+#include <mach/sps.h>
+#include <mach/clk.h>
+#include <mach/hardware.h>
+
+#include "mdss_fb.h"
+#include "mdss_qpic.h"
+
+static int mdss_qpic_probe(struct platform_device *pdev);
+static int mdss_qpic_remove(struct platform_device *pdev);
+
+struct qpic_data_type *qpic_res;
+
+/* for tuning */
+static u32 use_bam = true;
+static u32 use_irq;
+static u32 use_vsync;
+
+static const struct of_device_id mdss_qpic_dt_match[] = {
+ { .compatible = "qcom,mdss_qpic",},
+ {}
+};
+MODULE_DEVICE_TABLE(of, mdss_qpic_dt_match);
+
+static struct platform_driver mdss_qpic_driver = {
+ .probe = mdss_qpic_probe,
+ .remove = mdss_qpic_remove,
+ .shutdown = NULL,
+ .driver = {
+ /*
+ * Simulate mdp hw
+ */
+ .name = "mdp",
+ .of_match_table = mdss_qpic_dt_match,
+ },
+};
+
+int qpic_on(struct msm_fb_data_type *mfd)
+{
+ int ret;
+ ret = mdss_qpic_panel_on(qpic_res->panel_data);
+ return ret;
+}
+
+int qpic_off(struct msm_fb_data_type *mfd)
+{
+ int ret;
+ ret = mdss_qpic_panel_off(qpic_res->panel_data);
+ return ret;
+}
+
+static void mdss_qpic_pan_display(struct msm_fb_data_type *mfd)
+{
+
+ struct fb_info *fbi;
+ u32 offset, fb_offset, size;
+ int bpp;
+
+ if (!mfd) {
+ pr_err("%s: mfd is NULL!", __func__);
+ return;
+ }
+
+ fbi = mfd->fbi;
+
+ bpp = fbi->var.bits_per_pixel / 8;
+ offset = fbi->var.xoffset * bpp +
+ fbi->var.yoffset * fbi->fix.line_length;
+
+ if (offset > fbi->fix.smem_len) {
+ pr_err("invalid fb offset=%u total length=%u\n",
+ offset, fbi->fix.smem_len);
+ return;
+ }
+ fb_offset = (u32)fbi->fix.smem_start + offset;
+
+ mdss_qpic_panel_on(qpic_res->panel_data);
+ size = fbi->var.xres * fbi->var.yres * bpp;
+
+ qpic_send_frame(0, 0, fbi->var.xres, fbi->var.yres,
+ (u32 *)fb_offset, size);
+}
+
+int mdss_mdp_alloc_fb_mem(struct msm_fb_data_type *mfd,
+ u32 size, u32 *phys, void **virt)
+{
+ if (!qpic_res->res_init)
+ return -EINVAL;
+ if (!qpic_res->fb_virt) {
+ qpic_res->fb_virt = (void *)dmam_alloc_coherent(
+ &qpic_res->pdev->dev,
+ size + QPIC_MAX_CMD_BUF_SIZE,
+ &qpic_res->fb_phys,
+ GFP_KERNEL);
+ pr_err("%s size=%d vir_addr=%x phys_addr=%x",
+ __func__, size, (int)qpic_res->fb_virt,
+ (int)qpic_res->fb_phys);
+ if (!qpic_res->fb_virt)
+ return -ENOMEM;
+ qpic_res->cmd_buf_virt = qpic_res->fb_virt + size;
+ qpic_res->cmd_buf_phys = qpic_res->fb_phys + size;
+ }
+ *phys = qpic_res->fb_phys;
+ *virt = qpic_res->fb_virt;
+ return 0;
+}
+
+u32 mdss_mdp_fb_stride(u32 fb_index, u32 xres, int bpp)
+{
+ return xres * bpp;
+}
+
+int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd)
+{
+ mfd->on_fnc = qpic_on;
+ mfd->off_fnc = qpic_off;
+ mfd->dma_fnc = mdss_qpic_pan_display;
+ return 0;
+}
+
+u32 mdss_get_panel_framerate(struct msm_fb_data_type *mfd)
+{
+ return qpic_panel_get_framerate();
+}
+
+int qpic_register_panel(struct mdss_panel_data *pdata)
+{
+ struct platform_device *mdss_fb_dev = NULL;
+ int rc;
+
+ mdss_fb_dev = platform_device_alloc("mdss_fb", pdata->panel_info.pdest);
+ if (!mdss_fb_dev) {
+ pr_err("unable to allocate mdss_fb device\n");
+ return -ENOMEM;
+ }
+
+ mdss_fb_dev->dev.platform_data = pdata;
+
+ rc = platform_device_add(mdss_fb_dev);
+ if (rc) {
+ platform_device_put(mdss_fb_dev);
+ pr_err("unable to probe mdss_fb device (%d)\n", rc);
+ return rc;
+ }
+
+ qpic_res->panel_data = pdata;
+
+ return rc;
+}
+
+int qpic_init_sps(struct platform_device *pdev,
+ struct qpic_sps_endpt *end_point)
+{
+ int rc = 0;
+ struct sps_pipe *pipe_handle;
+ struct sps_connect *sps_config = &end_point->config;
+ struct sps_register_event *sps_event = &end_point->bam_event;
+ struct sps_bam_props bam = {0};
+ u32 bam_handle = 0;
+
+ if (qpic_res->sps_init)
+ return 0;
+ bam.phys_addr = qpic_res->qpic_phys + 0x4000;
+ bam.virt_addr = qpic_res->qpic_base + 0x4000;
+ bam.irq = qpic_res->irq - 4;
+ bam.manage = SPS_BAM_MGR_DEVICE_REMOTE | SPS_BAM_MGR_MULTI_EE;
+
+ rc = sps_phy2h(bam.phys_addr, &bam_handle);
+ if (rc)
+ rc = sps_register_bam_device(&bam, &bam_handle);
+ if (rc) {
+ pr_err("%s bam_handle is NULL", __func__);
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ pipe_handle = sps_alloc_endpoint();
+ if (!pipe_handle) {
+ pr_err("sps_alloc_endpoint() failed\n");
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ rc = sps_get_config(pipe_handle, sps_config);
+ if (rc) {
+ pr_err("sps_get_config() failed %d\n", rc);
+ goto free_endpoint;
+ }
+
+ /* WRITE CASE: source - system memory; destination - BAM */
+ sps_config->source = SPS_DEV_HANDLE_MEM;
+ sps_config->destination = bam_handle;
+ sps_config->mode = SPS_MODE_DEST;
+ sps_config->dest_pipe_index = 6;
+
+ sps_config->options = SPS_O_AUTO_ENABLE | SPS_O_EOT;
+ sps_config->lock_group = 0;
+ /*
+ * Descriptor FIFO is a cyclic FIFO. If 64 descriptors
+ * are allowed to be submitted before we get any ack for any of them,
+ * the descriptor FIFO size should be: (SPS_MAX_DESC_NUM + 1) *
+ * sizeof(struct sps_iovec).
+ */
+ sps_config->desc.size = (64) *
+ sizeof(struct sps_iovec);
+ sps_config->desc.base = dmam_alloc_coherent(&pdev->dev,
+ sps_config->desc.size,
+ &sps_config->desc.phys_base,
+ GFP_KERNEL);
+ if (!sps_config->desc.base) {
+ pr_err("dmam_alloc_coherent() failed for size %x\n",
+ sps_config->desc.size);
+ rc = -ENOMEM;
+ goto free_endpoint;
+ }
+ memset(sps_config->desc.base, 0x00, sps_config->desc.size);
+
+ rc = sps_connect(pipe_handle, sps_config);
+ if (rc) {
+ pr_err("sps_connect() failed %d\n", rc);
+ goto free_endpoint;
+ }
+
+ init_completion(&end_point->completion);
+ sps_event->mode = SPS_TRIGGER_WAIT;
+ sps_event->options = SPS_O_EOT;
+ sps_event->xfer_done = &end_point->completion;
+ sps_event->user = (void *)qpic_res;
+
+ rc = sps_register_event(pipe_handle, sps_event);
+ if (rc) {
+ pr_err("sps_register_event() failed %d\n", rc);
+ goto sps_disconnect;
+ }
+
+ end_point->handle = pipe_handle;
+ qpic_res->sps_init = true;
+ goto out;
+sps_disconnect:
+ sps_disconnect(pipe_handle);
+free_endpoint:
+ sps_free_endpoint(pipe_handle);
+out:
+ return rc;
+}
+
+void mdss_qpic_reset(void)
+{
+ u32 time_end;
+
+ QPIC_OUTP(QPIC_REG_QPIC_LCDC_RESET, 1 << 0);
+ /* wait 100 us after reset as suggested by hw */
+ usleep(100);
+ time_end = (u32)ktime_to_ms(ktime_get()) + QPIC_MAX_VSYNC_WAIT_TIME;
+ while (((QPIC_INP(QPIC_REG_QPIC_LCDC_STTS) & (1 << 8)) == 0)) {
+ if ((u32)ktime_to_ms(ktime_get()) > time_end) {
+ pr_err("%s reset not finished", __func__);
+ break;
+ }
+ /* yield 100 us for next polling by experiment*/
+ usleep(100);
+ }
+}
+
+void qpic_interrupt_en(u32 en)
+{
+ QPIC_OUTP(QPIC_REG_QPIC_LCDC_IRQ_CLR, 0xff);
+ if (en) {
+ if (!qpic_res->irq_ena) {
+ qpic_res->irq_ena = true;
+ enable_irq(qpic_res->irq);
+ QPIC_OUTP(QPIC_REG_QPIC_LCDC_IRQ_EN,
+ (1 << 0) | (1 << 2));
+ }
+ } else {
+ QPIC_OUTP(QPIC_REG_QPIC_LCDC_IRQ_EN, 0);
+ disable_irq(qpic_res->irq);
+ qpic_res->irq_ena = false;
+ }
+}
+
+static irqreturn_t qpic_irq_handler(int irq, void *ptr)
+{
+ u32 data;
+ data = QPIC_INP(QPIC_REG_QPIC_LCDC_IRQ_STTS);
+ QPIC_OUTP(QPIC_REG_QPIC_LCDC_IRQ_CLR, 0xff);
+ return 0;
+}
+
+int qpic_flush_buffer_bam(u32 cmd, u32 len, u32 *param, u32 is_cmd)
+{
+ int ret = 0;
+ u32 phys_addr, cfg2, block_len , flags;
+ if (is_cmd) {
+ memcpy((u8 *)qpic_res->cmd_buf_virt, param, len);
+ invalidate_caches((unsigned long)qpic_res->cmd_buf_virt,
+ len,
+ (unsigned long)qpic_res->cmd_buf_phys);
+ phys_addr = qpic_res->cmd_buf_phys;
+ } else {
+ phys_addr = (u32)param;
+ }
+
+ cfg2 = QPIC_INP(QPIC_REG_QPIC_LCDC_CFG2);
+ cfg2 &= ~0xFF;
+ cfg2 |= cmd;
+ QPIC_OUTP(QPIC_REG_QPIC_LCDC_CFG2, cfg2);
+ block_len = 0x7FF0;
+ while (len > 0) {
+ if (len <= 0x7FF0) {
+ flags = SPS_IOVEC_FLAG_EOT;
+ block_len = len;
+ } else {
+ flags = 0;
+ }
+ ret = sps_transfer_one(qpic_res->qpic_endpt.handle,
+ phys_addr, block_len, NULL, flags);
+ if (ret)
+ pr_err("failed to submit command %x ret %d\n",
+ cmd, ret);
+ phys_addr += block_len;
+ len -= block_len;
+ }
+ ret = wait_for_completion_interruptible_timeout(
+ &qpic_res->qpic_endpt.completion,
+ msecs_to_jiffies(100 * 4));
+ if (ret <= 0)
+ pr_err("%s timeout %x", __func__, ret);
+ else
+ ret = 0;
+ return ret;
+}
+
+int qpic_flush_buffer_sw(u32 cmd, u32 len, u32 *param, u32 is_cmd)
+{
+ u32 bytes_left, space, data, cfg2, time_end;
+ int i, ret = 0;
+ if ((len <= (sizeof(u32) * 4)) && (is_cmd)) {
+ len >>= 2;/* len in dwords */
+ data = 0;
+ for (i = 0; i < len; i++)
+ data |= param[i] << (8 * i);
+ QPIC_OUTP(QPIC_REG_QPIC_LCDC_CMD_DATA_CYCLE_CNT, len);
+ QPIC_OUTP(QPIC_REG_LCD_DEVICE_CMD0 + (4 * cmd), data);
+ return 0;
+ }
+ if ((len & 0x1) != 0) {
+ pr_err("%s: number of bytes needs be even", __func__);
+ len = (len + 1) & (~0x1);
+ }
+ QPIC_OUTP(QPIC_REG_QPIC_LCDC_IRQ_CLR, 0xff);
+ cfg2 = QPIC_INP(QPIC_REG_QPIC_LCDC_CFG2);
+ cfg2 |= (1 << 24); /* transparent mode */
+ cfg2 &= ~0xFF;
+ cfg2 |= cmd;
+ QPIC_OUTP(QPIC_REG_QPIC_LCDC_CFG2, cfg2);
+ QPIC_OUTP(QPIC_REG_QPIC_LCDC_FIFO_SOF, 0x0);
+ bytes_left = len;
+ while (bytes_left > 0) {
+ time_end = (u32)ktime_to_ms(ktime_get()) +
+ QPIC_MAX_VSYNC_WAIT_TIME;
+ while (1) {
+ data = QPIC_INP(QPIC_REG_QPIC_LCDC_STTS);
+ data &= 0x3F;
+ if (data == 0)
+ break;
+ /* yield 10 us for next polling by experiment*/
+ usleep(10);
+ if (ktime_to_ms(ktime_get()) > time_end) {
+ pr_err("%s time out", __func__);
+ ret = -EBUSY;
+ goto exit_send_cmd_sw;
+ }
+ }
+ space = (16 - data);
+
+ while ((space > 0) && (bytes_left > 0)) {
+ /* write to fifo */
+ if (bytes_left >= 4) {
+ QPIC_OUTP(QPIC_REG_QPIC_LCDC_FIFO_DATA_PORT0,
+ param[0]);
+ param++;
+ bytes_left -= 4;
+ space++;
+ } else if (bytes_left == 2) {
+ QPIC_OUTPW(QPIC_REG_QPIC_LCDC_FIFO_DATA_PORT0,
+ *(u16 *)param);
+ bytes_left -= 2;
+ }
+ }
+ }
+ /* finished */
+ QPIC_OUTP(QPIC_REG_QPIC_LCDC_FIFO_EOF, 0x0);
+
+ time_end = (u32)ktime_to_ms(ktime_get()) + QPIC_MAX_VSYNC_WAIT_TIME;
+ while (1) {
+ data = QPIC_INP(QPIC_REG_QPIC_LCDC_IRQ_STTS);
+ if (data & (1 << 2))
+ break;
+ /* yield 10 us for next polling by experiment*/
+ usleep(10);
+ if (ktime_to_ms(ktime_get()) > time_end) {
+ pr_err("%s wait for eof time out", __func__);
+ ret = -EBUSY;
+ goto exit_send_cmd_sw;
+ }
+ }
+exit_send_cmd_sw:
+ cfg2 &= ~(1 << 24);
+ QPIC_OUTP(QPIC_REG_QPIC_LCDC_CFG2, cfg2);
+ return ret;
+}
+
+int qpic_flush_buffer(u32 cmd, u32 len, u32 *param, u32 is_cmd)
+{
+ if (use_bam) {
+ if (is_cmd)
+ return qpic_flush_buffer_sw(cmd, len, param, is_cmd);
+ else
+ return qpic_flush_buffer_bam(cmd, len, param, is_cmd);
+ } else {
+ return qpic_flush_buffer_sw(cmd, len, param, is_cmd);
+ }
+}
+
+int mdss_qpic_init(void)
+{
+ int ret = 0;
+ u32 data;
+ mdss_qpic_reset();
+
+ pr_info("%s version=%x", __func__, QPIC_INP(QPIC_REG_LCDC_VERSION));
+ data = QPIC_INP(QPIC_REG_QPIC_LCDC_CTRL);
+ /* clear vsync wait , bam mode = 0*/
+ data &= ~(3 << 0);
+ data &= ~(0x1f << 3);
+ data |= (1 << 3); /* threshold */
+ data |= (1 << 8); /* lcd_en */
+ data &= ~(0x1f << 9);
+ data |= (1 << 9); /* threshold */
+ QPIC_OUTP(QPIC_REG_QPIC_LCDC_CTRL, data);
+
+ if (use_irq && qpic_res->irq_requested) {
+ ret = devm_request_irq(&qpic_res->pdev->dev,
+ qpic_res->irq, qpic_irq_handler,
+ IRQF_DISABLED, "QPIC", qpic_res);
+ if (ret) {
+ pr_err("qpic request_irq() failed!\n");
+ use_irq = false;
+ }
+ qpic_res->irq_requested = true;
+ }
+
+ qpic_interrupt_en(use_irq);
+ QPIC_OUTP(QPIC_REG_QPIC_LCDC_CFG0, 0x02108501);
+ data = QPIC_INP(QPIC_REG_QPIC_LCDC_CFG2);
+ data &= ~(0xFFF);
+ data |= 0x200; /* XRGB */
+ data |= 0x2C;
+ QPIC_OUTP(QPIC_REG_QPIC_LCDC_CFG2, data);
+
+ if (use_bam) {
+ qpic_init_sps(qpic_res->pdev , &qpic_res->qpic_endpt);
+ data = QPIC_INP(QPIC_REG_QPIC_LCDC_CTRL);
+ data |= (1 << 1);
+ QPIC_OUTP(QPIC_REG_QPIC_LCDC_CTRL, data);
+ }
+ /* TE enable */
+ if (use_vsync) {
+ data = QPIC_INP(QPIC_REG_QPIC_LCDC_CTRL);
+ data |= (1 << 0);
+ QPIC_OUTP(QPIC_REG_QPIC_LCDC_CTRL, data);
+ }
+
+ return ret;
+}
+
+static int mdss_qpic_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ int rc = 0;
+
+ if (!pdev->dev.of_node) {
+ pr_err("qpic driver only supports device tree probe\n");
+ return -ENOTSUPP;
+ }
+
+ if (!qpic_res)
+ qpic_res = devm_kzalloc(&pdev->dev,
+ sizeof(*qpic_res), GFP_KERNEL);
+
+ if (!qpic_res)
+ return -ENOMEM;
+
+ if (qpic_res->res_init) {
+ pr_err("qpic already initialized\n");
+ return -EINVAL;
+ }
+
+ pdev->id = 0;
+
+ qpic_res->pdev = pdev;
+ platform_set_drvdata(pdev, qpic_res);
+
+ res = platform_get_resource_byname(pdev,
+ IORESOURCE_MEM, "qpic_base");
+ if (!res) {
+ pr_err("unable to get QPIC reg base address\n");
+ rc = -ENOMEM;
+ goto probe_done;
+ }
+
+ qpic_res->qpic_reg_size = resource_size(res);
+ qpic_res->qpic_base = devm_ioremap(&pdev->dev, res->start,
+ qpic_res->qpic_reg_size);
+ if (unlikely(!qpic_res->qpic_base)) {
+ pr_err("unable to map MDSS QPIC base\n");
+ rc = -ENOMEM;
+ goto probe_done;
+ }
+ qpic_res->qpic_phys = res->start;
+ pr_info("MDSS QPIC HW Base phy_Address=0x%x virt=0x%x\n",
+ (int) res->start,
+ (int) qpic_res->qpic_base);
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res) {
+ pr_err("unable to get QPIC irq\n");
+ rc = -ENOMEM;
+ goto probe_done;
+ }
+
+ qpic_res->irq = res->start;
+ qpic_res->res_init = true;
+probe_done:
+ return rc;
+}
+
+static int mdss_qpic_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static int __init mdss_qpic_driver_init(void)
+{
+ int ret;
+
+ ret = platform_driver_register(&mdss_qpic_driver);
+ if (ret)
+ pr_err("mdss_qpic_register_driver() failed!\n");
+ return ret;
+}
+
+module_init(mdss_qpic_driver_init);
+
+int mdss_mdp_pa_config(struct mdss_mdp_ctl *ctl,
+ struct mdp_pa_cfg_data *config, u32 *copyback)
+{
+ return 0;
+}
+
+int mdss_mdp_pcc_config(struct mdss_mdp_ctl *ctl,
+ struct mdp_pcc_cfg_data *cfg_ptr, u32 *copyback)
+{
+ return 0;
+}
+
+int mdss_mdp_igc_lut_config(struct mdss_mdp_ctl *ctl,
+ struct mdp_igc_lut_data *config, u32 *copyback)
+{
+ return 0;
+}
+
+int mdss_mdp_argc_config(struct mdss_mdp_ctl *ctl,
+ struct mdp_pgc_lut_data *config, u32 *copyback)
+{
+ return 0;
+}
+
+int mdss_mdp_hist_lut_config(struct mdss_mdp_ctl *ctl,
+ struct mdp_hist_lut_data *config, u32 *copyback)
+{
+ return 0;
+}
+
+int mdss_mdp_dither_config(struct mdss_mdp_ctl *ctl,
+ struct mdp_dither_cfg_data *config, u32 *copyback)
+{
+ return 0;
+}
+
+int mdss_mdp_gamut_config(struct mdss_mdp_ctl *ctl,
+ struct mdp_gamut_cfg_data *config, u32 *copyback)
+{
+ return 0;
+}
+
+int mdss_mdp_histogram_start(struct mdss_mdp_ctl *ctl,
+ struct mdp_histogram_start_req *req)
+{
+ return 0;
+}
+
+int mdss_mdp_histogram_stop(struct mdss_mdp_ctl *ctl, u32 block)
+{
+ return 0;
+}
+
+int mdss_mdp_hist_collect(struct mdss_mdp_ctl *ctl,
+ struct mdp_histogram_data *hist,
+ u32 *hist_data_addr)
+{
+ return 0;
+}
+
+int mdss_mdp_overlay_kickoff(struct mdss_mdp_ctl *ctl)
+{
+ return 0;
+}
+
+void mdss_mdp_clk_ctrl(int enable, int isr)
+{
+}
+
+int mdss_mdp_copy_splash_screen(struct mdss_panel_data *pdata)
+{
+ return 0;
+}
+
+void mdss_mdp_footswitch_ctrl_splash(int on)
+{
+}
+
+int msm_fb_writeback_init(struct fb_info *info)
+{
+ return 0;
+}
+EXPORT_SYMBOL(msm_fb_writeback_init);
+
+int msm_fb_writeback_start(struct fb_info *info)
+{
+ return 0;
+}
+EXPORT_SYMBOL(msm_fb_writeback_start);
+
+int msm_fb_writeback_queue_buffer(struct fb_info *info,
+ struct msmfb_data *data)
+{
+ return 0;
+}
+EXPORT_SYMBOL(msm_fb_writeback_queue_buffer);
+
+int msm_fb_writeback_dequeue_buffer(struct fb_info *info,
+ struct msmfb_data *data)
+{
+ return 0;
+}
+EXPORT_SYMBOL(msm_fb_writeback_dequeue_buffer);
+
+int msm_fb_writeback_stop(struct fb_info *info)
+{
+ return 0;
+}
+EXPORT_SYMBOL(msm_fb_writeback_stop);
+
+int msm_fb_writeback_terminate(struct fb_info *info)
+{
+ return 0;
+}
+EXPORT_SYMBOL(msm_fb_writeback_terminate);
+
+int msm_fb_get_iommu_domain(struct fb_info *info, int domain)
+{
+ return 0;
+}
+EXPORT_SYMBOL(msm_fb_get_iommu_domain);
diff --git a/drivers/video/msm/mdss/mdss_qpic.h b/drivers/video/msm/mdss/mdss_qpic.h
new file mode 100644
index 0000000..086e8c8
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_qpic.h
@@ -0,0 +1,95 @@
+/* Copyright (c) 2013, 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 MDSS_QPIC_H
+#define MDSS_QPIC_H
+
+#include <linux/list.h>
+#include <mach/scm-io.h>
+#include <mach/sps.h>
+
+#include "mdss_panel.h"
+
+#define QPIC_REG_QPIC_LCDC_CTRL 0x22000
+#define QPIC_REG_LCDC_VERSION 0x22004
+#define QPIC_REG_QPIC_LCDC_IRQ_EN 0x22008
+#define QPIC_REG_QPIC_LCDC_IRQ_STTS 0x2200C
+#define QPIC_REG_QPIC_LCDC_IRQ_CLR 0x22010
+#define QPIC_REG_QPIC_LCDC_STTS 0x22014
+#define QPIC_REG_QPIC_LCDC_CMD_DATA_CYCLE_CNT 0x22018
+#define QPIC_REG_QPIC_LCDC_CFG0 0x22020
+#define QPIC_REG_QPIC_LCDC_CFG1 0x22024
+#define QPIC_REG_QPIC_LCDC_CFG2 0x22028
+#define QPIC_REG_QPIC_LCDC_RESET 0x2202C
+#define QPIC_REG_QPIC_LCDC_FIFO_SOF 0x22100
+#define QPIC_REG_LCD_DEVICE_CMD0 0x23000
+#define QPIC_REG_QPIC_LCDC_FIFO_DATA_PORT0 0x22140
+#define QPIC_REG_QPIC_LCDC_FIFO_EOF 0x22180
+
+#define QPIC_OUTP(off, data) \
+ writel_relaxed((data), qpic_res->qpic_base + (off))
+#define QPIC_OUTPW(off, data) \
+ writew_relaxed((data), qpic_res->qpic_base + (off))
+#define QPIC_INP(off) \
+ readl_relaxed(qpic_res->qpic_base + (off))
+
+#define QPIC_MAX_VSYNC_WAIT_TIME 500
+#define QPIC_MAX_CMD_BUF_SIZE 512
+
+int mdss_qpic_init(void);
+int qpic_flush_buffer(u32 cmd, u32 len, u32 *param, u32 is_cmd);
+
+u32 msm_qpic_get_bam_hdl(struct sps_bam_props *bam);
+int mdss_qpic_panel_on(struct mdss_panel_data *pdata);
+int mdss_qpic_panel_off(struct mdss_panel_data *pdata);
+int qpic_register_panel(struct mdss_panel_data *pdata);
+int ili9341_on(void);
+
+/* Structure that defines an SPS end point for a BAM pipe. */
+struct qpic_sps_endpt {
+ struct sps_pipe *handle;
+ struct sps_connect config;
+ struct sps_register_event bam_event;
+ struct completion completion;
+};
+
+struct qpic_data_type {
+ u32 rev;
+ struct platform_device *pdev;
+ size_t qpic_reg_size;
+ u32 qpic_phys;
+ char __iomem *qpic_base;
+ u32 irq;
+ u32 irq_ena;
+ u32 res_init;
+ void *fb_virt;
+ u32 fb_phys;
+ void *cmd_buf_virt;
+ u32 cmd_buf_phys;
+ struct qpic_sps_endpt qpic_endpt;
+ u32 sps_init;
+ u32 irq_requested;
+ struct mdss_panel_data *panel_data;
+};
+
+u32 qpic_send_frame(
+ u32 x_start,
+ u32 y_start,
+ u32 x_end,
+ u32 y_end,
+ u32 *data,
+ u32 total_bytes);
+
+u32 qpic_panel_get_framerate(void);
+
+#endif /* MDSS_QPIC_H */
diff --git a/drivers/video/msm/mdss/mdss_qpic_panel.c b/drivers/video/msm/mdss/mdss_qpic_panel.c
new file mode 100644
index 0000000..9825abc
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_qpic_panel.c
@@ -0,0 +1,246 @@
+/* Copyright (c) 2013, 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/interrupt.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/gpio.h>
+#include <linux/qpnp/pin.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/leds.h>
+#include <linux/regulator/consumer.h>
+#include <linux/dma-mapping.h>
+#include <linux/uaccess.h>
+
+#include <mach/sps.h>
+
+#include "mdss.h"
+#include "mdss_panel.h"
+#include "mdss_qpic.h"
+#include "mdss_qpic_panel.h"
+
+static u32 panel_is_on;
+static u32 panel_refresh_rate;
+static int (*qpic_panel_on)(void);
+static void (*qpic_panel_off)(void);
+static int (*qpic_panel_init)(struct platform_device *pdev,
+ struct device_node *np);
+
+u32 qpic_panel_get_framerate(void)
+{
+ return panel_refresh_rate;
+}
+
+u32 qpic_send_panel_cmd(u32 cmd, u32 *val, u32 length)
+{
+ u32 ret;
+ u32 cmd_index;
+ u32 size;
+ u32 buffer[LCDC_INTERNAL_BUFFER_SIZE];
+ u32 i;
+
+ cmd_index = LCDC_EXTRACT_OP_CMD(cmd);
+ size = LCDC_EXTRACT_OP_SIZE(cmd);
+ if (size == INV_SIZE)
+ size = length;
+ /* short or pixel data commands need not conversion */
+ if ((cmd == OP_WRITE_MEMORY_CONTINUE) ||
+ (cmd == OP_WRITE_MEMORY_START)) {
+ ret = qpic_flush_buffer(cmd_index, size, val, false);
+ } else {
+ if (size > LCDC_INTERNAL_BUFFER_SIZE)
+ size = LCDC_INTERNAL_BUFFER_SIZE;
+ /* correcting for encoding issues */
+ for (i = 0; i < size; i += sizeof(u32)) {
+ buffer[i] = (val[(i>>2)] >> 0) & 0xff;
+ buffer[i+1] = (val[(i>>2)] >> 8) & 0xff;
+ buffer[i+2] = (val[(i>>2)] >> 16) & 0xff;
+ buffer[i+3] = (val[(i>>2)] >> 24) & 0xff;
+ }
+ ret = qpic_flush_buffer(cmd_index,
+ size * sizeof(u32), buffer, true);
+ }
+ return ret;
+}
+
+u32 qpic_panel_set_cmd_only(u32 command)
+{
+ u32 param;
+ return qpic_send_panel_cmd(command, ¶m, 0);
+}
+
+/* write a frame of pixels to a MIPI screen */
+u32 qpic_send_frame(u32 x_start,
+ u32 y_start,
+ u32 x_end,
+ u32 y_end,
+ u32 *data,
+ u32 total_bytes)
+{
+ u32 param;
+ u32 status;
+ u32 start_0_7;
+ u32 end_0_7;
+ u32 start_8_15;
+ u32 end_8_15;
+
+ /* convert to 16 bit representation */
+ x_start = x_start & 0xffff;
+ y_start = y_start & 0xffff;
+ x_end = x_end & 0xffff;
+ y_end = y_end & 0xffff;
+
+ /* set column/page */
+ start_0_7 = x_start & 0xff;
+ end_0_7 = x_end & 0xff;
+ start_8_15 = (x_start >> 8) & 0xff;
+ end_8_15 = (x_end >> 8) & 0xff;
+ param = (start_8_15 << 0) | (start_0_7 << 8) |
+ (end_8_15 << 16) | (end_0_7 << 24U);
+ status = qpic_send_panel_cmd(OP_SET_COLUMN_ADDRESS, ¶m, 0);
+ if (status) {
+ pr_err("Failed to set column address");
+ return status;
+ }
+
+ start_0_7 = y_start & 0xff;
+ end_0_7 = y_end & 0xff;
+ start_8_15 = (y_start >> 8) & 0xff;
+ end_8_15 = (y_end >> 8) & 0xff;
+ param = (start_8_15 << 0) | (start_0_7 << 8) |
+ (end_8_15 << 16) | (end_0_7 << 24U);
+ status = qpic_send_panel_cmd(OP_SET_PAGE_ADDRESS, ¶m, 0);
+ if (status) {
+ pr_err("Failed to set page address");
+ return status;
+ }
+
+ status = qpic_send_panel_cmd(OP_WRITE_MEMORY_START,
+ &(data[0]), total_bytes);
+ if (status) {
+ pr_err("Failed to start memory write");
+ return status;
+ }
+ return 0;
+}
+
+int mdss_qpic_panel_on(struct mdss_panel_data *pdata)
+{
+ int rc = 0;
+
+ if (panel_is_on)
+ return 0;
+ mdss_qpic_init();
+
+ if (qpic_panel_on)
+ rc = qpic_panel_on();
+ if (rc)
+ return rc;
+ panel_is_on = true;
+ return 0;
+}
+
+int mdss_qpic_panel_off(struct mdss_panel_data *pdata)
+{
+ if (qpic_panel_off)
+ qpic_panel_off();
+ panel_is_on = false;
+ return 0;
+}
+
+static int mdss_panel_parse_dt(struct platform_device *pdev,
+ struct mdss_panel_data *panel_data)
+{
+ struct device_node *np = pdev->dev.of_node;
+ u32 res[6], tmp;
+ int rc;
+
+ rc = of_property_read_u32_array(np, "qcom,mdss-pan-res", res, 2);
+ if (rc) {
+ pr_err("%s:%d, panel resolution not specified\n",
+ __func__, __LINE__);
+ return -EINVAL;
+ }
+ panel_data->panel_info.xres = (!rc ? res[0] : 240);
+ panel_data->panel_info.yres = (!rc ? res[1] : 320);
+ rc = of_property_read_u32(np, "qcom,mdss-pan-bpp", &tmp);
+ if (rc) {
+ pr_err("%s:%d, panel bpp not specified\n",
+ __func__, __LINE__);
+ return -EINVAL;
+ }
+ panel_data->panel_info.bpp = (!rc ? tmp : 24);
+ of_property_read_u32(np, "qcom,refresh_rate", &panel_refresh_rate);
+
+ panel_data->panel_info.type = EBI2_PANEL;
+ panel_data->panel_info.pdest = DISPLAY_1;
+
+ if (qpic_panel_init)
+ rc = qpic_panel_init(pdev, np);
+
+ return rc;
+}
+
+static int __devinit mdss_qpic_panel_probe(struct platform_device *pdev)
+{
+ int rc = 0;
+ static struct mdss_panel_data vendor_pdata;
+ static const char *panel_name;
+
+ pr_debug("%s:%d, debug info id=%d", __func__, __LINE__, pdev->id);
+ if (!pdev->dev.of_node)
+ return -ENODEV;
+
+ panel_name = of_get_property(pdev->dev.of_node, "label", NULL);
+ if (!panel_name)
+ pr_info("%s:%d, panel name not specified\n",
+ __func__, __LINE__);
+ else
+ pr_info("%s: Panel Name = %s\n", __func__, panel_name);
+
+ /* select panel according to label */
+ qpic_panel_init = ili9341_init;
+ qpic_panel_on = ili9341_on;
+ qpic_panel_off = ili9341_off;
+
+ rc = mdss_panel_parse_dt(pdev, &vendor_pdata);
+ if (rc)
+ return rc;
+
+ rc = qpic_register_panel(&vendor_pdata);
+ if (rc)
+ return rc;
+
+ return 0;
+}
+
+static const struct of_device_id mdss_qpic_panel_match[] = {
+ {.compatible = "qcom,mdss-qpic-panel"},
+ {}
+};
+
+static struct platform_driver this_driver = {
+ .probe = mdss_qpic_panel_probe,
+ .driver = {
+ .name = "qpic_panel",
+ .of_match_table = mdss_qpic_panel_match,
+ },
+};
+
+static int __init mdss_qpic_panel_init(void)
+{
+ return platform_driver_register(&this_driver);
+}
+MODULE_DEVICE_TABLE(of, mdss_qpic_panel_match);
+module_init(mdss_qpic_panel_init);
diff --git a/drivers/video/msm/mdss/mdss_qpic_panel.h b/drivers/video/msm/mdss/mdss_qpic_panel.h
new file mode 100644
index 0000000..76f7dc2
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_qpic_panel.h
@@ -0,0 +1,114 @@
+/* Copyright (c) 2013, 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 MDSS_QPIC_PANEL_H
+#define MDSS_QPIC_PANEL_H
+
+#include <linux/list.h>
+#include <mach/sps.h>
+
+#include "mdss_panel.h"
+
+#define LCDC_INTERNAL_BUFFER_SIZE 30
+
+/**
+ Macros for coding MIPI commands
+*/
+#define INV_SIZE 0xFFFF
+/* Size of argument to MIPI command is variable */
+#define OP_SIZE_PAIR(op, size) ((op<<16) | size)
+/* MIPI {command, argument size} tuple */
+#define LCDC_EXTRACT_OP_SIZE(op_identifier) ((op_identifier&0xFFFF))
+/* extract size from command identifier */
+#define LCDC_EXTRACT_OP_CMD(op_identifier) (((op_identifier>>16)&0xFFFF))
+/* extract command id from command identifier */
+
+
+/* MIPI standard efinitions */
+#define LCDC_ADDRESS_MODE_ORDER_BOTTOM_TO_TOP 0x80
+#define LCDC_ADDRESS_MODE_ORDER_RIGHT_TO_LEFT 0x40
+#define LCDC_ADDRESS_MODE_ORDER_REVERSE 0x20
+#define LCDC_ADDRESS_MODE_ORDER_REFRESH_BOTTOM_TO_TOP 0x10
+#define LCDC_ADDRESS_MODE_ORDER_BGER_RGB 0x08
+#define LCDC_ADDRESS_MODE_ORDER_REFERESH_RIGHT_TO_LEFT 0x04
+#define LCDC_ADDRESS_MODE_FLIP_HORIZONTAL 0x02
+#define LCDC_ADDRESS_MODE_FLIP_VERTICAL 0x01
+
+#define LCDC_PIXEL_FORMAT_3_BITS_PER_PIXEL 0x1
+#define LCDC_PIXEL_FORMAT_8_BITS_PER_PIXEL 0x2
+#define LCDC_PIXEL_FORMAT_12_BITS_PER_PIXEL 0x3
+#define LCDC_PIXEL_FORMAT_16_BITS_PER_PIXEL 0x5
+#define LCDC_PIXEL_FORMAT_18_BITS_PER_PIXEL 0x6
+#define LCDC_PIXEL_FORMAT_24_BITS_PER_PIXEL 0x7
+
+#define LCDC_CREATE_PIXEL_FORMAT(dpi_format, dbi_format) \
+ (dpi_format | (dpi_format<<4))
+
+#define POWER_MODE_IDLE_ON 0x40
+#define POWER_MODE_PARTIAL_ON 0x20
+#define POWER_MODE_SLEEP_ON 0x10
+#define POWER_MODE_NORMAL_ON 0x08
+#define POWER_MODE_DISPLAY_ON 0x04
+
+#define LCDC_DISPLAY_MODE_SCROLLING_ON 0x80
+#define LCDC_DISPLAY_MODE_INVERSION_ON 0x20
+#define LCDC_DISPLAY_MODE_GAMMA_MASK 0x07
+
+/**
+ * LDCc MIPI Type B supported commands
+ */
+enum {
+ OP_ENTER_IDLE_MODE = OP_SIZE_PAIR(0x39, 0),
+ OP_ENTER_INVERT_MODE = OP_SIZE_PAIR(0x21, 0),
+ OP_ENTER_NORMAL_MODE = OP_SIZE_PAIR(0x13, 0),
+ OP_ENTER_PARTIAL_MODE = OP_SIZE_PAIR(0x12, 0),
+ OP_ENTER_SLEEP_MODE = OP_SIZE_PAIR(0x10, 0),
+ OP_EXIT_INVERT_MODE = OP_SIZE_PAIR(0x20, 0),
+ OP_EXIT_SLEEP_MODE = OP_SIZE_PAIR(0x11, 0),
+ OP_EXIT_IDLE_MODE = OP_SIZE_PAIR(0x38, 0),
+ OP_GET_ADDRESS_MODE = OP_SIZE_PAIR(0x0B, 1),
+ OP_GET_BLUE_CHANNEL = OP_SIZE_PAIR(0x08, 1),
+ OP_GET_DIAGNOSTIC_RESULT = OP_SIZE_PAIR(0x0F, 2),
+ OP_GET_DISPLAY_MODE = OP_SIZE_PAIR(0x0D, 1),
+ OP_GET_GREEN_CHANNEL = OP_SIZE_PAIR(0x07, 1),
+ OP_GET_PIXEL_FORMAT = OP_SIZE_PAIR(0x0C, 1),
+ OP_GET_POWER_MODE = OP_SIZE_PAIR(0x0A, 1),
+ OP_GET_RED_CHANNEL = OP_SIZE_PAIR(0x06, 1),
+ OP_GET_SCANLINE = OP_SIZE_PAIR(0x45, 2),
+ OP_GET_SIGNAL_MODE = OP_SIZE_PAIR(0x0E, 1),
+ OP_NOP = OP_SIZE_PAIR(0x00, 0),
+ OP_READ_DDB_CONTINUE = OP_SIZE_PAIR(0xA8, INV_SIZE),
+ OP_READ_DDB_START = OP_SIZE_PAIR(0xA1, INV_SIZE),
+ OP_READ_MEMORY_CONTINUE = OP_SIZE_PAIR(0x3E, INV_SIZE),
+ OP_READ_MEMORY_START = OP_SIZE_PAIR(0x2E, INV_SIZE),
+ OP_SET_ADDRESS_MODE = OP_SIZE_PAIR(0x36, 1),
+ OP_SET_COLUMN_ADDRESS = OP_SIZE_PAIR(0x2A, 4),
+ OP_SET_DISPLAY_OFF = OP_SIZE_PAIR(0x28, 0),
+ OP_SET_DISPLAY_ON = OP_SIZE_PAIR(0x29, 0),
+ OP_SET_GAMMA_CURVE = OP_SIZE_PAIR(0x26, 1),
+ OP_SET_PAGE_ADDRESS = OP_SIZE_PAIR(0x2B, 4),
+ OP_SET_PARTIAL_COLUMNS = OP_SIZE_PAIR(0x31, 4),
+ OP_SET_PARTIAL_ROWS = OP_SIZE_PAIR(0x30, 4),
+ OP_SET_PIXEL_FORMAT = OP_SIZE_PAIR(0x3A, 1),
+ OP_SOFT_RESET = OP_SIZE_PAIR(0x01, 0),
+ OP_WRITE_MEMORY_CONTINUE = OP_SIZE_PAIR(0x3C, INV_SIZE),
+ OP_WRITE_MEMORY_START = OP_SIZE_PAIR(0x2C, INV_SIZE),
+};
+
+u32 qpic_panel_set_cmd_only(u32 command);
+u32 qpic_send_panel_cmd(u32 cmd, u32 *val, u32 length);
+int ili9341_on(void);
+void ili9341_off(void);
+int ili9341_init(struct platform_device *pdev,
+ struct device_node *np);
+#endif /* MDSS_QPIC_PANEL_H */
diff --git a/drivers/video/msm/mdss/msm_mdss_io_8974.c b/drivers/video/msm/mdss/msm_mdss_io_8974.c
index 3b6fc38..2b07e43 100644
--- a/drivers/video/msm/mdss/msm_mdss_io_8974.c
+++ b/drivers/video/msm/mdss/msm_mdss_io_8974.c
@@ -173,6 +173,7 @@
void mdss_dsi_clk_enable(struct mdss_panel_data *pdata)
{
struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+ u32 esc_clk_rate = 19200000;
ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
panel_data);
@@ -186,17 +187,17 @@
return;
}
- if (clk_set_rate(ctrl_pdata->esc_clk, 19200000) < 0)
- pr_err("%s: dsi_esc_clk - clk_set_rate failed\n",
- __func__);
+ pr_debug("%s: Setting clock rates: pclk=%d, byteclk=%d escclk=%d\n",
+ __func__, ctrl_pdata->pclk_rate,
+ ctrl_pdata->byte_clk_rate, esc_clk_rate);
+ if (clk_set_rate(ctrl_pdata->esc_clk, esc_clk_rate) < 0)
+ pr_err("%s: dsi_esc_clk - clk_set_rate failed\n", __func__);
- if (clk_set_rate(ctrl_pdata->byte_clk, 53000000) < 0)
- pr_err("%s: dsi_byte_clk - clk_set_rate failed\n",
- __func__);
+ if (clk_set_rate(ctrl_pdata->byte_clk, ctrl_pdata->byte_clk_rate) < 0)
+ pr_err("%s: dsi_byte_clk - clk_set_rate failed\n", __func__);
- if (clk_set_rate(ctrl_pdata->pixel_clk, 70000000) < 0)
- pr_err("%s: dsi_pixel_clk - clk_set_rate failed\n",
- __func__);
+ if (clk_set_rate(ctrl_pdata->pixel_clk, ctrl_pdata->pclk_rate) < 0)
+ pr_err("%s: dsi_pixel_clk - clk_set_rate failed\n", __func__);
clk_enable(ctrl_pdata->esc_clk);
clk_enable(ctrl_pdata->byte_clk);
diff --git a/drivers/video/msm/mdss/qpic_panel_ili_qvga.c b/drivers/video/msm/mdss/qpic_panel_ili_qvga.c
new file mode 100644
index 0000000..4459c6b
--- /dev/null
+++ b/drivers/video/msm/mdss/qpic_panel_ili_qvga.c
@@ -0,0 +1,226 @@
+/* Copyright (c) 2013, 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/memory.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/time.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/proc_fs.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/delay.h>
+#include <linux/regulator/consumer.h>
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+#include <asm/system.h>
+#include <asm/mach-types.h>
+
+#include "mdss_qpic.h"
+#include "mdss_qpic_panel.h"
+
+enum {
+ OP_ILI9341_TEARING_EFFECT_LINE_ON = OP_SIZE_PAIR(0x35, 1),
+ OP_ILI9341_INTERFACE_CONTROL = OP_SIZE_PAIR(0xf6, 3),
+ OP_ILI9341_WRITE_CTRL_DISPLAY = OP_SIZE_PAIR(0x53, 1),
+ OP_ILI9341_POWER_CONTROL_A = OP_SIZE_PAIR(0xcb, 5),
+ OP_ILI9341_POWER_CONTROL_B = OP_SIZE_PAIR(0xcf, 3),
+ OP_ILI9341_DRIVER_TIMING_CONTROL_A = OP_SIZE_PAIR(0xe8, 3),
+ OP_ILI9341_DRIVER_TIMING_CONTROL_B = OP_SIZE_PAIR(0xea, 3),
+ OP_ILI9341_POWER_ON_SEQUENCE_CONTROL = OP_SIZE_PAIR(0xed, 4),
+ OP_ILI9341_PUMP_RATIO_CONTROL = OP_SIZE_PAIR(0xf7, 1),
+ OP_ILI9341_POWER_CONTROL_1 = OP_SIZE_PAIR(0xc0, 1),
+ OP_ILI9341_POWER_CONTROL_2 = OP_SIZE_PAIR(0xc1, 1),
+ OP_ILI9341_VCOM_CONTROL_1 = OP_SIZE_PAIR(0xc5, 2),
+ OP_ILI9341_VCOM_CONTROL_2 = OP_SIZE_PAIR(0xc7, 1),
+ OP_ILI9341_MEMORY_ACCESS_CONTROL = OP_SIZE_PAIR(0x36, 1),
+ OP_ILI9341_FRAME_RATE_CONTROL = OP_SIZE_PAIR(0xb1, 2),
+ OP_ILI9341_DISPLAY_FUNCTION_CONTROL = OP_SIZE_PAIR(0xb6, 4),
+ OP_ILI9341_ENABLE_3G = OP_SIZE_PAIR(0xf2, 1),
+ OP_ILI9341_COLMOD_PIXEL_FORMAT_SET = OP_SIZE_PAIR(0x3a, 1),
+ OP_ILI9341_GAMMA_SET = OP_SIZE_PAIR(0x26, 1),
+ OP_ILI9341_POSITIVE_GAMMA_CORRECTION = OP_SIZE_PAIR(0xe0, 15),
+ OP_ILI9341_NEGATIVE_GAMMA_CORRECTION = OP_SIZE_PAIR(0xe1, 15),
+ OP_ILI9341_READ_DISPLAY_ID = OP_SIZE_PAIR(0x04, 4),
+ OP_ILI9341_READ_DISPLAY_POWER_MODE = OP_SIZE_PAIR(0x0a, 2),
+ OP_ILI9341_READ_DISPLAY_MADCTL = OP_SIZE_PAIR(0x0b, 2),
+};
+
+static int rst_gpio;
+static int cs_gpio;
+static int ad8_gpio;
+static int te_gpio;
+struct regulator *vdd_vreg;
+struct regulator *avdd_vreg;
+
+int ili9341_init(struct platform_device *pdev,
+ struct device_node *np)
+{
+ int rc = 0;
+ rst_gpio = of_get_named_gpio(np, "qcom,rst-gpio", 0);
+ cs_gpio = of_get_named_gpio(np, "qcom,cs-gpio", 0);
+ ad8_gpio = of_get_named_gpio(np, "qcom,ad8-gpio", 0);
+ te_gpio = of_get_named_gpio(np, "qcom,te-gpio", 0);
+ if (!gpio_is_valid(rst_gpio)) {
+ pr_err("%s: reset gpio not specified\n" , __func__);
+ return -EINVAL;
+ }
+ if (!gpio_is_valid(cs_gpio)) {
+ pr_err("%s: cs gpio not specified\n", __func__);
+ return -EINVAL;
+ }
+ if (!gpio_is_valid(ad8_gpio)) {
+ pr_err("%s: ad8 gpio not specified\n", __func__);
+ return -EINVAL;
+ }
+ if (!gpio_is_valid(te_gpio)) {
+ pr_err("%s: te gpio not specified\n", __func__);
+ return -EINVAL;
+ }
+ vdd_vreg = devm_regulator_get(&pdev->dev, "vdd");
+ if (IS_ERR(vdd_vreg)) {
+ pr_err("%s could not get vdd,", __func__);
+ return -ENODEV;
+ }
+ avdd_vreg = devm_regulator_get(&pdev->dev, "avdd");
+ if (IS_ERR(avdd_vreg)) {
+ pr_err("%s could not get avdd,", __func__);
+ return -ENODEV;
+ }
+ rc = regulator_set_voltage(vdd_vreg, 1800000, 1800000);
+ if (rc) {
+ pr_err("vdd_vreg->set_voltage failed, rc=%d\n", rc);
+ return -EINVAL;
+ }
+ rc = regulator_set_voltage(avdd_vreg, 2700000, 2700000);
+ if (rc) {
+ pr_err("vdd_vreg->set_voltage failed, rc=%d\n", rc);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int ili9341_panel_power_on(void)
+{
+ int rc;
+ rc = regulator_enable(vdd_vreg);
+ if (rc) {
+ pr_err("enable vdd failed, rc=%d\n", rc);
+ return -ENODEV;
+ }
+ rc = regulator_enable(avdd_vreg);
+ if (rc) {
+ pr_err("enable avdd failed, rc=%d\n", rc);
+ return -ENODEV;
+ }
+
+ if (gpio_request(rst_gpio, "disp_rst_n")) {
+ pr_err("%s request reset gpio failed\n", __func__);
+ return -EINVAL;
+ }
+ if (gpio_request(cs_gpio, "disp_cs_n")) {
+ gpio_free(rst_gpio);
+ pr_err("%s request cs gpio failed\n", __func__);
+ return -EINVAL;
+ }
+
+ if (gpio_request(ad8_gpio, "disp_ad8_n")) {
+ gpio_free(cs_gpio);
+ gpio_free(rst_gpio);
+ pr_err("%s request ad8 gpio failed\n", __func__);
+ return -EINVAL;
+ }
+ if (gpio_request(te_gpio, "disp_te_n")) {
+ gpio_free(ad8_gpio);
+ gpio_free(cs_gpio);
+ gpio_free(rst_gpio);
+ pr_err("%s request te gpio failed\n", __func__);
+ return -EINVAL;
+ }
+ /* wait for 20 ms after enable gpio as suggested by hw */
+ msleep(20);
+ return 0;
+}
+
+static void ili9341_panel_power_off(void)
+{
+ gpio_free(ad8_gpio);
+ gpio_free(cs_gpio);
+ gpio_free(rst_gpio);
+ gpio_free(te_gpio);
+ regulator_disable(vdd_vreg);
+ regulator_disable(avdd_vreg);
+}
+
+int ili9341_on(void)
+{
+ u32 param[20];
+ int ret;
+ ret = ili9341_panel_power_on();
+ if (ret)
+ return ret;
+ qpic_panel_set_cmd_only(OP_SOFT_RESET);
+ /* wait for 120 ms after reset as panel spec suggests */
+ msleep(120);
+ qpic_panel_set_cmd_only(OP_SET_DISPLAY_OFF);
+ /* wait for 20 ms after disply off */
+ msleep(20);
+
+ /* set memory access control */
+ param[0] = ((0x48)<<0) | ((0x00)<<8) | ((0x00)<<16) | ((0x00U)<<24U);
+ qpic_send_panel_cmd(OP_ILI9341_MEMORY_ACCESS_CONTROL, param, 0);
+ /* wait for 20 ms after command sent as panel spec suggests */
+ msleep(20);
+
+ /* set COLMOD: Pixel Format Set */
+ param[0] = ((0x66)<<0) | ((0x00)<<8) | ((0x00)<<16) | ((0x00U)<<24U);
+ qpic_send_panel_cmd(OP_ILI9341_COLMOD_PIXEL_FORMAT_SET, param, 0);
+ /* wait for 20 ms after command sent as panel spec suggests */
+ msleep(20);
+
+ /* set interface */
+ param[0] = ((0x01)<<0) | ((0x00)<<8) | ((0x00)<<16) | ((0x00U)<<24U);
+ qpic_send_panel_cmd(OP_ILI9341_INTERFACE_CONTROL, ¶m[0], 0);
+ /* wait for 20 ms after command sent */
+ msleep(20);
+
+ /* exit sleep mode */
+ qpic_panel_set_cmd_only(OP_EXIT_SLEEP_MODE);
+ /* wait for 20 ms after command sent as panel spec suggests */
+ msleep(20);
+
+ /* normal mode */
+ qpic_panel_set_cmd_only(OP_ENTER_NORMAL_MODE);
+ /* wait for 20 ms after command sent as panel spec suggests */
+ msleep(20);
+
+ /* display on */
+ qpic_panel_set_cmd_only(OP_SET_DISPLAY_ON);
+ /* wait for 20 ms after command sent as panel spec suggests */
+ msleep(20);
+
+ /* tearing effect */
+ param[0] = ((0x00)<<0) | ((0x00)<<8) | ((0x00)<<16) | ((0x00U)<<24U);
+ qpic_send_panel_cmd(OP_ILI9341_TEARING_EFFECT_LINE_ON, param, 0);
+ /* wait for 20 ms after command sent as panel spec suggests */
+ msleep(20);
+
+ return 0;
+}
+
+void ili9341_off(void)
+{
+ ili9341_panel_power_off();
+}
diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c
index b96e093..7d0d862 100644
--- a/drivers/video/msm/msm_fb.c
+++ b/drivers/video/msm/msm_fb.c
@@ -41,6 +41,9 @@
#include <linux/android_pmem.h>
#include <linux/leds.h>
#include <linux/pm_runtime.h>
+#include <linux/sync.h>
+#include <linux/sw_sync.h>
+#include <linux/file.h>
#define MSM_FB_C
#include "msm_fb.h"
@@ -115,12 +118,17 @@
static int mdp_bl_scale_config(struct msm_fb_data_type *mfd,
struct mdp_bl_scale_data *data);
static void msm_fb_scale_bl(__u32 *bl_lvl);
+static void msm_fb_commit_wq_handler(struct work_struct *work);
+static int msm_fb_pan_idle(struct msm_fb_data_type *mfd);
#ifdef MSM_FB_ENABLE_DBGFS
#define MSM_FB_MAX_DBGFS 1024
#define MAX_BACKLIGHT_BRIGHTNESS 255
+/* 200 ms for time out */
+#define WAIT_FENCE_TIMEOUT 200
+
int msm_fb_debugfs_file_index;
struct dentry *msm_fb_debugfs_root;
struct dentry *msm_fb_debugfs_file[MSM_FB_MAX_DBGFS];
@@ -419,6 +427,16 @@
pdev_list[pdev_list_cnt++] = pdev;
msm_fb_create_sysfs(pdev);
+ if (mfd->timeline == NULL) {
+ mfd->timeline = sw_sync_timeline_create("mdp-timeline");
+ if (mfd->timeline == NULL) {
+ pr_err("%s: cannot create time line", __func__);
+ return -ENOMEM;
+ } else {
+ mfd->timeline_value = 0;
+ }
+ }
+
return 0;
}
@@ -863,6 +881,17 @@
if (ret)
mfd->panel_power_on = curr_pwr_state;
+ if (mfd->timeline) {
+ /* Adding 1 is enough when pan_display is still
+ * a blocking call and with mutex protection.
+ * But if it is an async call, we will still
+ * need to add 2. Adding 2 can be safer in
+ * order to signal all existing fences, and it
+ * is harmless. */
+ sw_sync_timeline_inc(mfd->timeline, 2);
+ mfd->timeline_value += 2;
+ }
+
mfd->op_enable = TRUE;
}
break;
@@ -905,7 +934,7 @@
const struct fb_fillrect *rect)
{
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
-
+ msm_fb_pan_idle(mfd);
cfb_fillrect(info, rect);
if (!mfd->hw_refresh && (info->var.yoffset == 0) &&
!mfd->sw_currently_refreshing) {
@@ -926,6 +955,7 @@
{
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+ msm_fb_pan_idle(mfd);
cfb_copyarea(info, area);
if (!mfd->hw_refresh && (info->var.yoffset == 0) &&
!mfd->sw_currently_refreshing) {
@@ -945,6 +975,7 @@
{
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+ msm_fb_pan_idle(mfd);
cfb_imageblit(info, image);
if (!mfd->hw_refresh && (info->var.yoffset == 0) &&
!mfd->sw_currently_refreshing) {
@@ -963,6 +994,7 @@
static int msm_fb_blank(int blank_mode, struct fb_info *info)
{
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+ msm_fb_pan_idle(mfd);
return msm_fb_blank_sub(blank_mode, info, mfd->op_enable);
}
@@ -989,6 +1021,7 @@
u32 len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len);
unsigned long off = vma->vm_pgoff << PAGE_SHIFT;
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+ msm_fb_pan_idle(mfd);
if (off >= len) {
/* memory mapped io */
off -= len;
@@ -1343,7 +1376,15 @@
mfd->msmfb_no_update_notify_timer.data = (unsigned long)mfd;
init_completion(&mfd->msmfb_update_notify);
init_completion(&mfd->msmfb_no_update_notify);
-
+ init_completion(&mfd->commit_comp);
+ mutex_init(&mfd->sync_mutex);
+ INIT_WORK(&mfd->commit_work, msm_fb_commit_wq_handler);
+ mfd->msm_fb_backup = kzalloc(sizeof(struct msm_fb_backup_type),
+ GFP_KERNEL);
+ if (mfd->msm_fb_backup == 0) {
+ pr_err("error: not enough memory!\n");
+ return -ENOMEM;
+ }
fbram_offset = PAGE_ALIGN((int)fbram)-(int)fbram;
fbram += fbram_offset;
fbram_phys += fbram_offset;
@@ -1653,7 +1694,34 @@
return ret;
}
-DEFINE_SEMAPHORE(msm_fb_pan_sem);
+int msm_fb_wait_for_fence(struct msm_fb_data_type *mfd)
+{
+ int i, ret = 0;
+ /* buf sync */
+ for (i = 0; i < mfd->acq_fen_cnt; i++) {
+ ret = sync_fence_wait(mfd->acq_fen[i], WAIT_FENCE_TIMEOUT);
+ sync_fence_put(mfd->acq_fen[i]);
+ if (ret < 0) {
+ pr_err("%s: sync_fence_wait failed! ret = %x\n",
+ __func__, ret);
+ break;
+ }
+ }
+ mfd->acq_fen_cnt = 0;
+ return ret;
+}
+int msm_fb_signal_timeline(struct msm_fb_data_type *mfd)
+{
+ mutex_lock(&mfd->sync_mutex);
+ if (mfd->timeline) {
+ sw_sync_timeline_inc(mfd->timeline, 1);
+ mfd->timeline_value++;
+ }
+ mfd->last_rel_fence = mfd->cur_rel_fence;
+ mfd->cur_rel_fence = 0;
+ mutex_unlock(&mfd->sync_mutex);
+ return 0;
+}
static void bl_workqueue_handler(struct work_struct *work)
{
@@ -1671,9 +1739,84 @@
}
}
+DEFINE_SEMAPHORE(msm_fb_pan_sem);
+static int msm_fb_pan_idle(struct msm_fb_data_type *mfd)
+{
+ int ret = 0;
+
+ mutex_lock(&mfd->sync_mutex);
+ if (mfd->is_committing) {
+ mutex_unlock(&mfd->sync_mutex);
+ ret = wait_for_completion_interruptible_timeout(
+ &mfd->commit_comp,
+ msecs_to_jiffies(WAIT_FENCE_TIMEOUT));
+ if (ret <= 0)
+ ret = -ERESTARTSYS;
+ else if (!ret)
+ pr_err("%s wait for commit_comp timeout %d %d",
+ __func__, ret, mfd->is_committing);
+ } else {
+ mutex_unlock(&mfd->sync_mutex);
+ }
+ return ret;
+}
+static int msm_fb_pan_display_ex(struct fb_var_screeninfo *var,
+ struct fb_info *info, u32 wait_for_finish)
+{
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+ struct msm_fb_backup_type *fb_backup;
+ int ret = 0;
+ /*
+ * If framebuffer is 2, io pen display is not allowed.
+ */
+ if (bf_supported && info->node == 2) {
+ pr_err("%s: no pan display for fb%d!",
+ __func__, info->node);
+ return -EPERM;
+ }
+
+ if (info->node != 0 || mfd->cont_splash_done) /* primary */
+ if ((!mfd->op_enable) || (!mfd->panel_power_on))
+ return -EPERM;
+
+ if (var->xoffset > (info->var.xres_virtual - info->var.xres))
+ return -EINVAL;
+
+ if (var->yoffset > (info->var.yres_virtual - info->var.yres))
+ return -EINVAL;
+ msm_fb_pan_idle(mfd);
+
+ mutex_lock(&mfd->sync_mutex);
+
+ if (info->fix.xpanstep)
+ info->var.xoffset =
+ (var->xoffset / info->fix.xpanstep) * info->fix.xpanstep;
+
+ if (info->fix.ypanstep)
+ info->var.yoffset =
+ (var->yoffset / info->fix.ypanstep) * info->fix.ypanstep;
+
+ fb_backup = (struct msm_fb_backup_type *)mfd->msm_fb_backup;
+ memcpy(&fb_backup->info, info, sizeof(struct fb_info));
+ memcpy(&fb_backup->var, var, sizeof(struct fb_var_screeninfo));
+ mfd->is_committing = 1;
+ INIT_COMPLETION(mfd->commit_comp);
+ schedule_work(&mfd->commit_work);
+ mutex_unlock(&mfd->sync_mutex);
+ if (wait_for_finish)
+ msm_fb_pan_idle(mfd);
+ return ret;
+}
+
static int msm_fb_pan_display(struct fb_var_screeninfo *var,
struct fb_info *info)
{
+ return msm_fb_pan_display_ex(var, info, TRUE);
+}
+
+static int msm_fb_pan_display_sub(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
struct mdp_dirty_region dirty;
struct mdp_dirty_region *dirtyPtr = NULL;
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
@@ -1748,18 +1891,24 @@
mutex_unlock(&msm_fb_notify_update_sem);
down(&msm_fb_pan_sem);
-
+ msm_fb_wait_for_fence(mfd);
if (info->node == 0 && !(mfd->cont_splash_done)) { /* primary */
mdp_set_dma_pan_info(info, NULL, TRUE);
if (msm_fb_blank_sub(FB_BLANK_UNBLANK, info, mfd->op_enable)) {
pr_err("%s: can't turn on display!\n", __func__);
+ if (mfd->timeline) {
+ sw_sync_timeline_inc(mfd->timeline, 2);
+ mfd->timeline_value += 2;
+ }
return -EINVAL;
}
}
mdp_set_dma_pan_info(info, dirtyPtr,
(var->activate & FB_ACTIVATE_VBL));
+ /* async call */
mdp_dma_pan_update(info);
+ msm_fb_signal_timeline(mfd);
up(&msm_fb_pan_sem);
if (unset_bl_level && !bl_updated)
@@ -1773,8 +1922,30 @@
return 0;
}
+static void msm_fb_commit_wq_handler(struct work_struct *work)
+{
+ struct msm_fb_data_type *mfd;
+ struct fb_var_screeninfo *var;
+ struct fb_info *info;
+ struct msm_fb_backup_type *fb_backup;
+
+ mfd = container_of(work, struct msm_fb_data_type, commit_work);
+ fb_backup = (struct msm_fb_backup_type *)mfd->msm_fb_backup;
+ var = &fb_backup->var;
+ info = &fb_backup->info;
+ msm_fb_pan_display_sub(var, info);
+ mutex_lock(&mfd->sync_mutex);
+ mfd->is_committing = 0;
+ complete_all(&mfd->commit_comp);
+ mutex_unlock(&mfd->sync_mutex);
+
+}
+
static int msm_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
{
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+
+ msm_fb_pan_idle(mfd);
if (var->rotate != FB_ROTATE_UR)
return -EINVAL;
if (var->grayscale != info->var.grayscale)
@@ -1899,7 +2070,7 @@
struct fb_var_screeninfo *var = &info->var;
int old_imgType;
int blank = 0;
-
+ msm_fb_pan_idle(mfd);
old_imgType = mfd->fb_imgType;
switch (var->bits_per_pixel) {
case 16:
@@ -3331,6 +3502,172 @@
return ret;
}
+static int msmfb_handle_buf_sync_ioctl(struct msm_fb_data_type *mfd,
+ struct mdp_buf_sync *buf_sync)
+{
+ int i, fence_cnt = 0, ret = 0;
+ int acq_fen_fd[MDP_MAX_FENCE_FD];
+ struct sync_fence *fence;
+
+ if ((buf_sync->acq_fen_fd_cnt > MDP_MAX_FENCE_FD) ||
+ (mfd->timeline == NULL))
+ return -EINVAL;
+
+ if (buf_sync->acq_fen_fd_cnt)
+ ret = copy_from_user(acq_fen_fd, buf_sync->acq_fen_fd,
+ buf_sync->acq_fen_fd_cnt * sizeof(int));
+ if (ret) {
+ pr_err("%s:copy_from_user failed", __func__);
+ return ret;
+ }
+ mutex_lock(&mfd->sync_mutex);
+ for (i = 0; i < buf_sync->acq_fen_fd_cnt; i++) {
+ fence = sync_fence_fdget(acq_fen_fd[i]);
+ if (fence == NULL) {
+ pr_info("%s: null fence! i=%d fd=%d\n", __func__, i,
+ acq_fen_fd[i]);
+ ret = -EINVAL;
+ break;
+ }
+ mfd->acq_fen[i] = fence;
+ }
+ fence_cnt = i;
+ if (ret)
+ goto buf_sync_err_1;
+ mfd->acq_fen_cnt = fence_cnt;
+ if (buf_sync->flags & MDP_BUF_SYNC_FLAG_WAIT)
+ msm_fb_wait_for_fence(mfd);
+
+ mfd->cur_rel_sync_pt = sw_sync_pt_create(mfd->timeline,
+ mfd->timeline_value + 2);
+ if (mfd->cur_rel_sync_pt == NULL) {
+ pr_err("%s: cannot create sync point", __func__);
+ ret = -ENOMEM;
+ goto buf_sync_err_1;
+ }
+ /* create fence */
+ mfd->cur_rel_fence = sync_fence_create("mdp-fence",
+ mfd->cur_rel_sync_pt);
+ if (mfd->cur_rel_fence == NULL) {
+ sync_pt_free(mfd->cur_rel_sync_pt);
+ mfd->cur_rel_sync_pt = NULL;
+ pr_err("%s: cannot create fence", __func__);
+ ret = -ENOMEM;
+ goto buf_sync_err_1;
+ }
+ /* create fd */
+ mfd->cur_rel_fen_fd = get_unused_fd_flags(0);
+ sync_fence_install(mfd->cur_rel_fence, mfd->cur_rel_fen_fd);
+ ret = copy_to_user(buf_sync->rel_fen_fd,
+ &mfd->cur_rel_fen_fd, sizeof(int));
+ if (ret) {
+ pr_err("%s:copy_to_user failed", __func__);
+ goto buf_sync_err_2;
+ }
+ mutex_unlock(&mfd->sync_mutex);
+ return ret;
+buf_sync_err_2:
+ sync_fence_put(mfd->cur_rel_fence);
+ put_unused_fd(mfd->cur_rel_fen_fd);
+ mfd->cur_rel_fence = NULL;
+ mfd->cur_rel_fen_fd = 0;
+buf_sync_err_1:
+ for (i = 0; i < fence_cnt; i++)
+ sync_fence_put(mfd->acq_fen[i]);
+ mfd->acq_fen_cnt = 0;
+ mutex_unlock(&mfd->sync_mutex);
+ return ret;
+}
+
+static int buf_fence_process(struct msm_fb_data_type *mfd,
+ struct mdp_buf_fence *buf_fence)
+{
+ int i, fence_cnt = 0, ret;
+ struct sync_fence *fence;
+
+ if ((buf_fence->acq_fen_fd_cnt == 0) ||
+ (buf_fence->acq_fen_fd_cnt > MDP_MAX_FENCE_FD) ||
+ (mfd->timeline == NULL))
+ return -EINVAL;
+
+ mutex_lock(&mfd->sync_mutex);
+ for (i = 0; i < buf_fence->acq_fen_fd_cnt; i++) {
+ fence = sync_fence_fdget(buf_fence->acq_fen_fd[i]);
+ if (fence == NULL) {
+ pr_info("%s: null fence! i=%d fd=%d\n", __func__, i,
+ buf_fence->acq_fen_fd[i]);
+ ret = -EINVAL;
+ break;
+ }
+ mfd->acq_fen[i] = fence;
+ }
+ fence_cnt = i;
+ if (ret)
+ goto buf_fence_err_1;
+ mfd->cur_rel_sync_pt = sw_sync_pt_create(mfd->timeline,
+ mfd->timeline_value + 2);
+ if (mfd->cur_rel_sync_pt == NULL) {
+ pr_err("%s: cannot create sync point", __func__);
+ ret = -ENOMEM;
+ goto buf_fence_err_1;
+ }
+ /* create fence */
+ mfd->cur_rel_fence = sync_fence_create("mdp-fence",
+ mfd->cur_rel_sync_pt);
+ if (mfd->cur_rel_fence == NULL) {
+ sync_pt_free(mfd->cur_rel_sync_pt);
+ mfd->cur_rel_sync_pt = NULL;
+ pr_err("%s: cannot create fence", __func__);
+ ret = -ENOMEM;
+ goto buf_fence_err_1;
+ }
+ /* create fd */
+ mfd->cur_rel_fen_fd = get_unused_fd_flags(0);
+ sync_fence_install(mfd->cur_rel_fence, mfd->cur_rel_fen_fd);
+ buf_fence->rel_fen_fd[0] = mfd->cur_rel_fen_fd;
+ /* Only one released fd for now, -1 indicates an end */
+ buf_fence->rel_fen_fd[1] = -1;
+ mfd->acq_fen_cnt = buf_fence->acq_fen_fd_cnt;
+ mutex_unlock(&mfd->sync_mutex);
+ return ret;
+buf_fence_err_1:
+ for (i = 0; i < fence_cnt; i++)
+ sync_fence_put(mfd->acq_fen[i]);
+ mfd->acq_fen_cnt = 0;
+ mutex_unlock(&mfd->sync_mutex);
+ return ret;
+}
+static int msmfb_display_commit(struct fb_info *info,
+ unsigned long *argp)
+{
+ int ret;
+ u32 copy_back = FALSE;
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+ struct mdp_display_commit disp_commit;
+ struct mdp_buf_fence *buf_fence;
+ ret = copy_from_user(&disp_commit, argp,
+ sizeof(disp_commit));
+ if (ret) {
+ pr_err("%s:copy_from_user failed", __func__);
+ return ret;
+ }
+ buf_fence = &disp_commit.buf_fence;
+ if (buf_fence->acq_fen_fd_cnt > 0)
+ ret = buf_fence_process(mfd, buf_fence);
+ if ((!ret) && (buf_fence->rel_fen_fd[0] > 0))
+ copy_back = TRUE;
+
+ ret = msm_fb_pan_display_ex(&disp_commit.var,
+ info, disp_commit.wait_for_finish);
+
+ if (copy_back) {
+ ret = copy_to_user(argp,
+ &disp_commit, sizeof(disp_commit));
+ if (ret)
+ pr_err("%s:copy_to_user failed", __func__);
+ }
+ return ret;
+}
static int msm_fb_ioctl(struct fb_info *info, unsigned int cmd,
unsigned long arg)
{
@@ -3349,7 +3686,9 @@
struct mdp_page_protection fb_page_protection;
struct msmfb_mdp_pp mdp_pp;
struct msmfb_metadata mdp_metadata;
+ struct mdp_buf_sync buf_sync;
int ret = 0;
+ msm_fb_pan_idle(mfd);
switch (cmd) {
#ifdef CONFIG_FB_MSM_OVERLAY
@@ -3636,12 +3975,24 @@
if (ret == 1)
ret = copy_to_user(argp, &mdp_pp, sizeof(mdp_pp));
break;
+ case MSMFB_BUFFER_SYNC:
+ ret = copy_from_user(&buf_sync, argp, sizeof(buf_sync));
+ if (ret)
+ return ret;
+
+ ret = msmfb_handle_buf_sync_ioctl(mfd, &buf_sync);
+
+ if (!ret)
+ ret = copy_to_user(argp, &buf_sync, sizeof(buf_sync));
+ break;
case MSMFB_METADATA_SET:
ret = copy_from_user(&mdp_metadata, argp, sizeof(mdp_metadata));
if (ret)
return ret;
ret = msmfb_handle_metadata_ioctl(mfd, &mdp_metadata);
+ case MSMFB_DISPLAY_COMMIT:
+ ret = msmfb_display_commit(info, argp);
break;
case MSMFB_METADATA_GET:
diff --git a/drivers/video/msm/msm_fb.h b/drivers/video/msm/msm_fb.h
index 34cb1fc..7519ac7 100644
--- a/drivers/video/msm/msm_fb.h
+++ b/drivers/video/msm/msm_fb.h
@@ -197,6 +197,26 @@
void *cpu_pm_hdl;
u32 avtimer_phy;
int vsync_sysfs_created;
+ u32 acq_fen_cnt;
+ struct sync_fence *acq_fen[MDP_MAX_FENCE_FD];
+ int cur_rel_fen_fd;
+ struct sync_pt *cur_rel_sync_pt;
+ struct sync_fence *cur_rel_fence;
+ struct sync_fence *last_rel_fence;
+ struct sw_sync_timeline *timeline;
+ int timeline_value;
+ u32 last_acq_fen_cnt;
+ struct sync_fence *last_acq_fen[MDP_MAX_FENCE_FD];
+ struct mutex sync_mutex;
+ struct completion commit_comp;
+ u32 is_committing;
+ struct work_struct commit_work;
+ void *msm_fb_backup;
+};
+struct msm_fb_backup_type {
+ struct fb_info info;
+ struct fb_var_screeninfo var;
+ struct msm_fb_data_type mfd;
};
struct dentry *msm_fb_get_debugfs_root(void);
@@ -216,7 +236,8 @@
int msm_fb_writeback_terminate(struct fb_info *info);
int msm_fb_detect_client(const char *name);
int calc_fb_offset(struct msm_fb_data_type *mfd, struct fb_info *fbi, int bpp);
-
+int msm_fb_wait_for_fence(struct msm_fb_data_type *mfd);
+int msm_fb_signal_timeline(struct msm_fb_data_type *mfd);
#ifdef CONFIG_FB_BACKLIGHT
void msm_fb_config_backlight(struct msm_fb_data_type *mfd);
#endif
diff --git a/drivers/video/msm/vidc/common/dec/vdec.c b/drivers/video/msm/vidc/common/dec/vdec.c
index afc5130..1c69d8f 100644
--- a/drivers/video/msm/vidc/common/dec/vdec.c
+++ b/drivers/video/msm/vidc/common/dec/vdec.c
@@ -25,7 +25,7 @@
#include <linux/uaccess.h>
#include <linux/wait.h>
#include <linux/workqueue.h>
-#include <linux/android_pmem.h>
+
#include <linux/clk.h>
#include <linux/timer.h>
#include <mach/msm_subsystem_map.h>
@@ -48,8 +48,6 @@
static dev_t vid_dec_dev_num;
static struct class *vid_dec_class;
-static unsigned int vidc_mmu_subsystem[] = {
- MSM_SUBSYSTEM_VIDEO};
static s32 vid_dec_get_empty_client_index(void)
{
u32 i, found = false;
@@ -875,11 +873,8 @@
{
struct vcd_property_hdr vcd_property_hdr;
struct vcd_property_meta_buffer *vcd_meta_buffer = NULL;
- struct msm_mapped_buffer *mapped_buffer = NULL;
- struct msm_mapped_buffer *mapped_buffer_iommu = NULL;
u32 vcd_status = VCD_ERR_FAIL;
- u32 len = 0, flags = 0, len_iommu = 0, flags_iommu = 0, buf_size = 0;
- struct file *file, *file_iommu;
+ 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;
@@ -903,54 +898,8 @@
vcd_meta_buffer->pmem_fd_iommu = meta_buffers->pmem_fd_iommu;
if (!vcd_get_ion_status()) {
- if (get_pmem_file(vcd_meta_buffer->pmem_fd,
- (unsigned long *) (&(vcd_meta_buffer->
- physical_addr)),
- (unsigned long *) (&vcd_meta_buffer->
- kernel_virtual_addr),
- (unsigned long *) (&len), &file)) {
- ERR("%s(): get_pmem_file failed\n", __func__);
- return false;
- }
- put_pmem_file(file);
- flags = MSM_SUBSYSTEM_MAP_IOVA;
- mapped_buffer = msm_subsystem_map_buffer(
- (unsigned long)vcd_meta_buffer->physical_addr,
- len, flags, vidc_mmu_subsystem,
- sizeof(vidc_mmu_subsystem)/
- sizeof(unsigned int));
- if (IS_ERR(mapped_buffer)) {
- pr_err("buffer map failed");
- return false;
- }
- vcd_meta_buffer->client_data = (void *) mapped_buffer;
- vcd_meta_buffer->dev_addr =
- (u8 *)mapped_buffer->iova[0];
-
- if (get_pmem_file(vcd_meta_buffer->pmem_fd_iommu,
- (unsigned long *) (&(vcd_meta_buffer->
- physical_addr_iommu)),
- (unsigned long *) (&vcd_meta_buffer->
- kernel_virt_addr_iommu),
- (unsigned long *) (&len_iommu), &file_iommu)) {
- ERR("%s(): get_pmem_file failed\n", __func__);
- return false;
- }
- put_pmem_file(file_iommu);
- flags_iommu = MSM_SUBSYSTEM_MAP_IOVA;
- mapped_buffer_iommu = msm_subsystem_map_buffer(
- (unsigned long)vcd_meta_buffer->physical_addr_iommu,
- len_iommu, flags_iommu, vidc_mmu_subsystem,
- sizeof(vidc_mmu_subsystem)/
- sizeof(unsigned int));
- if (IS_ERR(mapped_buffer_iommu)) {
- pr_err("buffer map failed");
- return false;
- }
- vcd_meta_buffer->client_data_iommu =
- (void *) mapped_buffer_iommu;
- vcd_meta_buffer->dev_addr_iommu =
- (u8 *)mapped_buffer_iommu->iova[0];
+ pr_err("PMEM Not available\n");
+ return false;
} else {
client_ctx->meta_buffer_ion_handle = ion_import_dma_buf(
client_ctx->user_ion_client,
@@ -1132,10 +1081,8 @@
{
struct vcd_property_hdr vcd_property_hdr;
struct vcd_property_h264_mv_buffer *vcd_h264_mv_buffer = NULL;
- struct msm_mapped_buffer *mapped_buffer = NULL;
u32 vcd_status = VCD_ERR_FAIL;
- u32 len = 0, flags = 0;
- struct file *file;
+ u32 len = 0;
int rc = 0;
unsigned long ionflag = 0;
unsigned long buffer_size = 0;
@@ -1156,28 +1103,8 @@
vcd_h264_mv_buffer->offset = mv_data->offset;
if (!vcd_get_ion_status()) {
- if (get_pmem_file(vcd_h264_mv_buffer->pmem_fd,
- (unsigned long *) (&(vcd_h264_mv_buffer->
- physical_addr)),
- (unsigned long *) (&vcd_h264_mv_buffer->
- kernel_virtual_addr),
- (unsigned long *) (&len), &file)) {
- ERR("%s(): get_pmem_file failed\n", __func__);
- return false;
- }
- put_pmem_file(file);
- flags = MSM_SUBSYSTEM_MAP_IOVA;
- mapped_buffer = msm_subsystem_map_buffer(
- (unsigned long)vcd_h264_mv_buffer->physical_addr, len,
- flags, vidc_mmu_subsystem,
- sizeof(vidc_mmu_subsystem)/
- sizeof(unsigned int));
- if (IS_ERR(mapped_buffer)) {
- pr_err("buffer map failed");
- return false;
- }
- vcd_h264_mv_buffer->client_data = (void *) mapped_buffer;
- vcd_h264_mv_buffer->dev_addr = (u8 *)mapped_buffer->iova[0];
+ pr_err("PMEM not available\n");
+ return false;
} else {
client_ctx->h264_mv_ion_handle = ion_import_dma_buf(
client_ctx->user_ion_client,
@@ -1818,7 +1745,6 @@
u32 vcd_status;
unsigned long kernel_vaddr, phy_addr, len;
unsigned long ker_vaddr;
- struct file *pmem_file;
u32 result = true;
void __user *arg = (void __user *)u_arg;
int rc = 0;
@@ -2133,12 +2059,8 @@
}
if (!vcd_get_ion_status()) {
- if (get_pmem_file(seq_header.pmem_fd,
- &phy_addr, &kernel_vaddr, &len, &pmem_file)) {
- ERR("%s(): get_pmem_file failed\n", __func__);
- return false;
- }
- put_pmem_file(pmem_file);
+ pr_err("PMEM Not available\n");
+ return -EINVAL;
} else {
client_ctx->seq_hdr_ion_handle = ion_import_dma_buf(
client_ctx->user_ion_client,
diff --git a/drivers/video/msm/vidc/common/enc/venc.c b/drivers/video/msm/vidc/common/enc/venc.c
index aa17f84..823626a 100644
--- a/drivers/video/msm/vidc/common/enc/venc.c
+++ b/drivers/video/msm/vidc/common/enc/venc.c
@@ -25,7 +25,7 @@
#include <linux/uaccess.h>
#include <linux/wait.h>
#include <linux/workqueue.h>
-#include <linux/android_pmem.h>
+
#include <linux/clk.h>
#include <media/msm/vidc_type.h>
#include <media/msm/vcd_api.h>
diff --git a/drivers/video/msm/vidc/common/enc/venc_internal.c b/drivers/video/msm/vidc/common/enc/venc_internal.c
index 14d8bfc..3dae4be1 100644
--- a/drivers/video/msm/vidc/common/enc/venc_internal.c
+++ b/drivers/video/msm/vidc/common/enc/venc_internal.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013, 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
@@ -25,7 +25,7 @@
#include <linux/uaccess.h>
#include <linux/wait.h>
#include <linux/workqueue.h>
-#include <linux/android_pmem.h>
+
#include <linux/clk.h>
#include <mach/msm_subsystem_map.h>
#include <media/msm/vidc_type.h>
@@ -41,9 +41,6 @@
#endif
#define ERR(x...) printk(KERN_ERR x)
-static unsigned int vidc_mmu_subsystem[] = {
- MSM_SUBSYSTEM_VIDEO};
-
u32 vid_enc_set_get_base_cfg(struct video_client_ctx *client_ctx,
struct venc_basecfg *base_config, u32 set_flag)
@@ -1801,11 +1798,9 @@
struct venc_recon_addr *venc_recon)
{
u32 vcd_status = VCD_ERR_FAIL;
- u32 len, i, flags = 0;
- struct file *file;
+ u32 len, i;
struct vcd_property_hdr vcd_property_hdr;
struct vcd_property_enc_recon_buffer *control = NULL;
- struct msm_mapped_buffer *mapped_buffer = NULL;
int rc = -1;
unsigned long ionflag = 0;
unsigned long iova = 0;
@@ -1837,25 +1832,8 @@
control->user_virtual_addr = venc_recon->pbuffer;
if (!vcd_get_ion_status()) {
- if (get_pmem_file(control->pmem_fd, (unsigned long *)
- (&(control->physical_addr)), (unsigned long *)
- (&control->kernel_virtual_addr),
- (unsigned long *) (&len), &file)) {
- ERR("%s(): get_pmem_file failed\n", __func__);
- return false;
- }
- put_pmem_file(file);
- flags = MSM_SUBSYSTEM_MAP_IOVA;
- mapped_buffer = msm_subsystem_map_buffer(
- (unsigned long)control->physical_addr, len,
- flags, vidc_mmu_subsystem,
- sizeof(vidc_mmu_subsystem)/sizeof(unsigned int));
- if (IS_ERR(mapped_buffer)) {
- pr_err("buffer map failed");
- return false;
- }
- control->client_data = (void *) mapped_buffer;
- control->dev_addr = (u8 *)mapped_buffer->iova[0];
+ pr_err("PMEM not available\n");
+ return false;
} else {
client_ctx->recon_buffer_ion_handle[i] = ion_import_dma_buf(
client_ctx->user_ion_client, control->pmem_fd);
diff --git a/drivers/video/msm/vidc/common/init/vidc_init.c b/drivers/video/msm/vidc/common/init/vidc_init.c
index 9007145..72a1d5f 100644
--- a/drivers/video/msm/vidc/common/init/vidc_init.c
+++ b/drivers/video/msm/vidc/common/init/vidc_init.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013, 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
@@ -24,7 +24,7 @@
#include <linux/uaccess.h>
#include <linux/wait.h>
#include <linux/workqueue.h>
-#include <linux/android_pmem.h>
+
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/debugfs.h>
@@ -49,7 +49,6 @@
static struct vidc_dev *vidc_device_p;
static dev_t vidc_dev_num;
static struct class *vidc_class;
-static unsigned int vidc_mmu_subsystem[] = {MSM_SUBSYSTEM_VIDEO};
static const struct file_operations vidc_fops = {
.owner = THIS_MODULE,
@@ -565,9 +564,8 @@
unsigned long len, phys_addr;
struct file *file = NULL;
u32 *num_of_buffers = NULL;
- u32 i, flags;
+ u32 i;
struct buf_addr_table *buf_addr_table;
- struct msm_mapped_buffer *mapped_buffer = NULL;
struct ion_handle *buff_ion_handle = NULL;
unsigned long ionflag = 0;
unsigned long iova = 0;
@@ -609,26 +607,8 @@
goto bail_out_add;
} else {
if (!vcd_get_ion_status()) {
- if (get_pmem_file(pmem_fd, &phys_addr,
- kernel_vaddr, &len, &file)) {
- ERR("%s(): get_pmem_file failed\n", __func__);
- goto bail_out_add;
- }
- put_pmem_file(file);
- flags = (buffer == BUFFER_TYPE_INPUT)
- ? MSM_SUBSYSTEM_MAP_IOVA :
- MSM_SUBSYSTEM_MAP_IOVA|MSM_SUBSYSTEM_ALIGN_IOVA_8K;
- mapped_buffer = msm_subsystem_map_buffer(phys_addr,
- length, flags, vidc_mmu_subsystem,
- sizeof(vidc_mmu_subsystem)/sizeof(unsigned int));
- if (IS_ERR(mapped_buffer)) {
- pr_err("buffer map failed");
- goto bail_out_add;
- }
- buf_addr_table[*num_of_buffers].client_data = (void *)
- mapped_buffer;
- buf_addr_table[*num_of_buffers].dev_addr =
- mapped_buffer->iova[0];
+ pr_err("PMEM not available\n");
+ return false;
} else {
buff_ion_handle = ion_import_dma_buf(
client_ctx->user_ion_client, pmem_fd);
diff --git a/fs/fat/Makefile b/fs/fat/Makefile
index 3f3e535..e061903 100644
--- a/fs/fat/Makefile
+++ b/fs/fat/Makefile
@@ -2,7 +2,6 @@
# Makefile for the Linux fat filesystem support.
#
-
obj-$(CONFIG_FAT_FS) += fat.o
obj-$(CONFIG_VFAT_FS) += vfat.o
obj-$(CONFIG_MSDOS_FS) += msdos.o
diff --git a/include/linux/cpuacct.h b/include/linux/cpuacct.h
deleted file mode 100644
index 8f68e73..0000000
--- a/include/linux/cpuacct.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/* include/linux/cpuacct.h
- *
- * Copyright (C) 2010 Google, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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 _CPUACCT_H_
-#define _CPUACCT_H_
-
-#include <linux/cgroup.h>
-
-#ifdef CONFIG_CGROUP_CPUACCT
-
-/*
- * Platform specific CPU frequency hooks for cpuacct. These functions are
- * called from the scheduler.
- */
-struct cpuacct_charge_calls {
- /*
- * Platforms can take advantage of this data and use
- * per-cpu allocations if necessary.
- */
- void (*init) (void **cpuacct_data);
- void (*charge) (void *cpuacct_data, u64 cputime, unsigned int cpu);
- void (*cpufreq_show) (void *cpuacct_data, struct cgroup_map_cb *cb);
- /* Returns power consumed in milliWatt seconds */
- u64 (*power_usage) (void *cpuacct_data);
-};
-
-int cpuacct_charge_register(struct cpuacct_charge_calls *fn);
-
-#endif /* CONFIG_CGROUP_CPUACCT */
-
-#endif // _CPUACCT_H_
diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
index 281c72a..235248c 100644
--- a/include/linux/devfreq.h
+++ b/include/linux/devfreq.h
@@ -25,12 +25,12 @@
* struct devfreq_dev_status - Data given from devfreq user device to
* governors. Represents the performance
* statistics.
- * @total_time The total time represented by this instance of
+ * @total_time: The total time represented by this instance of
* devfreq_dev_status
- * @busy_time The time that the device was working among the
+ * @busy_time: The time that the device was working among the
* total_time.
- * @current_frequency The operating frequency.
- * @private_data An entry not specified by the devfreq framework.
+ * @current_frequency: The operating frequency.
+ * @private_data: An entry not specified by the devfreq framework.
* A device and a specific governor may have their
* own protocol with private_data. However, because
* this is governor-specific, a governor using this
@@ -54,23 +54,27 @@
/**
* struct devfreq_dev_profile - Devfreq's user device profile
- * @initial_freq The operating frequency when devfreq_add_device() is
+ * @initial_freq: The operating frequency when devfreq_add_device() is
* called.
- * @polling_ms The polling interval in ms. 0 disables polling.
- * @target The device should set its operating frequency at
+ * @polling_ms: The polling interval in ms. 0 disables polling.
+ * @target: The device should set its operating frequency at
* freq or lowest-upper-than-freq value. If freq is
* higher than any operable frequency, set maximum.
* Before returning, target function should set
* freq at the current frequency.
* The "flags" parameter's possible values are
* explained above with "DEVFREQ_FLAG_*" macros.
- * @get_dev_status The device should provide the current performance
+ * @get_dev_status: The device should provide the current performance
* status to devfreq, which is used by governors.
- * @exit An optional callback that is called when devfreq
+ * @get_cur_freq: The device should provide the current frequency
+ * at which it is operating.
+ * @exit: An optional callback that is called when devfreq
* is removing the devfreq object due to error or
* from devfreq_remove_device() call. If the user
* has registered devfreq->nb at a notifier-head,
* this is the time to unregister it.
+ * @freq_table: Optional list of frequencies to support statistics.
+ * @max_state: The size of freq_table.
*/
struct devfreq_dev_profile {
unsigned long initial_freq;
@@ -79,63 +83,63 @@
int (*target)(struct device *dev, unsigned long *freq, u32 flags);
int (*get_dev_status)(struct device *dev,
struct devfreq_dev_status *stat);
+ int (*get_cur_freq)(struct device *dev, unsigned long *freq);
void (*exit)(struct device *dev);
+
+ unsigned int *freq_table;
+ unsigned int max_state;
};
/**
* struct devfreq_governor - Devfreq policy governor
- * @name Governor's name
- * @get_target_freq Returns desired operating frequency for the device.
+ * @node: list node - contains registered devfreq governors
+ * @name: Governor's name
+ * @get_target_freq: Returns desired operating frequency for the device.
* Basically, get_target_freq will run
* devfreq_dev_profile.get_dev_status() to get the
* status of the device (load = busy_time / total_time).
* If no_central_polling is set, this callback is called
* only with update_devfreq() notified by OPP.
- * @init Called when the devfreq is being attached to a device
- * @exit Called when the devfreq is being removed from a
- * device. Governor should stop any internal routines
- * before return because related data may be
- * freed after exit().
- * @no_central_polling Do not use devfreq's central polling mechanism.
- * When this is set, devfreq will not call
- * get_target_freq with devfreq_monitor(). However,
- * devfreq will call get_target_freq with
- * devfreq_update() notified by OPP framework.
+ * @event_handler: Callback for devfreq core framework to notify events
+ * to governors. Events include per device governor
+ * init and exit, opp changes out of devfreq, suspend
+ * and resume of per device devfreq during device idle.
*
* Note that the callbacks are called with devfreq->lock locked by devfreq.
*/
struct devfreq_governor {
+ struct list_head node;
+
const char name[DEVFREQ_NAME_LEN];
int (*get_target_freq)(struct devfreq *this, unsigned long *freq);
- int (*init)(struct devfreq *this);
- void (*exit)(struct devfreq *this);
- const bool no_central_polling;
+ int (*event_handler)(struct devfreq *devfreq,
+ unsigned int event, void *data);
};
/**
* struct devfreq - Device devfreq structure
- * @node list node - contains the devices with devfreq that have been
+ * @node: list node - contains the devices with devfreq that have been
* registered.
- * @lock a mutex to protect accessing devfreq.
- * @dev device registered by devfreq class. dev.parent is the device
+ * @lock: a mutex to protect accessing devfreq.
+ * @dev: device registered by devfreq class. dev.parent is the device
* using devfreq.
- * @profile device-specific devfreq profile
- * @governor method how to choose frequency based on the usage.
- * @nb notifier block used to notify devfreq object that it should
+ * @profile: device-specific devfreq profile
+ * @governor: method how to choose frequency based on the usage.
+ * @governor_name: devfreq governor name for use with this devfreq
+ * @nb: notifier block used to notify devfreq object that it should
* reevaluate operable frequencies. Devfreq users may use
* devfreq.nb to the corresponding register notifier call chain.
- * @polling_jiffies interval in jiffies.
- * @previous_freq previously configured frequency value.
- * @next_polling the number of remaining jiffies to poll with
- * "devfreq_monitor" executions to reevaluate
- * frequency/voltage of the device. Set by
- * profile's polling_ms interval.
- * @data Private data of the governor. The devfreq framework does not
+ * @work: delayed work for load monitoring.
+ * @previous_freq: previously configured frequency value.
+ * @data: Private data of the governor. The devfreq framework does not
* touch this.
- * @being_removed a flag to mark that this object is being removed in
- * order to prevent trying to remove the object multiple times.
- * @min_freq Limit minimum frequency requested by user (0: none)
- * @max_freq Limit maximum frequency requested by user (0: none)
+ * @min_freq: Limit minimum frequency requested by user (0: none)
+ * @max_freq: Limit maximum frequency requested by user (0: none)
+ * @stop_polling: devfreq polling status of a device.
+ * @total_trans: Number of devfreq transitions
+ * @trans_table: Statistics of devfreq transitions
+ * @time_in_state: Statistics of devfreq states
+ * @last_stat_updated: The last time stat updated
*
* This structure stores the devfreq information for a give device.
*
@@ -152,26 +156,33 @@
struct device dev;
struct devfreq_dev_profile *profile;
const struct devfreq_governor *governor;
+ char governor_name[DEVFREQ_NAME_LEN];
struct notifier_block nb;
+ struct delayed_work work;
- unsigned long polling_jiffies;
unsigned long previous_freq;
- unsigned int next_polling;
void *data; /* private data for governors */
- bool being_removed;
-
unsigned long min_freq;
unsigned long max_freq;
+ bool stop_polling;
+
+ /* information for device freqeuncy transition */
+ unsigned int total_trans;
+ unsigned int *trans_table;
+ unsigned long *time_in_state;
+ unsigned long last_stat_updated;
};
#if defined(CONFIG_PM_DEVFREQ)
extern struct devfreq *devfreq_add_device(struct device *dev,
struct devfreq_dev_profile *profile,
- const struct devfreq_governor *governor,
+ const char *governor_name,
void *data);
extern int devfreq_remove_device(struct devfreq *devfreq);
+extern int devfreq_suspend_device(struct devfreq *devfreq);
+extern int devfreq_resume_device(struct devfreq *devfreq);
/* Helper functions for devfreq user device driver with OPP. */
extern struct opp *devfreq_recommended_opp(struct device *dev,
@@ -181,23 +192,13 @@
extern int devfreq_unregister_opp_notifier(struct device *dev,
struct devfreq *devfreq);
-#ifdef CONFIG_DEVFREQ_GOV_POWERSAVE
-extern const struct devfreq_governor devfreq_powersave;
-#endif
-#ifdef CONFIG_DEVFREQ_GOV_PERFORMANCE
-extern const struct devfreq_governor devfreq_performance;
-#endif
-#ifdef CONFIG_DEVFREQ_GOV_USERSPACE
-extern const struct devfreq_governor devfreq_userspace;
-#endif
#ifdef CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND
-extern const struct devfreq_governor devfreq_simple_ondemand;
/**
* struct devfreq_simple_ondemand_data - void *data fed to struct devfreq
* and devfreq_add_device
- * @ upthreshold If the load is over this value, the frequency jumps.
+ * @upthreshold: If the load is over this value, the frequency jumps.
* Specify 0 to use the default. Valid value = 0 to 100.
- * @ downdifferential If the load is under upthreshold - downdifferential,
+ * @downdifferential: If the load is under upthreshold - downdifferential,
* the governor may consider slowing the frequency down.
* Specify 0 to use the default. Valid value = 0 to 100.
* downdifferential < upthreshold must hold.
@@ -214,7 +215,7 @@
#else /* !CONFIG_PM_DEVFREQ */
static struct devfreq *devfreq_add_device(struct device *dev,
struct devfreq_dev_profile *profile,
- struct devfreq_governor *governor,
+ const char *governor_name,
void *data)
{
return NULL;
@@ -225,6 +226,16 @@
return 0;
}
+static int devfreq_suspend_device(struct devfreq *devfreq)
+{
+ return 0;
+}
+
+static int devfreq_resume_device(struct devfreq *devfreq)
+{
+ return 0;
+}
+
static struct opp *devfreq_recommended_opp(struct device *dev,
unsigned long *freq, u32 flags)
{
@@ -243,11 +254,6 @@
return -EINVAL;
}
-#define devfreq_powersave NULL
-#define devfreq_performance NULL
-#define devfreq_userspace NULL
-#define devfreq_simple_ondemand NULL
-
#endif /* CONFIG_PM_DEVFREQ */
#endif /* __LINUX_DEVFREQ_H__ */
diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h
index 7a5ab0d..d208f1e 100644
--- a/include/linux/diagchar.h
+++ b/include/linux/diagchar.h
@@ -43,6 +43,10 @@
#define DIAG_IOCTL_DCI_REG 23
#define DIAG_IOCTL_DCI_STREAM_INIT 24
#define DIAG_IOCTL_DCI_HEALTH_STATS 25
+#define DIAG_IOCTL_DCI_LOG_STATUS 26
+#define DIAG_IOCTL_DCI_EVENT_STATUS 27
+#define DIAG_IOCTL_DCI_CLEAR_LOGS 28
+#define DIAG_IOCTL_DCI_CLEAR_EVENTS 29
#define DIAG_IOCTL_REMOTE_DEV 32
/* PC Tools IDs */
diff --git a/include/linux/dvb/dmx.h b/include/linux/dvb/dmx.h
index 2cea256..6e50578 100644
--- a/include/linux/dvb/dmx.h
+++ b/include/linux/dvb/dmx.h
@@ -189,28 +189,28 @@
/* Events associated with each demux filter */
enum dmx_event {
/* New PES packet is ready to be consumed */
- DMX_EVENT_NEW_PES,
+ DMX_EVENT_NEW_PES = 0x00000001,
/* New section is ready to be consumed */
- DMX_EVENT_NEW_SECTION,
+ DMX_EVENT_NEW_SECTION = 0x00000002,
/* New recording chunk is ready to be consumed */
- DMX_EVENT_NEW_REC_CHUNK,
+ DMX_EVENT_NEW_REC_CHUNK = 0x00000004,
/* New PCR value is ready */
- DMX_EVENT_NEW_PCR,
+ DMX_EVENT_NEW_PCR = 0x00000008,
/* Overflow */
- DMX_EVENT_BUFFER_OVERFLOW,
+ DMX_EVENT_BUFFER_OVERFLOW = 0x00000010,
/* Section was dropped due to CRC error */
- DMX_EVENT_SECTION_CRC_ERROR,
+ DMX_EVENT_SECTION_CRC_ERROR = 0x00000020,
/* End-of-stream, no more data from this filter */
- DMX_EVENT_EOS,
+ DMX_EVENT_EOS = 0x00000040,
/* New Elementary Stream data is ready */
- DMX_EVENT_NEW_ES_DATA
+ DMX_EVENT_NEW_ES_DATA = 0x00000080
};
/* Flags passed in filter events */
@@ -552,7 +552,6 @@
int handle;
};
-
struct dmx_decoder_buffers {
/*
* Specify if linear buffer support is requested. If set, buffers_num
@@ -587,6 +586,35 @@
__u32 key_ladder_id;
};
+struct dmx_events_mask {
+ /*
+ * Bitmask of events to be disabled (dmx_event).
+ * Disabled events will not be notified to the user.
+ * By default all events are enabled except for
+ * DMX_EVENT_NEW_ES_DATA.
+ * Overflow event can't be disabled.
+ */
+ __u32 disable_mask;
+
+ /*
+ * Bitmask of events that will not wake-up the user
+ * when user calls poll with POLLPRI flag.
+ * Events that are used as wake-up source should not be
+ * disabled in disable_mask or they would not be used
+ * as a wake-up source.
+ * By default all enabled events are set as wake-up events.
+ * Overflow event can't be disabled as a wake-up source.
+ */
+ __u32 no_wakeup_mask;
+
+ /*
+ * Number of ready wake-up events which will trigger
+ * a wake-up when user calls poll with POLLPRI flag.
+ * Default is set to 1.
+ */
+ __u32 wakeup_threshold;
+};
+
#define DMX_START _IO('o', 41)
#define DMX_STOP _IO('o', 42)
#define DMX_SET_FILTER _IOW('o', 43, struct dmx_sct_filter_params)
@@ -611,6 +639,8 @@
#define DMX_SET_DECODER_BUFFER _IOW('o', 63, struct dmx_decoder_buffers)
#define DMX_REUSE_DECODER_BUFFER _IO('o', 64)
#define DMX_SET_SECURE_MODE _IOW('o', 65, struct dmx_secure_mode)
+#define DMX_SET_EVENTS_MASK _IOW('o', 66, struct dmx_events_mask)
+#define DMX_GET_EVENTS_MASK _IOR('o', 67, struct dmx_events_mask)
#endif /*_DVBDMX_H_*/
diff --git a/include/linux/epm_adc.h b/include/linux/epm_adc.h
index 14cb148..4fa41b5 100644
--- a/include/linux/epm_adc.h
+++ b/include/linux/epm_adc.h
@@ -39,7 +39,8 @@
uint8_t dev_num;
uint8_t chan_num;
uint32_t timestamp_resp_value;
- uint32_t reading_value;
+ int16_t reading_raw;
+ int32_t reading_value;
};
struct epm_psoc_get_buffered_data {
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 03fc44b..093f0b8 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -17,8 +17,8 @@
* nr_file rlimit, so it's safe to set up a ridiculously high absolute
* upper limit on files-per-process.
*
- * Some programs (notably those using select()) may have to be
- * recompiled to take full advantage of the new limits..
+ * Some programs (notably those using select()) may have to be
+ * recompiled to take full advantage of the new limits..
*/
/* Fixed constants first: */
@@ -178,7 +178,7 @@
#define SEL_EX 4
/* public flags for file_system_type */
-#define FS_REQUIRES_DEV 1
+#define FS_REQUIRES_DEV 1
#define FS_BINARY_MOUNTDATA 2
#define FS_HAS_SUBTYPE 4
#define FS_REVAL_DOT 16384 /* Check the paths ".", ".." for staleness */
@@ -490,7 +490,7 @@
*/
#include <linux/quota.h>
-/**
+/**
* enum positive_aop_returns - aop return codes with specific semantics
*
* @AOP_WRITEPAGE_ACTIVATE: Informs the caller that page writeback has
@@ -500,7 +500,7 @@
* be a candidate for writeback again in the near
* future. Other callers must be careful to unlock
* the page if they get this return. Returned by
- * writepage();
+ * writepage();
*
* @AOP_TRUNCATED_PAGE: The AOP method that was handed a locked page has
* unlocked it and the page might have been truncated.
@@ -1078,10 +1078,10 @@
#define MAX_NON_LFS ((1UL<<31) - 1)
-/* Page cache limit. The filesystems should put that into their s_maxbytes
- limits, otherwise bad things can happen in VM. */
+/* Page cache limit. The filesystems should put that into their s_maxbytes
+ limits, otherwise bad things can happen in VM. */
#if BITS_PER_LONG==32
-#define MAX_LFS_FILESIZE (((u64)PAGE_CACHE_SIZE << (BITS_PER_LONG-1))-1)
+#define MAX_LFS_FILESIZE (((u64)PAGE_CACHE_SIZE << (BITS_PER_LONG-1))-1)
#elif BITS_PER_LONG==64
#define MAX_LFS_FILESIZE 0x7fffffffffffffffUL
#endif
@@ -2282,7 +2282,7 @@
extern int kernel_read(struct file *, loff_t, char *, unsigned long);
extern struct file * open_exec(const char *);
-
+
/* fs/dcache.c -- generic fs support functions */
extern int is_subdir(struct dentry *, struct dentry *);
extern int path_is_under(struct path *, struct path *);
diff --git a/include/linux/ion.h b/include/linux/ion.h
index f159fe2..fb1c5f6 100644
--- a/include/linux/ion.h
+++ b/include/linux/ion.h
@@ -74,7 +74,6 @@
be converted to phys_addr_t. For the time being many kernel interfaces
do not accept phys_addr_t's that would have to */
#define ion_phys_addr_t unsigned long
-#define ion_virt_addr_t unsigned long
/**
* struct ion_platform_heap - defines a heap in the given platform
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 37b1fdc..fb0c7af 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -710,7 +710,4 @@
#endif /* __KERNEL__ */
-/* To identify board information in panic logs, set this */
-extern char *mach_panic_string;
-
#endif
diff --git a/include/linux/memory_hotplug.h b/include/linux/memory_hotplug.h
index fc7d1a4..4473d69 100644
--- a/include/linux/memory_hotplug.h
+++ b/include/linux/memory_hotplug.h
@@ -243,10 +243,6 @@
extern struct page *sparse_decode_mem_map(unsigned long coded_mem_map,
unsigned long pnum);
-extern void reserve_hotplug_pages(unsigned long start_pfn,
- unsigned long nr_pages);
-extern void unreserve_hotplug_pages(unsigned long start_pfn,
- unsigned long nr_pages);
#endif /* __LINUX_MEMORY_HOTPLUG_H */
extern int physical_remove_memory(u64 start, u64 size);
extern int arch_physical_remove_memory(u64 start, u64 size);
diff --git a/include/linux/mfd/wcd9xxx/wcd9306_registers.h b/include/linux/mfd/wcd9xxx/wcd9306_registers.h
index 1254fac..564e5b3 100644
--- a/include/linux/mfd/wcd9xxx/wcd9306_registers.h
+++ b/include/linux/mfd/wcd9xxx/wcd9306_registers.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, 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
@@ -15,20 +15,20 @@
#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
-#define TAPAN_A_CHIP_CTL WCD9XXX_A_CHIP_CTL
-#define TAPAN_A_CHIP_CTL__POR WCD9XXX_A_CHIP_CTL__POR
-#define TAPAN_A_CHIP_STATUS WCD9XXX_A_CHIP_STATUS
-#define TAPAN_A_CHIP_STATUS__POR WCD9XXX_A_CHIP_STATUS__POR
-#define TAPAN_A_CHIP_ID_BYTE_0 WCD9XXX_A_CHIP_ID_BYTE_0
-#define TAPAN_A_CHIP_ID_BYTE_0__POR WCD9XXX_A_CHIP_ID_BYTE_0__POR
-#define TAPAN_A_CHIP_ID_BYTE_1 WCD9XXX_A_CHIP_ID_BYTE_1
-#define TAPAN_A_CHIP_ID_BYTE_1__POR WCD9XXX_A_CHIP_ID_BYTE_1__POR
-#define TAPAN_A_CHIP_ID_BYTE_2 WCD9XXX_A_CHIP_ID_BYTE_2
-#define TAPAN_A_CHIP_ID_BYTE_2__POR WCD9XXX_A_CHIP_ID_BYTE_2__POR
-#define TAPAN_A_CHIP_ID_BYTE_3 WCD9XXX_A_CHIP_ID_BYTE_3
-#define TAPAN_A_CHIP_ID_BYTE_3__POR WCD9XXX_A_CHIP_ID_BYTE_3__POR
-#define TAPAN_A_CHIP_VERSION WCD9XXX_A_CHIP_VERSION
-#define TAPAN_A_CHIP_VERSION__POR WCD9XXX_A_CHIP_VERSION__POR
+#define TAPAN_A_CHIP_CTL (0x000)
+#define TAPAN_A_CHIP_CTL__POR (0x00)
+#define TAPAN_A_CHIP_STATUS (0x001)
+#define TAPAN_A_CHIP_STATUS__POR (0x00)
+#define TAPAN_A_CHIP_ID_BYTE_0 (0x004)
+#define TAPAN_A_CHIP_ID_BYTE_0__POR (0x00)
+#define TAPAN_A_CHIP_ID_BYTE_1 (0x005)
+#define TAPAN_A_CHIP_ID_BYTE_1__POR (0x00)
+#define TAPAN_A_CHIP_ID_BYTE_2 (0x006)
+#define TAPAN_A_CHIP_ID_BYTE_2__POR (0x03)
+#define TAPAN_A_CHIP_ID_BYTE_3 (0x007)
+#define TAPAN_A_CHIP_ID_BYTE_3__POR (0x01)
+#define TAPAN_A_CHIP_VERSION (0x008)
+#define TAPAN_A_CHIP_VERSION__POR (0x20)
#define TAPAN_A_CHIP_DEBUG_CTL (0x009)
#define TAPAN_A_CHIP_DEBUG_CTL__POR (0x00)
#define TAPAN_A_SLAVE_ID_1 (0x00C)
@@ -566,21 +566,21 @@
#define TAPAN_A_CDC_TX4_VOL_CTL_CFG (0x23A)
#define TAPAN_A_CDC_TX4_VOL_CTL_CFG__POR (0x00)
#define TAPAN_A_CDC_TX1_MUX_CTL (0x223)
-#define TAPAN_A_CDC_TX1_MUX_CTL__POR (0x00)
+#define TAPAN_A_CDC_TX1_MUX_CTL__POR (0x08)
#define TAPAN_A_CDC_TX2_MUX_CTL (0x22B)
-#define TAPAN_A_CDC_TX2_MUX_CTL__POR (0x00)
+#define TAPAN_A_CDC_TX2_MUX_CTL__POR (0x08)
#define TAPAN_A_CDC_TX3_MUX_CTL (0x233)
-#define TAPAN_A_CDC_TX3_MUX_CTL__POR (0x00)
+#define TAPAN_A_CDC_TX3_MUX_CTL__POR (0x08)
#define TAPAN_A_CDC_TX4_MUX_CTL (0x23B)
-#define TAPAN_A_CDC_TX4_MUX_CTL__POR (0x00)
+#define TAPAN_A_CDC_TX4_MUX_CTL__POR (0x08)
#define TAPAN_A_CDC_TX1_CLK_FS_CTL (0x224)
-#define TAPAN_A_CDC_TX1_CLK_FS_CTL__POR (0x00)
+#define TAPAN_A_CDC_TX1_CLK_FS_CTL__POR (0x03)
#define TAPAN_A_CDC_TX2_CLK_FS_CTL (0x22C)
-#define TAPAN_A_CDC_TX2_CLK_FS_CTL__POR (0x00)
+#define TAPAN_A_CDC_TX2_CLK_FS_CTL__POR (0x03)
#define TAPAN_A_CDC_TX3_CLK_FS_CTL (0x234)
-#define TAPAN_A_CDC_TX3_CLK_FS_CTL__POR (0x00)
+#define TAPAN_A_CDC_TX3_CLK_FS_CTL__POR (0x03)
#define TAPAN_A_CDC_TX4_CLK_FS_CTL (0x23C)
-#define TAPAN_A_CDC_TX4_CLK_FS_CTL__POR (0x00)
+#define TAPAN_A_CDC_TX4_CLK_FS_CTL__POR (0x03)
#define TAPAN_A_CDC_TX1_DMIC_CTL (0x225)
#define TAPAN_A_CDC_TX1_DMIC_CTL__POR (0x00)
#define TAPAN_A_CDC_TX2_DMIC_CTL (0x22D)
@@ -608,9 +608,9 @@
#define TAPAN_A_CDC_SRC2_PDA_CFG (0x2A8)
#define TAPAN_A_CDC_SRC2_PDA_CFG__POR (0x00)
#define TAPAN_A_CDC_SRC1_FS_CTL (0x2A1)
-#define TAPAN_A_CDC_SRC1_FS_CTL__POR (0x00)
+#define TAPAN_A_CDC_SRC1_FS_CTL__POR (0x1B)
#define TAPAN_A_CDC_SRC2_FS_CTL (0x2A9)
-#define TAPAN_A_CDC_SRC2_FS_CTL__POR (0x00)
+#define TAPAN_A_CDC_SRC2_FS_CTL__POR (0x1B)
#define TAPAN_A_CDC_RX1_B1_CTL (0x2B0)
#define TAPAN_A_CDC_RX1_B1_CTL__POR (0x00)
#define TAPAN_A_CDC_RX2_B1_CTL (0x2B8)
@@ -644,21 +644,21 @@
#define TAPAN_A_CDC_RX4_B4_CTL (0x2CB)
#define TAPAN_A_CDC_RX4_B4_CTL__POR (0x00)
#define TAPAN_A_CDC_RX1_B5_CTL (0x2B4)
-#define TAPAN_A_CDC_RX1_B5_CTL__POR (0x00)
+#define TAPAN_A_CDC_RX1_B5_CTL__POR (0x78)
#define TAPAN_A_CDC_RX2_B5_CTL (0x2BC)
-#define TAPAN_A_CDC_RX2_B5_CTL__POR (0x00)
+#define TAPAN_A_CDC_RX2_B5_CTL__POR (0x78)
#define TAPAN_A_CDC_RX3_B5_CTL (0x2C4)
-#define TAPAN_A_CDC_RX3_B5_CTL__POR (0x00)
+#define TAPAN_A_CDC_RX3_B5_CTL__POR (0x78)
#define TAPAN_A_CDC_RX4_B5_CTL (0x2CC)
-#define TAPAN_A_CDC_RX4_B5_CTL__POR (0x00)
+#define TAPAN_A_CDC_RX4_B5_CTL__POR (0x78)
#define TAPAN_A_CDC_RX1_B6_CTL (0x2B5)
-#define TAPAN_A_CDC_RX1_B6_CTL__POR (0x00)
+#define TAPAN_A_CDC_RX1_B6_CTL__POR (0x80)
#define TAPAN_A_CDC_RX2_B6_CTL (0x2BD)
-#define TAPAN_A_CDC_RX2_B6_CTL__POR (0x00)
+#define TAPAN_A_CDC_RX2_B6_CTL__POR (0x80)
#define TAPAN_A_CDC_RX3_B6_CTL (0x2C5)
-#define TAPAN_A_CDC_RX3_B6_CTL__POR (0x00)
+#define TAPAN_A_CDC_RX3_B6_CTL__POR (0x80)
#define TAPAN_A_CDC_RX4_B6_CTL (0x2CD)
-#define TAPAN_A_CDC_RX4_B6_CTL__POR (0x00)
+#define TAPAN_A_CDC_RX4_B6_CTL__POR (0x80)
#define TAPAN_A_CDC_RX1_VOL_CTL_B1_CTL (0x2B6)
#define TAPAN_A_CDC_RX1_VOL_CTL_B1_CTL__POR (0x00)
#define TAPAN_A_CDC_RX2_VOL_CTL_B1_CTL (0x2BE)
@@ -784,9 +784,9 @@
#define TAPAN_A_CDC_IIR2_GAIN_B8_CTL (0x357)
#define TAPAN_A_CDC_IIR2_GAIN_B8_CTL__POR (0x00)
#define TAPAN_A_CDC_IIR1_CTL (0x348)
-#define TAPAN_A_CDC_IIR1_CTL__POR (0x00)
+#define TAPAN_A_CDC_IIR1_CTL__POR (0x40)
#define TAPAN_A_CDC_IIR2_CTL (0x358)
-#define TAPAN_A_CDC_IIR2_CTL__POR (0x00)
+#define TAPAN_A_CDC_IIR2_CTL__POR (0x40)
#define TAPAN_A_CDC_IIR1_GAIN_TIMER_CTL (0x349)
#define TAPAN_A_CDC_IIR1_GAIN_TIMER_CTL__POR (0x00)
#define TAPAN_A_CDC_IIR2_GAIN_TIMER_CTL (0x359)
@@ -802,35 +802,35 @@
#define TAPAN_A_CDC_TOP_GAIN_UPDATE (0x360)
#define TAPAN_A_CDC_TOP_GAIN_UPDATE__POR (0x00)
#define TAPAN_A_CDC_COMP0_B1_CTL (0x368)
-#define TAPAN_A_CDC_COMP0_B1_CTL__POR (0x00)
+#define TAPAN_A_CDC_COMP0_B1_CTL__POR (0x30)
#define TAPAN_A_CDC_COMP1_B1_CTL (0x370)
-#define TAPAN_A_CDC_COMP1_B1_CTL__POR (0x00)
+#define TAPAN_A_CDC_COMP1_B1_CTL__POR (0x30)
#define TAPAN_A_CDC_COMP2_B1_CTL (0x378)
-#define TAPAN_A_CDC_COMP2_B1_CTL__POR (0x00)
+#define TAPAN_A_CDC_COMP2_B1_CTL__POR (0x30)
#define TAPAN_A_CDC_COMP0_B2_CTL (0x369)
-#define TAPAN_A_CDC_COMP0_B2_CTL__POR (0x00)
+#define TAPAN_A_CDC_COMP0_B2_CTL__POR (0xB5)
#define TAPAN_A_CDC_COMP1_B2_CTL (0x371)
-#define TAPAN_A_CDC_COMP1_B2_CTL__POR (0x00)
+#define TAPAN_A_CDC_COMP1_B2_CTL__POR (0xB5)
#define TAPAN_A_CDC_COMP2_B2_CTL (0x379)
-#define TAPAN_A_CDC_COMP2_B2_CTL__POR (0x00)
+#define TAPAN_A_CDC_COMP2_B2_CTL__POR (0xB5)
#define TAPAN_A_CDC_COMP0_B3_CTL (0x36A)
-#define TAPAN_A_CDC_COMP0_B3_CTL__POR (0x00)
+#define TAPAN_A_CDC_COMP0_B3_CTL__POR (0x28)
#define TAPAN_A_CDC_COMP1_B3_CTL (0x372)
-#define TAPAN_A_CDC_COMP1_B3_CTL__POR (0x00)
+#define TAPAN_A_CDC_COMP1_B3_CTL__POR (0x28)
#define TAPAN_A_CDC_COMP2_B3_CTL (0x37A)
-#define TAPAN_A_CDC_COMP2_B3_CTL__POR (0x00)
+#define TAPAN_A_CDC_COMP2_B3_CTL__POR (0x28)
#define TAPAN_A_CDC_COMP0_B4_CTL (0x36B)
-#define TAPAN_A_CDC_COMP0_B4_CTL__POR (0x00)
+#define TAPAN_A_CDC_COMP0_B4_CTL__POR (0x37)
#define TAPAN_A_CDC_COMP1_B4_CTL (0x373)
-#define TAPAN_A_CDC_COMP1_B4_CTL__POR (0x00)
+#define TAPAN_A_CDC_COMP1_B4_CTL__POR (0x37)
#define TAPAN_A_CDC_COMP2_B4_CTL (0x37B)
-#define TAPAN_A_CDC_COMP2_B4_CTL__POR (0x00)
+#define TAPAN_A_CDC_COMP2_B4_CTL__POR (0x37)
#define TAPAN_A_CDC_COMP0_B5_CTL (0x36C)
-#define TAPAN_A_CDC_COMP0_B5_CTL__POR (0x00)
+#define TAPAN_A_CDC_COMP0_B5_CTL__POR (0x7F)
#define TAPAN_A_CDC_COMP1_B5_CTL (0x374)
-#define TAPAN_A_CDC_COMP1_B5_CTL__POR (0x00)
+#define TAPAN_A_CDC_COMP1_B5_CTL__POR (0x7F)
#define TAPAN_A_CDC_COMP2_B5_CTL (0x37C)
-#define TAPAN_A_CDC_COMP2_B5_CTL__POR (0x00)
+#define TAPAN_A_CDC_COMP2_B5_CTL__POR (0x7F)
#define TAPAN_A_CDC_COMP0_B6_CTL (0x36D)
#define TAPAN_A_CDC_COMP0_B6_CTL__POR (0x00)
#define TAPAN_A_CDC_COMP1_B6_CTL (0x375)
@@ -838,17 +838,17 @@
#define TAPAN_A_CDC_COMP2_B6_CTL (0x37D)
#define TAPAN_A_CDC_COMP2_B6_CTL__POR (0x00)
#define TAPAN_A_CDC_COMP0_SHUT_DOWN_STATUS (0x36E)
-#define TAPAN_A_CDC_COMP0_SHUT_DOWN_STATUS__POR (0x00)
+#define TAPAN_A_CDC_COMP0_SHUT_DOWN_STATUS__POR (0x03)
#define TAPAN_A_CDC_COMP1_SHUT_DOWN_STATUS (0x376)
-#define TAPAN_A_CDC_COMP1_SHUT_DOWN_STATUS__POR (0x00)
+#define TAPAN_A_CDC_COMP1_SHUT_DOWN_STATUS__POR (0x03)
#define TAPAN_A_CDC_COMP2_SHUT_DOWN_STATUS (0x37E)
-#define TAPAN_A_CDC_COMP2_SHUT_DOWN_STATUS__POR (0x00)
+#define TAPAN_A_CDC_COMP2_SHUT_DOWN_STATUS__POR (0x03)
#define TAPAN_A_CDC_COMP0_FS_CFG (0x36F)
-#define TAPAN_A_CDC_COMP0_FS_CFG__POR (0x00)
+#define TAPAN_A_CDC_COMP0_FS_CFG__POR (0x03)
#define TAPAN_A_CDC_COMP1_FS_CFG (0x377)
-#define TAPAN_A_CDC_COMP1_FS_CFG__POR (0x00)
+#define TAPAN_A_CDC_COMP1_FS_CFG__POR (0x03)
#define TAPAN_A_CDC_COMP2_FS_CFG (0x37F)
-#define TAPAN_A_CDC_COMP2_FS_CFG__POR (0x00)
+#define TAPAN_A_CDC_COMP2_FS_CFG__POR (0x03)
#define TAPAN_A_CDC_CONN_RX1_B1_CTL (0x380)
#define TAPAN_A_CDC_CONN_RX1_B1_CTL__POR (0x00)
#define TAPAN_A_CDC_CONN_RX1_B2_CTL (0x381)
@@ -992,12 +992,18 @@
#define TAPAN_A_CDC_MBHC_SPARE (0x3DF)
#define TAPAN_A_CDC_MBHC_SPARE__POR (0x00)
-
/* SLIMBUS Slave Registers */
-#define TAPAN_SLIM_PGD_PORT_INT_EN0 (0x30)
-#define TAPAN_SLIM_PGD_PORT_INT_STATUS0 (0x34)
-#define TAPAN_SLIM_PGD_PORT_INT_CLR0 (0x38)
-#define TAPAN_SLIM_PGD_PORT_INT_SOURCE0 (0x60)
+#define TAPAN_SLIM_PGD_PORT_INT_EN0 (0x30)
+#define TAPAN_SLIM_PGD_PORT_INT_STATUS_RX_0 (0x34)
+#define TAPAN_SLIM_PGD_PORT_INT_STATUS_RX_1 (0x35)
+#define TAPAN_SLIM_PGD_PORT_INT_STATUS_TX_0 (0x36)
+#define TAPAN_SLIM_PGD_PORT_INT_STATUS_TX_1 (0x37)
+#define TAPAN_SLIM_PGD_PORT_INT_CLR_RX_0 (0x38)
+#define TAPAN_SLIM_PGD_PORT_INT_CLR_RX_1 (0x39)
+#define TAPAN_SLIM_PGD_PORT_INT_CLR_TX_0 (0x3A)
+#define TAPAN_SLIM_PGD_PORT_INT_CLR_TX_1 (0x3B)
+#define TAPAN_SLIM_PGD_PORT_INT_RX_SOURCE0 (0x60)
+#define TAPAN_SLIM_PGD_PORT_INT_TX_SOURCE0 (0x70)
/* Macros for Packing Register Writes into a U32 */
#define TAPAN_PACKED_REG_SIZE sizeof(u32)
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index e4aab43..9a4e61d 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -385,6 +385,9 @@
struct mmc_wr_pack_stats wr_pack_stats; /* packed commands stats*/
struct mmc_bkops_info bkops_info;
+
+ struct device_attribute rpm_attrib;
+ unsigned int idle_timeout;
};
/*
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
index 4eacd55..995f8a2 100644
--- a/include/linux/mmc/core.h
+++ b/include/linux/mmc/core.h
@@ -203,6 +203,8 @@
extern int mmc_detect_card_removed(struct mmc_host *host);
extern void mmc_blk_init_bkops_statistics(struct mmc_card *card);
+extern void mmc_rpm_hold(struct mmc_host *host, struct device *dev);
+extern void mmc_rpm_release(struct mmc_host *host, struct device *dev);
/**
* mmc_claim_host - exclusively claim a host
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 3e8917f..05271ba 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -281,6 +281,8 @@
#define MMC_CAP2_INIT_BKOPS (1 << 16) /* Need to set BKOPS_EN */
#define MMC_CAP2_CLK_SCALE (1 << 17) /* Allow dynamic clk scaling */
#define MMC_CAP2_STOP_REQUEST (1 << 18) /* Allow stop ongoing request */
+/* Use runtime PM framework provided by MMC core */
+#define MMC_CAP2_CORE_RUNTIME_PM (1 << 19)
mmc_pm_flag_t pm_caps; /* supported pm features */
int clk_requests; /* internal reference counter */
@@ -537,4 +539,10 @@
return host->ios.clock;
}
#endif
+
+static inline int mmc_use_core_runtime_pm(struct mmc_host *host)
+{
+ return host->caps2 & MMC_CAP2_CORE_RUNTIME_PM;
+}
+
#endif /* LINUX_MMC_HOST_H */
diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
index bd24575..f26b903 100644
--- a/include/linux/mmc/sdhci.h
+++ b/include/linux/mmc/sdhci.h
@@ -18,6 +18,11 @@
#include <linux/mmc/host.h>
#include <linux/pm_qos.h>
+struct sdhci_next {
+ unsigned int sg_count;
+ s32 cookie;
+};
+
struct sdhci_host {
/* Data set by hardware interface driver */
const char *hw_name; /* Hardware bus name */
@@ -191,6 +196,8 @@
unsigned int cpu_dma_latency_us;
struct pm_qos_request pm_qos_req_dma;
+ struct sdhci_next next_data;
+
unsigned long private[0] ____cacheline_aligned;
};
#endif /* LINUX_MMC_SDHCI_H */
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index 6e12694..ca7a586 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -529,12 +529,6 @@
return test_bit(ZONE_OOM_LOCKED, &zone->flags);
}
-#ifdef CONFIG_SMP
-unsigned long zone_nr_free_pages(struct zone *zone);
-#else
-#define zone_nr_free_pages(zone) zone_page_state(zone, NR_FREE_PAGES)
-#endif /* CONFIG_SMP */
-
/*
* The "priority" of VM scanning is how much of the queues we will scan in one
* go. A value of 12 for DEF_PRIORITY implies that we will scan 1/4096th of the
diff --git a/include/linux/msm_ion.h b/include/linux/msm_ion.h
index ff22e12..a683ed4 100644
--- a/include/linux/msm_ion.h
+++ b/include/linux/msm_ion.h
@@ -163,7 +163,7 @@
enum ion_fixed_position fixed_position;
int iommu_map_all;
int iommu_2x_map_domain;
- ion_virt_addr_t *virt_addr;
+ void *virt_addr;
int (*request_region)(void *);
int (*release_region)(void *);
void *(*setup_region)(void);
diff --git a/include/linux/msm_kgsl.h b/include/linux/msm_kgsl.h
index 4e62b4f..b7d393f 100644
--- a/include/linux/msm_kgsl.h
+++ b/include/linux/msm_kgsl.h
@@ -20,6 +20,8 @@
#define KGSL_CONTEXT_TRASH_STATE 0x00000020
#define KGSL_CONTEXT_PER_CONTEXT_TS 0x00000040
#define KGSL_CONTEXT_USER_GENERATED_TS 0x00000080
+#define KGSL_CONTEXT_NO_FAULT_TOLERANCE 0x00000200
+
#define KGSL_CONTEXT_INVALID 0xffffffff
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index 45bc0ea..6a2c95d 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -70,11 +70,11 @@
#define MSMFB_MDP_PP _IOWR(MSMFB_IOCTL_MAGIC, 156, struct msmfb_mdp_pp)
#define MSMFB_OVERLAY_VSYNC_CTRL _IOW(MSMFB_IOCTL_MAGIC, 160, unsigned int)
#define MSMFB_VSYNC_CTRL _IOW(MSMFB_IOCTL_MAGIC, 161, unsigned int)
-#define MSMFB_METADATA_SET _IOW(MSMFB_IOCTL_MAGIC, 162, struct msmfb_metadata)
+#define MSMFB_BUFFER_SYNC _IOW(MSMFB_IOCTL_MAGIC, 162, struct mdp_buf_sync)
#define MSMFB_OVERLAY_COMMIT _IO(MSMFB_IOCTL_MAGIC, 163)
-#define MSMFB_BUFFER_SYNC _IOW(MSMFB_IOCTL_MAGIC, 164, struct mdp_buf_sync)
-#define MSMFB_DISPLAY_COMMIT _IOW(MSMFB_IOCTL_MAGIC, 165, \
+#define MSMFB_DISPLAY_COMMIT _IOW(MSMFB_IOCTL_MAGIC, 164, \
struct mdp_display_commit)
+#define MSMFB_METADATA_SET _IOW(MSMFB_IOCTL_MAGIC, 165, struct msmfb_metadata)
#define MSMFB_METADATA_GET _IOW(MSMFB_IOCTL_MAGIC, 166, struct msmfb_metadata)
#define FB_TYPE_3D_PANEL 0x10101010
@@ -595,6 +595,7 @@
metadata_op_frame_rate,
metadata_op_vic,
metadata_op_wb_format,
+ metadata_op_get_caps,
metadata_op_max
};
@@ -607,6 +608,13 @@
uint32_t alpha;
};
+struct mdss_hw_caps {
+ uint32_t mdp_rev;
+ uint8_t rgb_pipes;
+ uint8_t vig_pipes;
+ uint8_t dma_pipes;
+};
+
struct msmfb_metadata {
uint32_t op;
uint32_t flags;
@@ -615,6 +623,7 @@
struct mdp_mixer_cfg mixer_cfg;
uint32_t panel_frame_rate;
uint32_t video_info_code;
+ struct mdss_hw_caps caps;
} data;
};
@@ -629,11 +638,19 @@
};
#define MDP_DISPLAY_COMMIT_OVERLAY 1
+struct mdp_buf_fence {
+ uint32_t flags;
+ uint32_t acq_fen_fd_cnt;
+ int acq_fen_fd[MDP_MAX_FENCE_FD];
+ int rel_fen_fd[MDP_MAX_FENCE_FD];
+};
+
struct mdp_display_commit {
uint32_t flags;
uint32_t wait_for_finish;
struct fb_var_screeninfo var;
+ struct mdp_buf_fence buf_fence;
};
struct mdp_page_protection {
diff --git a/include/linux/msm_vidc_dec.h b/include/linux/msm_vidc_dec.h
index cc864f0..35279bf 100644
--- a/include/linux/msm_vidc_dec.h
+++ b/include/linux/msm_vidc_dec.h
@@ -282,7 +282,8 @@
VDEC_CODECTYPE_MPEG1 = 0x9,
VDEC_CODECTYPE_MPEG2 = 0xa,
VDEC_CODECTYPE_VC1 = 0xb,
- VDEC_CODECTYPE_VC1_RCV = 0xc
+ VDEC_CODECTYPE_VC1_RCV = 0xc,
+ VDEC_CODECTYPE_HEVC = 0xd,
};
enum vdec_mpeg2_profile {
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 6e4b7a6..ce5ddf3 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -1135,55 +1135,6 @@
* %NL80211_CMD_SET_BEACON to provide extra IEs (e.g., WPS/P2P IE) into
* (Re)Association Response frames when the driver (or firmware) replies to
* (Re)Association Request frames.
- * @NL80211_ATTR_STA_WME: Nested attribute containing the wme configuration
- * of the station, see &enum nl80211_sta_wme_attr.
- * @NL80211_ATTR_SUPPORT_AP_UAPSD: the device supports uapsd when working
- * as AP.
- *
- * @NL80211_ATTR_ROAM_SUPPORT: Indicates whether the firmware is capable of
- * roaming to another AP in the same ESS if the signal lever is low.
- *
- * @NL80211_ATTR_PMKSA_CANDIDATE: Nested attribute containing the PMKSA caching
- * candidate information, see &enum nl80211_pmksa_candidate_attr.
- *
- * @NL80211_ATTR_TX_NO_CCK_RATE: Indicates whether to use CCK rate or not
- * for management frames transmission. In order to avoid p2p probe/action
- * frames are being transmitted at CCK rate in 2GHz band, the user space
- * applications use this attribute.
- * This attribute is used with %NL80211_CMD_TRIGGER_SCAN and
- * %NL80211_CMD_FRAME commands.
- *
- * @NL80211_ATTR_TDLS_ACTION: Low level TDLS action code (e.g. link setup
- * request, link setup confirm, link teardown, etc.). Values are
- * described in the TDLS (802.11z) specification.
- * @NL80211_ATTR_TDLS_DIALOG_TOKEN: Non-zero token for uniquely identifying a
- * TDLS conversation between two devices.
- * @NL80211_ATTR_TDLS_OPERATION: High level TDLS operation; see
- * &enum nl80211_tdls_operation, represented as a u8.
- * @NL80211_ATTR_TDLS_SUPPORT: A flag indicating the device can operate
- * as a TDLS peer sta.
- * @NL80211_ATTR_TDLS_EXTERNAL_SETUP: The TDLS discovery/setup and teardown
- * procedures should be performed by sending TDLS packets via
- * %NL80211_CMD_TDLS_MGMT. Otherwise %NL80211_CMD_TDLS_OPER should be
- * used for asking the driver to perform a TDLS operation.
- *
- * @NL80211_ATTR_DEVICE_AP_SME: This u32 attribute may be listed for devices
- * that have AP support to indicate that they have the AP SME integrated
- * with support for the features listed in this attribute, see
- * &enum nl80211_ap_sme_features.
- *
- * @NL80211_ATTR_DONT_WAIT_FOR_ACK: Used with %NL80211_CMD_FRAME, this tells
- * the driver to not wait for an acknowledgement. Note that due to this,
- * it will also not give a status callback nor return a cookie. This is
- * mostly useful for probe responses to save airtime.
- *
- * @NL80211_ATTR_FEATURE_FLAGS: This u32 attribute contains flags from
- * &enum nl80211_feature_flags and is advertised in wiphy information.
- * @NL80211_ATTR_PROBE_RESP_OFFLOAD: Indicates that the HW responds to probe
- *
- * requests while operating in AP-mode.
- * This attribute holds a bitmap of the supported protocols for
- * offloading (see &enum nl80211_probe_resp_offload_support_attr).
*
* @NL80211_ATTR_STA_WME: Nested attribute containing the wme configuration
* of the station, see &enum nl80211_sta_wme_attr.
diff --git a/include/linux/opp.h b/include/linux/opp.h
index 2a4e5fa..214e0eb 100644
--- a/include/linux/opp.h
+++ b/include/linux/opp.h
@@ -48,6 +48,14 @@
struct srcu_notifier_head *opp_get_notifier(struct device *dev);
+#ifdef CONFIG_OF
+int of_init_opp_table(struct device *dev);
+#else
+static inline int of_init_opp_table(struct device *dev)
+{
+ return -EINVAL;
+}
+#endif /* CONFIG_OF */
#else
static inline unsigned long opp_get_voltage(struct opp *opp)
{
diff --git a/include/linux/platform_data/ram_console.h b/include/linux/platform_data/ram_console.h
deleted file mode 100644
index 9f1125c..0000000
--- a/include/linux/platform_data/ram_console.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2010 Google, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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 _INCLUDE_LINUX_PLATFORM_DATA_RAM_CONSOLE_H_
-#define _INCLUDE_LINUX_PLATFORM_DATA_RAM_CONSOLE_H_
-
-struct ram_console_platform_data {
- const char *bootinfo;
-};
-
-#endif /* _INCLUDE_LINUX_PLATFORM_DATA_RAM_CONSOLE_H_ */
diff --git a/include/linux/regulator/krait-regulator.h b/include/linux/regulator/krait-regulator.h
index b784531..2683fd7 100644
--- a/include/linux/regulator/krait-regulator.h
+++ b/include/linux/regulator/krait-regulator.h
@@ -27,22 +27,6 @@
#ifdef CONFIG_ARCH_MSM8974
int __init krait_power_init(void);
void secondary_cpu_hs_init(void *base_ptr);
-
-/**
- * krait_power_mdd_enable - function to turn on/off MDD. Turning off MDD
- * turns off badngap reference for LDO. If
- * a core is running on a LDO, requests to
- * turn off MDD will not be honoured
- * @on: boolean to indicate whether to turn MDD on/off
- *
- * CONTEXT: Can be called in interrupt context, only when the core
- * is about to go to idle, this guarantees that there are no
- * frequency changes on that cpu happening. Note if going from off
- * to on mode there will be settling delays
- *
- * RETURNS: -EINVAL if MDD cannot be turned off
- */
-int krait_power_mdd_enable(int cpu_num, bool on);
#else
static inline int __init krait_power_init(void)
{
@@ -50,10 +34,6 @@
}
static inline void secondary_cpu_hs_init(void *base_ptr) {}
-static inline int krait_power_mdd_enable(int cpu_num, bool on)
-{
- return -EINVAL;
-}
#endif
#endif
diff --git a/include/linux/rq_stats.h b/include/linux/rq_stats.h
index 65d8e8f..0accf38 100644
--- a/include/linux/rq_stats.h
+++ b/include/linux/rq_stats.h
@@ -19,6 +19,7 @@
unsigned long rq_poll_total_jiffies;
unsigned long def_timer_last_jiffy;
unsigned int def_interval;
+ unsigned int hotplug_disabled;
int64_t def_start_time;
struct attribute_group *attr_group;
struct kobject *kobj;
diff --git a/include/linux/stop_machine.h b/include/linux/stop_machine.h
index f9547f4..3b5e910 100644
--- a/include/linux/stop_machine.h
+++ b/include/linux/stop_machine.h
@@ -27,8 +27,6 @@
struct cpu_stop_done *done;
};
-extern struct mutex stop_cpus_mutex;
-
int stop_one_cpu(unsigned int cpu, cpu_stop_fn_t fn, void *arg);
void stop_one_cpu_nowait(unsigned int cpu, cpu_stop_fn_t fn, void *arg,
struct cpu_stop_work *work_buf);
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index c5943c9..79fe16b 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -1,4 +1,4 @@
-/* linux/include/asm-arm/arch-msm/hsusb.h
+/* include/linux/usb/msm_hsusb.h
*
* Copyright (C) 2008 Google, Inc.
* Author: Brian Swetland <swetland@google.com>
@@ -406,6 +406,9 @@
struct msm_bus_scale_pdata *bus_scale_table;
unsigned log2_irq_thresh;
+ /* gpio used to resume peripheral */
+ unsigned resume_gpio;
+
/*swfi latency is required while driving resume on to the bus */
u32 swfi_latency;
@@ -432,68 +435,6 @@
bool core_clk_always_on_workaround;
};
-enum usb_pipe_mem_type {
- SPS_PIPE_MEM = 0, /* Default, SPS dedicated pipe memory */
- USB_PRIVATE_MEM, /* USB's private memory */
- SYSTEM_MEM, /* System RAM, requires allocation */
-};
-
-/**
- * struct usb_bam_pipe_connect: pipe connection information
- * between USB/HSIC BAM and another BAM. USB/HSIC BAM can be
- * either src BAM or dst BAM
- * @src_phy_addr: src bam physical address.
- * @src_pipe_index: src bam pipe index.
- * @dst_phy_addr: dst bam physical address.
- * @dst_pipe_index: dst bam pipe index.
- * @mem_type: type of memory used for BAM FIFOs
- * @data_fifo_base_offset: data fifo offset.
- * @data_fifo_size: data fifo size.
- * @desc_fifo_base_offset: descriptor fifo offset.
- * @desc_fifo_size: descriptor fifo size.
- */
-struct usb_bam_pipe_connect {
- u32 src_phy_addr;
- u32 src_pipe_index;
- u32 dst_phy_addr;
- u32 dst_pipe_index;
- enum usb_pipe_mem_type mem_type;
- u32 data_fifo_base_offset;
- u32 data_fifo_size;
- u32 desc_fifo_base_offset;
- u32 desc_fifo_size;
-};
-
-enum usb_bam {
- SSUSB_BAM = 0,
- HSUSB_BAM,
- HSIC_BAM,
- MAX_BAMS,
-};
-
-/**
- * struct msm_usb_bam_platform_data: pipe connection information
- * between USB/HSIC BAM and another BAM. USB/HSIC BAM can be
- * either src BAM or dst BAM
- * @connections: holds all pipe connections data.
- * @usb_active_bam: set USB or HSIC as the active BAM.
- * @usb_bam_num_pipes: max number of pipes to use.
- * @active_conn_num: number of active pipe connections.
- * @usb_base_address: BAM physical address.
- * @ignore_core_reset_ack: BAM can ignore ACK from USB core during PIPE RESET
- * @disable_clk_gating: Disable clock gating
- */
-struct msm_usb_bam_platform_data {
- struct usb_bam_pipe_connect *connections;
- int usb_active_bam;
- int usb_bam_num_pipes;
- u32 total_bam_num;
- u32 usb_base_address;
- bool ignore_core_reset_ack;
- bool reset_on_connect[MAX_BAMS];
- bool disable_clk_gating;
-};
-
/**
* struct usb_ext_notification: event notification structure
* @notify: pointer to client function to call when ID event is detected.
diff --git a/include/linux/usb/otg_id.h b/include/linux/usb/otg_id.h
deleted file mode 100644
index f9f5189..0000000
--- a/include/linux/usb/otg_id.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2011 Google, Inc.
- *
- * Author:
- * Colin Cross <ccross@android.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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 __LINUX_USB_OTG_ID_H
-#define __LINUX_USB_OTG_ID_H
-
-#include <linux/notifier.h>
-#include <linux/plist.h>
-
-/**
- * otg_id_notifier_block
- *
- * @priority: Order the notifications will be called in. Higher numbers
- * get called first.
- * @detect: Called during otg_id_notify. Return OTG_ID_HANDLED if the USB cable
- * has been identified
- * @proxy_wait: Called during otg_id_notify if a previous handler returns
- * OTG_ID_PROXY_WAIT. This should wait on ID change then call otg_id_notify.
- * This is used when a handler knows what's connected but can't detect
- * the change itself.
- * @cancel: Called after detect has returned OTG_ID_HANDLED to ask it to
- * release detection resources to allow a new identification to occur.
- */
-
-struct otg_id_notifier_block {
- int priority;
- int (*detect)(struct otg_id_notifier_block *otg_id_nb);
- int (*proxy_wait)(struct otg_id_notifier_block *otg_id_nb);
- void (*cancel)(struct otg_id_notifier_block *otg_id_nb);
- struct plist_node p;
-};
-
-#define OTG_ID_PROXY_WAIT 2
-#define OTG_ID_HANDLED 1
-#define OTG_ID_UNHANDLED 0
-
-int otg_id_register_notifier(struct otg_id_notifier_block *otg_id_nb);
-void otg_id_unregister_notifier(struct otg_id_notifier_block *otg_id_nb);
-
-void otg_id_notify(void);
-int otg_id_suspend(void);
-void otg_id_resume(void);
-
-#endif /* __LINUX_USB_OTG_ID_H */
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 2972dc0..74b09cb 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -402,6 +402,7 @@
#define V4L2_PIX_FMT_DIVX_311 v4l2_fourcc('D', 'I', 'V', '3') /* DIVX311 */
#define V4L2_PIX_FMT_DIVX v4l2_fourcc('D', 'I', 'V', 'X') /* DIVX */
#define V4L2_PIX_FMT_VP8 v4l2_fourcc('V', 'P', '8', '0') /* ON2 VP8 stream */
+#define V4L2_PIX_FMT_HEVC v4l2_fourcc('H', 'E', 'V', 'C') /* for HEVC stream */
/* Vendor-specific formats */
#define V4L2_PIX_FMT_CPIA1 v4l2_fourcc('C', 'P', 'I', 'A') /* cpia1 YUV */
@@ -1491,6 +1492,7 @@
V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE = 0,
V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME = 1,
V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_I_FRAME = 2,
+
};
#define V4L2_CID_MPEG_VIDEO_MAX_REF_PIC (V4L2_CID_MPEG_BASE+217)
#define V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE (V4L2_CID_MPEG_BASE+218)
@@ -1602,7 +1604,6 @@
#define V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP (V4L2_CID_MPEG_BASE+403)
#define V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP (V4L2_CID_MPEG_BASE+404)
#define V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL (V4L2_CID_MPEG_BASE+405)
-
enum v4l2_mpeg_video_mpeg4_level {
V4L2_MPEG_VIDEO_MPEG4_LEVEL_0 = 0,
V4L2_MPEG_VIDEO_MPEG4_LEVEL_0B = 1,
@@ -1851,6 +1852,8 @@
};
#define V4L2_CID_MPEG_VIDEO_MULTI_SLICE_GOB \
(V4L2_CID_MPEG_MSM_VIDC_BASE+27)
+#define V4L2_CID_MPEG_VIDEO_MULTI_SLICE_DELIVERY_MODE \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE+28)
/* Camera class control IDs */
#define V4L2_CID_CAMERA_CLASS_BASE (V4L2_CTRL_CLASS_CAMERA | 0x900)
#define V4L2_CID_CAMERA_CLASS (V4L2_CTRL_CLASS_CAMERA | 1)
diff --git a/include/media/gpio-ir-recv.h b/include/media/gpio-ir-recv.h
index 63f40f7..a81f0bb 100644
--- a/include/media/gpio-ir-recv.h
+++ b/include/media/gpio-ir-recv.h
@@ -14,7 +14,7 @@
#define __GPIO_IR_RECV_H__
struct gpio_ir_recv_platform_data {
- unsigned int gpio_nr;
+ int gpio_nr;
bool active_low;
bool can_wakeup;
u32 swfi_latency;
diff --git a/include/media/msm/vidc_type.h b/include/media/msm/vidc_type.h
index 77bae5a..5463fc6 100644
--- a/include/media/msm/vidc_type.h
+++ b/include/media/msm/vidc_type.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013, 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
@@ -21,7 +21,7 @@
#include <linux/list.h>
#include <linux/time.h>
#include <linux/dma-mapping.h>
-#include <linux/android_pmem.h>
+
#define DDL_MSG_LOG 0
#define DEBUG 0
diff --git a/include/media/msm_vidc.h b/include/media/msm_vidc.h
index c53d604..f632ad6 100644
--- a/include/media/msm_vidc.h
+++ b/include/media/msm_vidc.h
@@ -8,6 +8,7 @@
enum core_id {
MSM_VIDC_CORE_0 = 0,
+ MSM_VIDC_CORE_1, /* for Q6 core */
MSM_VIDC_CORES_MAX,
};
@@ -45,6 +46,7 @@
int msm_vidc_dqevent(void *instance, struct v4l2_event *event);
int msm_vidc_wait(void *instance);
int msm_vidc_s_parm(void *instance, struct v4l2_streamparm *a);
+int msm_vidc_enum_framesizes(void *instance, struct v4l2_frmsizeenum *fsize);
#endif
struct msm_vidc_interlace_payload {
unsigned int format;
diff --git a/include/media/msmb_pproc.h b/include/media/msmb_pproc.h
index 56c257d..6f8e865 100644
--- a/include/media/msmb_pproc.h
+++ b/include/media/msmb_pproc.h
@@ -109,6 +109,9 @@
#define VIDIOC_MSM_CPP_GET_HW_INFO \
_IOWR('V', BASE_VIDIOC_PRIVATE + 4, struct msm_camera_v4l2_ioctl_t)
+#define VIDIOC_MSM_CPP_FLUSH_QUEUE \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 5, struct msm_camera_v4l2_ioctl_t)
+
#define V4L2_EVENT_CPP_FRAME_DONE (V4L2_EVENT_PRIVATE_START + 0)
struct msm_camera_v4l2_ioctl_t {
diff --git a/include/media/rc-map.h b/include/media/rc-map.h
index a51f84c..5b4ad6d 100644
--- a/include/media/rc-map.h
+++ b/include/media/rc-map.h
@@ -152,8 +152,8 @@
#define RC_MAP_TREKSTOR "rc-trekstor"
#define RC_MAP_TT_1500 "rc-tt-1500"
#define RC_MAP_TWINHAN_VP1027_DVBS "rc-twinhan1027"
-#define RC_MAP_VIDEOMATE_K100 "rc-videomate-k100"
#define RC_MAP_UE_RF4CE "rc-ue-rf4ce"
+#define RC_MAP_VIDEOMATE_K100 "rc-videomate-k100"
#define RC_MAP_VIDEOMATE_S350 "rc-videomate-s350"
#define RC_MAP_VIDEOMATE_TV_PVR "rc-videomate-tv-pvr"
#define RC_MAP_WINFAST "rc-winfast"
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index efc11bb..c68d427 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -26,7 +26,6 @@
#define __HCI_CORE_H
#include <net/bluetooth/hci.h>
-#include <linux/wakelock.h>
/* HCI upper protocols */
#define HCI_PROTO_L2CAP 0
#define HCI_PROTO_SCO 1
@@ -327,7 +326,6 @@
struct work_struct work_add;
struct work_struct work_del;
- struct wake_lock idle_lock;
struct device dev;
atomic_t devref;
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 3a7edf3..1645608 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -669,7 +669,9 @@
const u8 *assoc_req_ies;
size_t assoc_req_ies_len;
+
u32 beacon_loss_count;
+
/*
* Note: Add a new enum station_info_flags value for each new field and
* use it to check which fields are initialized.
diff --git a/include/net/transp_v6.h b/include/net/transp_v6.h
index 6f1470f..498433d 100644
--- a/include/net/transp_v6.h
+++ b/include/net/transp_v6.h
@@ -14,8 +14,6 @@
struct flowi6;
-extern void initialize_hashidentrnd(void);
-
/* extension headers */
extern int ipv6_exthdrs_init(void);
extern void ipv6_exthdrs_exit(void);
diff --git a/include/sound/Kbuild b/include/sound/Kbuild
index ba75dca..edadaa9 100644
--- a/include/sound/Kbuild
+++ b/include/sound/Kbuild
@@ -11,3 +11,4 @@
header-y += tlv.h
header-y += compress_params.h
header-y += compress_offload.h
+header-y += lsm_params.h
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index bc68c24..f88c817 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -658,6 +658,11 @@
#define SLIMBUS_3_TX 0x4007
#define SLIMBUS_4_RX 0x4008
#define SLIMBUS_4_TX 0x4009 /* index = 24 */
+#define SLIMBUS_5_RX 0x400a
+#define SLIMBUS_5_TX 0x400b
+#define SLIMBUS_6_RX 0x400c
+#define SLIMBUS_6_TX 0x400d
+#define SLIMBUS_PORT_LAST SLIMBUS_6_TX
#define INT_BT_SCO_RX 0x3000 /* index = 25 */
#define INT_BT_SCO_TX 0x3001 /* index = 26 */
#define INT_BT_A2DP_RX 0x3002 /* index = 27 */
@@ -798,6 +803,15 @@
#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_4_RX 0x4008
/* SLIMbus Tx port on channel 4. */
#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_4_TX 0x4009
+/* SLIMbus Rx port on channel 5. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_5_RX 0x400a
+/* SLIMbus Tx port on channel 5. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_5_TX 0x400b
+/* SLIMbus Rx port on channel 6. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_6_RX 0x400c
+/* SLIMbus Tx port on channel 6. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_6_TX 0x400d
+
/* Generic pseudoport 1. */
#define AFE_PORT_ID_PSEUDOPORT_01 0x8001
/* Generic pseudoport 2. */
@@ -1972,7 +1986,6 @@
*/
} __packed;
-
union afe_port_config {
struct afe_param_id_pcm_cfg pcm;
struct afe_param_id_i2s_cfg i2s;
@@ -6442,6 +6455,56 @@
} __packed;
/* SRS TruMedia end */
+/* LSM Specific */
+#define VW_FEAT_DIM (39)
+
+#define APRV2_IDS_SERVICE_ID_ADSP_LSM_V (0xD)
+#define APRV2_IDS_DOMAIN_ID_ADSP_V (0x4)
+#define APRV2_IDS_DOMAIN_ID_APPS_V (0x5)
+
+#define LSM_SESSION_CMD_SHARED_MEM_MAP_REGIONS (0x00012A7F)
+#define LSM_SESSION_CMDRSP_SHARED_MEM_MAP_REGIONS (0x00012A80)
+#define LSM_SESSION_CMD_SHARED_MEM_UNMAP_REGIONS (0x00012A81)
+#define LSM_SESSION_CMD_OPEN_TX (0x00012A82)
+#define LSM_SESSION_CMD_CLOSE_TX (0x00012A88)
+#define LSM_SESSION_CMD_SET_PARAMS (0x00012A83)
+#define LSM_SESSION_CMD_REGISTER_SOUND_MODEL (0x00012A84)
+#define LSM_SESSION_CMD_DEREGISTER_SOUND_MODEL (0x00012A85)
+#define LSM_SESSION_CMD_START (0x00012A86)
+#define LSM_SESSION_CMD_STOP (0x00012A87)
+
+#define LSM_SESSION_EVENT_DETECTION_STATUS (0x00012B00)
+
+#define LSM_MODULE_ID_VOICE_WAKEUP (0x00012C00)
+#define LSM_PARAM_ID_ENDPOINT_DETECT_THRESHOLD (0x00012C01)
+#define LSM_PARAM_ID_OPERATION_MODE (0x00012C02)
+#define LSM_PARAM_ID_GAIN (0x00012C03)
+#define LSM_PARAM_ID_CONNECT_TO_PORT (0x00012C04)
+#define LSM_PARAM_ID_KEYWORD_DETECT_SENSITIVITY (0x00012C05)
+#define LSM_PARAM_ID_USER_DETECT_SENSITIVITY (0x00012C06)
+#define LSM_PARAM_ID_FEATURE_COMPENSATION_DATA (0x00012C07)
+
+
+/* HW MAD specific */
+#define AFE_MODULE_HW_MAD (0x00010230)
+#define AFE_PARAM_ID_HW_MAD_CFG (0x00010231)
+#define AFE_PARAM_ID_HW_MAD_CTRL (0x00010232)
+#define AFE_PARAM_ID_SLIMBUS_SLAVE_PORT_CFG (0x00010233)
+
+/* SW MAD specific */
+#define AFE_MODULE_SW_MAD (0x0001022D)
+#define AFE_PARAM_ID_SW_MAD_CFG (0x0001022E)
+#define AFE_PARAM_ID_SVM_MODEL (0x0001022F)
+
+/* Commands/Params to pass the codec/slimbus data to DSP */
+#define AFE_SVC_CMD_SET_PARAM (0x000100f3)
+#define AFE_MODULE_CDC_DEV_CFG (0x00010234)
+#define AFE_PARAM_ID_CDC_SLIMBUS_SLAVE_CFG (0x00010235)
+#define AFE_PARAM_ID_CDC_REG_CFG (0x00010236)
+#define AFE_PARAM_ID_CDC_REG_CFG_INIT (0x00010237)
+
+#define AFE_MAX_CDC_REGISTERS_TO_CONFIG (20)
+
/* ERROR CODES */
/* Success. The operation completed with no errors. */
#define ADSP_EOK 0x00000000
@@ -6669,4 +6732,104 @@
uint16_t reserved;
} __packed;
+enum afe_config_type {
+ AFE_SLIMBUS_SLAVE_PORT_CONFIG,
+ AFE_SLIMBUS_SLAVE_CONFIG,
+ AFE_CDC_REGISTERS_CONFIG,
+ AFE_MAX_CONFIG_TYPES,
+};
+
+struct afe_param_slimbus_slave_port_cfg {
+ uint32_t minor_version;
+ uint16_t slimbus_dev_id;
+ uint16_t slave_dev_pgd_la;
+ uint16_t slave_dev_intfdev_la;
+ uint16_t bit_width;
+ uint16_t data_format;
+ uint16_t num_channels;
+ uint16_t slave_port_mapping[AFE_PORT_MAX_AUDIO_CHAN_CNT];
+} __packed;
+
+struct afe_param_cdc_slimbus_slave_cfg {
+ uint32_t minor_version;
+ uint32_t device_enum_addr_lsw;
+ uint32_t device_enum_addr_msw;
+ uint16_t tx_slave_port_offset;
+ uint16_t rx_slave_port_offset;
+} __packed;
+
+struct afe_param_cdc_reg_cfg {
+ uint32_t minor_version;
+ uint32_t reg_logical_addr;
+ uint32_t reg_field_type;
+ uint32_t reg_field_bit_mask;
+ uint16_t reg_bit_width;
+ uint16_t reg_offset_scale;
+} __packed;
+
+struct afe_param_cdc_reg_cfg_data {
+ uint32_t num_registers;
+ struct afe_param_cdc_reg_cfg *reg_data;
+} __packed;
+
+struct afe_svc_cmd_set_param {
+ uint32_t payload_size;
+ uint32_t payload_address_lsw;
+ uint32_t payload_address_msw;
+ uint32_t mem_map_handle;
+} __packed;
+
+struct afe_param_hw_mad_ctrl {
+ uint32_t minor_version;
+ uint16_t mad_type;
+ uint16_t mad_enable;
+} __packed;
+
+struct afe_cmd_hw_mad_ctrl {
+ struct apr_hdr hdr;
+ struct afe_port_cmd_set_param_v2 param;
+ struct afe_port_param_data_v2 pdata;
+ struct afe_param_hw_mad_ctrl payload;
+} __packed;
+
+struct afe_cmd_hw_mad_slimbus_slave_port_cfg {
+ struct apr_hdr hdr;
+ struct afe_port_cmd_set_param_v2 param;
+ struct afe_port_param_data_v2 pdata;
+ struct afe_param_slimbus_slave_port_cfg sb_port_cfg;
+} __packed;
+
+struct afe_cmd_sw_mad_enable {
+ struct apr_hdr hdr;
+ struct afe_port_cmd_set_param_v2 param;
+ struct afe_port_param_data_v2 pdata;
+} __packed;
+
+struct afe_param_cdc_reg_cfg_payload {
+ struct afe_port_param_data_v2 common;
+ struct afe_param_cdc_reg_cfg reg_cfg;
+} __packed;
+
+/*
+ * reg_data's size can be up to AFE_MAX_CDC_REGISTERS_TO_CONFIG
+ */
+struct afe_svc_cmd_cdc_reg_cfg {
+ struct apr_hdr hdr;
+ struct afe_svc_cmd_set_param param;
+ struct afe_param_cdc_reg_cfg_payload reg_data[0];
+} __packed;
+
+struct afe_svc_cmd_init_cdc_reg_cfg {
+ struct apr_hdr hdr;
+ struct afe_svc_cmd_set_param param;
+ struct afe_port_param_data_v2 init;
+} __packed;
+
+struct afe_svc_cmd_sb_slave_cfg {
+ struct apr_hdr hdr;
+ struct afe_svc_cmd_set_param param;
+ struct afe_port_param_data_v2 pdata;
+ struct afe_param_cdc_slimbus_slave_cfg sb_slave_cfg;
+} __packed;
+
#endif /*_APR_AUDIO_V2_H_ */
diff --git a/include/sound/lsm_params.h b/include/sound/lsm_params.h
new file mode 100644
index 0000000..0edd8b5
--- /dev/null
+++ b/include/sound/lsm_params.h
@@ -0,0 +1,36 @@
+#ifndef __LSM_PARAMS_H__
+#define __LSM_PARAMS_H__
+
+#include <linux/types.h>
+#include <sound/asound.h>
+
+#define SNDRV_LSM_VERSION SNDRV_PROTOCOL_VERSION(0, 1, 0)
+
+enum lsm_detection_mode {
+ LSM_MODE_KEYWORD_ONLY_DETECTION = 1,
+ LSM_MODE_USER_KEYWORD_DETECTION
+};
+
+struct snd_lsm_sound_model {
+ __u8 *data;
+ __u32 data_size;
+ enum lsm_detection_mode detection_mode;
+ __u16 min_keyw_confidence;
+ __u16 min_user_confidence;
+ bool detect_failure;
+};
+
+struct snd_lsm_event_status {
+ __u16 status;
+ __u16 payload_size;
+ __u8 payload[0];
+};
+
+#define SNDRV_LSM_REG_SND_MODEL _IOW('U', 0x00, struct snd_lsm_sound_model)
+#define SNDRV_LSM_DEREG_SND_MODEL _IOW('U', 0x01, int)
+#define SNDRV_LSM_EVENT_STATUS _IOW('U', 0x02, struct snd_lsm_event_status)
+#define SNDRV_LSM_ABORT_EVENT _IOW('U', 0x03, int)
+#define SNDRV_LSM_START _IOW('U', 0x04, int)
+#define SNDRV_LSM_STOP _IOW('U', 0x05, int)
+
+#endif
diff --git a/include/sound/q6afe-v2.h b/include/sound/q6afe-v2.h
index feac314..22ddbbc 100644
--- a/include/sound/q6afe-v2.h
+++ b/include/sound/q6afe-v2.h
@@ -64,24 +64,34 @@
IDX_SLIMBUS_3_TX = 22,
IDX_SLIMBUS_4_RX = 23,
IDX_SLIMBUS_4_TX = 24,
- IDX_INT_BT_SCO_RX = 25,
- IDX_INT_BT_SCO_TX = 26,
- IDX_INT_BT_A2DP_RX = 27,
- IDX_INT_FM_RX = 28,
- IDX_INT_FM_TX = 29,
- IDX_RT_PROXY_PORT_001_RX = 30,
- IDX_RT_PROXY_PORT_001_TX = 31,
- IDX_AFE_PORT_ID_QUATERNARY_MI2S_RX = 32,
- IDX_AFE_PORT_ID_QUATERNARY_MI2S_TX = 33,
- IDX_AFE_PORT_ID_SECONDARY_MI2S_RX = 34,
- IDX_AFE_PORT_ID_SECONDARY_MI2S_TX = 35,
- IDX_AFE_PORT_ID_TERTIARY_MI2S_RX = 36,
- IDX_AFE_PORT_ID_TERTIARY_MI2S_TX = 37,
- IDX_AFE_PORT_ID_PRIMARY_MI2S_RX = 38,
- IDX_AFE_PORT_ID_PRIMARY_MI2S_TX = 39,
+ IDX_SLIMBUS_5_RX = 25,
+ IDX_SLIMBUS_5_TX = 26,
+ IDX_INT_BT_SCO_RX = 27,
+ IDX_INT_BT_SCO_TX = 28,
+ IDX_INT_BT_A2DP_RX = 29,
+ IDX_INT_FM_RX = 30,
+ IDX_INT_FM_TX = 31,
+ IDX_RT_PROXY_PORT_001_RX = 32,
+ IDX_RT_PROXY_PORT_001_TX = 33,
+ IDX_AFE_PORT_ID_QUATERNARY_MI2S_RX = 34,
+ IDX_AFE_PORT_ID_QUATERNARY_MI2S_TX = 35,
+ IDX_AFE_PORT_ID_SECONDARY_MI2S_RX = 36,
+ IDX_AFE_PORT_ID_SECONDARY_MI2S_TX = 37,
+ IDX_AFE_PORT_ID_TERTIARY_MI2S_RX = 38,
+ IDX_AFE_PORT_ID_TERTIARY_MI2S_TX = 39,
+ IDX_AFE_PORT_ID_PRIMARY_MI2S_RX = 40,
+ IDX_AFE_PORT_ID_PRIMARY_MI2S_TX = 41,
+ IDX_GLOBAL_CFG,
AFE_MAX_PORTS
};
+enum afe_mad_type {
+ MAD_HW_NONE = 0x00,
+ MAD_HW_AUDIO = 0x01,
+ MAD_HW_BEACON = 0x02,
+ MAD_HW_ULTRASOUND = 0x04
+};
+
struct afe_audio_buffer {
dma_addr_t phys;
void *data;
@@ -172,4 +182,10 @@
struct afe_digital_clk_cfg *cfg);
int q6afe_check_osr_clk_freq(u32 freq);
+int afe_turn_onoff_hw_mad(u16 mad_type, u16 mad_enable);
+int afe_port_set_mad_type(u16 port_id, enum afe_mad_type mad_type);
+enum afe_mad_type afe_port_get_mad_type(u16 port_id);
+int afe_set_config(enum afe_config_type config_type, void *config_data,
+ int arg);
+
#endif /* __Q6AFE_V2_H__ */
diff --git a/include/sound/q6lsm.h b/include/sound/q6lsm.h
new file mode 100644
index 0000000..5c9d4b9
--- /dev/null
+++ b/include/sound/q6lsm.h
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 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.
+ */
+#ifndef __Q6LSM_H__
+#define __Q6LSM_H__
+
+#include <linux/list.h>
+#include <linux/msm_ion.h>
+#include <sound/apr_audio-v2.h>
+#include <sound/lsm_params.h>
+#include <mach/qdsp6v2/apr.h>
+#include <mach/msm_subsystem_map.h>
+
+typedef void (*app_cb)(uint32_t opcode, uint32_t token,
+ uint32_t *payload, void *priv);
+
+struct lsm_sound_model {
+ dma_addr_t phys;
+ void *data;
+ uint32_t size; /* size of buffer */
+ uint32_t actual_size; /* actual number of bytes read by DSP */
+ struct ion_handle *handle;
+ struct ion_client *client;
+ uint32_t mem_map_handle;
+};
+
+struct lsm_client {
+ int session;
+ app_cb cb;
+ atomic_t cmd_state;
+ void *priv;
+ struct apr_svc *apr;
+ struct apr_svc *mmap_apr;
+ struct mutex cmd_lock;
+ struct lsm_sound_model sound_model;
+ wait_queue_head_t cmd_wait;
+ uint16_t mode;
+ uint16_t connect_to_port;
+ uint16_t user_sensitivity;
+ uint16_t kw_sensitivity;
+ bool started;
+};
+
+struct lsm_stream_cmd_open_tx {
+ struct apr_hdr hdr;
+ uint16_t app_id;
+ uint16_t reserved;
+ uint32_t sampling_rate;
+} __packed;
+
+struct lsm_param_payload_common {
+ uint32_t module_id;
+ uint32_t param_id;
+ uint16_t param_size;
+ uint16_t reserved;
+} __packed;
+
+struct lsm_param_op_mode {
+ struct lsm_param_payload_common common;
+ uint32_t minor_version;
+ uint16_t mode;
+ uint16_t reserved;
+} __packed;
+
+struct lsm_param_connect_to_port {
+ struct lsm_param_payload_common common;
+ uint32_t minor_version;
+ /* AFE port id that receives voice wake up data */
+ uint16_t port_id;
+ uint16_t reserved;
+} __packed;
+
+struct lsm_param_kw_detect_sensitivity {
+ struct lsm_param_payload_common common;
+ uint32_t minor_version;
+ /* scale factor to change the keyword confidence thresholds */
+ uint16_t keyword_sensitivity;
+ uint16_t reserved;
+} __packed;
+
+struct lsm_param_user_detect_sensitivity {
+ struct lsm_param_payload_common common;
+ uint32_t minor_version;
+ /* scale factor to change the user confidence thresholds */
+ uint16_t user_sensitivity;
+ uint16_t reserved;
+} __packed;
+
+struct lsm_params_payload {
+ struct lsm_param_connect_to_port connect_to_port;
+ struct lsm_param_op_mode op_mode;
+ struct lsm_param_kw_detect_sensitivity kwds;
+ struct lsm_param_user_detect_sensitivity uds;
+} __packed;
+
+struct lsm_cmd_set_params {
+ struct apr_hdr hdr;
+ uint32_t data_payload_size;
+ uint32_t data_payload_addr_lsw;
+ uint32_t data_payload_addr_msw;
+ uint32_t mem_map_handle;
+ struct lsm_params_payload payload;
+} __packed;
+
+struct lsm_cmd_reg_snd_model {
+ struct apr_hdr hdr;
+ uint32_t model_size;
+ uint32_t model_addr_lsw;
+ uint32_t model_addr_msw;
+ uint32_t mem_map_handle;
+} __packed;
+
+struct lsm_client *q6lsm_client_alloc(app_cb cb, void *priv);
+void q6lsm_client_free(struct lsm_client *client);
+int q6lsm_open(struct lsm_client *client);
+int q6lsm_start(struct lsm_client *client, bool wait);
+int q6lsm_stop(struct lsm_client *client, bool wait);
+int q6lsm_snd_model_buf_alloc(struct lsm_client *client, uint32_t len);
+int q6lsm_close(struct lsm_client *client);
+int q6lsm_register_sound_model(struct lsm_client *client,
+ enum lsm_detection_mode mode, u16 minkeyword,
+ u16 minuser, bool detectfailure);
+int q6lsm_deregister_sound_model(struct lsm_client *client);
+
+#endif /* __Q6LSM_H__ */
diff --git a/init/Kconfig b/init/Kconfig
index b2126bc..e4b67a1 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1132,15 +1132,6 @@
option replaces shmem and tmpfs with the much simpler ramfs code,
which may be appropriate on small systems without swap.
-config ASHMEM
- bool "Enable the Anonymous Shared Memory Subsystem"
- default n
- depends on SHMEM || TINY_SHMEM
- help
- The ashmem subsystem is a new shared memory allocator, similar to
- POSIX SHM but with different behavior and sporting a simpler
- file-based API.
-
config AIO
bool "Enable AIO support" if EXPERT
default y
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index ae34bf5..d1e73a4 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -61,6 +61,7 @@
DEFINE_PER_CPU(struct hrtimer_cpu_base, hrtimer_bases) =
{
+ .lock = __RAW_SPIN_LOCK_UNLOCKED(hrtimer_bases.lock),
.clock_base =
{
{
@@ -1619,8 +1620,6 @@
struct hrtimer_cpu_base *cpu_base = &per_cpu(hrtimer_bases, cpu);
int i;
- raw_spin_lock_init(&cpu_base->lock);
-
for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++) {
cpu_base->clock_base[i].cpu_base = cpu_base;
timerqueue_init_head(&cpu_base->clock_base[i].active);
diff --git a/kernel/power/main.c b/kernel/power/main.c
index b54da02..7aac5f6 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -666,7 +666,6 @@
tc_ev_timer.function = &tc_ev_stop;
tc_ev_processed = 1;
-
power_kobj = kobject_create_and_add("power", NULL);
if (!power_kobj)
return -ENOMEM;
diff --git a/kernel/stop_machine.c b/kernel/stop_machine.c
index b0f118e..2f194e9 100644
--- a/kernel/stop_machine.c
+++ b/kernel/stop_machine.c
@@ -133,8 +133,8 @@
cpu_stop_queue_work(&per_cpu(cpu_stopper, cpu), work_buf);
}
-DEFINE_MUTEX(stop_cpus_mutex);
/* static data for stop_cpus */
+static DEFINE_MUTEX(stop_cpus_mutex);
static DEFINE_PER_CPU(struct cpu_stop_work, stop_cpus_work);
static void queue_stop_cpus_work(const struct cpumask *cpumask,
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 50f73be..7ffcc1b 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -543,7 +543,6 @@
conn->disc_timeout = HCI_DISCONN_TIMEOUT;
conn->conn_valid = true;
spin_lock_init(&conn->lock);
- wake_lock_init(&conn->idle_lock, WAKE_LOCK_SUSPEND, "bt_idle");
switch (type) {
case ACL_LINK:
@@ -621,7 +620,6 @@
/* Make sure no timers are running */
del_timer(&conn->idle_timer);
- wake_lock_destroy(&conn->idle_lock);
del_timer(&conn->disc_timer);
del_timer(&conn->smp_timer);
__cancel_delayed_work(&conn->rssi_update_work);
@@ -1082,7 +1080,6 @@
if (conn->conn_valid) {
mod_timer(&conn->idle_timer,
jiffies + msecs_to_jiffies(hdev->idle_timeout));
- wake_lock(&conn->idle_lock);
}
spin_unlock_bh(&conn->lock);
}
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 198773c..d243646 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -2596,9 +2596,6 @@
else
conn->power_save = 0;
}
- if (conn->mode == HCI_CM_SNIFF)
- if (wake_lock_active(&conn->idle_lock))
- wake_unlock(&conn->idle_lock);
if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->pend))
hci_sco_setup(conn, ev->status);
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index d778ae3..83087d1 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -201,7 +201,7 @@
l2cap_pi(sk)->mode, sk->sk_state);
if (!addr || alen < sizeof(addr->sa_family) ||
- addr->sa_family != AF_BLUETOOTH)
+ addr->sa_family != AF_BLUETOOTH)
return -EINVAL;
memset(&la, 0, sizeof(la));
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile
index 291934b..a00a904 100644
--- a/net/ipv4/netfilter/Makefile
+++ b/net/ipv4/netfilter/Makefile
@@ -69,3 +69,4 @@
obj-$(CONFIG_IP_NF_ARPFILTER) += arptable_filter.o
obj-$(CONFIG_IP_NF_QUEUE) += ip_queue.o
+
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index ab7bd2c..0cb86ce 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1991,49 +1991,6 @@
}
EXPORT_SYMBOL(tcp_v4_destroy_sock);
-/*
- * tcp_v4_nuke_addr - destroy all sockets on the given local address
- */
-void tcp_v4_nuke_addr(__u32 saddr)
-{
- unsigned int bucket;
-
- for (bucket = 0; bucket < tcp_hashinfo.ehash_mask; bucket++) {
- struct hlist_nulls_node *node;
- struct sock *sk;
- spinlock_t *lock = inet_ehash_lockp(&tcp_hashinfo, bucket);
-
-restart:
- spin_lock_bh(lock);
- sk_nulls_for_each(sk, node, &tcp_hashinfo.ehash[bucket].chain) {
- struct inet_sock *inet = inet_sk(sk);
-
- if (inet->inet_rcv_saddr != saddr)
- continue;
- if (sysctl_ip_dynaddr && sk->sk_state == TCP_SYN_SENT)
- continue;
- if (sock_flag(sk, SOCK_DEAD))
- continue;
-
- sock_hold(sk);
- spin_unlock_bh(lock);
-
- local_bh_disable();
- bh_lock_sock(sk);
- sk->sk_err = ETIMEDOUT;
- sk->sk_error_report(sk);
-
- tcp_done(sk);
- bh_unlock_sock(sk);
- local_bh_enable();
- sock_put(sk);
-
- goto restart;
- }
- spin_unlock_bh(lock);
- }
-}
-
#ifdef CONFIG_PROC_FS
/* Proc filesystem TCP sock list dumping. */
diff --git a/net/wireless/util.c b/net/wireless/util.c
index a448b80..017d4fc 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -1038,6 +1038,7 @@
if (!found)
return -EINVAL;
}
+
/*
* mask must have at least one bit set here since we
* didn't accept a 0-length rates array nor allowed
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 4636247..7403b40 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -1534,6 +1534,20 @@
err = substream->ops->ioctl(substream, cmd, arg);
return err;
}
+
+static int snd_user_ioctl(struct snd_pcm_substream *substream,
+ unsigned int cmd, void __user *arg)
+{
+ struct snd_pcm_runtime *runtime;
+ int err = 0;
+
+ if (PCM_RUNTIME_CHECK(substream))
+ return -ENXIO;
+ runtime = substream->runtime;
+ err = substream->ops->ioctl(substream, cmd, arg);
+ return err;
+}
+
/*
* drop ioctl
*
@@ -2605,6 +2619,9 @@
case SNDRV_COMPRESS_TSTAMP:
case SNDRV_COMPRESS_DRAIN:
return snd_compressed_ioctl(substream, cmd, arg);
+ default:
+ if (((cmd >> 8) & 0xff) == 'U')
+ return snd_user_ioctl(substream, cmd, arg);
}
snd_printd("unknown ioctl = 0x%x\n", cmd);
return -ENOTTY;
@@ -2788,10 +2805,12 @@
unsigned long arg)
{
struct snd_pcm_file *pcm_file;
+ unsigned char ioctl_magic;
pcm_file = file->private_data;
+ ioctl_magic = ((cmd >> 8) & 0xff);
- if ((((cmd >> 8) & 0xff) != 'A') && (((cmd >> 8) & 0xff) != 'C'))
+ if (ioctl_magic != 'A' && ioctl_magic != 'C' && ioctl_magic != 'U')
return -ENOTTY;
return snd_pcm_capture_ioctl1(file, pcm_file->substream, cmd,
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index a09dab3..f0cd026 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -52,7 +52,7 @@
snd-soc-wcd9310-objs := wcd9310.o wcd9310-tables.o
snd-soc-cs8427-objs := cs8427.o
snd-soc-wcd9320-objs := wcd9xxx-resmgr.o wcd9320.o wcd9320-tables.o wcd9xxx-mbhc.o wcd9xxx-common.o
-snd-soc-wcd9306-objs := wcd9306.o wcd9306-tables.o
+snd-soc-wcd9306-objs := wcd9306.o wcd9306-tables.o wcd9xxx-common.o
snd-soc-msm8x10-wcd-objs := msm8x10-wcd.o msm8x10-wcd-tables.o
snd-soc-wl1273-objs := wl1273.o
snd-soc-wm1250-ev1-objs := wm1250-ev1.o
diff --git a/sound/soc/codecs/wcd9306.c b/sound/soc/codecs/wcd9306.c
index 25d3f56..634493b 100644
--- a/sound/soc/codecs/wcd9306.c
+++ b/sound/soc/codecs/wcd9306.c
@@ -18,6 +18,8 @@
#include <linux/printk.h>
#include <linux/ratelimit.h>
#include <linux/debugfs.h>
+#include <linux/wait.h>
+#include <linux/bitops.h>
#include <linux/mfd/wcd9xxx/core.h>
#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
#include <linux/mfd/wcd9xxx/wcd9306_registers.h>
@@ -34,6 +36,20 @@
#include <linux/gpio.h>
#include "wcd9306.h"
#include "wcd9xxx-resmgr.h"
+#include "wcd9xxx-common.h"
+
+static atomic_t kp_tapan_priv;
+static int spkr_drv_wrnd_param_set(const char *val,
+ const struct kernel_param *kp);
+static int spkr_drv_wrnd = 1;
+
+static struct kernel_param_ops spkr_drv_wrnd_param_ops = {
+ .set = spkr_drv_wrnd_param_set,
+ .get = param_get_int,
+};
+module_param_cb(spkr_drv_wrnd, &spkr_drv_wrnd_param_ops, &spkr_drv_wrnd, 0644);
+MODULE_PARM_DESC(spkr_drv_wrnd,
+ "Run software workaround to avoid leakage on the speaker drive");
#define WCD9306_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\
@@ -42,10 +58,22 @@
#define NUM_DECIMATORS 4
#define NUM_INTERPOLATORS 4
#define BITS_PER_REG 8
+/* This actual number of TX ports supported in slimbus slave */
#define TAPAN_TX_PORT_NUMBER 16
-#define TAPAN_I2S_MASTER_MODE_MASK 0x08
+/* Nummer of TX ports actually connected from Slimbus slave to codec Digital */
+#define TAPAN_SLIM_CODEC_TX_PORTS 5
+#define TAPAN_I2S_MASTER_MODE_MASK 0x08
+#define TAPAN_MCLK_CLK_12P288MHZ 12288000
+#define TAPAN_MCLK_CLK_9P6HZ 9600000
+
+#define TAPAN_SLIM_CLOSE_TIMEOUT 1000
+#define TAPAN_SLIM_IRQ_OVERFLOW (1 << 0)
+#define TAPAN_SLIM_IRQ_UNDERFLOW (1 << 1)
+#define TAPAN_SLIM_IRQ_PORT_CLOSED (1 << 2)
+#define TAPAN_MCLK_CLK_12P288MHZ 12288000
+#define TAPAN_MCLK_CLK_9P6HZ 9600000
enum {
AIF1_PB = 0,
AIF1_CAP,
@@ -67,8 +95,6 @@
RX_MIX1_INP_SEL_RX3,
RX_MIX1_INP_SEL_RX4,
RX_MIX1_INP_SEL_RX5,
- RX_MIX1_INP_SEL_RX6,
- RX_MIX1_INP_SEL_RX7,
RX_MIX1_INP_SEL_AUXRX,
};
@@ -97,7 +123,8 @@
};
enum {
- COMPANDER_1 = 0,
+ COMPANDER_0,
+ COMPANDER_1,
COMPANDER_2,
COMPANDER_MAX,
};
@@ -152,6 +179,11 @@
(1 << AIF1_CAP) | (1 << AIF2_CAP), /* AIF2_CAP */
};
+static const u32 vport_i2s_check_table[NUM_CODEC_DAIS] = {
+ 0, /* AIF1_PB */
+ 0, /* AIF1_CAP */
+};
+
struct tapan_priv {
struct snd_soc_codec *codec;
u32 adc_count;
@@ -168,22 +200,82 @@
/* num of slim ports required */
struct wcd9xxx_codec_dai_data dai[NUM_CODEC_DAIS];
+ /*compander*/
+ int comp_enabled[COMPANDER_MAX];
+ u32 comp_fs[COMPANDER_MAX];
+
/* Maintain the status of AUX PGA */
int aux_pga_cnt;
u8 aux_l_gain;
u8 aux_r_gain;
+ bool spkr_pa_widget_on;
+
/* resmgr module */
struct wcd9xxx_resmgr resmgr;
/* mbhc module */
struct wcd9xxx_mbhc mbhc;
+
+ /* class h specific data */
+ struct wcd9xxx_clsh_cdc_data clsh_d;
};
static const u32 comp_shift[] = {
+ 4, /* Compander 0's clock source is on interpolator 7 */
0,
2,
};
+static const int comp_rx_path[] = {
+ COMPANDER_1,
+ COMPANDER_1,
+ COMPANDER_2,
+ COMPANDER_2,
+ COMPANDER_2,
+ COMPANDER_2,
+ COMPANDER_0,
+ COMPANDER_MAX,
+};
+
+static const struct comp_sample_dependent_params comp_samp_params[] = {
+ {
+ /* 8 Khz */
+ .peak_det_timeout = 0x02,
+ .rms_meter_div_fact = 0x09,
+ .rms_meter_resamp_fact = 0x06,
+ },
+ {
+ /* 16 Khz */
+ .peak_det_timeout = 0x03,
+ .rms_meter_div_fact = 0x0A,
+ .rms_meter_resamp_fact = 0x0C,
+ },
+ {
+ /* 32 Khz */
+ .peak_det_timeout = 0x05,
+ .rms_meter_div_fact = 0x0B,
+ .rms_meter_resamp_fact = 0x1E,
+ },
+ {
+ /* 48 Khz */
+ .peak_det_timeout = 0x05,
+ .rms_meter_div_fact = 0x0B,
+ .rms_meter_resamp_fact = 0x28,
+ },
+ {
+ /* 96 Khz */
+ .peak_det_timeout = 0x06,
+ .rms_meter_div_fact = 0x0C,
+ .rms_meter_resamp_fact = 0x50,
+ },
+ {
+ /* 192 Khz */
+ .peak_det_timeout = 0x07,
+ .rms_meter_div_fact = 0xD,
+ .rms_meter_resamp_fact = 0xA0,
+ },
+};
+
static unsigned short rx_digital_gain_reg[] = {
TAPAN_A_CDC_RX1_VOL_CTL_B2_CTL,
TAPAN_A_CDC_RX2_VOL_CTL_B2_CTL,
@@ -198,71 +290,61 @@
TAPAN_A_CDC_TX4_VOL_CTL_GAIN,
};
-static int tapan_codec_enable_class_h_clk(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
+static int spkr_drv_wrnd_param_set(const char *val,
+ const struct kernel_param *kp)
{
- struct snd_soc_codec *codec = w->codec;
+ struct snd_soc_codec *codec;
+ int ret, old;
+ struct tapan_priv *priv;
- dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
-
- switch (event) {
- case SND_SOC_DAPM_PRE_PMU:
- snd_soc_update_bits(codec, TAPAN_A_CDC_CLSH_B1_CTL, 0x01, 0x01);
- break;
- case SND_SOC_DAPM_PRE_PMD:
- snd_soc_update_bits(codec, TAPAN_A_BUCK_MODE_1, 0x80, 0x00);
- snd_soc_update_bits(codec, TAPAN_A_CDC_CLSH_B1_CTL, 0x01, 0x00);
- break;
+ priv = (struct tapan_priv *)atomic_read(&kp_tapan_priv);
+ if (!priv) {
+ pr_debug("%s: codec isn't yet registered\n", __func__);
+ return 0;
}
+
+ WCD9XXX_BCL_LOCK(&priv->resmgr);
+ old = spkr_drv_wrnd;
+ ret = param_set_int(val, kp);
+ if (ret) {
+ WCD9XXX_BCL_UNLOCK(&priv->resmgr);
+ return ret;
+ }
+
+ codec = priv->codec;
+ dev_dbg(codec->dev, "%s: spkr_drv_wrnd %d -> %d\n",
+ __func__, old, spkr_drv_wrnd);
+ if (old == 0 && spkr_drv_wrnd == 1) {
+ wcd9xxx_resmgr_get_bandgap(&priv->resmgr,
+ WCD9XXX_BANDGAP_AUDIO_MODE);
+ snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_EN, 0x80, 0x80);
+ } else if (old == 1 && spkr_drv_wrnd == 0) {
+ wcd9xxx_resmgr_put_bandgap(&priv->resmgr,
+ WCD9XXX_BANDGAP_AUDIO_MODE);
+ if (!priv->spkr_pa_widget_on)
+ snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_EN, 0x80,
+ 0x00);
+ }
+
+ WCD9XXX_BCL_UNLOCK(&priv->resmgr);
return 0;
}
-static int tapan_codec_enable_class_h(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
+static int tapan_get_anc_slot(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = w->codec;
-
- dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
-
- switch (event) {
- case SND_SOC_DAPM_POST_PMU:
- snd_soc_update_bits(codec, TAPAN_A_BUCK_MODE_5, 0x02, 0x02);
- snd_soc_update_bits(codec, TAPAN_A_BUCK_MODE_4, 0xFF, 0xFF);
- snd_soc_update_bits(codec, TAPAN_A_BUCK_MODE_1, 0x04, 0x04);
- snd_soc_update_bits(codec, TAPAN_A_BUCK_MODE_1, 0x04, 0x00);
- snd_soc_update_bits(codec, TAPAN_A_BUCK_MODE_3, 0x04, 0x00);
- snd_soc_update_bits(codec, TAPAN_A_BUCK_MODE_3, 0x08, 0x00);
- snd_soc_update_bits(codec, TAPAN_A_BUCK_MODE_1, 0x80, 0x80);
- usleep_range(1000, 1000);
- break;
- }
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
+ ucontrol->value.integer.value[0] = tapan->anc_slot;
return 0;
}
-static int tapan_codec_enable_charge_pump(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
+static int tapan_put_anc_slot(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = w->codec;
-
- dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
-
- switch (event) {
- case SND_SOC_DAPM_PRE_PMU:
- snd_soc_update_bits(codec, w->reg, 0x01, 0x01);
- snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
- snd_soc_update_bits(codec, TAPAN_A_NCP_STATIC, 0x0f, 0x01);
- break;
-
- case SND_SOC_DAPM_POST_PMU:
- usleep_range(1000, 1000);
- break;
-
- case SND_SOC_DAPM_PRE_PMD:
- snd_soc_update_bits(codec, w->reg, 0x01, 0x00);
- snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
- snd_soc_update_bits(codec, TAPAN_A_NCP_STATIC, 0x0f, 0x08);
- break;
- }
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
+ tapan->anc_slot = ucontrol->value.integer.value[0];
return 0;
}
@@ -464,6 +546,168 @@
return 0;
}
+static int tapan_get_compander(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ int comp = ((struct soc_multi_mixer_control *)
+ kcontrol->private_value)->shift;
+ struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
+
+ ucontrol->value.integer.value[0] = tapan->comp_enabled[comp];
+ return 0;
+}
+
+static int tapan_set_compander(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
+ int comp = ((struct soc_multi_mixer_control *)
+ kcontrol->private_value)->shift;
+ int value = ucontrol->value.integer.value[0];
+
+ dev_dbg(codec->dev, "%s: Compander %d enable current %d, new %d\n",
+ __func__, comp, tapan->comp_enabled[comp], value);
+ tapan->comp_enabled[comp] = value;
+ return 0;
+}
+
+static int tapan_config_gain_compander(struct snd_soc_codec *codec,
+ int comp, bool enable)
+{
+ int ret = 0;
+
+ switch (comp) {
+ case COMPANDER_0:
+ snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_GAIN,
+ 1 << 2, !enable << 2);
+ break;
+ case COMPANDER_1:
+ snd_soc_update_bits(codec, TAPAN_A_RX_HPH_L_GAIN,
+ 1 << 5, !enable << 5);
+ snd_soc_update_bits(codec, TAPAN_A_RX_HPH_R_GAIN,
+ 1 << 5, !enable << 5);
+ break;
+ case COMPANDER_2:
+ snd_soc_update_bits(codec, TAPAN_A_RX_LINE_1_GAIN,
+ 1 << 5, !enable << 5);
+ snd_soc_update_bits(codec, TAPAN_A_RX_LINE_2_GAIN,
+ 1 << 5, !enable << 5);
+ break;
+ default:
+ WARN_ON(1);
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static void tapan_discharge_comp(struct snd_soc_codec *codec, int comp)
+{
+ /* Update RSM to 1, DIVF to 5 */
+ snd_soc_write(codec, TAPAN_A_CDC_COMP0_B3_CTL + (comp * 8), 1);
+ snd_soc_update_bits(codec, TAPAN_A_CDC_COMP0_B2_CTL + (comp * 8), 0xF0,
+ 1 << 5);
+ /* Wait for 1ms */
+ usleep_range(1000, 1000);
+}
+
+static int tapan_config_compander(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ int mask, emask;
+ bool timedout;
+ unsigned long timeout;
+ struct snd_soc_codec *codec = w->codec;
+ struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
+ const int comp = w->shift;
+ const u32 rate = tapan->comp_fs[comp];
+ const struct comp_sample_dependent_params *comp_params =
+ &comp_samp_params[rate];
+
+ dev_dbg(codec->dev, "%s: %s event %d compander %d, enabled %d",
+ __func__, w->name, event, comp, tapan->comp_enabled[comp]);
+
+ if (!tapan->comp_enabled[comp])
+ return 0;
+
+ /* Compander 0 has single channel */
+ mask = (comp == COMPANDER_0 ? 0x01 : 0x03);
+ emask = (comp == COMPANDER_0 ? 0x02 : 0x03);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ /* Set gain source to compander */
+ tapan_config_gain_compander(codec, comp, true);
+ /* Enable RX interpolation path clocks */
+ snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_RX_B2_CTL,
+ mask << comp_shift[comp],
+ mask << comp_shift[comp]);
+
+ tapan_discharge_comp(codec, comp);
+
+ /* Clear compander halt */
+ snd_soc_update_bits(codec, TAPAN_A_CDC_COMP0_B1_CTL +
+ (comp * 8),
+ 1 << 2, 0);
+ /* Toggle compander reset bits */
+ snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_OTHR_RESET_B2_CTL,
+ mask << comp_shift[comp],
+ mask << comp_shift[comp]);
+ snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_OTHR_RESET_B2_CTL,
+ mask << comp_shift[comp], 0);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ /* Set sample rate dependent paramater */
+ snd_soc_update_bits(codec,
+ TAPAN_A_CDC_COMP0_FS_CFG + (comp * 8),
+ 0x07, rate);
+ snd_soc_write(codec, TAPAN_A_CDC_COMP0_B3_CTL + (comp * 8),
+ comp_params->rms_meter_resamp_fact);
+ snd_soc_update_bits(codec,
+ TAPAN_A_CDC_COMP0_B2_CTL + (comp * 8),
+ 0x0F, comp_params->peak_det_timeout);
+ snd_soc_update_bits(codec,
+ TAPAN_A_CDC_COMP0_B2_CTL + (comp * 8),
+ 0xF0, comp_params->rms_meter_div_fact << 4);
+ /* Compander enable */
+ snd_soc_update_bits(codec, TAPAN_A_CDC_COMP0_B1_CTL +
+ (comp * 8), emask, emask);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ /* Halt compander */
+ snd_soc_update_bits(codec,
+ TAPAN_A_CDC_COMP0_B1_CTL + (comp * 8),
+ 1 << 2, 1 << 2);
+ /* Wait up to a second for shutdown complete */
+ timeout = jiffies + HZ;
+ do {
+ if ((snd_soc_read(codec,
+ TAPAN_A_CDC_COMP0_SHUT_DOWN_STATUS +
+ (comp * 8)) & mask) == mask)
+ break;
+ } while (!(timedout = time_after(jiffies, timeout)));
+ dev_dbg(codec->dev, "%s: Compander %d shutdown %s in %dms\n",
+ __func__, comp, timedout ? "timedout" : "completed",
+ jiffies_to_msecs(timeout - HZ - jiffies));
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ /* Disable compander */
+ snd_soc_update_bits(codec,
+ TAPAN_A_CDC_COMP0_B1_CTL + (comp * 8),
+ emask, 0x00);
+ /* Turn off the clock for compander in pair */
+ snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_RX_B2_CTL,
+ mask << comp_shift[comp], 0);
+ /* Set gain source to register */
+ tapan_config_gain_compander(codec, comp, false);
+ break;
+ }
+ return 0;
+}
+
static const char * const tapan_ear_pa_gain_text[] = {"POS_6_DB", "POS_2_DB"};
static const struct soc_enum tapan_ear_pa_gain_enum[] = {
SOC_ENUM_SINGLE_EXT(2, tapan_ear_pa_gain_text),
@@ -498,21 +742,40 @@
static const struct soc_enum cf_rxmix4_enum =
SOC_ENUM_SINGLE(TAPAN_A_CDC_RX4_B4_CTL, 0, 3, cf_text);
+static const char * const class_h_dsm_text[] = {
+ "ZERO", "RX_HPHL", "RX_SPKR"
+};
+
+static const struct soc_enum class_h_dsm_enum =
+ SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_CLSH_CTL, 2, 3, class_h_dsm_text);
+
+static const struct snd_kcontrol_new class_h_dsm_mux =
+ SOC_DAPM_ENUM("CLASS_H_DSM MUX Mux", class_h_dsm_enum);
+
static const struct snd_kcontrol_new tapan_snd_controls[] = {
SOC_ENUM_EXT("EAR PA Gain", tapan_ear_pa_gain_enum[0],
tapan_pa_gain_get, tapan_pa_gain_put),
- SOC_SINGLE_TLV("LINEOUT1 Volume", TAPAN_A_RX_LINE_1_GAIN, 0, 12, 1,
+ SOC_SINGLE_TLV("HPHL Volume", TAPAN_A_RX_HPH_L_GAIN, 0, 14, 1,
line_gain),
- SOC_SINGLE_TLV("LINEOUT2 Volume", TAPAN_A_RX_LINE_2_GAIN, 0, 12, 1,
+ SOC_SINGLE_TLV("HPHR Volume", TAPAN_A_RX_HPH_R_GAIN, 0, 14, 1,
line_gain),
- SOC_SINGLE_TLV("HPHL Volume", TAPAN_A_RX_HPH_L_GAIN, 0, 12, 1,
+ SOC_SINGLE_TLV("LINEOUT1 Volume", TAPAN_A_RX_LINE_1_GAIN, 0, 14, 1,
line_gain),
- SOC_SINGLE_TLV("HPHR Volume", TAPAN_A_RX_HPH_R_GAIN, 0, 12, 1,
+ SOC_SINGLE_TLV("LINEOUT2 Volume", TAPAN_A_RX_LINE_2_GAIN, 0, 14, 1,
line_gain),
+ SOC_SINGLE_TLV("SPK DRV Volume", TAPAN_A_SPKR_DRV_GAIN, 3, 7, 1,
+ line_gain),
+
+ SOC_SINGLE_TLV("ADC1 Volume", TAPAN_A_TX_1_EN, 2, 13, 0, analog_gain),
+ SOC_SINGLE_TLV("ADC2 Volume", TAPAN_A_TX_2_EN, 2, 13, 0, analog_gain),
+ SOC_SINGLE_TLV("ADC3 Volume", TAPAN_A_TX_3_EN, 2, 13, 0, analog_gain),
+ SOC_SINGLE_TLV("ADC4 Volume", TAPAN_A_TX_4_EN, 2, 13, 0, analog_gain),
+ SOC_SINGLE_TLV("ADC5 Volume", TAPAN_A_TX_5_EN, 2, 13, 0, analog_gain),
+
SOC_SINGLE_S8_TLV("RX1 Digital Volume", TAPAN_A_CDC_RX1_VOL_CTL_B2_CTL,
-84, 40, digital_gain),
SOC_SINGLE_S8_TLV("RX2 Digital Volume", TAPAN_A_CDC_RX2_VOL_CTL_B2_CTL,
@@ -540,9 +803,8 @@
SOC_SINGLE_S8_TLV("IIR1 INP4 Volume", TAPAN_A_CDC_IIR1_GAIN_B4_CTL, -84,
40, digital_gain),
- SOC_SINGLE("MICBIAS1 CAPLESS Switch", TAPAN_A_MICB_1_CTL, 4, 1, 1),
- SOC_SINGLE("MICBIAS2 CAPLESS Switch", TAPAN_A_MICB_2_CTL, 4, 1, 1),
- SOC_SINGLE("MICBIAS3 CAPLESS Switch", TAPAN_A_MICB_3_CTL, 4, 1, 1),
+ SOC_SINGLE_EXT("ANC Slot", SND_SOC_NOPM, 0, 0, 100, tapan_get_anc_slot,
+ tapan_put_anc_slot),
SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
SOC_ENUM("TX2 HPF cut off", cf_dec2_enum),
@@ -606,11 +868,23 @@
SOC_SINGLE_MULTI_EXT("IIR2 Band5", IIR2, BAND5, 255, 0, 5,
tapan_get_iir_band_audio_mixer, tapan_put_iir_band_audio_mixer),
+ SOC_SINGLE_EXT("COMP0 Switch", SND_SOC_NOPM, COMPANDER_0, 1, 0,
+ tapan_get_compander, tapan_set_compander),
+ SOC_SINGLE_EXT("COMP1 Switch", SND_SOC_NOPM, COMPANDER_1, 1, 0,
+ tapan_get_compander, tapan_set_compander),
+ SOC_SINGLE_EXT("COMP2 Switch", SND_SOC_NOPM, COMPANDER_2, 1, 0,
+ tapan_get_compander, tapan_set_compander),
+
};
-static const char * const rx_mix1_text[] = {
+static const char * const rx_1_2_mix1_text[] = {
"ZERO", "SRC1", "SRC2", "IIR1", "IIR2", "RX1", "RX2", "RX3", "RX4",
- "RX5", "RX6", "RX7"
+ "RX5", "AUXRX", "AUXTX1"
+};
+
+static const char * const rx_3_4_mix1_text[] = {
+ "ZERO", "SRC1", "SRC2", "IIR1", "IIR2", "RX1", "RX2", "RX3", "RX4",
+ "RX5", "AUXRX", "AUXTX1", "AUXTX2"
};
static const char * const rx_mix2_text[] = {
@@ -621,86 +895,85 @@
"DEM4", "DEM3_INV"
};
-static const char * const rx_rdac7_text[] = {
- "DEM6", "DEM5_INV"
-};
-
-static const char * const sb_tx1_mux_text[] = {
- "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
- "DEC1"
-};
-
-static const char * const sb_tx2_mux_text[] = {
- "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
- "DEC2"
+static const char * const sb_tx_1_2_mux_text[] = {
+ "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4",
+ "RSVD", "RSVD", "RSVD",
+ "DEC1", "DEC2", "DEC3", "DEC4"
};
static const char * const sb_tx3_mux_text[] = {
- "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
- "DEC3"
+ "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4",
+ "RSVD", "RSVD", "RSVD", "RSVD", "RSVD",
+ "DEC3"
};
static const char * const sb_tx4_mux_text[] = {
- "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
- "DEC4"
+ "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4",
+ "RSVD", "RSVD", "RSVD", "RSVD", "RSVD", "RSVD",
+ "DEC4"
};
-static const char * const dec1_mux_text[] = {
- "ZERO", "DMIC1", "ADC6",
+static const char * const sb_tx5_mux_text[] = {
+ "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4",
+ "RSVD", "RSVD", "RSVD",
+ "DEC1"
};
-static const char * const dec2_mux_text[] = {
- "ZERO", "DMIC2", "ADC5",
+static const char * const dec_1_2_mux_text[] = {
+ "ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADCMB",
+ "DMIC1", "DMIC2", "DMIC3", "DMIC4"
};
static const char * const dec3_mux_text[] = {
- "ZERO", "DMIC3", "ADC4",
+ "ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5", "ADCMB",
+ "DMIC1", "DMIC2", "DMIC3", "DMIC4",
+ "ANCFBTUNE1"
};
static const char * const dec4_mux_text[] = {
- "ZERO", "DMIC4", "ADC3",
+ "ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5", "ADCMB",
+ "DMIC1", "DMIC2", "DMIC3", "DMIC4",
+ "ANCFBTUNE2"
};
static const char * const anc_mux_text[] = {
- "ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5", "ADC6", "ADC_MB",
- "RSVD_1", "DMIC1", "DMIC2", "DMIC3", "DMIC4", "DMIC5", "DMIC6"
-};
-
-static const char * const anc1_fb_mux_text[] = {
- "ZERO", "EAR_HPH_L", "EAR_LINE_1",
+ "ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5",
+ "RSVD", "RSVD", "RSVD",
+ "DMIC1", "DMIC2", "DMIC3", "DMIC4",
+ "RSVD", "RSVD"
};
static const char * const iir1_inp1_text[] = {
- "ZERO", "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
- "DEC9", "DEC10", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7"
+ "ZERO", "DEC1", "DEC2", "DEC3", "DEC4",
+ "RX1", "RX2", "RX3", "RX4", "RX5"
};
static const struct soc_enum rx_mix1_inp1_chain_enum =
- SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX1_B1_CTL, 0, 12, rx_mix1_text);
+ SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX1_B1_CTL, 0, 12, rx_1_2_mix1_text);
static const struct soc_enum rx_mix1_inp2_chain_enum =
- SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX1_B1_CTL, 4, 12, rx_mix1_text);
+ SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX1_B1_CTL, 4, 12, rx_1_2_mix1_text);
static const struct soc_enum rx_mix1_inp3_chain_enum =
- SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX1_B2_CTL, 0, 12, rx_mix1_text);
+ SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX1_B2_CTL, 0, 12, rx_1_2_mix1_text);
static const struct soc_enum rx2_mix1_inp1_chain_enum =
- SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX2_B1_CTL, 0, 12, rx_mix1_text);
+ SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX2_B1_CTL, 0, 12, rx_1_2_mix1_text);
static const struct soc_enum rx2_mix1_inp2_chain_enum =
- SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX2_B1_CTL, 4, 12, rx_mix1_text);
+ SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX2_B1_CTL, 4, 12, rx_1_2_mix1_text);
static const struct soc_enum rx3_mix1_inp1_chain_enum =
- SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX3_B1_CTL, 0, 12, rx_mix1_text);
+ SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX3_B1_CTL, 0, 13, rx_3_4_mix1_text);
static const struct soc_enum rx3_mix1_inp2_chain_enum =
- SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX3_B1_CTL, 4, 12, rx_mix1_text);
+ SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX3_B1_CTL, 4, 13, rx_3_4_mix1_text);
static const struct soc_enum rx4_mix1_inp1_chain_enum =
- SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX4_B1_CTL, 0, 12, rx_mix1_text);
+ SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX4_B1_CTL, 0, 13, rx_3_4_mix1_text);
static const struct soc_enum rx4_mix1_inp2_chain_enum =
- SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX4_B1_CTL, 4, 12, rx_mix1_text);
+ SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX4_B1_CTL, 4, 13, rx_3_4_mix1_text);
static const struct soc_enum rx1_mix2_inp1_chain_enum =
SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX1_B3_CTL, 0, 5, rx_mix2_text);
@@ -714,38 +987,52 @@
static const struct soc_enum rx2_mix2_inp2_chain_enum =
SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX2_B3_CTL, 3, 5, rx_mix2_text);
+static const struct soc_enum rx4_mix2_inp1_chain_enum =
+ SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX4_B3_CTL, 0, 5, rx_mix2_text);
+
+static const struct soc_enum rx4_mix2_inp2_chain_enum =
+ SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX4_B3_CTL, 3, 5, rx_mix2_text);
+
static const struct soc_enum rx_rdac5_enum =
SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_MISC, 2, 2, rx_rdac5_text);
-static const struct soc_enum rx_rdac7_enum =
- SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_MISC, 1, 2, rx_rdac7_text);
-
static const struct soc_enum sb_tx1_mux_enum =
- SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_SB_B1_CTL, 0, 9, sb_tx1_mux_text);
+ SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_SB_B1_CTL, 0, 12,
+ sb_tx_1_2_mux_text);
static const struct soc_enum sb_tx2_mux_enum =
- SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_SB_B2_CTL, 0, 9, sb_tx2_mux_text);
+ SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_SB_B2_CTL, 0, 12,
+ sb_tx_1_2_mux_text);
static const struct soc_enum sb_tx3_mux_enum =
- SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_SB_B3_CTL, 0, 9, sb_tx3_mux_text);
+ SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_SB_B3_CTL, 0, 11, sb_tx3_mux_text);
static const struct soc_enum sb_tx4_mux_enum =
- SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_SB_B4_CTL, 0, 9, sb_tx4_mux_text);
+ SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_SB_B4_CTL, 0, 12, sb_tx4_mux_text);
+
+static const struct soc_enum sb_tx5_mux_enum =
+ SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_SB_B5_CTL, 0, 9, sb_tx5_mux_text);
static const struct soc_enum dec1_mux_enum =
- SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_B1_CTL, 0, 3, dec1_mux_text);
+ SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_B1_CTL, 0, 10, dec_1_2_mux_text);
static const struct soc_enum dec2_mux_enum =
- SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_B1_CTL, 2, 3, dec2_mux_text);
+ SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_B1_CTL, 4, 10, dec_1_2_mux_text);
static const struct soc_enum dec3_mux_enum =
- SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_B1_CTL, 4, 3, dec3_mux_text);
+ SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_B2_CTL, 0, 12, dec3_mux_text);
static const struct soc_enum dec4_mux_enum =
- SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_B1_CTL, 6, 3, dec4_mux_text);
+ SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_B2_CTL, 4, 12, dec4_mux_text);
+
+static const struct soc_enum anc1_mux_enum =
+ SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_ANC_B1_CTL, 0, 15, anc_mux_text);
+
+static const struct soc_enum anc2_mux_enum =
+ SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_ANC_B1_CTL, 4, 15, anc_mux_text);
static const struct soc_enum iir1_inp1_mux_enum =
- SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_EQ1_B1_CTL, 0, 18, iir1_inp1_text);
+ SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_EQ1_B1_CTL, 0, 10, iir1_inp1_text);
static const struct snd_kcontrol_new rx_mix1_inp1_mux =
SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
@@ -786,6 +1073,12 @@
static const struct snd_kcontrol_new rx2_mix2_inp2_mux =
SOC_DAPM_ENUM("RX2 MIX2 INP2 Mux", rx2_mix2_inp2_chain_enum);
+static const struct snd_kcontrol_new rx4_mix2_inp1_mux =
+ SOC_DAPM_ENUM("RX4 MIX2 INP1 Mux", rx4_mix2_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx4_mix2_inp2_mux =
+ SOC_DAPM_ENUM("RX4 MIX2 INP2 Mux", rx4_mix2_inp2_chain_enum);
+
static const struct snd_kcontrol_new rx_dac5_mux =
SOC_DAPM_ENUM("RDAC5 MUX Mux", rx_rdac5_enum);
@@ -801,9 +1094,8 @@
static const struct snd_kcontrol_new sb_tx4_mux =
SOC_DAPM_ENUM("SLIM TX4 MUX Mux", sb_tx4_mux_enum);
-/*static const struct snd_kcontrol_new sb_tx5_mux =
+static const struct snd_kcontrol_new sb_tx5_mux =
SOC_DAPM_ENUM("SLIM TX5 MUX Mux", sb_tx5_mux_enum);
-*/
static int wcd9306_put_dec_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
@@ -851,23 +1143,17 @@
switch (decimator) {
case 1:
case 2:
+ if ((dec_mux >= 1) && (dec_mux <= 5))
+ adc_dmic_sel = 0x0;
+ else if ((dec_mux >= 6) && (dec_mux <= 9))
+ adc_dmic_sel = 0x1;
+ break;
case 3:
case 4:
- case 5:
- case 6:
- if (dec_mux == 1)
- adc_dmic_sel = 0x1;
- else
+ if ((dec_mux >= 1) && (dec_mux <= 6))
adc_dmic_sel = 0x0;
- break;
- case 7:
- case 8:
- case 9:
- case 10:
- if ((dec_mux == 1) || (dec_mux == 2))
+ else if ((dec_mux >= 7) && (dec_mux <= 10))
adc_dmic_sel = 0x1;
- else
- adc_dmic_sel = 0x0;
break;
default:
pr_err("%s: Invalid Decimator = %u\n", __func__, decimator);
@@ -908,6 +1194,12 @@
static const struct snd_kcontrol_new iir1_inp1_mux =
SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
+static const struct snd_kcontrol_new anc1_mux =
+ SOC_DAPM_ENUM("ANC1 MUX Mux", anc1_mux_enum);
+
+static const struct snd_kcontrol_new anc2_mux =
+ SOC_DAPM_ENUM("ANC2 MUX Mux", anc2_mux_enum);
+
static const struct snd_kcontrol_new dac1_switch[] = {
SOC_DAPM_SINGLE("Switch", TAPAN_A_RX_EAR_EN, 5, 1, 0)
};
@@ -915,6 +1207,10 @@
SOC_DAPM_SINGLE("Switch", TAPAN_A_RX_HPH_L_DAC_CTL, 6, 1, 0)
};
+static const struct snd_kcontrol_new spk_dac_switch[] = {
+ SOC_DAPM_SINGLE("Switch", TAPAN_A_SPKR_DRV_DAC_CTL, 2, 1, 0)
+};
+
static const struct snd_kcontrol_new hphl_pa_mix[] = {
SOC_DAPM_SINGLE("AUX_PGA_L Switch", TAPAN_A_RX_PA_AUX_IN_CONN,
7, 1, 0),
@@ -939,15 +1235,6 @@
3, 1, 0),
};
-static const struct snd_kcontrol_new lineout3_pa_mix[] = {
- SOC_DAPM_SINGLE("AUX_PGA_L Switch", TAPAN_A_RX_PA_AUX_IN_CONN,
- 2, 1, 0),
-};
-
-static const struct snd_kcontrol_new lineout4_pa_mix[] = {
- SOC_DAPM_SINGLE("AUX_PGA_R Switch", TAPAN_A_RX_PA_AUX_IN_CONN,
- 1, 1, 0),
-};
/* virtual port entries */
static int slim_tx_mixer_get(struct snd_kcontrol *kcontrol,
@@ -973,6 +1260,7 @@
u32 dai_id = widget->shift;
u32 port_id = mixer->shift;
u32 enable = ucontrol->value.integer.value[0];
+ u32 vtable = vport_check_table[dai_id];
dev_dbg(codec->dev, "%s: wname %s cname %s\n",
__func__, widget->name, ucontrol->id.name);
@@ -997,8 +1285,15 @@
/* only add to the list if value not set
*/
if (enable && !(widget->value & 1 << port_id)) {
+ if (tapan_p->intf_type ==
+ WCD9XXX_INTERFACE_TYPE_SLIMBUS)
+ vtable = vport_check_table[dai_id];
+ if (tapan_p->intf_type ==
+ WCD9XXX_INTERFACE_TYPE_I2C)
+ vtable = vport_i2s_check_table[dai_id];
+
if (wcd9xxx_tx_vport_validation(
- vport_check_table[dai_id],
+ vtable,
port_id,
tapan_p->dai)) {
dev_dbg(codec->dev, "%s: TX%u is used by other virtual port\n",
@@ -1009,27 +1304,29 @@
widget->value |= 1 << port_id;
list_add_tail(&core->tx_chs[port_id].list,
&tapan_p->dai[dai_id].wcd9xxx_ch_list
- );
+ );
} else if (!enable && (widget->value & 1 << port_id)) {
widget->value &= ~(1 << port_id);
list_del_init(&core->tx_chs[port_id].list);
} else {
if (enable)
- dev_dbg(codec->dev, "%s: TX%u port is used by this virtual port\n",
+ dev_dbg(codec->dev, "%s: TX%u port is used by\n"
+ "this virtual port\n",
__func__, port_id + 1);
else
- dev_dbg(codec->dev, "%s: TX%u port is not used by this virtual port\n",
+ dev_dbg(codec->dev, "%s: TX%u port is not used by\n"
+ "this virtual port\n",
__func__, port_id + 1);
/* avoid update power function */
mutex_unlock(&codec->mutex);
return 0;
}
break;
- default:
- pr_err("Unknown AIF %d\n", dai_id);
- mutex_unlock(&codec->mutex);
- return -EINVAL;
- }
+ default:
+ dev_err(codec->dev, "Unknown AIF %d\n", dai_id);
+ mutex_unlock(&codec->mutex);
+ return -EINVAL;
+ }
dev_dbg(codec->dev, "%s: name %s sname %s updated value %u shift %d\n",
__func__, widget->name, widget->sname,
widget->value, widget->shift);
@@ -1153,6 +1450,49 @@
slim_tx_mixer_get, slim_tx_mixer_put),
};
+static int tapan_codec_enable_adc(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ u16 adc_reg;
+ u8 init_bit_shift;
+
+ dev_dbg(codec->dev, "%s(): %s %d\n", __func__, w->name, event);
+
+ if (w->reg == TAPAN_A_TX_1_EN) {
+ init_bit_shift = 7;
+ adc_reg = TAPAN_A_TX_1_2_TEST_CTL;
+ } else if (w->reg == TAPAN_A_TX_2_EN) {
+ init_bit_shift = 6;
+ adc_reg = TAPAN_A_TX_1_2_TEST_CTL;
+ } else if (w->reg == TAPAN_A_TX_3_EN) {
+ init_bit_shift = 6;
+ adc_reg = TAPAN_A_TX_1_2_TEST_CTL;
+ } else if (w->reg == TAPAN_A_TX_4_EN) {
+ init_bit_shift = 7;
+ adc_reg = TAPAN_A_TX_4_5_TEST_CTL;
+ } else if (w->reg == TAPAN_A_TX_5_EN) {
+ init_bit_shift = 6;
+ adc_reg = TAPAN_A_TX_4_5_TEST_CTL;
+ } else {
+ pr_err("%s: Error, invalid adc register\n", __func__);
+ return -EINVAL;
+ }
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift,
+ 1 << init_bit_shift);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+
+ snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, 0x00);
+
+ break;
+ }
+ return 0;
+}
+
static int tapan_codec_enable_aux_pga(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
@@ -1188,6 +1528,7 @@
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = w->codec;
+ struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
u16 lineout_gain_reg;
dev_dbg(codec->dev, "%s %d %s\n", __func__, event, w->name);
@@ -1207,15 +1548,21 @@
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
- snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x40);
break;
case SND_SOC_DAPM_POST_PMU:
- dev_dbg(codec->dev, "%s: sleeping 16 ms after %s PA turn on\n",
+ wcd9xxx_clsh_fsm(codec, &tapan->clsh_d,
+ WCD9XXX_CLSH_STATE_LO,
+ WCD9XXX_CLSH_REQ_ENABLE,
+ WCD9XXX_CLSH_EVENT_POST_PA);
+ dev_dbg(codec->dev, "%s: sleeping 3 ms after %s PA turn on\n",
__func__, w->name);
- usleep_range(16000, 16000);
+ usleep_range(3000, 3010);
break;
case SND_SOC_DAPM_POST_PMD:
- snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x00);
+ wcd9xxx_clsh_fsm(codec, &tapan->clsh_d,
+ WCD9XXX_CLSH_STATE_LO,
+ WCD9XXX_CLSH_REQ_DISABLE,
+ WCD9XXX_CLSH_EVENT_POST_PA);
break;
}
return 0;
@@ -1224,7 +1571,22 @@
static int tapan_codec_enable_spk_pa(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
- dev_dbg(w->codec->dev, "%s %d %s\n", __func__, event, w->name);
+ struct snd_soc_codec *codec = w->codec;
+ struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
+
+ dev_dbg(codec->dev, "%s: %s %d\n", __func__, w->name, event);
+ WCD9XXX_BCL_LOCK(&tapan->resmgr);
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ tapan->spkr_pa_widget_on = true;
+ snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_EN, 0x80, 0x80);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ tapan->spkr_pa_widget_on = false;
+ snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_EN, 0x80, 0x00);
+ break;
+ }
+ WCD9XXX_BCL_UNLOCK(&tapan->resmgr);
return 0;
}
@@ -1239,7 +1601,7 @@
unsigned int dmic;
int ret;
- ret = kstrtouint(strpbrk(w->name, "123456"), 10, &dmic);
+ ret = kstrtouint(strpbrk(w->name, "1234"), 10, &dmic);
if (ret < 0) {
pr_err("%s: Invalid DMIC line on the codec\n", __func__);
return -EINVAL;
@@ -1266,17 +1628,6 @@
__func__, event, dmic, *dmic_clk_cnt);
break;
- case 5:
- case 6:
- dmic_clk_en = 0x01;
- dmic_clk_cnt = &(tapan->dmic_5_6_clk_cnt);
- dmic_clk_reg = TAPAN_A_CDC_CLK_DMIC_B2_CTL;
-
- dev_dbg(codec->dev, "%s() event %d DMIC%d dmic_5_6_clk_cnt %d\n",
- __func__, event, dmic, *dmic_clk_cnt);
-
- break;
-
default:
pr_err("%s: Invalid DMIC Selection\n", __func__);
return -EINVAL;
@@ -1600,7 +1951,7 @@
msecs_to_jiffies(300));
}
/* apply the digital gain after the decimator is enabled*/
- if ((w->shift) < ARRAY_SIZE(tx_digital_gain_reg))
+ if ((w->shift + offset) < ARRAY_SIZE(tx_digital_gain_reg))
snd_soc_write(codec,
tx_digital_gain_reg[w->shift + offset],
snd_soc_read(codec,
@@ -1628,6 +1979,42 @@
return ret;
}
+static int tapan_codec_enable_vdd_spkr(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
+
+ dev_dbg(codec->dev, "%s: %s %d\n", __func__, w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+
+ if (spkr_drv_wrnd > 0) {
+ WARN_ON(!(snd_soc_read(codec, TAPAN_A_SPKR_DRV_EN) &
+ 0x80));
+ snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_EN, 0x80,
+ 0x00);
+ }
+ if (TAPAN_IS_1_0(core->version))
+ snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_DBG_PWRSTG,
+ 0x24, 0x00);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ if (TAPAN_IS_1_0(core->version))
+ snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_DBG_PWRSTG,
+ 0x24, 0x24);
+ if (spkr_drv_wrnd > 0) {
+ WARN_ON(!!(snd_soc_read(codec, TAPAN_A_SPKR_DRV_EN) &
+ 0x80));
+ snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_EN, 0x80,
+ 0x80);
+ }
+ break;
+ }
+ return 0;
+}
+
static int tapan_codec_enable_interpolator(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
@@ -1685,18 +2072,53 @@
}
return 0;
}
-static int tapan_hphr_dac_event(struct snd_soc_dapm_widget *w,
+
+
+static int tapan_hphl_dac_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = w->codec;
+ struct tapan_priv *tapan_p = snd_soc_codec_get_drvdata(codec);
dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
- snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
+ snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_RDAC_CLK_EN_CTL,
+ 0x02, 0x02);
+ wcd9xxx_clsh_fsm(codec, &tapan_p->clsh_d,
+ WCD9XXX_CLSH_STATE_HPHL,
+ WCD9XXX_CLSH_REQ_ENABLE,
+ WCD9XXX_CLSH_EVENT_PRE_DAC);
break;
case SND_SOC_DAPM_POST_PMD:
+ snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_RDAC_CLK_EN_CTL,
+ 0x02, 0x00);
+ }
+ return 0;
+}
+
+static int tapan_hphr_dac_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ struct tapan_priv *tapan_p = snd_soc_codec_get_drvdata(codec);
+
+ dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_RDAC_CLK_EN_CTL,
+ 0x04, 0x04);
+ snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
+ wcd9xxx_clsh_fsm(codec, &tapan_p->clsh_d,
+ WCD9XXX_CLSH_STATE_HPHR,
+ WCD9XXX_CLSH_REQ_ENABLE,
+ WCD9XXX_CLSH_EVENT_PRE_DAC);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_RDAC_CLK_EN_CTL,
+ 0x04, 0x00);
snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
break;
}
@@ -1709,14 +2131,17 @@
struct snd_soc_codec *codec = w->codec;
struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
enum wcd9xxx_notify_event e_pre_on, e_post_off;
+ u8 req_clsh_state;
dev_dbg(codec->dev, "%s: %s event = %d\n", __func__, w->name, event);
if (w->shift == 5) {
e_pre_on = WCD9XXX_EVENT_PRE_HPHR_PA_ON;
e_post_off = WCD9XXX_EVENT_POST_HPHR_PA_OFF;
+ req_clsh_state = WCD9XXX_CLSH_STATE_HPHL;
} else if (w->shift == 4) {
e_pre_on = WCD9XXX_EVENT_PRE_HPHL_PA_ON;
e_post_off = WCD9XXX_EVENT_POST_HPHL_PA_OFF;
+ req_clsh_state = WCD9XXX_CLSH_STATE_HPHR;
} else {
pr_err("%s: Invalid w->shift %d\n", __func__, w->shift);
return -EINVAL;
@@ -1729,43 +2154,51 @@
break;
case SND_SOC_DAPM_POST_PMU:
- usleep_range(10000, 10000);
+ wcd9xxx_clsh_fsm(codec, &tapan->clsh_d,
+ req_clsh_state,
+ WCD9XXX_CLSH_REQ_ENABLE,
+ WCD9XXX_CLSH_EVENT_POST_PA);
- snd_soc_update_bits(codec, TAPAN_A_BUCK_MODE_5, 0x02, 0x00);
- snd_soc_update_bits(codec, TAPAN_A_NCP_STATIC, 0x20, 0x00);
- snd_soc_update_bits(codec, TAPAN_A_BUCK_MODE_3, 0x04, 0x04);
- snd_soc_update_bits(codec, TAPAN_A_BUCK_MODE_3, 0x08, 0x00);
- usleep_range(10, 10);
+ usleep_range(5000, 5010);
break;
case SND_SOC_DAPM_POST_PMD:
/* Let MBHC module know PA turned off */
wcd9xxx_resmgr_notifier_call(&tapan->resmgr, e_post_off);
- /*
- * schedule work is required because at the time HPH PA DAPM
- * event callback is called by DAPM framework, CODEC dapm mutex
- * would have been locked while snd_soc_jack_report also
- * attempts to acquire same lock.
- */
+ wcd9xxx_clsh_fsm(codec, &tapan->clsh_d,
+ req_clsh_state,
+ WCD9XXX_CLSH_REQ_DISABLE,
+ WCD9XXX_CLSH_EVENT_POST_PA);
+
dev_dbg(codec->dev, "%s: sleep 10 ms after %s PA disable.\n",
__func__, w->name);
- usleep_range(5000, 5000);
+ usleep_range(5000, 5010);
break;
}
return 0;
}
+static const struct snd_soc_dapm_widget tapan_dapm_i2s_widgets[] = {
+ SND_SOC_DAPM_SUPPLY("I2S_CLK", TAPAN_A_CDC_CLK_I2S_CTL,
+ 4, 0, NULL, 0),
+};
+
static int tapan_lineout_dac_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = w->codec;
+ struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
+ wcd9xxx_clsh_fsm(codec, &tapan->clsh_d,
+ WCD9XXX_CLSH_STATE_LO,
+ WCD9XXX_CLSH_REQ_ENABLE,
+ WCD9XXX_CLSH_EVENT_PRE_DAC);
snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
break;
@@ -1786,12 +2219,12 @@
}
static const struct snd_soc_dapm_route audio_i2s_map[] = {
- {"RX_I2S_CLK", NULL, "CDC_CONN"},
- {"SLIM RX1", NULL, "RX_I2S_CLK"},
- {"SLIM RX2", NULL, "RX_I2S_CLK"},
+ {"I2S_CLK", NULL, "CDC_CONN"},
+ {"SLIM RX1", NULL, "I2S_CLK"},
+ {"SLIM RX2", NULL, "I2S_CLK"},
- {"SLIM TX1 MUX", NULL, "TX_I2S_CLK"},
- {"SLIM TX2 MUX", NULL, "TX_I2S_CLK"},
+ {"SLIM TX1 MUX", NULL, "I2S_CLK"},
+ {"SLIM TX2 MUX", NULL, "I2S_CLK"},
};
static const struct snd_soc_dapm_route audio_map[] = {
@@ -1806,122 +2239,60 @@
{"AIF1_CAP Mixer", "SLIM TX3", "SLIM TX3 MUX"},
{"AIF1_CAP Mixer", "SLIM TX4", "SLIM TX4 MUX"},
{"AIF1_CAP Mixer", "SLIM TX5", "SLIM TX5 MUX"},
- {"AIF1_CAP Mixer", "SLIM TX6", "SLIM TX6 MUX"},
- {"AIF1_CAP Mixer", "SLIM TX7", "SLIM TX7 MUX"},
- {"AIF1_CAP Mixer", "SLIM TX8", "SLIM TX8 MUX"},
- {"AIF1_CAP Mixer", "SLIM TX9", "SLIM TX9 MUX"},
- {"AIF1_CAP Mixer", "SLIM TX10", "SLIM TX10 MUX"},
/* SLIM_MIXER("AIF2_CAP Mixer"),*/
{"AIF2_CAP Mixer", "SLIM TX1", "SLIM TX1 MUX"},
{"AIF2_CAP Mixer", "SLIM TX2", "SLIM TX2 MUX"},
{"AIF2_CAP Mixer", "SLIM TX3", "SLIM TX3 MUX"},
{"AIF2_CAP Mixer", "SLIM TX4", "SLIM TX4 MUX"},
{"AIF2_CAP Mixer", "SLIM TX5", "SLIM TX5 MUX"},
- {"AIF2_CAP Mixer", "SLIM TX6", "SLIM TX6 MUX"},
- {"AIF2_CAP Mixer", "SLIM TX7", "SLIM TX7 MUX"},
- {"AIF2_CAP Mixer", "SLIM TX8", "SLIM TX8 MUX"},
- {"AIF2_CAP Mixer", "SLIM TX9", "SLIM TX9 MUX"},
- {"AIF2_CAP Mixer", "SLIM TX10", "SLIM TX10 MUX"},
/* SLIM_MIXER("AIF3_CAP Mixer"),*/
{"AIF3_CAP Mixer", "SLIM TX1", "SLIM TX1 MUX"},
{"AIF3_CAP Mixer", "SLIM TX2", "SLIM TX2 MUX"},
{"AIF3_CAP Mixer", "SLIM TX3", "SLIM TX3 MUX"},
{"AIF3_CAP Mixer", "SLIM TX4", "SLIM TX4 MUX"},
{"AIF3_CAP Mixer", "SLIM TX5", "SLIM TX5 MUX"},
- {"AIF3_CAP Mixer", "SLIM TX6", "SLIM TX6 MUX"},
- {"AIF3_CAP Mixer", "SLIM TX7", "SLIM TX7 MUX"},
- {"AIF3_CAP Mixer", "SLIM TX8", "SLIM TX8 MUX"},
- {"AIF3_CAP Mixer", "SLIM TX9", "SLIM TX9 MUX"},
- {"AIF3_CAP Mixer", "SLIM TX10", "SLIM TX10 MUX"},
{"SLIM TX1 MUX", "DEC1", "DEC1 MUX"},
+ {"SLIM TX1 MUX", "DEC2", "DEC2 MUX"},
+ {"SLIM TX1 MUX", "DEC3", "DEC3 MUX"},
+ {"SLIM TX1 MUX", "DEC4", "DEC4 MUX"},
+ {"SLIM TX1 MUX", "RMIX1", "RX1 MIX1"},
+ {"SLIM TX1 MUX", "RMIX2", "RX2 MIX1"},
+ {"SLIM TX1 MUX", "RMIX3", "RX3 MIX1"},
+ {"SLIM TX1 MUX", "RMIX4", "RX4 MIX1"},
+ {"SLIM TX2 MUX", "DEC1", "DEC1 MUX"},
{"SLIM TX2 MUX", "DEC2", "DEC2 MUX"},
+ {"SLIM TX2 MUX", "DEC3", "DEC3 MUX"},
+ {"SLIM TX2 MUX", "DEC4", "DEC4 MUX"},
+ {"SLIM TX2 MUX", "RMIX1", "RX1 MIX1"},
+ {"SLIM TX2 MUX", "RMIX2", "RX2 MIX1"},
+ {"SLIM TX2 MUX", "RMIX3", "RX3 MIX1"},
+ {"SLIM TX2 MUX", "RMIX4", "RX4 MIX1"},
{"SLIM TX3 MUX", "DEC3", "DEC3 MUX"},
{"SLIM TX3 MUX", "RMIX1", "RX1 MIX1"},
{"SLIM TX3 MUX", "RMIX2", "RX2 MIX1"},
{"SLIM TX3 MUX", "RMIX3", "RX3 MIX1"},
{"SLIM TX3 MUX", "RMIX4", "RX4 MIX1"},
- {"SLIM TX3 MUX", "RMIX5", "RX5 MIX1"},
- {"SLIM TX3 MUX", "RMIX6", "RX6 MIX1"},
- {"SLIM TX3 MUX", "RMIX7", "RX7 MIX1"},
{"SLIM TX4 MUX", "DEC4", "DEC4 MUX"},
+ {"SLIM TX4 MUX", "RMIX1", "RX1 MIX1"},
+ {"SLIM TX4 MUX", "RMIX2", "RX2 MIX1"},
+ {"SLIM TX4 MUX", "RMIX3", "RX3 MIX1"},
+ {"SLIM TX4 MUX", "RMIX4", "RX4 MIX1"},
- {"SLIM TX5 MUX", "DEC5", "DEC5 MUX"},
+ {"SLIM TX5 MUX", "DEC1", "DEC1 MUX"},
{"SLIM TX5 MUX", "RMIX1", "RX1 MIX1"},
{"SLIM TX5 MUX", "RMIX2", "RX2 MIX1"},
{"SLIM TX5 MUX", "RMIX3", "RX3 MIX1"},
{"SLIM TX5 MUX", "RMIX4", "RX4 MIX1"},
- {"SLIM TX5 MUX", "RMIX5", "RX5 MIX1"},
- {"SLIM TX5 MUX", "RMIX6", "RX6 MIX1"},
- {"SLIM TX5 MUX", "RMIX7", "RX7 MIX1"},
-
- {"SLIM TX6 MUX", "DEC6", "DEC6 MUX"},
-
- {"SLIM TX7 MUX", "DEC1", "DEC1 MUX"},
- {"SLIM TX7 MUX", "DEC2", "DEC2 MUX"},
- {"SLIM TX7 MUX", "DEC3", "DEC3 MUX"},
- {"SLIM TX7 MUX", "DEC4", "DEC4 MUX"},
- {"SLIM TX7 MUX", "DEC5", "DEC5 MUX"},
- {"SLIM TX7 MUX", "DEC6", "DEC6 MUX"},
- {"SLIM TX7 MUX", "DEC7", "DEC7 MUX"},
- {"SLIM TX7 MUX", "DEC8", "DEC8 MUX"},
- {"SLIM TX7 MUX", "DEC9", "DEC9 MUX"},
- {"SLIM TX7 MUX", "DEC10", "DEC10 MUX"},
- {"SLIM TX7 MUX", "RMIX1", "RX1 MIX1"},
- {"SLIM TX7 MUX", "RMIX2", "RX2 MIX1"},
- {"SLIM TX7 MUX", "RMIX3", "RX3 MIX1"},
- {"SLIM TX7 MUX", "RMIX4", "RX4 MIX1"},
- {"SLIM TX7 MUX", "RMIX5", "RX5 MIX1"},
- {"SLIM TX7 MUX", "RMIX6", "RX6 MIX1"},
- {"SLIM TX7 MUX", "RMIX7", "RX7 MIX1"},
-
- {"SLIM TX8 MUX", "DEC1", "DEC1 MUX"},
- {"SLIM TX8 MUX", "DEC2", "DEC2 MUX"},
- {"SLIM TX8 MUX", "DEC3", "DEC3 MUX"},
- {"SLIM TX8 MUX", "DEC4", "DEC4 MUX"},
- {"SLIM TX8 MUX", "DEC5", "DEC5 MUX"},
- {"SLIM TX8 MUX", "DEC6", "DEC6 MUX"},
- {"SLIM TX8 MUX", "DEC7", "DEC7 MUX"},
- {"SLIM TX8 MUX", "DEC8", "DEC8 MUX"},
- {"SLIM TX8 MUX", "DEC9", "DEC9 MUX"},
- {"SLIM TX8 MUX", "DEC10", "DEC10 MUX"},
-
- {"SLIM TX9 MUX", "DEC1", "DEC1 MUX"},
- {"SLIM TX9 MUX", "DEC2", "DEC2 MUX"},
- {"SLIM TX9 MUX", "DEC3", "DEC3 MUX"},
- {"SLIM TX9 MUX", "DEC4", "DEC4 MUX"},
- {"SLIM TX9 MUX", "DEC5", "DEC5 MUX"},
- {"SLIM TX9 MUX", "DEC6", "DEC6 MUX"},
- {"SLIM TX9 MUX", "DEC7", "DEC7 MUX"},
- {"SLIM TX9 MUX", "DEC8", "DEC8 MUX"},
- {"SLIM TX9 MUX", "DEC9", "DEC9 MUX"},
- {"SLIM TX9 MUX", "DEC10", "DEC10 MUX"},
-
- {"SLIM TX10 MUX", "DEC1", "DEC1 MUX"},
- {"SLIM TX10 MUX", "DEC2", "DEC2 MUX"},
- {"SLIM TX10 MUX", "DEC3", "DEC3 MUX"},
- {"SLIM TX10 MUX", "DEC4", "DEC4 MUX"},
- {"SLIM TX10 MUX", "DEC5", "DEC5 MUX"},
- {"SLIM TX10 MUX", "DEC6", "DEC6 MUX"},
- {"SLIM TX10 MUX", "DEC7", "DEC7 MUX"},
- {"SLIM TX10 MUX", "DEC8", "DEC8 MUX"},
- {"SLIM TX10 MUX", "DEC9", "DEC9 MUX"},
- {"SLIM TX10 MUX", "DEC10", "DEC10 MUX"},
/* Earpiece (RX MIX1) */
{"EAR", NULL, "EAR PA"},
{"EAR PA", NULL, "EAR_PA_MIXER"},
{"EAR_PA_MIXER", NULL, "DAC1"},
- {"DAC1", NULL, "CP"},
- {"CP", NULL, "CLASS_H_EAR"},
- {"CLASS_H_EAR", NULL, "CLASS_H_CLK"},
-
- {"ANC1 FB MUX", "EAR_HPH_L", "RX1 MIX2"},
- {"ANC1 FB MUX", "EAR_LINE_1", "RX2 MIX2"},
- {"ANC", NULL, "ANC1 FB MUX"},
+ {"DAC1", NULL, "RX_BIAS"},
/* Headset (RX MIX1 and RX MIX2) */
{"HEADPHONE", NULL, "HPHL"},
@@ -1929,93 +2300,47 @@
{"HPHL", NULL, "HPHL_PA_MIXER"},
{"HPHL_PA_MIXER", NULL, "HPHL DAC"},
+ {"HPHL DAC", NULL, "RX_BIAS"},
{"HPHR", NULL, "HPHR_PA_MIXER"},
{"HPHR_PA_MIXER", NULL, "HPHR DAC"},
+ {"HPHR DAC", NULL, "RX_BIAS"},
- {"HPHL DAC", NULL, "CP"},
- {"CP", NULL, "CLASS_H_HPH_L"},
- {"CLASS_H_HPH_L", NULL, "CLASS_H_CLK"},
-
- {"HPHR DAC", NULL, "CP"},
- {"CP", NULL, "CLASS_H_HPH_R"},
- {"CLASS_H_HPH_R", NULL, "CLASS_H_CLK"},
-
- {"ANC", NULL, "ANC1 MUX"},
- {"ANC", NULL, "ANC2 MUX"},
- {"ANC1 MUX", "ADC1", "ADC1"},
- {"ANC1 MUX", "ADC2", "ADC2"},
- {"ANC1 MUX", "ADC3", "ADC3"},
- {"ANC1 MUX", "ADC4", "ADC4"},
- {"ANC2 MUX", "ADC1", "ADC1"},
- {"ANC2 MUX", "ADC2", "ADC2"},
- {"ANC2 MUX", "ADC3", "ADC3"},
- {"ANC2 MUX", "ADC4", "ADC4"},
-
- {"ANC", NULL, "CDC_CONN"},
-
- {"DAC1", "Switch", "RX1 CHAIN"},
- {"HPHL DAC", "Switch", "RX1 CHAIN"},
+ {"DAC1", "Switch", "CLASS_H_DSM MUX"},
+ {"HPHL DAC", "Switch", "CLASS_H_DSM MUX"},
{"HPHR DAC", NULL, "RX2 CHAIN"},
{"LINEOUT1", NULL, "LINEOUT1 PA"},
{"LINEOUT2", NULL, "LINEOUT2 PA"},
- {"LINEOUT3", NULL, "LINEOUT3 PA"},
- {"LINEOUT4", NULL, "LINEOUT4 PA"},
{"SPK_OUT", NULL, "SPK PA"},
- {"LINEOUT1 PA", NULL, "CP"},
{"LINEOUT1 PA", NULL, "LINEOUT1_PA_MIXER"},
{"LINEOUT1_PA_MIXER", NULL, "LINEOUT1 DAC"},
- {"LINEOUT2 PA", NULL, "CP"},
{"LINEOUT2 PA", NULL, "LINEOUT2_PA_MIXER"},
{"LINEOUT2_PA_MIXER", NULL, "LINEOUT2 DAC"},
- {"LINEOUT3 PA", NULL, "CP"},
- {"LINEOUT3 PA", NULL, "LINEOUT3_PA_MIXER"},
- {"LINEOUT3_PA_MIXER", NULL, "LINEOUT3 DAC"},
-
- {"LINEOUT4 PA", NULL, "CP"},
- {"LINEOUT4 PA", NULL, "LINEOUT4_PA_MIXER"},
- {"LINEOUT4_PA_MIXER", NULL, "LINEOUT4 DAC"},
-
- {"CP", NULL, "CLASS_H_LINEOUTS_PA"},
- {"CLASS_H_LINEOUTS_PA", NULL, "CLASS_H_CLK"},
-
{"LINEOUT1 DAC", NULL, "RX3 MIX1"},
{"RDAC5 MUX", "DEM3_INV", "RX3 MIX1"},
- {"RDAC5 MUX", "DEM4", "RX4 MIX1"},
+ {"RDAC5 MUX", "DEM4", "RX4 MIX2"},
- {"LINEOUT3 DAC", NULL, "RDAC5 MUX"},
-
- {"LINEOUT2 DAC", NULL, "RX5 MIX1"},
-
- {"RDAC7 MUX", "DEM5_INV", "RX5 MIX1"},
- {"RDAC7 MUX", "DEM6", "RX6 MIX1"},
-
- {"LINEOUT4 DAC", NULL, "RDAC7 MUX"},
+ {"LINEOUT2 DAC", NULL, "RDAC5 MUX"},
{"SPK PA", NULL, "SPK DAC"},
- {"SPK DAC", NULL, "RX7 MIX2"},
+ {"SPK DAC", "Switch", "RX4 MIX2"},
+ {"SPK DAC", NULL, "VDD_SPKDRV"},
{"RX1 CHAIN", NULL, "RX1 MIX2"},
{"RX2 CHAIN", NULL, "RX2 MIX2"},
- {"RX1 CHAIN", NULL, "ANC"},
- {"RX2 CHAIN", NULL, "ANC"},
+ {"CLASS_H_DSM MUX", "RX_HPHL", "RX1 CHAIN"},
- {"CLASS_H_CLK", NULL, "RX_BIAS"},
{"LINEOUT1 DAC", NULL, "RX_BIAS"},
{"LINEOUT2 DAC", NULL, "RX_BIAS"},
- {"LINEOUT3 DAC", NULL, "RX_BIAS"},
- {"LINEOUT4 DAC", NULL, "RX_BIAS"},
- {"SPK DAC", NULL, "RX_BIAS"},
{"RX1 MIX1", NULL, "COMP1_CLK"},
{"RX2 MIX1", NULL, "COMP1_CLK"},
{"RX3 MIX1", NULL, "COMP2_CLK"},
- {"RX5 MIX1", NULL, "COMP2_CLK"},
{"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
{"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
@@ -2026,21 +2351,15 @@
{"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
{"RX4 MIX1", NULL, "RX4 MIX1 INP1"},
{"RX4 MIX1", NULL, "RX4 MIX1 INP2"},
- {"RX5 MIX1", NULL, "RX5 MIX1 INP1"},
- {"RX5 MIX1", NULL, "RX5 MIX1 INP2"},
- {"RX6 MIX1", NULL, "RX6 MIX1 INP1"},
- {"RX6 MIX1", NULL, "RX6 MIX1 INP2"},
- {"RX7 MIX1", NULL, "RX7 MIX1 INP1"},
- {"RX7 MIX1", NULL, "RX7 MIX1 INP2"},
{"RX1 MIX2", NULL, "RX1 MIX1"},
{"RX1 MIX2", NULL, "RX1 MIX2 INP1"},
{"RX1 MIX2", NULL, "RX1 MIX2 INP2"},
{"RX2 MIX2", NULL, "RX2 MIX1"},
{"RX2 MIX2", NULL, "RX2 MIX2 INP1"},
{"RX2 MIX2", NULL, "RX2 MIX2 INP2"},
- {"RX7 MIX2", NULL, "RX7 MIX1"},
- {"RX7 MIX2", NULL, "RX7 MIX2 INP1"},
- {"RX7 MIX2", NULL, "RX7 MIX2 INP2"},
+ {"RX4 MIX2", NULL, "RX4 MIX1"},
+ {"RX4 MIX2", NULL, "RX4 MIX2 INP1"},
+ {"RX4 MIX2", NULL, "RX4 MIX2 INP2"},
/* SLIM_MUX("AIF1_PB", "AIF1 PB"),*/
{"SLIM RX1 MUX", "AIF1_PB", "AIF1 PB"},
@@ -2048,198 +2367,128 @@
{"SLIM RX3 MUX", "AIF1_PB", "AIF1 PB"},
{"SLIM RX4 MUX", "AIF1_PB", "AIF1 PB"},
{"SLIM RX5 MUX", "AIF1_PB", "AIF1 PB"},
- {"SLIM RX6 MUX", "AIF1_PB", "AIF1 PB"},
- {"SLIM RX7 MUX", "AIF1_PB", "AIF1 PB"},
/* SLIM_MUX("AIF2_PB", "AIF2 PB"),*/
{"SLIM RX1 MUX", "AIF2_PB", "AIF2 PB"},
{"SLIM RX2 MUX", "AIF2_PB", "AIF2 PB"},
{"SLIM RX3 MUX", "AIF2_PB", "AIF2 PB"},
{"SLIM RX4 MUX", "AIF2_PB", "AIF2 PB"},
{"SLIM RX5 MUX", "AIF2_PB", "AIF2 PB"},
- {"SLIM RX6 MUX", "AIF2_PB", "AIF2 PB"},
- {"SLIM RX7 MUX", "AIF2_PB", "AIF2 PB"},
/* SLIM_MUX("AIF3_PB", "AIF3 PB"),*/
{"SLIM RX1 MUX", "AIF3_PB", "AIF3 PB"},
{"SLIM RX2 MUX", "AIF3_PB", "AIF3 PB"},
{"SLIM RX3 MUX", "AIF3_PB", "AIF3 PB"},
{"SLIM RX4 MUX", "AIF3_PB", "AIF3 PB"},
{"SLIM RX5 MUX", "AIF3_PB", "AIF3 PB"},
- {"SLIM RX6 MUX", "AIF3_PB", "AIF3 PB"},
- {"SLIM RX7 MUX", "AIF3_PB", "AIF3 PB"},
{"SLIM RX1", NULL, "SLIM RX1 MUX"},
{"SLIM RX2", NULL, "SLIM RX2 MUX"},
{"SLIM RX3", NULL, "SLIM RX3 MUX"},
{"SLIM RX4", NULL, "SLIM RX4 MUX"},
{"SLIM RX5", NULL, "SLIM RX5 MUX"},
- {"SLIM RX6", NULL, "SLIM RX6 MUX"},
- {"SLIM RX7", NULL, "SLIM RX7 MUX"},
{"RX1 MIX1 INP1", "RX1", "SLIM RX1"},
{"RX1 MIX1 INP1", "RX2", "SLIM RX2"},
{"RX1 MIX1 INP1", "RX3", "SLIM RX3"},
{"RX1 MIX1 INP1", "RX4", "SLIM RX4"},
{"RX1 MIX1 INP1", "RX5", "SLIM RX5"},
- {"RX1 MIX1 INP1", "RX6", "SLIM RX6"},
- {"RX1 MIX1 INP1", "RX7", "SLIM RX7"},
{"RX1 MIX1 INP1", "IIR1", "IIR1"},
{"RX1 MIX1 INP2", "RX1", "SLIM RX1"},
{"RX1 MIX1 INP2", "RX2", "SLIM RX2"},
{"RX1 MIX1 INP2", "RX3", "SLIM RX3"},
{"RX1 MIX1 INP2", "RX4", "SLIM RX4"},
{"RX1 MIX1 INP2", "RX5", "SLIM RX5"},
- {"RX1 MIX1 INP2", "RX6", "SLIM RX6"},
- {"RX1 MIX1 INP2", "RX7", "SLIM RX7"},
{"RX1 MIX1 INP2", "IIR1", "IIR1"},
{"RX1 MIX1 INP3", "RX1", "SLIM RX1"},
{"RX1 MIX1 INP3", "RX2", "SLIM RX2"},
{"RX1 MIX1 INP3", "RX3", "SLIM RX3"},
{"RX1 MIX1 INP3", "RX4", "SLIM RX4"},
{"RX1 MIX1 INP3", "RX5", "SLIM RX5"},
- {"RX1 MIX1 INP3", "RX6", "SLIM RX6"},
- {"RX1 MIX1 INP3", "RX7", "SLIM RX7"},
{"RX2 MIX1 INP1", "RX1", "SLIM RX1"},
{"RX2 MIX1 INP1", "RX2", "SLIM RX2"},
{"RX2 MIX1 INP1", "RX3", "SLIM RX3"},
{"RX2 MIX1 INP1", "RX4", "SLIM RX4"},
{"RX2 MIX1 INP1", "RX5", "SLIM RX5"},
- {"RX2 MIX1 INP1", "RX6", "SLIM RX6"},
- {"RX2 MIX1 INP1", "RX7", "SLIM RX7"},
{"RX2 MIX1 INP1", "IIR1", "IIR1"},
{"RX2 MIX1 INP2", "RX1", "SLIM RX1"},
{"RX2 MIX1 INP2", "RX2", "SLIM RX2"},
{"RX2 MIX1 INP2", "RX3", "SLIM RX3"},
{"RX2 MIX1 INP2", "RX4", "SLIM RX4"},
{"RX2 MIX1 INP2", "RX5", "SLIM RX5"},
- {"RX2 MIX1 INP2", "RX6", "SLIM RX6"},
- {"RX2 MIX1 INP2", "RX7", "SLIM RX7"},
{"RX2 MIX1 INP2", "IIR1", "IIR1"},
{"RX3 MIX1 INP1", "RX1", "SLIM RX1"},
{"RX3 MIX1 INP1", "RX2", "SLIM RX2"},
{"RX3 MIX1 INP1", "RX3", "SLIM RX3"},
{"RX3 MIX1 INP1", "RX4", "SLIM RX4"},
{"RX3 MIX1 INP1", "RX5", "SLIM RX5"},
- {"RX3 MIX1 INP1", "RX6", "SLIM RX6"},
- {"RX3 MIX1 INP1", "RX7", "SLIM RX7"},
{"RX3 MIX1 INP1", "IIR1", "IIR1"},
{"RX3 MIX1 INP2", "RX1", "SLIM RX1"},
{"RX3 MIX1 INP2", "RX2", "SLIM RX2"},
{"RX3 MIX1 INP2", "RX3", "SLIM RX3"},
{"RX3 MIX1 INP2", "RX4", "SLIM RX4"},
{"RX3 MIX1 INP2", "RX5", "SLIM RX5"},
- {"RX3 MIX1 INP2", "RX6", "SLIM RX6"},
- {"RX3 MIX1 INP2", "RX7", "SLIM RX7"},
{"RX3 MIX1 INP2", "IIR1", "IIR1"},
{"RX4 MIX1 INP1", "RX1", "SLIM RX1"},
{"RX4 MIX1 INP1", "RX2", "SLIM RX2"},
{"RX4 MIX1 INP1", "RX3", "SLIM RX3"},
{"RX4 MIX1 INP1", "RX4", "SLIM RX4"},
{"RX4 MIX1 INP1", "RX5", "SLIM RX5"},
- {"RX4 MIX1 INP1", "RX6", "SLIM RX6"},
- {"RX4 MIX1 INP1", "RX7", "SLIM RX7"},
{"RX4 MIX1 INP1", "IIR1", "IIR1"},
{"RX4 MIX1 INP2", "RX1", "SLIM RX1"},
{"RX4 MIX1 INP2", "RX2", "SLIM RX2"},
{"RX4 MIX1 INP2", "RX3", "SLIM RX3"},
{"RX4 MIX1 INP2", "RX5", "SLIM RX5"},
{"RX4 MIX1 INP2", "RX4", "SLIM RX4"},
- {"RX4 MIX1 INP2", "RX6", "SLIM RX6"},
- {"RX4 MIX1 INP2", "RX7", "SLIM RX7"},
{"RX4 MIX1 INP2", "IIR1", "IIR1"},
- {"RX5 MIX1 INP1", "RX1", "SLIM RX1"},
- {"RX5 MIX1 INP1", "RX2", "SLIM RX2"},
- {"RX5 MIX1 INP1", "RX3", "SLIM RX3"},
- {"RX5 MIX1 INP1", "RX4", "SLIM RX4"},
- {"RX5 MIX1 INP1", "RX5", "SLIM RX5"},
- {"RX5 MIX1 INP1", "RX6", "SLIM RX6"},
- {"RX5 MIX1 INP1", "RX7", "SLIM RX7"},
- {"RX5 MIX1 INP1", "IIR1", "IIR1"},
- {"RX5 MIX1 INP2", "RX1", "SLIM RX1"},
- {"RX5 MIX1 INP2", "RX2", "SLIM RX2"},
- {"RX5 MIX1 INP2", "RX3", "SLIM RX3"},
- {"RX5 MIX1 INP2", "RX4", "SLIM RX4"},
- {"RX5 MIX1 INP2", "RX5", "SLIM RX5"},
- {"RX5 MIX1 INP2", "RX6", "SLIM RX6"},
- {"RX5 MIX1 INP2", "RX7", "SLIM RX7"},
- {"RX5 MIX1 INP2", "IIR1", "IIR1"},
- {"RX6 MIX1 INP1", "RX1", "SLIM RX1"},
- {"RX6 MIX1 INP1", "RX2", "SLIM RX2"},
- {"RX6 MIX1 INP1", "RX3", "SLIM RX3"},
- {"RX6 MIX1 INP1", "RX4", "SLIM RX4"},
- {"RX6 MIX1 INP1", "RX5", "SLIM RX5"},
- {"RX6 MIX1 INP1", "RX6", "SLIM RX6"},
- {"RX6 MIX1 INP1", "RX7", "SLIM RX7"},
- {"RX6 MIX1 INP1", "IIR1", "IIR1"},
- {"RX6 MIX1 INP2", "RX1", "SLIM RX1"},
- {"RX6 MIX1 INP2", "RX2", "SLIM RX2"},
- {"RX6 MIX1 INP2", "RX3", "SLIM RX3"},
- {"RX6 MIX1 INP2", "RX4", "SLIM RX4"},
- {"RX6 MIX1 INP2", "RX5", "SLIM RX5"},
- {"RX6 MIX1 INP2", "RX6", "SLIM RX6"},
- {"RX6 MIX1 INP2", "RX7", "SLIM RX7"},
- {"RX6 MIX1 INP2", "IIR1", "IIR1"},
- {"RX7 MIX1 INP1", "RX1", "SLIM RX1"},
- {"RX7 MIX1 INP1", "RX2", "SLIM RX2"},
- {"RX7 MIX1 INP1", "RX3", "SLIM RX3"},
- {"RX7 MIX1 INP1", "RX4", "SLIM RX4"},
- {"RX7 MIX1 INP1", "RX5", "SLIM RX5"},
- {"RX7 MIX1 INP1", "RX6", "SLIM RX6"},
- {"RX7 MIX1 INP1", "RX7", "SLIM RX7"},
- {"RX7 MIX1 INP1", "IIR1", "IIR1"},
- {"RX7 MIX1 INP2", "RX1", "SLIM RX1"},
- {"RX7 MIX1 INP2", "RX2", "SLIM RX2"},
- {"RX7 MIX1 INP2", "RX3", "SLIM RX3"},
- {"RX7 MIX1 INP2", "RX4", "SLIM RX4"},
- {"RX7 MIX1 INP2", "RX5", "SLIM RX5"},
- {"RX7 MIX1 INP2", "RX6", "SLIM RX6"},
- {"RX7 MIX1 INP2", "RX7", "SLIM RX7"},
- {"RX7 MIX1 INP2", "IIR1", "IIR1"},
+
{"RX1 MIX2 INP1", "IIR1", "IIR1"},
{"RX1 MIX2 INP2", "IIR1", "IIR1"},
{"RX2 MIX2 INP1", "IIR1", "IIR1"},
{"RX2 MIX2 INP2", "IIR1", "IIR1"},
- {"RX7 MIX2 INP1", "IIR1", "IIR1"},
- {"RX7 MIX2 INP2", "IIR1", "IIR1"},
+ {"RX4 MIX2 INP1", "IIR1", "IIR1"},
+ {"RX4 MIX2 INP2", "IIR1", "IIR1"},
/* Decimator Inputs */
+ {"DEC1 MUX", "ADC1", "ADC1"},
+ {"DEC1 MUX", "ADC2", "ADC2"},
+ {"DEC1 MUX", "ADC3", "ADC3"},
+ {"DEC1 MUX", "ADC4", "ADC4"},
{"DEC1 MUX", "DMIC1", "DMIC1"},
- {"DEC1 MUX", "ADC6", "ADC6"},
+ {"DEC1 MUX", "DMIC2", "DMIC2"},
+ {"DEC1 MUX", "DMIC3", "DMIC3"},
+ {"DEC1 MUX", "DMIC4", "DMIC4"},
{"DEC1 MUX", NULL, "CDC_CONN"},
+
+ {"DEC2 MUX", "ADC1", "ADC1"},
+ {"DEC2 MUX", "ADC2", "ADC2"},
+ {"DEC2 MUX", "ADC3", "ADC3"},
+ {"DEC2 MUX", "ADC4", "ADC4"},
+ {"DEC2 MUX", "DMIC1", "DMIC1"},
{"DEC2 MUX", "DMIC2", "DMIC2"},
- {"DEC2 MUX", "ADC5", "ADC5"},
+ {"DEC2 MUX", "DMIC3", "DMIC3"},
+ {"DEC2 MUX", "DMIC4", "DMIC4"},
{"DEC2 MUX", NULL, "CDC_CONN"},
- {"DEC3 MUX", "DMIC3", "DMIC3"},
+
+ {"DEC3 MUX", "ADC1", "ADC1"},
+ {"DEC3 MUX", "ADC2", "ADC2"},
+ {"DEC3 MUX", "ADC3", "ADC3"},
{"DEC3 MUX", "ADC4", "ADC4"},
+ {"DEC3 MUX", "ADC5", "ADC5"},
+ {"DEC3 MUX", "DMIC1", "DMIC1"},
+ {"DEC3 MUX", "DMIC2", "DMIC2"},
+ {"DEC3 MUX", "DMIC3", "DMIC3"},
+ {"DEC3 MUX", "DMIC4", "DMIC4"},
{"DEC3 MUX", NULL, "CDC_CONN"},
- {"DEC4 MUX", "DMIC4", "DMIC4"},
+
+ {"DEC4 MUX", "ADC1", "ADC1"},
+ {"DEC4 MUX", "ADC2", "ADC2"},
{"DEC4 MUX", "ADC3", "ADC3"},
+ {"DEC4 MUX", "ADC4", "ADC4"},
+ {"DEC4 MUX", "ADC5", "ADC5"},
+ {"DEC4 MUX", "DMIC1", "DMIC1"},
+ {"DEC4 MUX", "DMIC2", "DMIC2"},
+ {"DEC4 MUX", "DMIC3", "DMIC3"},
+ {"DEC4 MUX", "DMIC4", "DMIC4"},
{"DEC4 MUX", NULL, "CDC_CONN"},
- {"DEC5 MUX", "DMIC5", "DMIC5"},
- {"DEC5 MUX", "ADC2", "ADC2"},
- {"DEC5 MUX", NULL, "CDC_CONN"},
- {"DEC6 MUX", "DMIC6", "DMIC6"},
- {"DEC6 MUX", "ADC1", "ADC1"},
- {"DEC6 MUX", NULL, "CDC_CONN"},
- {"DEC7 MUX", "DMIC1", "DMIC1"},
- {"DEC7 MUX", "DMIC6", "DMIC6"},
- {"DEC7 MUX", "ADC1", "ADC1"},
- {"DEC7 MUX", "ADC6", "ADC6"},
- {"DEC7 MUX", NULL, "CDC_CONN"},
- {"DEC8 MUX", "DMIC2", "DMIC2"},
- {"DEC8 MUX", "DMIC5", "DMIC5"},
- {"DEC8 MUX", "ADC2", "ADC2"},
- {"DEC8 MUX", "ADC5", "ADC5"},
- {"DEC8 MUX", NULL, "CDC_CONN"},
- {"DEC9 MUX", "DMIC4", "DMIC4"},
- {"DEC9 MUX", "DMIC5", "DMIC5"},
- {"DEC9 MUX", "ADC2", "ADC2"},
- {"DEC9 MUX", "ADC3", "ADC3"},
- {"DEC9 MUX", NULL, "CDC_CONN"},
- {"DEC10 MUX", "DMIC3", "DMIC3"},
- {"DEC10 MUX", "DMIC6", "DMIC6"},
- {"DEC10 MUX", "ADC1", "ADC1"},
- {"DEC10 MUX", "ADC4", "ADC4"},
- {"DEC10 MUX", NULL, "CDC_CONN"},
/* ADC Connections */
{"ADC1", NULL, "AMIC1"},
@@ -2247,7 +2496,6 @@
{"ADC3", NULL, "AMIC3"},
{"ADC4", NULL, "AMIC4"},
{"ADC5", NULL, "AMIC5"},
- {"ADC6", NULL, "AMIC6"},
/* AUX PGA Connections */
{"EAR_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
@@ -2255,22 +2503,13 @@
{"HPHR_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
{"LINEOUT1_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
{"LINEOUT2_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
- {"LINEOUT3_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
- {"LINEOUT4_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
{"AUX_PGA_Left", NULL, "AMIC5"},
- {"AUX_PGA_Right", NULL, "AMIC6"},
{"IIR1", NULL, "IIR1 INP1 MUX"},
{"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
{"IIR1 INP1 MUX", "DEC2", "DEC2 MUX"},
{"IIR1 INP1 MUX", "DEC3", "DEC3 MUX"},
{"IIR1 INP1 MUX", "DEC4", "DEC4 MUX"},
- {"IIR1 INP1 MUX", "DEC5", "DEC5 MUX"},
- {"IIR1 INP1 MUX", "DEC6", "DEC6 MUX"},
- {"IIR1 INP1 MUX", "DEC7", "DEC7 MUX"},
- {"IIR1 INP1 MUX", "DEC8", "DEC8 MUX"},
- {"IIR1 INP1 MUX", "DEC9", "DEC9 MUX"},
- {"IIR1 INP1 MUX", "DEC10", "DEC10 MUX"},
{"MIC BIAS1 Internal1", NULL, "LDO_H"},
{"MIC BIAS1 Internal2", NULL, "LDO_H"},
@@ -2282,7 +2521,6 @@
{"MIC BIAS3 Internal1", NULL, "LDO_H"},
{"MIC BIAS3 Internal2", NULL, "LDO_H"},
{"MIC BIAS3 External", NULL, "LDO_H"},
- {"MIC BIAS4 External", NULL, "LDO_H"},
};
static int tapan_readable(struct snd_soc_codec *ssc, unsigned int reg)
@@ -2313,7 +2551,7 @@
static int tapan_volatile(struct snd_soc_codec *ssc, unsigned int reg)
{
/* Registers lower than 0x100 are top level registers which can be
- * written by the Taiko core driver.
+ * written by the Tapan core driver.
*/
if ((reg >= TAPAN_A_CDC_MBHC_EN_CTL) || (reg < 0x100))
@@ -2445,6 +2683,40 @@
static int tapan_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
+ u8 val = 0;
+ struct snd_soc_codec *codec = dai->codec;
+ struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
+
+ dev_dbg(codec->dev, "%s\n", __func__);
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ /* CPU is master */
+ if (tapan->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
+ if (dai->id == AIF1_CAP)
+ snd_soc_update_bits(codec,
+ TAPAN_A_CDC_CLK_I2S_CTL,
+ TAPAN_I2S_MASTER_MODE_MASK, 0);
+ else if (dai->id == AIF1_PB)
+ snd_soc_update_bits(codec,
+ TAPAN_A_CDC_CLK_I2S_CTL,
+ TAPAN_I2S_MASTER_MODE_MASK, 0);
+ }
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ /* CPU is slave */
+ if (tapan->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
+ val = TAPAN_I2S_MASTER_MODE_MASK;
+ if (dai->id == AIF1_CAP)
+ snd_soc_update_bits(codec,
+ TAPAN_A_CDC_CLK_I2S_CTL, val, val);
+ else if (dai->id == AIF1_PB)
+ snd_soc_update_bits(codec,
+ TAPAN_A_CDC_CLK_I2S_CTL, val, val);
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
return 0;
}
@@ -2490,7 +2762,7 @@
}
list_for_each_entry(ch, &tapan_p->dai[dai->id].wcd9xxx_ch_list,
list) {
- dev_dbg(dai->codec->dev, "%s: rx_slot[%d] %d ch->ch_num %d\n",
+ dev_dbg(dai->codec->dev, "%s: rx_slot[%d] %d, ch->ch_num %d\n",
__func__, i, rx_slot[i], ch->ch_num);
rx_slot[i++] = ch->ch_num;
}
@@ -2524,7 +2796,7 @@
}
static int tapan_set_interpolator_rate(struct snd_soc_dai *dai,
- u8 rx_fs_rate_reg_val, u32 sample_rate)
+ u8 rx_fs_rate_reg_val, u32 compander_fs, u32 sample_rate)
{
u32 j;
u8 rx_mix1_inp;
@@ -2540,7 +2812,7 @@
rx_mix1_inp = ch->port + RX_MIX1_INP_SEL_RX1 -
TAPAN_TX_PORT_NUMBER;
if ((rx_mix1_inp < RX_MIX1_INP_SEL_RX1) ||
- (rx_mix1_inp > RX_MIX1_INP_SEL_RX7)) {
+ (rx_mix1_inp > RX_MIX1_INP_SEL_RX5)) {
pr_err("%s: Invalid TAPAN_RX%u port. Dai ID is %d\n",
__func__, rx_mix1_inp - 5 , dai->id);
return -EINVAL;
@@ -2572,6 +2844,9 @@
snd_soc_update_bits(codec, rx_fs_reg,
0xE0, rx_fs_rate_reg_val);
+ if (comp_rx_path[j] < COMPANDER_MAX)
+ tapan->comp_fs[comp_rx_path[j]]
+ = compander_fs;
}
if (j <= 2)
rx_mix_1_reg_1 += 3;
@@ -2599,7 +2874,7 @@
dev_dbg(codec->dev, "%s: dai->id = %d, tx_port = %d",
__func__, dai->id, tx_port);
- if ((tx_port < 1) || (tx_port > NUM_DECIMATORS)) {
+ if ((tx_port < 1) || (tx_port > TAPAN_SLIM_CODEC_TX_PORTS)) {
pr_err("%s: Invalid SLIM TX%u port. DAI ID is %d\n",
__func__, tx_port, dai->id);
return -EINVAL;
@@ -2610,23 +2885,15 @@
decimator = 0;
- if ((tx_port >= 1) && (tx_port <= 6)) {
+ tx_port_reg_val = tx_port_reg_val & 0x0F;
- tx_port_reg_val = tx_port_reg_val & 0x0F;
- if (tx_port_reg_val == 0x8)
- decimator = tx_port;
-
- } else if ((tx_port >= 7) && (tx_port <= NUM_DECIMATORS)) {
-
- tx_port_reg_val = tx_port_reg_val & 0x1F;
-
- if ((tx_port_reg_val >= 0x8) &&
+ if ((tx_port_reg_val >= 0x8) &&
(tx_port_reg_val <= 0x11)) {
decimator = (tx_port_reg_val - 0x8) + 1;
- }
}
+
if (decimator) { /* SLIM_TX port has a DEC as input */
tx_fs_reg = TAPAN_A_CDC_TX1_CLK_FS_CTL +
@@ -2640,7 +2907,7 @@
} else {
if ((tx_port_reg_val >= 0x1) &&
- (tx_port_reg_val <= 0x7)) {
+ (tx_port_reg_val <= 0x4)) {
dev_dbg(codec->dev, "%s: RMIX%u going to SLIM TX%u\n",
__func__, tx_port_reg_val, tx_port);
@@ -2673,8 +2940,10 @@
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
+ struct snd_soc_codec *codec = dai->codec;
struct tapan_priv *tapan = snd_soc_codec_get_drvdata(dai->codec);
u8 tx_fs_rate, rx_fs_rate;
+ u32 compander_fs;
int ret;
dev_dbg(dai->codec->dev, "%s: dai_name = %s DAI-ID %x rate %d num_ch %d\n",
@@ -2685,26 +2954,32 @@
case 8000:
tx_fs_rate = 0x00;
rx_fs_rate = 0x00;
+ compander_fs = COMPANDER_FS_8KHZ;
break;
case 16000:
tx_fs_rate = 0x01;
rx_fs_rate = 0x20;
+ compander_fs = COMPANDER_FS_16KHZ;
break;
case 32000:
tx_fs_rate = 0x02;
rx_fs_rate = 0x40;
+ compander_fs = COMPANDER_FS_32KHZ;
break;
case 48000:
tx_fs_rate = 0x03;
rx_fs_rate = 0x60;
+ compander_fs = COMPANDER_FS_48KHZ;
break;
case 96000:
tx_fs_rate = 0x04;
rx_fs_rate = 0x80;
+ compander_fs = COMPANDER_FS_96KHZ;
break;
case 192000:
tx_fs_rate = 0x05;
rx_fs_rate = 0xA0;
+ compander_fs = COMPANDER_FS_192KHZ;
break;
default:
pr_err("%s: Invalid sampling rate %d\n", __func__,
@@ -2722,31 +2997,85 @@
return ret;
}
- if (tapan->intf_type == WCD9XXX_INTERFACE_TYPE_I2C)
- pr_err("%s: I2C interface not yet supported\n",
- __func__);
- else
- tapan->dai[dai->id].rate = params_rate(params);
-
+ if (tapan->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ snd_soc_update_bits(codec,
+ TAPAN_A_CDC_CLK_I2S_CTL,
+ 0x20, 0x20);
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ snd_soc_update_bits(codec,
+ TAPAN_A_CDC_CLK_I2S_CTL,
+ 0x20, 0x00);
+ break;
+ default:
+ pr_err("invalid format\n");
+ break;
+ }
+ snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_I2S_CTL,
+ 0x07, tx_fs_rate);
+ } else {
+ tapan->dai[dai->id].rate = params_rate(params);
+ }
break;
case SNDRV_PCM_STREAM_PLAYBACK:
ret = tapan_set_interpolator_rate(dai, rx_fs_rate,
+ compander_fs,
params_rate(params));
if (ret < 0) {
- pr_err("%s: set decimator rate failed %d\n", __func__,
- ret);
+ dev_err(codec->dev, "%s: set decimator rate failed %d\n",
+ __func__, ret);
return ret;
}
- if (tapan->intf_type == WCD9XXX_INTERFACE_TYPE_I2C)
- pr_err("%s: I2C interface not yet supported\n",
- __func__);
- else
+ if (tapan->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ snd_soc_update_bits(codec,
+ TAPAN_A_CDC_CLK_I2S_CTL,
+ 0x20, 0x20);
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ snd_soc_update_bits(codec,
+ TAPAN_A_CDC_CLK_I2S_CTL,
+ 0x20, 0x00);
+ break;
+ default:
+ dev_err(codec->dev, "invalid format\n");
+ break;
+ }
+ snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_I2S_CTL,
+ 0x03, (rx_fs_rate >> 0x05));
+ } else {
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ snd_soc_update_bits(codec,
+ TAPAN_A_CDC_CONN_RX_SB_B1_CTL,
+ 0xFF, 0xAA);
+ snd_soc_update_bits(codec,
+ TAPAN_A_CDC_CONN_RX_SB_B2_CTL,
+ 0xFF, 0x2A);
+ tapan->dai[dai->id].bit_width = 16;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ snd_soc_update_bits(codec,
+ TAPAN_A_CDC_CONN_RX_SB_B1_CTL,
+ 0xFF, 0x00);
+ snd_soc_update_bits(codec,
+ TAPAN_A_CDC_CONN_RX_SB_B2_CTL,
+ 0xFF, 0x00);
+ tapan->dai[dai->id].bit_width = 24;
+ break;
+ default:
+ dev_err(codec->dev, "Invalid format\n");
+ break;
+ }
tapan->dai[dai->id].rate = params_rate(params);
-
+ }
break;
default:
- pr_err("%s: Invalid stream type %d\n", __func__,
+ dev_err(codec->dev, "%s: Invalid stream type %d\n", __func__,
substream->stream);
return -EINVAL;
}
@@ -2882,6 +3211,38 @@
},
};
+static int tapan_codec_enable_slim_chmask(struct wcd9xxx_codec_dai_data *dai,
+ bool up)
+{
+ int ret = 0;
+ struct wcd9xxx_ch *ch;
+
+ if (up) {
+ list_for_each_entry(ch, &dai->wcd9xxx_ch_list, list) {
+ ret = wcd9xxx_get_slave_port(ch->ch_num);
+ if (ret < 0) {
+ pr_debug("%s: Invalid slave port ID: %d\n",
+ __func__, ret);
+ ret = -EINVAL;
+ } else {
+ set_bit(ret, &dai->ch_mask);
+ }
+ }
+ } else {
+ ret = wait_event_timeout(dai->dai_wait, (dai->ch_mask == 0),
+ msecs_to_jiffies(
+ TAPAN_SLIM_CLOSE_TIMEOUT));
+ if (!ret) {
+ pr_debug("%s: Slim close tx/rx wait timeout\n",
+ __func__);
+ ret = -ETIMEDOUT;
+ } else {
+ ret = 0;
+ }
+ }
+ return ret;
+}
+
static int tapan_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol,
int event)
@@ -2889,7 +3250,7 @@
struct wcd9xxx *core;
struct snd_soc_codec *codec = w->codec;
struct tapan_priv *tapan_p = snd_soc_codec_get_drvdata(codec);
- u32 ret = 0;
+ int ret = 0;
struct wcd9xxx_codec_dai_data *dai;
core = dev_get_drvdata(codec->dev->parent);
@@ -2909,6 +3270,7 @@
switch (event) {
case SND_SOC_DAPM_POST_PMU:
+ (void) tapan_codec_enable_slim_chmask(dai, true);
ret = wcd9xxx_cfg_slim_sch_rx(core, &dai->wcd9xxx_ch_list,
dai->rate, dai->bit_width,
&dai->grph);
@@ -2916,7 +3278,14 @@
case SND_SOC_DAPM_POST_PMD:
ret = wcd9xxx_close_slim_sch_rx(core, &dai->wcd9xxx_ch_list,
dai->grph);
- usleep_range(15000, 15000);
+ ret = tapan_codec_enable_slim_chmask(dai, false);
+ if (ret < 0) {
+ ret = wcd9xxx_disconnect_port(core,
+ &dai->wcd9xxx_ch_list,
+ dai->grph);
+ dev_dbg(codec->dev, "%s: Disconnect RX port, ret = %d\n",
+ __func__, ret);
+ }
break;
}
return ret;
@@ -2938,7 +3307,6 @@
__func__, w->codec->name);
dev_dbg(codec->dev, "%s: num_dai %d stream name %s\n",
__func__, w->codec->num_dai, w->sname);
-
/* Execute the callback only if interface type is slimbus */
if (tapan_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
return 0;
@@ -2949,6 +3317,7 @@
dai = &tapan_p->dai[w->shift];
switch (event) {
case SND_SOC_DAPM_POST_PMU:
+ (void) tapan_codec_enable_slim_chmask(dai, true);
ret = wcd9xxx_cfg_slim_sch_tx(core, &dai->wcd9xxx_ch_list,
dai->rate, dai->bit_width,
&dai->grph);
@@ -2956,45 +3325,103 @@
case SND_SOC_DAPM_POST_PMD:
ret = wcd9xxx_close_slim_sch_tx(core, &dai->wcd9xxx_ch_list,
dai->grph);
+ ret = tapan_codec_enable_slim_chmask(dai, false);
+ if (ret < 0) {
+ ret = wcd9xxx_disconnect_port(core,
+ &dai->wcd9xxx_ch_list,
+ dai->grph);
+ dev_dbg(codec->dev, "%s: Disconnect RX port, ret = %d\n",
+ __func__, ret);
+ }
break;
}
return ret;
}
+
static int tapan_codec_enable_ear_pa(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = w->codec;
+ struct tapan_priv *tapan_p = snd_soc_codec_get_drvdata(codec);
dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
switch (event) {
-
case SND_SOC_DAPM_POST_PMU:
+ wcd9xxx_clsh_fsm(codec, &tapan_p->clsh_d,
+ WCD9XXX_CLSH_STATE_EAR,
+ WCD9XXX_CLSH_REQ_ENABLE,
+ WCD9XXX_CLSH_EVENT_POST_PA);
- snd_soc_update_bits(codec, TAPAN_A_BUCK_MODE_5, 0x02, 0x00);
- snd_soc_update_bits(codec, TAPAN_A_NCP_STATIC, 0x20, 0x00);
- snd_soc_update_bits(codec, TAPAN_A_BUCK_MODE_3, 0x04, 0x04);
- snd_soc_update_bits(codec, TAPAN_A_BUCK_MODE_3, 0x08, 0x00);
+ usleep_range(5000, 5010);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ wcd9xxx_clsh_fsm(codec, &tapan_p->clsh_d,
+ WCD9XXX_CLSH_STATE_EAR,
+ WCD9XXX_CLSH_REQ_DISABLE,
+ WCD9XXX_CLSH_EVENT_POST_PA);
+ usleep_range(5000, 5010);
+ }
+ return 0;
+}
- usleep_range(5000, 5000);
+static int tapan_codec_ear_dac_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ struct tapan_priv *tapan_p = snd_soc_codec_get_drvdata(codec);
+
+ dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ wcd9xxx_clsh_fsm(codec, &tapan_p->clsh_d,
+ WCD9XXX_CLSH_STATE_EAR,
+ WCD9XXX_CLSH_REQ_ENABLE,
+ WCD9XXX_CLSH_EVENT_PRE_DAC);
+ break;
+ }
+
+ return 0;
+}
+
+static int tapan_codec_dsm_mux_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ u8 reg_val, zoh_mux_val = 0x00;
+
+ dev_dbg(codec->dev, "%s: event = %d\n", __func__, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ reg_val = snd_soc_read(codec, TAPAN_A_CDC_CONN_CLSH_CTL);
+
+ if ((reg_val & 0x30) == 0x10)
+ zoh_mux_val = 0x04;
+ else if ((reg_val & 0x30) == 0x20)
+ zoh_mux_val = 0x08;
+
+ if (zoh_mux_val != 0x00)
+ snd_soc_update_bits(codec,
+ TAPAN_A_CDC_CONN_CLSH_CTL,
+ 0x0C, zoh_mux_val);
+ break;
+
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_update_bits(codec, TAPAN_A_CDC_CONN_CLSH_CTL,
+ 0x0C, 0x00);
break;
}
return 0;
}
+
/* Todo: Have seperate dapm widgets for I2S and Slimbus.
* Might Need to have callbacks registered only for slimbus
*/
static const struct snd_soc_dapm_widget tapan_dapm_widgets[] = {
- /*RX stuff */
- SND_SOC_DAPM_OUTPUT("EAR"),
-
- SND_SOC_DAPM_PGA_E("EAR PA", TAPAN_A_RX_EAR_EN, 4, 0, NULL, 0,
- tapan_codec_enable_ear_pa, SND_SOC_DAPM_POST_PMU),
-
- SND_SOC_DAPM_MIXER("DAC1", TAPAN_A_RX_EAR_EN, 6, 0, dac1_switch,
- ARRAY_SIZE(dac1_switch)),
SND_SOC_DAPM_AIF_IN_E("AIF1 PB", "AIF1 Playback", 0, SND_SOC_NOPM,
AIF1_PB, 0, tapan_codec_enable_slimrx,
@@ -3023,51 +3450,61 @@
SND_SOC_DAPM_MIXER("SLIM RX4", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_MIXER("SLIM RX5", SND_SOC_NOPM, 0, 0, NULL, 0),
- /* Headphone */
- SND_SOC_DAPM_OUTPUT("HEADPHONE"),
- SND_SOC_DAPM_PGA_E("HPHL", TAPAN_A_RX_HPH_CNP_EN, 5, 0, NULL, 0,
- tapan_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MIXER("HPHL DAC", TAPAN_A_RX_HPH_L_DAC_CTL, 7, 0,
- hphl_switch, ARRAY_SIZE(hphl_switch)),
- SND_SOC_DAPM_PGA_E("HPHR", TAPAN_A_RX_HPH_CNP_EN, 4, 0, NULL, 0,
- tapan_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ /* RX1 MIX1 mux inputs */
+ SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+ &rx_mix1_inp1_mux),
+ SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+ &rx_mix1_inp2_mux),
+ SND_SOC_DAPM_MUX("RX1 MIX1 INP3", SND_SOC_NOPM, 0, 0,
+ &rx_mix1_inp3_mux),
- SND_SOC_DAPM_DAC_E("HPHR DAC", NULL, TAPAN_A_RX_HPH_R_DAC_CTL, 7, 0,
- tapan_hphr_dac_event,
- SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ /* RX2 MIX1 mux inputs */
+ SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+ &rx2_mix1_inp1_mux),
+ SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+ &rx2_mix1_inp2_mux),
+ SND_SOC_DAPM_MUX("RX2 MIX1 INP3", SND_SOC_NOPM, 0, 0,
+ &rx2_mix1_inp2_mux),
- /* Speaker */
- SND_SOC_DAPM_OUTPUT("LINEOUT1"),
- SND_SOC_DAPM_OUTPUT("LINEOUT2"),
- SND_SOC_DAPM_OUTPUT("SPK_OUT"),
+ /* RX3 MIX1 mux inputs */
+ SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+ &rx3_mix1_inp1_mux),
+ SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+ &rx3_mix1_inp2_mux),
+ SND_SOC_DAPM_MUX("RX3 MIX1 INP3", SND_SOC_NOPM, 0, 0,
+ &rx3_mix1_inp2_mux),
- SND_SOC_DAPM_PGA_E("LINEOUT1 PA", TAPAN_A_RX_LINE_CNP_EN, 0, 0, NULL,
- 0, tapan_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_PGA_E("LINEOUT2 PA", TAPAN_A_RX_LINE_CNP_EN, 1, 0, NULL,
- 0, tapan_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ /* RX4 MIX1 mux inputs */
+ SND_SOC_DAPM_MUX("RX4 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+ &rx4_mix1_inp1_mux),
+ SND_SOC_DAPM_MUX("RX4 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+ &rx4_mix1_inp2_mux),
+ SND_SOC_DAPM_MUX("RX4 MIX1 INP3", SND_SOC_NOPM, 0, 0,
+ &rx4_mix1_inp2_mux),
- SND_SOC_DAPM_PGA_E("SPK PA", TAPAN_A_SPKR_DRV_EN, 7, 0 , NULL,
- 0, tapan_codec_enable_spk_pa, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ /* RX1 MIX2 mux inputs */
+ SND_SOC_DAPM_MUX("RX1 MIX2 INP1", SND_SOC_NOPM, 0, 0,
+ &rx1_mix2_inp1_mux),
+ SND_SOC_DAPM_MUX("RX1 MIX2 INP2", SND_SOC_NOPM, 0, 0,
+ &rx1_mix2_inp2_mux),
- SND_SOC_DAPM_DAC_E("LINEOUT1 DAC", NULL, TAPAN_A_RX_LINE_1_DAC_CTL, 7, 0
- , tapan_lineout_dac_event,
- SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_DAC_E("LINEOUT2 DAC", NULL, TAPAN_A_RX_LINE_2_DAC_CTL, 7, 0
- , tapan_lineout_dac_event,
- SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ /* RX2 MIX2 mux inputs */
+ SND_SOC_DAPM_MUX("RX2 MIX2 INP1", SND_SOC_NOPM, 0, 0,
+ &rx2_mix2_inp1_mux),
+ SND_SOC_DAPM_MUX("RX2 MIX2 INP2", SND_SOC_NOPM, 0, 0,
+ &rx2_mix2_inp2_mux),
- SND_SOC_DAPM_DAC_E("SPK DAC", NULL, SND_SOC_NOPM, 0, 0,
- tapan_spk_dac_event,
- SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ /* RX4 MIX2 mux inputs */
+ SND_SOC_DAPM_MUX("RX4 MIX2 INP1", SND_SOC_NOPM, 0, 0,
+ &rx4_mix2_inp1_mux),
+ SND_SOC_DAPM_MUX("RX4 MIX2 INP2", SND_SOC_NOPM, 0, 0,
+ &rx4_mix2_inp2_mux),
+
SND_SOC_DAPM_MIXER("RX1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_MIXER("RX2 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX4 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_MIXER_E("RX1 MIX2", TAPAN_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
0, tapan_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
@@ -3078,94 +3515,116 @@
SND_SOC_DAPM_MIXER_E("RX3 MIX1", TAPAN_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
0, tapan_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU),
- SND_SOC_DAPM_MIXER_E("RX4 MIX1", TAPAN_A_CDC_CLK_RX_B1_CTL, 3, 0, NULL,
- 0, tapan_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU),
- SND_SOC_DAPM_MIXER_E("RX5 MIX1", TAPAN_A_CDC_CLK_RX_B1_CTL, 4, 0, NULL,
+ SND_SOC_DAPM_MIXER_E("RX4 MIX2", TAPAN_A_CDC_CLK_RX_B1_CTL, 3, 0, NULL,
0, tapan_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU),
- SND_SOC_DAPM_MIXER("RX1 CHAIN", TAPAN_A_CDC_RX1_B6_CTL, 5, 0, NULL, 0),
- SND_SOC_DAPM_MIXER("RX2 CHAIN", TAPAN_A_CDC_RX2_B6_CTL, 5, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX1 CHAIN", TAPAN_A_CDC_RX1_B6_CTL, 5, 0,
+ NULL, 0),
+ SND_SOC_DAPM_MIXER("RX2 CHAIN", TAPAN_A_CDC_RX2_B6_CTL, 5, 0,
+ NULL, 0),
- SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
- &rx_mix1_inp1_mux),
- SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
- &rx_mix1_inp2_mux),
- SND_SOC_DAPM_MUX("RX1 MIX1 INP3", SND_SOC_NOPM, 0, 0,
- &rx_mix1_inp3_mux),
- SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
- &rx2_mix1_inp1_mux),
- SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
- &rx2_mix1_inp2_mux),
- SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
- &rx3_mix1_inp1_mux),
- SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
- &rx3_mix1_inp2_mux),
- SND_SOC_DAPM_MUX("RX4 MIX1 INP1", SND_SOC_NOPM, 0, 0,
- &rx4_mix1_inp1_mux),
- SND_SOC_DAPM_MUX("RX4 MIX1 INP2", SND_SOC_NOPM, 0, 0,
- &rx4_mix1_inp2_mux),
- SND_SOC_DAPM_MUX("RX1 MIX2 INP1", SND_SOC_NOPM, 0, 0,
- &rx1_mix2_inp1_mux),
- SND_SOC_DAPM_MUX("RX1 MIX2 INP2", SND_SOC_NOPM, 0, 0,
- &rx1_mix2_inp2_mux),
- SND_SOC_DAPM_MUX("RX2 MIX2 INP1", SND_SOC_NOPM, 0, 0,
- &rx2_mix2_inp1_mux),
- SND_SOC_DAPM_MUX("RX2 MIX2 INP2", SND_SOC_NOPM, 0, 0,
- &rx2_mix2_inp2_mux),
+ SND_SOC_DAPM_MUX_E("CLASS_H_DSM MUX", SND_SOC_NOPM, 0, 0,
+ &class_h_dsm_mux, tapan_codec_dsm_mux_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MUX("RDAC5 MUX", SND_SOC_NOPM, 0, 0,
- &rx_dac5_mux),
-
- SND_SOC_DAPM_SUPPLY("CLASS_H_CLK", TAPAN_A_CDC_CLK_OTHR_CTL, 0, 0,
- tapan_codec_enable_class_h_clk, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_PRE_PMD),
-
- SND_SOC_DAPM_SUPPLY("CLASS_H_EAR", TAPAN_A_CDC_CLSH_B1_CTL, 4, 0,
- tapan_codec_enable_class_h, SND_SOC_DAPM_POST_PMU),
-
- SND_SOC_DAPM_SUPPLY("CLASS_H_HPH_L", TAPAN_A_CDC_CLSH_B1_CTL, 3, 0,
- tapan_codec_enable_class_h, SND_SOC_DAPM_POST_PMU),
-
- SND_SOC_DAPM_SUPPLY("CLASS_H_HPH_R", TAPAN_A_CDC_CLSH_B1_CTL, 2, 0,
- tapan_codec_enable_class_h, SND_SOC_DAPM_POST_PMU),
-
- SND_SOC_DAPM_SUPPLY("CLASS_H_LINEOUTS_PA", SND_SOC_NOPM, 0, 0,
- tapan_codec_enable_class_h, SND_SOC_DAPM_POST_PMU),
-
- SND_SOC_DAPM_SUPPLY("CP", TAPAN_A_NCP_EN, 0, 0,
- tapan_codec_enable_charge_pump, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
-
+ /* RX Bias */
SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0,
tapan_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMD),
- /* TX */
+ /*EAR */
+ SND_SOC_DAPM_PGA_E("EAR PA", TAPAN_A_RX_EAR_EN, 4, 0, NULL, 0,
+ tapan_codec_enable_ear_pa, SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_SUPPLY("CDC_CONN", TAPAN_A_CDC_CLK_OTHR_CTL, 2, 0, NULL,
+ SND_SOC_DAPM_MIXER_E("DAC1", TAPAN_A_RX_EAR_EN, 6, 0, dac1_switch,
+ ARRAY_SIZE(dac1_switch), tapan_codec_ear_dac_event,
+ SND_SOC_DAPM_PRE_PMU),
+
+ /* Headphone Left */
+ SND_SOC_DAPM_PGA_E("HPHL", TAPAN_A_RX_HPH_CNP_EN, 5, 0, NULL, 0,
+ tapan_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MIXER_E("HPHL DAC", TAPAN_A_RX_HPH_L_DAC_CTL, 7, 0,
+ hphl_switch, ARRAY_SIZE(hphl_switch), tapan_hphl_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ /* Headphone Right */
+ SND_SOC_DAPM_PGA_E("HPHR", TAPAN_A_RX_HPH_CNP_EN, 4, 0, NULL, 0,
+ tapan_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_DAC_E("HPHR DAC", NULL, TAPAN_A_RX_HPH_R_DAC_CTL, 7, 0,
+ tapan_hphr_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ /* LINEOUT1*/
+ SND_SOC_DAPM_DAC_E("LINEOUT1 DAC", NULL, TAPAN_A_RX_LINE_1_DAC_CTL, 7, 0
+ , tapan_lineout_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_PGA_E("LINEOUT1 PA", TAPAN_A_RX_LINE_CNP_EN, 0, 0, NULL,
+ 0, tapan_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ /* LINEOUT2*/
+ SND_SOC_DAPM_MUX("RDAC5 MUX", SND_SOC_NOPM, 0, 0,
+ &rx_dac5_mux),
+
+ SND_SOC_DAPM_DAC_E("LINEOUT2 DAC", NULL, TAPAN_A_RX_LINE_2_DAC_CTL, 7, 0
+ , tapan_lineout_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_PGA_E("LINEOUT2 PA", TAPAN_A_RX_LINE_CNP_EN, 1, 0, NULL,
+ 0, tapan_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ /* CLASS-D SPK */
+ SND_SOC_DAPM_MIXER_E("SPK DAC", SND_SOC_NOPM, 0, 0,
+ spk_dac_switch, ARRAY_SIZE(spk_dac_switch), tapan_spk_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_PGA_E("SPK PA", SND_SOC_NOPM, 0, 0 , NULL,
+ 0, tapan_codec_enable_spk_pa,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_SUPPLY("VDD_SPKDRV", SND_SOC_NOPM, 0, 0,
+ tapan_codec_enable_vdd_spkr,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_OUTPUT("EAR"),
+ SND_SOC_DAPM_OUTPUT("HEADPHONE"),
+ SND_SOC_DAPM_OUTPUT("LINEOUT1"),
+ SND_SOC_DAPM_OUTPUT("LINEOUT2"),
+ SND_SOC_DAPM_OUTPUT("SPK_OUT"),
+
+ /* TX Path*/
+ SND_SOC_DAPM_MIXER("AIF1_CAP Mixer", SND_SOC_NOPM, AIF1_CAP, 0,
+ aif_cap_mixer, ARRAY_SIZE(aif_cap_mixer)),
+
+ SND_SOC_DAPM_MIXER("AIF2_CAP Mixer", SND_SOC_NOPM, AIF2_CAP, 0,
+ aif_cap_mixer, ARRAY_SIZE(aif_cap_mixer)),
+
+ SND_SOC_DAPM_MIXER("AIF3_CAP Mixer", SND_SOC_NOPM, AIF3_CAP, 0,
+ aif_cap_mixer, ARRAY_SIZE(aif_cap_mixer)),
+
+ SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, TAPAN_TX1, 0,
+ &sb_tx1_mux),
+ SND_SOC_DAPM_MUX("SLIM TX2 MUX", SND_SOC_NOPM, TAPAN_TX2, 0,
+ &sb_tx2_mux),
+ SND_SOC_DAPM_MUX("SLIM TX3 MUX", SND_SOC_NOPM, TAPAN_TX3, 0,
+ &sb_tx3_mux),
+ SND_SOC_DAPM_MUX("SLIM TX4 MUX", SND_SOC_NOPM, TAPAN_TX4, 0,
+ &sb_tx4_mux),
+ SND_SOC_DAPM_MUX("SLIM TX5 MUX", SND_SOC_NOPM, TAPAN_TX5, 0,
+ &sb_tx5_mux),
+
+ SND_SOC_DAPM_SUPPLY("CDC_CONN", WCD9XXX_A_CDC_CLK_OTHR_CTL, 2, 0, NULL,
0),
- SND_SOC_DAPM_SUPPLY("LDO_H", TAPAN_A_LDO_H_MODE_1, 7, 0,
- tapan_codec_enable_ldo_h, SND_SOC_DAPM_POST_PMU),
-
- SND_SOC_DAPM_INPUT("AMIC1"),
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", TAPAN_A_MICB_1_CTL, 7, 0,
- tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal1", TAPAN_A_MICB_1_CTL, 7, 0,
- tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal2", TAPAN_A_MICB_1_CTL, 7, 0,
- tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_INPUT("AMIC3"),
-
- SND_SOC_DAPM_INPUT("AMIC4"),
-
- SND_SOC_DAPM_INPUT("AMIC5"),
-
+ /* Decimator MUX */
SND_SOC_DAPM_MUX_E("DEC1 MUX", TAPAN_A_CDC_CLK_TX_CLK_EN_B1_CTL, 0, 0,
&dec1_mux, tapan_codec_enable_dec,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
@@ -3186,6 +3645,54 @@
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY("LDO_H", TAPAN_A_LDO_H_MODE_1, 7, 0,
+ tapan_codec_enable_ldo_h, SND_SOC_DAPM_POST_PMU),
+
+ SND_SOC_DAPM_SUPPLY("COMP0_CLK", SND_SOC_NOPM, 0, 0,
+ tapan_config_compander, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
+ SND_SOC_DAPM_SUPPLY("COMP1_CLK", SND_SOC_NOPM, 1, 0,
+ tapan_config_compander, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
+ SND_SOC_DAPM_SUPPLY("COMP2_CLK", SND_SOC_NOPM, 2, 0,
+ tapan_config_compander, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
+
+ SND_SOC_DAPM_INPUT("AMIC1"),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", TAPAN_A_MICB_1_CTL, 7, 0,
+ tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal1", TAPAN_A_MICB_1_CTL, 7, 0,
+ tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal2", TAPAN_A_MICB_1_CTL, 7, 0,
+ tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_ADC_E("ADC1", NULL, TAPAN_A_TX_1_EN, 7, 0,
+ tapan_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC_E("ADC2", NULL, TAPAN_A_TX_2_EN, 7, 0,
+ tapan_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_INPUT("AMIC3"),
+ SND_SOC_DAPM_ADC_E("ADC3", NULL, TAPAN_A_TX_3_EN, 7, 0,
+ tapan_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_INPUT("AMIC4"),
+ SND_SOC_DAPM_ADC_E("ADC4", NULL, TAPAN_A_TX_4_EN, 7, 0,
+ tapan_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_INPUT("AMIC5"),
+ SND_SOC_DAPM_ADC_E("ADC5", NULL, TAPAN_A_TX_5_EN, 7, 0,
+ tapan_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
+
+ SND_SOC_DAPM_MUX("ANC1 MUX", SND_SOC_NOPM, 0, 0, &anc1_mux),
+ SND_SOC_DAPM_MUX("ANC2 MUX", SND_SOC_NOPM, 0, 0, &anc2_mux),
+
SND_SOC_DAPM_MIXER_E("ANC", SND_SOC_NOPM, 0, 0, NULL, 0,
tapan_codec_enable_anc, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMD),
@@ -3225,25 +3732,7 @@
AIF3_CAP, 0, tapan_codec_enable_slimtx,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MIXER("AIF1_CAP Mixer", SND_SOC_NOPM, AIF1_CAP, 0,
- aif_cap_mixer, ARRAY_SIZE(aif_cap_mixer)),
-
- SND_SOC_DAPM_MIXER("AIF2_CAP Mixer", SND_SOC_NOPM, AIF2_CAP, 0,
- aif_cap_mixer, ARRAY_SIZE(aif_cap_mixer)),
-
- SND_SOC_DAPM_MIXER("AIF3_CAP Mixer", SND_SOC_NOPM, AIF3_CAP, 0,
- aif_cap_mixer, ARRAY_SIZE(aif_cap_mixer)),
-
- SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, TAPAN_TX1, 0,
- &sb_tx1_mux),
- SND_SOC_DAPM_MUX("SLIM TX2 MUX", SND_SOC_NOPM, TAPAN_TX2, 0,
- &sb_tx2_mux),
- SND_SOC_DAPM_MUX("SLIM TX3 MUX", SND_SOC_NOPM, TAPAN_TX3, 0,
- &sb_tx3_mux),
- SND_SOC_DAPM_MUX("SLIM TX4 MUX", SND_SOC_NOPM, TAPAN_TX4, 0,
- &sb_tx4_mux),
-
- /* Digital Mic Inputs */
+ /* Digital Mic Inputs */
SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
tapan_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMD),
@@ -3289,142 +3778,98 @@
SND_SOC_DAPM_MIXER("LINEOUT2_PA_MIXER", SND_SOC_NOPM, 0, 0,
lineout2_pa_mix, ARRAY_SIZE(lineout2_pa_mix)),
-
};
-static unsigned long slimbus_value;
-
static irqreturn_t tapan_slimbus_irq(int irq, void *data)
{
struct tapan_priv *priv = data;
struct snd_soc_codec *codec = priv->codec;
- int i, j;
+ unsigned long status = 0;
+ int i, j, port_id, k;
+ u32 bit;
u8 val;
+ bool tx, cleared;
- for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++) {
- slimbus_value = wcd9xxx_interface_reg_read(codec->control_data,
- TAPAN_SLIM_PGD_PORT_INT_STATUS0 + i);
- for_each_set_bit(j, &slimbus_value, BITS_PER_BYTE) {
- val = wcd9xxx_interface_reg_read(codec->control_data,
- TAPAN_SLIM_PGD_PORT_INT_SOURCE0 + i*8 + j);
- if (val & 0x1)
- pr_err_ratelimited(
- "overflow error on port %x, value %x\n",
- i*8 + j, val);
- if (val & 0x2)
- pr_err_ratelimited(
- "underflow error on port %x, value %x\n",
- i*8 + j, val);
+ for (i = TAPAN_SLIM_PGD_PORT_INT_STATUS_RX_0, j = 0;
+ i <= TAPAN_SLIM_PGD_PORT_INT_STATUS_TX_1; i++, j++) {
+ val = wcd9xxx_interface_reg_read(codec->control_data, i);
+ status |= ((u32)val << (8 * j));
+ }
+
+ for_each_set_bit(j, &status, 32) {
+ tx = (j >= 16 ? true : false);
+ port_id = (tx ? j - 16 : j);
+ val = wcd9xxx_interface_reg_read(codec->control_data,
+ TAPAN_SLIM_PGD_PORT_INT_RX_SOURCE0 + j);
+ if (val & TAPAN_SLIM_IRQ_OVERFLOW)
+ pr_err_ratelimited(
+ "%s: overflow error on %s port %d, value %x\n",
+ __func__, (tx ? "TX" : "RX"), port_id, val);
+ if (val & TAPAN_SLIM_IRQ_UNDERFLOW)
+ pr_err_ratelimited(
+ "%s: underflow error on %s port %d, value %x\n",
+ __func__, (tx ? "TX" : "RX"), port_id, val);
+ if (val & TAPAN_SLIM_IRQ_PORT_CLOSED) {
+ /*
+ * INT SOURCE register starts from RX to TX
+ * but port number in the ch_mask is in opposite way
+ */
+ bit = (tx ? j - 16 : j + 16);
+ dev_dbg(codec->dev, "%s: %s port %d closed value %x, bit %u\n",
+ __func__, (tx ? "TX" : "RX"), port_id, val,
+ bit);
+ for (k = 0, cleared = false; k < NUM_CODEC_DAIS; k++) {
+ dev_dbg(codec->dev, "%s: priv->dai[%d].ch_mask = 0x%lx\n",
+ __func__, k, priv->dai[k].ch_mask);
+ if (test_and_clear_bit(bit,
+ &priv->dai[k].ch_mask)) {
+ cleared = true;
+ if (!priv->dai[k].ch_mask)
+ wake_up(&priv->dai[k].dai_wait);
+ /*
+ * There are cases when multiple DAIs
+ * might be using the same slimbus
+ * channel. Hence don't break here.
+ */
+ }
+ }
+ WARN(!cleared,
+ "Couldn't find slimbus %s port %d for closing\n",
+ (tx ? "TX" : "RX"), port_id);
}
wcd9xxx_interface_reg_write(codec->control_data,
- TAPAN_SLIM_PGD_PORT_INT_CLR0 + i, 0xFF);
-
+ TAPAN_SLIM_PGD_PORT_INT_CLR_RX_0 +
+ (j / 8),
+ 1 << (j % 8));
}
+
return IRQ_HANDLED;
}
-static const struct tapan_reg_mask_val tapan_1_0_class_h_ear[] = {
-
- /* CLASS-H EAR IDLE_THRESHOLD Table */
- TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_IDLE_EAR_THSD, 0x26),
- TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_FCLKONLY_EAR_THSD, 0x2C),
-
- /* CLASS-H EAR I_PA_FACT Table. */
- TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_I_PA_FACT_EAR_L, 0xA9),
- TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_I_PA_FACT_EAR_U, 0x07),
-
- /* CLASS-H EAR Voltage Headroom , Voltage Min. */
- TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_V_PA_HD_EAR, 0x0D),
- TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_V_PA_MIN_EAR, 0x3A),
-
- /* CLASS-H EAR K values --chnages from load. */
- TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_K_ADDR, 0x08),
- TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_K_DATA, 0x1B),
- TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_K_DATA, 0x00),
- TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_K_DATA, 0x2D),
- TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_K_DATA, 0x00),
- TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_K_DATA, 0x36),
- TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_K_DATA, 0x00),
- TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_K_DATA, 0x37),
- TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_K_DATA, 0x00),
- /** end of Ear PA load 32 */
-};
-
-static const struct tapan_reg_mask_val tapan_1_0_class_h_hph[] = {
-
- /* CLASS-H HPH IDLE_THRESHOLD Table */
- TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_IDLE_HPH_THSD, 0x13),
- TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0x19),
-
- /* CLASS-H HPH I_PA_FACT Table */
- TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_I_PA_FACT_HPH_L, 0x9A),
- TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_I_PA_FACT_HPH_U, 0x06),
-
- /* CLASS-H HPH Voltage Headroom , Voltage Min */
- TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_V_PA_HD_HPH, 0x0D),
- TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_V_PA_MIN_HPH, 0x1D),
-
- /* CLASS-H HPH K values --chnages from load .*/
- TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_K_ADDR, 0x00),
- TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_K_DATA, 0xAE),
- TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_K_DATA, 0x01),
- TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_K_DATA, 0x1C),
- TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_K_DATA, 0x00),
- TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_K_DATA, 0x25),
- TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_K_DATA, 0x00),
- TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_K_DATA, 0x27),
- TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_K_DATA, 0x00),
-};
-
-static int tapan_config_ear_class_h(struct snd_soc_codec *codec, u32 ear_load)
-{
- u32 i;
-
- if (ear_load != 32)
- return -EINVAL;
-
- for (i = 0; i < ARRAY_SIZE(tapan_1_0_class_h_ear); i++)
- snd_soc_write(codec, tapan_1_0_class_h_ear[i].reg,
- tapan_1_0_class_h_ear[i].val);
- return 0;
-}
-
-static int tapan_config_hph_class_h(struct snd_soc_codec *codec, u32 hph_load)
-{
- u32 i;
- if (hph_load != 16)
- return -EINVAL;
-
- for (i = 0; i < ARRAY_SIZE(tapan_1_0_class_h_hph); i++)
- snd_soc_write(codec, tapan_1_0_class_h_hph[i].reg,
- tapan_1_0_class_h_hph[i].val);
- return 0;
-}
-
static int tapan_handle_pdata(struct tapan_priv *tapan)
{
struct snd_soc_codec *codec = tapan->codec;
struct wcd9xxx_pdata *pdata = tapan->resmgr.pdata;
int k1, k2, k3, rc = 0;
- u8 leg_mode, txfe_bypass, txfe_buff, flag;
- u8 value = 0;
+ u8 txfe_bypass = pdata->amic_settings.txfe_enable;
+ u8 txfe_buff = pdata->amic_settings.txfe_buff;
+ u8 flag = pdata->amic_settings.use_pdata;
+ u8 i = 0, j = 0;
+ u8 val_txfe = 0, value = 0;
if (!pdata) {
- pr_err("%s: NULL pdata\n", __func__);
+ dev_err(codec->dev, "%s: NULL pdata\n", __func__);
rc = -ENODEV;
goto done;
}
- leg_mode = pdata->amic_settings.legacy_mode;
- txfe_bypass = pdata->amic_settings.txfe_enable;
- txfe_buff = pdata->amic_settings.txfe_buff;
- flag = pdata->amic_settings.use_pdata;
-
/* Make sure settings are correct */
if ((pdata->micbias.ldoh_v > WCD9XXX_LDOH_3P0_V) ||
(pdata->micbias.bias1_cfilt_sel > WCD9XXX_CFILT3_SEL) ||
(pdata->micbias.bias2_cfilt_sel > WCD9XXX_CFILT3_SEL) ||
(pdata->micbias.bias3_cfilt_sel > WCD9XXX_CFILT3_SEL)) {
+ dev_err(codec->dev, "%s: Invalid ldoh voltage or bias cfilt\n",
+ __func__);
rc = -EINVAL;
goto done;
}
@@ -3434,6 +3879,9 @@
k3 = wcd9xxx_resmgr_get_k_val(&tapan->resmgr, pdata->micbias.cfilt3_mv);
if (IS_ERR_VALUE(k1) || IS_ERR_VALUE(k2) || IS_ERR_VALUE(k3)) {
+ dev_err(codec->dev,
+ "%s: could not get K value. k1 = %d k2 = %d k3 = %d\n",
+ __func__, k1, k2, k3);
rc = -EINVAL;
goto done;
}
@@ -3445,19 +3893,34 @@
snd_soc_update_bits(codec, TAPAN_A_MICB_CFILT_2_VAL, 0xFC, (k2 << 2));
snd_soc_update_bits(codec, TAPAN_A_MICB_CFILT_3_VAL, 0xFC, (k3 << 2));
- snd_soc_update_bits(codec, TAPAN_A_MICB_1_CTL, 0x60,
- (pdata->micbias.bias1_cfilt_sel << 5));
- snd_soc_update_bits(codec, TAPAN_A_MICB_2_CTL, 0x60,
- (pdata->micbias.bias2_cfilt_sel << 5));
- snd_soc_update_bits(codec, TAPAN_A_MICB_3_CTL, 0x60,
- (pdata->micbias.bias3_cfilt_sel << 5));
+ i = 0;
+ while (i < 5) {
+ if (flag & (0x01 << i)) {
+ val_txfe = (txfe_bypass & (0x01 << i)) ? 0x20 : 0x00;
+ val_txfe = val_txfe |
+ ((txfe_buff & (0x01 << i)) ? 0x10 : 0x00);
+ snd_soc_update_bits(codec,
+ TAPAN_A_TX_1_2_TEST_EN + j * 10,
+ 0x30, val_txfe);
+ }
+ if (flag & (0x01 << (i + 1))) {
+ val_txfe = (txfe_bypass &
+ (0x01 << (i + 1))) ? 0x02 : 0x00;
+ val_txfe |= (txfe_buff &
+ (0x01 << (i + 1))) ? 0x01 : 0x00;
+ snd_soc_update_bits(codec,
+ TAPAN_A_TX_1_2_TEST_EN + j * 10,
+ 0x03, val_txfe);
+ }
+ /* Tapan only has TAPAN_A_TX_1_2_TEST_EN and
+ TAPAN_A_TX_4_5_TEST_EN reg */
- if (flag & 0x40) {
- value = (leg_mode & 0x40) ? 0x10 : 0x00;
- value = value | ((txfe_bypass & 0x40) ? 0x02 : 0x00);
- value = value | ((txfe_buff & 0x40) ? 0x01 : 0x00);
- snd_soc_update_bits(codec, TAPAN_A_TX_7_MBHC_EN,
- 0x13, value);
+ if (i == 0) {
+ i = 3;
+ continue;
+ } else if (i == 3) {
+ break;
+ }
}
if (pdata->ocp.use_pdata) {
@@ -3475,8 +3938,16 @@
0xE0, (pdata->ocp.hph_ocp_limit << 5));
}
- tapan_config_ear_class_h(codec, 32);
- tapan_config_hph_class_h(codec, 16);
+ /* Set micbias capless mode with tail current */
+ value = (pdata->micbias.bias1_cap_mode == MICBIAS_EXT_BYP_CAP ?
+ 0x00 : 0x10);
+ snd_soc_update_bits(codec, TAPAN_A_MICB_1_CTL, 0x10, value);
+ value = (pdata->micbias.bias2_cap_mode == MICBIAS_EXT_BYP_CAP ?
+ 0x00 : 0x10);
+ snd_soc_update_bits(codec, TAPAN_A_MICB_2_CTL, 0x10, value);
+ value = (pdata->micbias.bias3_cap_mode == MICBIAS_EXT_BYP_CAP ?
+ 0x00 : 0x10);
+ snd_soc_update_bits(codec, TAPAN_A_MICB_3_CTL, 0x10, value);
done:
return rc;
@@ -3484,60 +3955,54 @@
static const struct tapan_reg_mask_val tapan_reg_defaults[] = {
- /* set MCLk to 9.6 */
- TAPAN_REG_VAL(TAPAN_A_CHIP_CTL, 0x0A),
+ /* enable QFUSE for wcd9306 */
+ TAPAN_REG_VAL(TAPAN_A_QFUSE_CTL, 0x03),
+
+ /* PROGRAM_THE_0P85V_VBG_REFERENCE = V_0P858V */
+ TAPAN_REG_VAL(TAPAN_A_BIAS_CURR_CTL_2, 0x04),
+
TAPAN_REG_VAL(TAPAN_A_CDC_CLK_POWER_CTL, 0x03),
/* EAR PA deafults */
TAPAN_REG_VAL(TAPAN_A_RX_EAR_CMBUFF, 0x05),
- /** BUCK and NCP defaults for EAR and HS */
- TAPAN_REG_VAL(TAPAN_A_BUCK_CTRL_CCL_4, 0x50),
- TAPAN_REG_VAL(TAPAN_A_BUCK_CTRL_CCL_1, 0x5B),
-
- /* CLASS-H defaults for EAR and HS */
- TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_BUCK_NCP_VARS, 0x00),
- TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_BUCK_NCP_VARS, 0x04),
- TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_B2_CTL, 0x01),
- TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_B2_CTL, 0x05),
- TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_B2_CTL, 0x35),
- TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_B3_CTL, 0x30),
- TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_B3_CTL, 0x3B),
-
- /*
- * For CLASS-H, Enable ANC delay buffer,
- * set HPHL and EAR PA ref gain to 0 DB.
- */
- TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_B1_CTL, 0x26),
-
- /* RX deafults */
- TAPAN_REG_VAL(TAPAN_A_CDC_RX1_B5_CTL, 0x78),
- TAPAN_REG_VAL(TAPAN_A_CDC_RX2_B5_CTL, 0x78),
- TAPAN_REG_VAL(TAPAN_A_CDC_RX3_B5_CTL, 0x78),
- TAPAN_REG_VAL(TAPAN_A_CDC_RX4_B5_CTL, 0x78),
-
/* RX1 and RX2 defaults */
TAPAN_REG_VAL(TAPAN_A_CDC_RX1_B6_CTL, 0xA0),
TAPAN_REG_VAL(TAPAN_A_CDC_RX2_B6_CTL, 0xA0),
- /* RX3 to RX7 defaults */
- TAPAN_REG_VAL(TAPAN_A_CDC_RX3_B6_CTL, 0x80),
- TAPAN_REG_VAL(TAPAN_A_CDC_RX4_B6_CTL, 0x80),
+ /* Heaset set Right from RX2 */
+ TAPAN_REG_VAL(TAPAN_A_CDC_CONN_RX2_B2_CTL, 0x10),
+
/*
- * The following only need to be written for Taiko 1.0 parts.
- * Taiko 2.0 will have appropriate defaults for these registers.
+ * The following only need to be written for Tapan 1.0 parts.
+ * Tapan 2.0 will have appropriate defaults for these registers.
*/
+
+ /* Required defaults for class H operation */
+ /* borrowed from Taiko class-h */
+ TAPAN_REG_VAL(TAPAN_A_RX_HPH_CHOP_CTL, 0xF4),
+ TAPAN_REG_VAL(TAPAN_A_BIAS_CURR_CTL_2, 0x08),
+ TAPAN_REG_VAL(WCD9XXX_A_BUCK_CTRL_CCL_1, 0x5B),
+ TAPAN_REG_VAL(WCD9XXX_A_BUCK_CTRL_CCL_3, 0x60),
+
+ /* TODO: Check below reg writes conflict with above */
+ /* PROGRAM_THE_0P85V_VBG_REFERENCE = V_0P858V */
+ TAPAN_REG_VAL(TAPAN_A_BIAS_CURR_CTL_2, 0x04),
+ TAPAN_REG_VAL(WCD9XXX_A_BUCK_CTRL_CCL_4, 0x54),
+ TAPAN_REG_VAL(TAPAN_A_RX_HPH_CHOP_CTL, 0x74),
+ TAPAN_REG_VAL(TAPAN_A_RX_BUCK_BIAS1, 0x62),
+
/* Choose max non-overlap time for NCP */
TAPAN_REG_VAL(TAPAN_A_NCP_CLK, 0xFC),
/* Use 25mV/50mV for deltap/m to reduce ripple */
- TAPAN_REG_VAL(TAPAN_A_BUCK_CTRL_VCL_1, 0x08),
+ TAPAN_REG_VAL(WCD9XXX_A_BUCK_CTRL_VCL_1, 0x08),
/*
* Set DISABLE_MODE_SEL<1:0> to 0b10 (disable PWM in auto mode).
* Note that the other bits of this register will be changed during
* Rx PA bring up.
*/
- TAPAN_REG_VAL(TAPAN_A_BUCK_MODE_3, 0xCE),
+ TAPAN_REG_VAL(WCD9XXX_A_BUCK_MODE_3, 0xCE),
/* Reduce HPH DAC bias to 70% */
TAPAN_REG_VAL(TAPAN_A_RX_HPH_BIAS_PA, 0x7A),
/*Reduce EAR DAC bias to 70% */
@@ -3553,17 +4018,64 @@
*/
TAPAN_REG_VAL(TAPAN_A_MICB_2_MBHC, 0x41),
+ /* not needed if MBHC is not needed */
/* Disable TX7 internal biasing path which can cause leakage */
TAPAN_REG_VAL(TAPAN_A_TX_SUP_SWITCH_CTRL_1, 0xBF),
};
+static const struct tapan_reg_mask_val tapan_2_x_reg_reset_values[] = {
+
+ TAPAN_REG_VAL(TAPAN_A_TX_7_MBHC_EN, 0x6C),
+ TAPAN_REG_VAL(TAPAN_A_BUCK_CTRL_CCL_4, 0x51),
+ TAPAN_REG_VAL(TAPAN_A_RX_HPH_CNP_WG_CTL, 0xDA),
+ TAPAN_REG_VAL(TAPAN_A_RX_EAR_CNP, 0xC0),
+ TAPAN_REG_VAL(TAPAN_A_RX_LINE_1_TEST, 0x02),
+ TAPAN_REG_VAL(TAPAN_A_RX_LINE_2_TEST, 0x02),
+ TAPAN_REG_VAL(TAPAN_A_SPKR_DRV_OCP_CTL, 0x97),
+ TAPAN_REG_VAL(TAPAN_A_SPKR_DRV_CLIP_DET, 0x01),
+ TAPAN_REG_VAL(TAPAN_A_SPKR_DRV_IEC, 0x00),
+ TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_B1_CTL, 0xE4),
+ TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_B2_CTL, 0x00),
+ TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_B3_CTL, 0x00),
+ TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_BUCK_NCP_VARS, 0x00),
+ TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_V_PA_HD_EAR, 0x00),
+ TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_V_PA_HD_HPH, 0x00),
+ TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_V_PA_MIN_EAR, 0x00),
+ TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_V_PA_MIN_HPH, 0x00),
+};
+
+static const struct tapan_reg_mask_val tapan_1_0_reg_defaults[] = {
+ /* Close leakage on the spkdrv */
+ TAPAN_REG_VAL(TAPAN_A_SPKR_DRV_DBG_PWRSTG, 0x24),
+ TAPAN_REG_VAL(TAPAN_A_SPKR_DRV_DBG_DAC, 0xE5),
+
+};
+
static void tapan_update_reg_defaults(struct snd_soc_codec *codec)
{
u32 i;
+ struct wcd9xxx *tapan_core = dev_get_drvdata(codec->dev->parent);
+
+ if (!TAPAN_IS_1_0(tapan_core->version)) {
+ for (i = 0; i < ARRAY_SIZE(tapan_2_x_reg_reset_values); i++)
+ snd_soc_write(codec, tapan_2_x_reg_reset_values[i].reg,
+ tapan_2_x_reg_reset_values[i].val);
+ }
for (i = 0; i < ARRAY_SIZE(tapan_reg_defaults); i++)
snd_soc_write(codec, tapan_reg_defaults[i].reg,
tapan_reg_defaults[i].val);
+
+ if (TAPAN_IS_1_0(tapan_core->version)) {
+ for (i = 0; i < ARRAY_SIZE(tapan_1_0_reg_defaults); i++)
+ snd_soc_write(codec, tapan_1_0_reg_defaults[i].reg,
+ tapan_1_0_reg_defaults[i].val);
+ }
+
+ if (!TAPAN_IS_1_0(tapan_core->version))
+ spkr_drv_wrnd = -1;
+ else if (spkr_drv_wrnd == 1)
+ snd_soc_write(codec, TAPAN_A_SPKR_DRV_EN, 0xEF);
}
static const struct tapan_reg_mask_val tapan_codec_reg_init_val[] = {
@@ -3578,17 +4090,27 @@
{TAPAN_A_RX_HPH_R_GAIN, 0x20, 0x20},
{TAPAN_A_RX_LINE_1_GAIN, 0x20, 0x20},
{TAPAN_A_RX_LINE_2_GAIN, 0x20, 0x20},
+ {TAPAN_A_SPKR_DRV_GAIN, 0x04, 0x04},
+
+ /* Set RDAC5 MUX to take input from DEM3_INV.
+ * This sets LO2 DAC to get input from DEM3_INV
+ * for LO1 and LO2 to work as differential outputs.
+ */
+ {TAPAN_A_CDC_CONN_MISC, 0x04, 0x04},
/* CLASS H config */
{TAPAN_A_CDC_CONN_CLSH_CTL, 0x3C, 0x14},
- /* Use 16 bit sample size for TX1 to TX6 */
+ /* Use 16 bit sample size for TX1 to TX5 */
{TAPAN_A_CDC_CONN_TX_SB_B1_CTL, 0x30, 0x20},
{TAPAN_A_CDC_CONN_TX_SB_B2_CTL, 0x30, 0x20},
{TAPAN_A_CDC_CONN_TX_SB_B3_CTL, 0x30, 0x20},
{TAPAN_A_CDC_CONN_TX_SB_B4_CTL, 0x30, 0x20},
{TAPAN_A_CDC_CONN_TX_SB_B5_CTL, 0x30, 0x20},
+ /* Disable SPK SWITCH */
+ {TAPAN_A_SPKR_DRV_DAC_CTL, 0x04, 0x00},
+
/* Use 16 bit sample size for RX */
{TAPAN_A_CDC_CONN_RX_SB_B1_CTL, 0xFF, 0xAA},
{TAPAN_A_CDC_CONN_RX_SB_B2_CTL, 0xFF, 0x2A},
@@ -3607,8 +4129,14 @@
/* config DMIC clk to CLK_MODE_1 (3.2Mhz@9.6Mhz mclk) */
{TAPAN_A_CDC_CLK_DMIC_B1_CTL, 0xEE, 0x22},
- {TAPAN_A_CDC_CLK_DMIC_B2_CTL, 0x0E, 0x02},
+ /* Compander zone selection */
+ {TAPAN_A_CDC_COMP0_B4_CTL, 0x3F, 0x37},
+ {TAPAN_A_CDC_COMP1_B4_CTL, 0x3F, 0x37},
+ {TAPAN_A_CDC_COMP2_B4_CTL, 0x3F, 0x37},
+ {TAPAN_A_CDC_COMP0_B5_CTL, 0x7F, 0x7F},
+ {TAPAN_A_CDC_COMP1_B5_CTL, 0x7F, 0x7F},
+ {TAPAN_A_CDC_COMP2_B5_CTL, 0x7F, 0x7F},
};
static void tapan_codec_init_reg(struct snd_soc_codec *codec)
@@ -3684,6 +4212,10 @@
snd_soc_codec_set_drvdata(codec, tapan);
+ /* TODO: Read buck voltage from DT property */
+ tapan->clsh_d.buck_mv = WCD9XXX_CDC_BUCK_MV_1P8;
+ wcd9xxx_clsh_init(&tapan->clsh_d, &tapan->resmgr);
+
/* codec resmgr module init */
wcd9xxx = codec->control_data;
pdata = dev_get_platdata(codec->dev->parent);
@@ -3691,28 +4223,44 @@
&tapan_reg_address);
if (ret) {
pr_err("%s: wcd9xxx init failed %d\n", __func__, ret);
- goto err_codec;
+ return ret;
}
- /* init and start mbhc */
- ret = wcd9xxx_mbhc_init(&tapan->mbhc, &tapan->resmgr, codec);
- if (ret) {
- pr_err("%s: mbhc init failed %d\n", __func__, ret);
- goto err_codec;
- }
+ /* TODO: wcd9xxx_mbhc_init to enable mbhc */
tapan->codec = codec;
-
+ for (i = 0; i < COMPANDER_MAX; i++) {
+ tapan->comp_enabled[i] = 0;
+ tapan->comp_fs[i] = COMPANDER_FS_48KHZ;
+ }
tapan->intf_type = wcd9xxx_get_intf_type();
tapan->aux_pga_cnt = 0;
tapan->aux_l_gain = 0x1F;
tapan->aux_r_gain = 0x1F;
tapan_update_reg_defaults(codec);
+
+ dev_dbg(codec->dev, "%s: MCLK Rate = %x\n",
+ __func__, wcd9xxx->mclk_rate);
+
+ if (wcd9xxx->mclk_rate == TAPAN_MCLK_CLK_12P288MHZ) {
+ snd_soc_update_bits(codec, TAPAN_A_CHIP_CTL, 0x06, 0x0);
+ snd_soc_update_bits(codec, TAPAN_A_RX_COM_TIMER_DIV, 0x01,
+ 0x01);
+ } else if (wcd9xxx->mclk_rate == TAPAN_MCLK_CLK_9P6HZ) {
+ snd_soc_update_bits(codec, TAPAN_A_CHIP_CTL, 0x06, 0x2);
+ }
tapan_codec_init_reg(codec);
ret = tapan_handle_pdata(tapan);
if (IS_ERR_VALUE(ret)) {
- pr_err("%s: bad pdata\n", __func__);
- goto err_codec;
+ dev_err(codec->dev, "%s: bad pdata\n", __func__);
+ goto err_pdata;
+ }
+
+ if (spkr_drv_wrnd > 0) {
+ WCD9XXX_BCL_LOCK(&tapan->resmgr);
+ wcd9xxx_resmgr_get_bandgap(&tapan->resmgr,
+ WCD9XXX_BANDGAP_AUDIO_MODE);
+ WCD9XXX_BCL_UNLOCK(&tapan->resmgr);
}
ptr = kmalloc((sizeof(tapan_rx_chs) +
@@ -3724,8 +4272,12 @@
}
if (tapan->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
- pr_err("%s: I2C interface not supported yet\n",
- __func__);
+ snd_soc_dapm_new_controls(dapm, tapan_dapm_i2s_widgets,
+ ARRAY_SIZE(tapan_dapm_i2s_widgets));
+ snd_soc_dapm_add_routes(dapm, audio_i2s_map,
+ ARRAY_SIZE(audio_i2s_map));
+ for (i = 0; i < ARRAY_SIZE(tapan_i2s_dai); i++)
+ INIT_LIST_HEAD(&tapan->dai[i].wcd9xxx_ch_list);
} else if (tapan->intf_type == WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
for (i = 0; i < NUM_CODEC_DAIS; i++) {
INIT_LIST_HEAD(&tapan->dai[i].wcd9xxx_ch_list);
@@ -3744,12 +4296,14 @@
(void) tapan_setup_irqs(tapan);
+ atomic_set(&kp_tapan_priv, (unsigned long)tapan);
+
codec->ignore_pmdown_time = 1;
return ret;
-err_nomem_slimch:
+err_pdata:
kfree(ptr);
-err_codec:
+err_nomem_slimch:
kfree(tapan);
return ret;
}
@@ -3758,6 +4312,13 @@
{
struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
+ WCD9XXX_BCL_LOCK(&tapan->resmgr);
+ atomic_set(&kp_tapan_priv, 0);
+
+ if (spkr_drv_wrnd > 0)
+ wcd9xxx_resmgr_put_bandgap(&tapan->resmgr,
+ WCD9XXX_BANDGAP_AUDIO_MODE);
+ WCD9XXX_BCL_UNLOCK(&tapan->resmgr);
/* cleanup MBHC */
wcd9xxx_mbhc_deinit(&tapan->mbhc);
/* cleanup resmgr */
@@ -3801,6 +4362,7 @@
struct platform_device *pdev = to_platform_device(dev);
struct tapan_priv *tapan = platform_get_drvdata(pdev);
dev_dbg(dev, "%s: system resume\n", __func__);
+ /* Notify */
wcd9xxx_resmgr_notifier_call(&tapan->resmgr, WCD9XXX_EVENT_POST_RESUME);
return 0;
}
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index f4ea679..78d1749 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -38,6 +38,9 @@
#include "wcd9xxx-resmgr.h"
#include "wcd9xxx-common.h"
+#define TAIKO_MAD_SLIMBUS_TX_PORT 12
+#define TAIKO_MAD_AUDIO_FIRMWARE_PATH "wcd9320/wcd9320_mad_audio.bin"
+
static atomic_t kp_taiko_priv;
static int spkr_drv_wrnd_param_set(const char *val,
const struct kernel_param *kp);
@@ -47,6 +50,121 @@
.set = spkr_drv_wrnd_param_set,
.get = param_get_int,
};
+
+static struct afe_param_slimbus_slave_port_cfg taiko_slimbus_slave_port_cfg = {
+ .minor_version = 1,
+ .slimbus_dev_id = AFE_SLIMBUS_DEVICE_1,
+ .slave_dev_pgd_la = 0,
+ .slave_dev_intfdev_la = 0,
+ .bit_width = 16,
+ .data_format = 0,
+ .num_channels = 1
+};
+
+enum {
+ RESERVED = 0,
+ AANC_LPF_FF_FB = 1,
+ AANC_LPF_COEFF_MSB,
+ AANC_LPF_COEFF_LSB,
+ HW_MAD_AUDIO_ENABLE,
+ HW_MAD_ULTR_ENABLE,
+ HW_MAD_BEACON_ENABLE,
+ HW_MAD_AUDIO_SLEEP_TIME,
+ HW_MAD_ULTR_SLEEP_TIME,
+ HW_MAD_BEACON_SLEEP_TIME,
+ HW_MAD_TX_AUDIO_SWITCH_OFF,
+ HW_MAD_TX_ULTR_SWITCH_OFF,
+ HW_MAD_TX_BEACON_SWITCH_OFF,
+ MAD_AUDIO_INT_DEST_SELECT_REG,
+ MAD_ULT_INT_DEST_SELECT_REG,
+ MAD_BEACON_INT_DEST_SELECT_REG,
+ MAD_CLIP_INT_DEST_SELECT_REG,
+ MAD_VBAT_INT_DEST_SELECT_REG,
+ MAD_AUDIO_INT_MASK_REG,
+ MAD_ULT_INT_MASK_REG,
+ MAD_BEACON_INT_MASK_REG,
+ MAD_CLIP_INT_MASK_REG,
+ MAD_VBAT_INT_MASK_REG,
+ MAD_AUDIO_INT_STATUS_REG,
+ MAD_ULT_INT_STATUS_REG,
+ MAD_BEACON_INT_STATUS_REG,
+ MAD_CLIP_INT_STATUS_REG,
+ MAD_VBAT_INT_STATUS_REG,
+ MAD_AUDIO_INT_CLEAR_REG,
+ MAD_ULT_INT_CLEAR_REG,
+ MAD_BEACON_INT_CLEAR_REG,
+ MAD_CLIP_INT_CLEAR_REG,
+ MAD_VBAT_INT_CLEAR_REG,
+ SB_PGD_PORT_TX_WATERMARK_n,
+ SB_PGD_PORT_TX_ENABLE_n,
+ SB_PGD_PORT_RX_WATERMARK_n,
+ SB_PGD_PORT_RX_ENABLE_n,
+ MAX_CFG_REGISTERS,
+};
+
+static struct afe_param_cdc_reg_cfg mad_audio_reg_cfg[] = {
+ {
+ 1,
+ (TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_MAD_MAIN_CTL_1),
+ HW_MAD_AUDIO_ENABLE, 0x1, 8, 0
+ },
+ {
+ 1,
+ (TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_MAD_AUDIO_CTL_3),
+ HW_MAD_AUDIO_SLEEP_TIME, 0xF, 8, 0
+ },
+ {
+ 1,
+ (TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_MAD_AUDIO_CTL_4),
+ HW_MAD_TX_AUDIO_SWITCH_OFF, 0x1, 8, 0
+ },
+ {
+ 1,
+ (TAIKO_REGISTER_START_OFFSET + TAIKO_A_INTR_DESTN3),
+ MAD_AUDIO_INT_DEST_SELECT_REG, 0x1, 8, 0
+ },
+ {
+ 1,
+ (TAIKO_REGISTER_START_OFFSET + TAIKO_A_INTR_MASK3),
+ MAD_AUDIO_INT_MASK_REG, 0x1, 8, 0
+ },
+ {
+ 1,
+ (TAIKO_REGISTER_START_OFFSET + TAIKO_A_INTR_STATUS3),
+ MAD_AUDIO_INT_STATUS_REG, 0x1, 8, 0
+ },
+ {
+ 1,
+ (TAIKO_REGISTER_START_OFFSET + TAIKO_A_INTR_CLEAR3),
+ MAD_AUDIO_INT_CLEAR_REG, 0x1, 8, 0
+ },
+ {
+ 1,
+ (TAIKO_REGISTER_START_OFFSET + TAIKO_SB_PGD_PORT_TX_BASE),
+ SB_PGD_PORT_TX_WATERMARK_n, 0x1E, 8, 0x1
+ },
+ {
+ 1,
+ (TAIKO_REGISTER_START_OFFSET + TAIKO_SB_PGD_PORT_TX_BASE),
+ SB_PGD_PORT_TX_ENABLE_n, 0x1, 8, 0x1
+ },
+ {
+ 1,
+ (TAIKO_REGISTER_START_OFFSET + TAIKO_SB_PGD_PORT_RX_BASE),
+ SB_PGD_PORT_RX_WATERMARK_n, 0x1E, 8, 0x1
+ },
+ {
+ 1,
+ (TAIKO_REGISTER_START_OFFSET + TAIKO_SB_PGD_PORT_RX_BASE),
+ SB_PGD_PORT_RX_ENABLE_n, 0x1, 8, 0x1
+ }
+};
+
+static struct afe_param_cdc_reg_cfg_data taiko_mad_audio_reg_cfg = {
+ .num_registers = ARRAY_SIZE(mad_audio_reg_cfg),
+ .reg_data = mad_audio_reg_cfg,
+};
+
module_param_cb(spkr_drv_wrnd, &spkr_drv_wrnd_param_ops, &spkr_drv_wrnd, 0644);
MODULE_PARM_DESC(spkr_drv_wrnd,
"Run software workaround to avoid leakage on the speaker drive");
@@ -84,6 +202,7 @@
AIF3_PB,
AIF3_CAP,
AIF4_VIFEED,
+ AIF4_MAD_TX,
NUM_CODEC_DAIS,
};
@@ -237,6 +356,8 @@
bool spkr_pa_widget_on;
+ struct afe_param_cdc_slimbus_slave_cfg slimbus_slave_cfg;
+
/* resmgr module */
struct wcd9xxx_resmgr resmgr;
/* mbhc module */
@@ -1555,6 +1676,9 @@
static const struct snd_kcontrol_new lineout4_ground_switch =
SOC_DAPM_SINGLE("Switch", TAIKO_A_RX_LINE_4_DAC_CTL, 6, 1, 0);
+static const struct snd_kcontrol_new aif4_mad_switch =
+ SOC_DAPM_SINGLE("Switch", TAIKO_A_CDC_CLK_OTHR_CTL, 4, 1, 0);
+
/* virtual port entries */
static int slim_tx_mixer_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
@@ -2155,6 +2279,108 @@
return 0;
}
+static int taiko_codec_config_mad(struct snd_soc_codec *codec)
+{
+ int ret;
+ const struct firmware *fw;
+ struct mad_audio_cal *mad_cal;
+ const char *filename = TAIKO_MAD_AUDIO_FIRMWARE_PATH;
+
+ pr_debug("%s: enter\n", __func__);
+ ret = request_firmware(&fw, filename, codec->dev);
+ if (ret != 0) {
+ pr_err("Failed to acquire MAD firwmare data %s: %d\n", filename,
+ ret);
+ return -ENODEV;
+ }
+
+ if (fw->size < sizeof(struct mad_audio_cal)) {
+ pr_err("%s: incorrect firmware size %u\n", __func__, fw->size);
+ release_firmware(fw);
+ return -ENOMEM;
+ }
+
+ mad_cal = (struct mad_audio_cal *)(fw->data);
+ if (!mad_cal) {
+ pr_err("%s: Invalid calibration data\n", __func__);
+ release_firmware(fw);
+ return -EINVAL;
+ }
+
+ snd_soc_update_bits(codec, TAIKO_A_CDC_CONN_MAD,
+ 0x0F, mad_cal->microphone_info.input_microphone);
+ snd_soc_write(codec, TAIKO_A_CDC_MAD_MAIN_CTL_2,
+ mad_cal->microphone_info.cycle_time);
+ snd_soc_update_bits(codec, TAIKO_A_CDC_MAD_MAIN_CTL_1, 0xFF << 3,
+ ((uint16_t)mad_cal->microphone_info.settle_time)
+ << 3);
+
+ /* Audio */
+ snd_soc_write(codec, TAIKO_A_CDC_MAD_AUDIO_CTL_8,
+ mad_cal->audio_info.rms_omit_samples);
+ snd_soc_update_bits(codec, TAIKO_A_CDC_MAD_AUDIO_CTL_1,
+ 0x07 << 4, mad_cal->audio_info.rms_comp_time << 4);
+ snd_soc_update_bits(codec, TAIKO_A_CDC_MAD_AUDIO_CTL_2, 0x03 << 2,
+ mad_cal->audio_info.detection_mechanism << 2);
+ snd_soc_write(codec, TAIKO_A_CDC_MAD_AUDIO_CTL_7,
+ mad_cal->audio_info.rms_diff_threshold & 0x3F);
+ snd_soc_write(codec, TAIKO_A_CDC_MAD_AUDIO_CTL_5,
+ mad_cal->audio_info.rms_threshold_lsb);
+ snd_soc_write(codec, TAIKO_A_CDC_MAD_AUDIO_CTL_6,
+ mad_cal->audio_info.rms_threshold_msb);
+
+
+ /* Beacon */
+ snd_soc_write(codec, TAIKO_A_CDC_MAD_BEACON_CTL_8,
+ mad_cal->beacon_info.rms_omit_samples);
+ snd_soc_update_bits(codec, TAIKO_A_CDC_MAD_BEACON_CTL_1,
+ 0x07 << 4, mad_cal->beacon_info.rms_comp_time);
+ snd_soc_update_bits(codec, TAIKO_A_CDC_MAD_BEACON_CTL_2, 0x03 << 2,
+ mad_cal->beacon_info.detection_mechanism << 2);
+ snd_soc_write(codec, TAIKO_A_CDC_MAD_BEACON_CTL_7,
+ mad_cal->beacon_info.rms_diff_threshold & 0x1F);
+ snd_soc_write(codec, TAIKO_A_CDC_MAD_BEACON_CTL_5,
+ mad_cal->beacon_info.rms_threshold_lsb);
+ snd_soc_write(codec, TAIKO_A_CDC_MAD_BEACON_CTL_6,
+ mad_cal->beacon_info.rms_threshold_msb);
+
+ /* Ultrasound */
+ snd_soc_update_bits(codec, TAIKO_A_CDC_MAD_BEACON_CTL_1,
+ 0x07 << 4, mad_cal->beacon_info.rms_comp_time);
+ snd_soc_update_bits(codec, TAIKO_A_CDC_MAD_ULTR_CTL_2, 0x03 << 2,
+ mad_cal->ultrasound_info.detection_mechanism);
+ snd_soc_write(codec, TAIKO_A_CDC_MAD_ULTR_CTL_7,
+ mad_cal->ultrasound_info.rms_diff_threshold & 0x1F);
+ snd_soc_write(codec, TAIKO_A_CDC_MAD_ULTR_CTL_5,
+ mad_cal->ultrasound_info.rms_threshold_lsb);
+ snd_soc_write(codec, TAIKO_A_CDC_MAD_ULTR_CTL_6,
+ mad_cal->ultrasound_info.rms_threshold_msb);
+
+ release_firmware(fw);
+ pr_debug("%s: leave ret %d\n", __func__, ret);
+
+ return ret;
+}
+
+static int taiko_codec_enable_mad(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ int ret = 0;
+
+ pr_debug("%s %d\n", __func__, event);
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ ret = taiko_codec_config_mad(codec);
+ if (ret) {
+ pr_err("%s: Failed to config MAD\n", __func__);
+ break;
+ }
+ break;
+ }
+ return ret;
+}
+
static int taiko_codec_enable_micbias(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
@@ -2564,12 +2790,12 @@
pr_debug("%s: %s event = %d\n", __func__, w->name, event);
if (w->shift == 5) {
- e_pre_on = WCD9XXX_EVENT_PRE_HPHR_PA_ON;
- e_post_off = WCD9XXX_EVENT_POST_HPHR_PA_OFF;
- req_clsh_state = WCD9XXX_CLSH_STATE_HPHL;
- } else if (w->shift == 4) {
e_pre_on = WCD9XXX_EVENT_PRE_HPHL_PA_ON;
e_post_off = WCD9XXX_EVENT_POST_HPHL_PA_OFF;
+ req_clsh_state = WCD9XXX_CLSH_STATE_HPHL;
+ } else if (w->shift == 4) {
+ e_pre_on = WCD9XXX_EVENT_PRE_HPHR_PA_ON;
+ e_post_off = WCD9XXX_EVENT_POST_HPHR_PA_OFF;
req_clsh_state = WCD9XXX_CLSH_STATE_HPHR;
} else {
pr_err("%s: Invalid w->shift %d\n", __func__, w->shift);
@@ -2674,6 +2900,11 @@
{"AIF3 CAP", NULL, "AIF3_CAP Mixer"},
{"AIF4 VI", NULL, "SPK_OUT"},
+ /* MAD */
+ {"AIF4 MAD", NULL, "CDC_CONN"},
+ {"MADONOFF", "Switch", "MADINPUT"},
+ {"AIF4 MAD", NULL, "MADONOFF"},
+
/* SLIM_MIXER("AIF1_CAP Mixer"),*/
{"AIF1_CAP Mixer", "SLIM TX1", "SLIM TX1 MUX"},
{"AIF1_CAP Mixer", "SLIM TX2", "SLIM TX2 MUX"},
@@ -3184,6 +3415,8 @@
static int taiko_volatile(struct snd_soc_codec *ssc, unsigned int reg)
{
+ int i;
+
/* Registers lower than 0x100 are top level registers which can be
* written by the Taiko core driver.
*/
@@ -3222,6 +3455,11 @@
return 1;
}
+ for (i = 0; i < ARRAY_SIZE(mad_audio_reg_cfg); i++)
+ if (mad_audio_reg_cfg[i].reg_logical_addr -
+ TAIKO_REGISTER_START_OFFSET == reg)
+ return 1;
+
return 0;
}
@@ -3428,6 +3666,7 @@
case AIF2_CAP:
case AIF3_CAP:
case AIF4_VIFEED:
+ case AIF4_MAD_TX:
if (!tx_slot || !tx_num) {
pr_err("%s: Invalid tx_slot %d or tx_num %d\n",
__func__, (u32) tx_slot, (u32) tx_num);
@@ -3858,6 +4097,20 @@
},
.ops = &taiko_dai_ops,
},
+ {
+ .name = "taiko_mad1",
+ .id = AIF4_MAD_TX,
+ .capture = {
+ .stream_name = "AIF4 MAD TX",
+ .rates = SNDRV_PCM_RATE_16000,
+ .formats = TAIKO_FORMATS,
+ .rate_min = 16000,
+ .rate_max = 16000,
+ .channels_min = 1,
+ .channels_max = 1,
+ },
+ .ops = &taiko_dai_ops,
+ },
};
static struct snd_soc_dai_driver taiko_i2s_dai[] = {
@@ -4556,6 +4809,12 @@
SND_SOC_DAPM_AIF_OUT_E("AIF4 VI", "VIfeed", 0, SND_SOC_NOPM,
AIF4_VIFEED, 0, taiko_codec_enable_slimvi_feedback,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_AIF_OUT_E("AIF4 MAD", "AIF4 MAD TX", 0,
+ SND_SOC_NOPM, 0, 0,
+ taiko_codec_enable_mad, SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_SWITCH("MADONOFF", SND_SOC_NOPM, 0, 0,
+ &aif4_mad_switch),
+ SND_SOC_DAPM_INPUT("MADINPUT"),
SND_SOC_DAPM_MIXER("AIF1_CAP Mixer", SND_SOC_NOPM, AIF1_CAP, 0,
aif_cap_mixer, ARRAY_SIZE(aif_cap_mixer)),
@@ -4884,6 +5143,26 @@
TAIKO_REG_VAL(TAIKO_A_CDC_RX5_B6_CTL, 0x80),
TAIKO_REG_VAL(TAIKO_A_CDC_RX6_B6_CTL, 0x80),
TAIKO_REG_VAL(TAIKO_A_CDC_RX7_B6_CTL, 0x80),
+
+ /* MAD registers */
+ TAIKO_REG_VAL(TAIKO_A_MAD_ANA_CTRL, 0xF1),
+ TAIKO_REG_VAL(TAIKO_A_CDC_MAD_MAIN_CTL_1, 0x00),
+ TAIKO_REG_VAL(TAIKO_A_CDC_MAD_MAIN_CTL_2, 0x00),
+ TAIKO_REG_VAL(TAIKO_A_CDC_MAD_AUDIO_CTL_1, 0x00),
+ /* Set SAMPLE_TX_EN bit */
+ TAIKO_REG_VAL(TAIKO_A_CDC_MAD_AUDIO_CTL_2, 0x03),
+ TAIKO_REG_VAL(TAIKO_A_CDC_MAD_AUDIO_CTL_3, 0x00),
+ TAIKO_REG_VAL(TAIKO_A_CDC_MAD_AUDIO_CTL_4, 0x00),
+ TAIKO_REG_VAL(TAIKO_A_CDC_MAD_AUDIO_CTL_5, 0x00),
+ TAIKO_REG_VAL(TAIKO_A_CDC_MAD_AUDIO_CTL_6, 0x00),
+ TAIKO_REG_VAL(TAIKO_A_CDC_MAD_AUDIO_CTL_7, 0x00),
+ TAIKO_REG_VAL(TAIKO_A_CDC_MAD_AUDIO_CTL_8, 0x00),
+ TAIKO_REG_VAL(TAIKO_A_CDC_MAD_AUDIO_IIR_CTL_PTR, 0x00),
+ TAIKO_REG_VAL(TAIKO_A_CDC_MAD_AUDIO_IIR_CTL_VAL, 0x40),
+ TAIKO_REG_VAL(TAIKO_A_CDC_DEBUG_B7_CTL, 0x00),
+ TAIKO_REG_VAL(TAIKO_A_CDC_CLK_OTHR_RESET_B1_CTL, 0x00),
+ TAIKO_REG_VAL(TAIKO_A_CDC_CLK_OTHR_CTL, 0x00),
+ TAIKO_REG_VAL(TAIKO_A_CDC_CONN_MAD, 0x01),
};
static const struct wcd9xxx_reg_mask_val taiko_1_0_reg_defaults[] = {
@@ -5121,6 +5400,26 @@
}
EXPORT_SYMBOL_GPL(taiko_hs_detect);
+static void taiko_init_slim_slave_cfg(struct snd_soc_codec *codec)
+{
+ struct taiko_priv *priv = snd_soc_codec_get_drvdata(codec);
+ struct afe_param_cdc_slimbus_slave_cfg *cfg;
+ struct wcd9xxx *wcd9xxx = codec->control_data;
+ uint64_t eaddr = 0;
+
+ cfg = &priv->slimbus_slave_cfg;
+ cfg->minor_version = 1;
+ cfg->tx_slave_port_offset = 0;
+ cfg->rx_slave_port_offset = 16;
+
+ memcpy(&eaddr, &wcd9xxx->slim->e_addr, sizeof(wcd9xxx->slim->e_addr));
+ WARN_ON(sizeof(wcd9xxx->slim->e_addr) != 6);
+ cfg->device_enum_addr_lsw = eaddr & 0xFFFFFFFF;
+ cfg->device_enum_addr_msw = eaddr >> 32;
+
+ pr_debug("%s: slimbus logical address 0x%llx\n", __func__, eaddr);
+}
+
static int taiko_post_reset_cb(struct wcd9xxx *wcd9xxx)
{
int ret = 0;
@@ -5150,6 +5449,8 @@
if (IS_ERR_VALUE(ret))
pr_err("%s: bad pdata\n", __func__);
+ taiko_init_slim_slave_cfg(codec);
+
wcd9xxx_mbhc_deinit(&taiko->mbhc);
ret = wcd9xxx_mbhc_init(&taiko->mbhc, &taiko->resmgr, codec);
if (ret)
@@ -5160,6 +5461,23 @@
return ret;
}
+void *taiko_get_afe_config(struct snd_soc_codec *codec,
+ enum afe_config_type config_type)
+{
+ struct taiko_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+ switch (config_type) {
+ case AFE_SLIMBUS_SLAVE_CONFIG:
+ return &priv->slimbus_slave_cfg;
+ case AFE_CDC_REGISTERS_CONFIG:
+ return &taiko_mad_audio_reg_cfg;
+ case AFE_SLIMBUS_SLAVE_PORT_CONFIG:
+ return &taiko_slimbus_slave_port_cfg;
+ default:
+ pr_err("%s: Unknown config_type 0x%x\n", __func__, config_type);
+ return NULL;
+ }
+}
static struct wcd9xxx_reg_address taiko_reg_address = {
.micb_4_mbhc = TAIKO_A_MICB_4_MBHC,
@@ -5353,6 +5671,14 @@
INIT_LIST_HEAD(&taiko->dai[i].wcd9xxx_ch_list);
init_waitqueue_head(&taiko->dai[i].dai_wait);
}
+ taiko_slimbus_slave_port_cfg.slave_dev_intfdev_la =
+ control->slim_slave->laddr;
+ taiko_slimbus_slave_port_cfg.slave_dev_pgd_la =
+ control->slim->laddr;
+ taiko_slimbus_slave_port_cfg.slave_port_mapping[0] =
+ TAIKO_MAD_SLIMBUS_TX_PORT;
+
+ taiko_init_slim_slave_cfg(codec);
}
if (TAIKO_IS_1_0(control->version))
diff --git a/sound/soc/codecs/wcd9320.h b/sound/soc/codecs/wcd9320.h
index 89a0b9f..36310e5 100644
--- a/sound/soc/codecs/wcd9320.h
+++ b/sound/soc/codecs/wcd9320.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, 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
@@ -14,6 +14,7 @@
#include <sound/soc.h>
#include <sound/jack.h>
+#include <sound/apr_audio-v2.h>
#include <linux/mfd/wcd9xxx/wcd9xxx-slimslave.h>
#include "wcd9xxx-mbhc.h"
#include "wcd9xxx-resmgr.h"
@@ -25,6 +26,10 @@
#define TAIKO_REG_VAL(reg, val) {reg, 0, val}
#define TAIKO_MCLK_ID 0
+#define TAIKO_REGISTER_START_OFFSET 0x800
+#define TAIKO_SB_PGD_PORT_RX_BASE 0x40
+#define TAIKO_SB_PGD_PORT_TX_BASE 0x50
+
extern const u8 taiko_reg_readable[TAIKO_CACHE_SIZE];
extern const u8 taiko_reset_reg_defaults[TAIKO_CACHE_SIZE];
struct taiko_codec_dai_data {
@@ -90,9 +95,62 @@
u32 num_anc_slots;
};
+struct mad_audio_header {
+ u32 reserved[3];
+ u32 num_reg_cfg;
+};
+
+struct mad_microphone_info {
+ uint8_t input_microphone;
+ uint8_t cycle_time;
+ uint8_t settle_time;
+ uint8_t padding;
+} __packed;
+
+struct mad_micbias_info {
+ uint8_t micbias;
+ uint8_t k_factor;
+ uint8_t external_bypass_capacitor;
+ uint8_t internal_biasing;
+ uint8_t cfilter;
+ uint8_t padding[3];
+} __packed;
+
+struct mad_rms_audio_beacon_info {
+ uint8_t rms_omit_samples;
+ uint8_t rms_comp_time;
+ uint8_t detection_mechanism;
+ uint8_t rms_diff_threshold;
+ uint8_t rms_threshold_lsb;
+ uint8_t rms_threshold_msb;
+ uint8_t padding[2];
+ uint8_t iir_coefficients[36];
+} __packed;
+
+struct mad_rms_ultrasound_info {
+ uint8_t rms_comp_time;
+ uint8_t detection_mechanism;
+ uint8_t rms_diff_threshold;
+ uint8_t rms_threshold_lsb;
+ uint8_t rms_threshold_msb;
+ uint8_t padding[3];
+ uint8_t iir_coefficients[36];
+} __packed;
+
+struct mad_audio_cal {
+ uint32_t version;
+ struct mad_microphone_info microphone_info;
+ struct mad_micbias_info micbias_info;
+ struct mad_rms_audio_beacon_info audio_info;
+ struct mad_rms_audio_beacon_info beacon_info;
+ struct mad_rms_ultrasound_info ultrasound_info;
+} __packed;
+
extern int taiko_mclk_enable(struct snd_soc_codec *codec, int mclk_enable,
bool dapm);
extern int taiko_hs_detect(struct snd_soc_codec *codec,
struct wcd9xxx_mbhc_config *mbhc_cfg);
+extern void *taiko_get_afe_config(struct snd_soc_codec *codec,
+ enum afe_config_type config_type);
#endif
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index 88f0567..5b54e1b 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -1039,7 +1039,7 @@
goto exit;
}
- for (i = 0, d = dt, ch = 0; i < size; i++, d++) {
+ for (i = 0, d = dt; i < size; i++, d++) {
if ((i > 0) && (d->_type != dprev->_type)) {
pr_debug("%s: Invalid, inconsistent types\n", __func__);
type = PLUG_TYPE_INVALID;
@@ -1068,7 +1068,12 @@
maxv))
type = PLUG_TYPE_GND_MIC_SWAP;
}
-
+ if (((type == PLUG_TYPE_HEADSET || type == PLUG_TYPE_HEADPHONE) &&
+ ch != size) || (type == PLUG_TYPE_GND_MIC_SWAP && ch)) {
+ pr_debug("%s: Invalid, not fully inserted, TYPE %d\n",
+ __func__, type);
+ type = PLUG_TYPE_INVALID;
+ }
exit:
pr_debug("%s: Plug type %d detected\n", __func__, type);
return type;
@@ -2455,8 +2460,10 @@
if (mbhc) {
codec = mbhc->codec;
- if (mbhc->hphlocp_cnt++ < OCP_ATTEMPT) {
+ if ((mbhc->hphlocp_cnt < OCP_ATTEMPT) &&
+ (!mbhc->hphrocp_cnt)) {
pr_info("%s: retry\n", __func__);
+ mbhc->hphlocp_cnt++;
snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_OCP_CTL,
0x10, 0x00);
snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_OCP_CTL,
@@ -2464,7 +2471,6 @@
} else {
wcd9xxx_disable_irq(codec->control_data,
WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
- mbhc->hphlocp_cnt = 0;
mbhc->hph_status |= SND_JACK_OC_HPHL;
wcd9xxx_jack_report(mbhc, &mbhc->headset_jack,
mbhc->hph_status,
@@ -2484,8 +2490,10 @@
pr_info("%s: received HPHR OCP irq\n", __func__);
codec = mbhc->codec;
- if (mbhc->hphrocp_cnt++ < OCP_ATTEMPT) {
+ if ((mbhc->hphrocp_cnt < OCP_ATTEMPT) &&
+ (!mbhc->hphlocp_cnt)) {
pr_info("%s: retry\n", __func__);
+ mbhc->hphrocp_cnt++;
snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_OCP_CTL, 0x10,
0x00);
snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_OCP_CTL, 0x10,
@@ -2493,7 +2501,6 @@
} else {
wcd9xxx_disable_irq(mbhc->resmgr->core,
WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
- mbhc->hphrocp_cnt = 0;
mbhc->hph_status |= SND_JACK_OC_HPHR;
wcd9xxx_jack_report(mbhc, &mbhc->headset_jack,
mbhc->hph_status, WCD9XXX_JACK_MASK);
diff --git a/sound/soc/msm/apq8064.c b/sound/soc/msm/apq8064.c
index fb77c8d..cafc5c3 100644
--- a/sound/soc/msm/apq8064.c
+++ b/sound/soc/msm/apq8064.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, 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
@@ -41,8 +41,9 @@
#define MSM_SLIM_0_RX_MAX_CHANNELS 2
#define MSM_SLIM_0_TX_MAX_CHANNELS 4
-#define BTSCO_RATE_8KHZ 8000
-#define BTSCO_RATE_16KHZ 16000
+#define SAMPLE_RATE_8KHZ 8000
+#define SAMPLE_RATE_16KHZ 16000
+#define SAMPLE_RATE_48KHZ 48000
#define BOTTOM_SPK_AMP_POS 0x1
#define BOTTOM_SPK_AMP_NEG 0x2
@@ -67,6 +68,7 @@
enum {
SLIM_1_RX_1 = 145, /* BT-SCO and USB TX */
SLIM_1_TX_1 = 146, /* BT-SCO and USB RX */
+ SLIM_1_TX_2 = 147, /* USB RX */
SLIM_3_RX_1 = 151, /* External echo-cancellation ref */
SLIM_3_RX_2 = 152, /* External echo-cancellation ref */
SLIM_3_TX_1 = 153, /* HDMI RX */
@@ -90,8 +92,11 @@
static int msm_slim_0_tx_ch = 1;
static int msm_slim_3_rx_ch = 1;
-static int msm_btsco_rate = BTSCO_RATE_8KHZ;
+static int msm_slim_1_rate = SAMPLE_RATE_8KHZ;
static int msm_btsco_ch = 1;
+static int msm_slim_1_rx_ch = 1;
+static int msm_slim_1_tx_ch = 1;
+
static int hdmi_rate_variable;
static int rec_mode = INCALL_REC_MONO;
@@ -651,11 +656,14 @@
SOC_ENUM_SINGLE_EXT(2, hdmi_rate),
};
-static const char *btsco_rate_text[] = {"8000", "16000"};
-static const struct soc_enum msm_btsco_enum[] = {
- SOC_ENUM_SINGLE_EXT(2, btsco_rate_text),
+static const char * const slim1_rate_text[] = {"8000", "16000", "48000"};
+static const struct soc_enum msm_slim_1_rate_enum[] = {
+ SOC_ENUM_SINGLE_EXT(3, slim1_rate_text),
};
-
+static const char * const slim1_tx_ch_text[] = {"One", "Two"};
+static const struct soc_enum msm_slim_1_tx_ch_enum[] = {
+ SOC_ENUM_SINGLE_EXT(2, slim1_tx_ch_text),
+};
static int msm_slim_0_rx_ch_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -671,7 +679,7 @@
msm_slim_0_rx_ch = ucontrol->value.integer.value[0] + 1;
pr_debug("%s: msm_slim_0_rx_ch = %d\n", __func__,
- msm_slim_0_rx_ch);
+ msm_slim_0_rx_ch);
return 1;
}
@@ -694,6 +702,27 @@
return 1;
}
+static int msm_slim_1_tx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: msm_slim_1_tx_ch = %d\n", __func__,
+ msm_slim_1_tx_ch);
+
+ ucontrol->value.integer.value[0] = msm_slim_1_tx_ch - 1;
+ return 0;
+}
+
+static int msm_slim_1_tx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ msm_slim_1_tx_ch = ucontrol->value.integer.value[0] + 1;
+
+ pr_debug("%s: msm_slim_1_tx_ch = %d\n", __func__,
+ msm_slim_1_tx_ch);
+
+ return 1;
+}
+
static int msm_slim_3_rx_ch_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -713,31 +742,35 @@
return 1;
}
-static int msm_btsco_rate_get(struct snd_kcontrol *kcontrol,
+static int msm_slim_1_rate_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- pr_debug("%s: msm_btsco_rate = %d", __func__,
- msm_btsco_rate);
- ucontrol->value.integer.value[0] = msm_btsco_rate;
+ pr_debug("%s: msm_slim_1_rate = %d", __func__,
+ msm_slim_1_rate);
+
+ ucontrol->value.integer.value[0] = msm_slim_1_rate;
return 0;
}
-static int msm_btsco_rate_put(struct snd_kcontrol *kcontrol,
+static int msm_slim_1_rate_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
switch (ucontrol->value.integer.value[0]) {
case 8000:
- msm_btsco_rate = BTSCO_RATE_8KHZ;
+ msm_slim_1_rate = SAMPLE_RATE_8KHZ;
break;
case 16000:
- msm_btsco_rate = BTSCO_RATE_16KHZ;
+ msm_slim_1_rate = SAMPLE_RATE_16KHZ;
+ break;
+ case 48000:
+ msm_slim_1_rate = SAMPLE_RATE_48KHZ;
break;
default:
- msm_btsco_rate = BTSCO_RATE_8KHZ;
+ msm_slim_1_rate = SAMPLE_RATE_8KHZ;
break;
}
- pr_debug("%s: msm_btsco_rate = %d\n", __func__,
- msm_btsco_rate);
+ pr_debug("%s: msm_slim_1_rate = %d\n", __func__,
+ msm_slim_1_rate);
return 0;
}
@@ -780,8 +813,10 @@
msm_slim_0_rx_ch_get, msm_slim_0_rx_ch_put),
SOC_ENUM_EXT("SLIM_0_TX Channels", msm_enum[2],
msm_slim_0_tx_ch_get, msm_slim_0_tx_ch_put),
- SOC_ENUM_EXT("Internal BTSCO SampleRate", msm_btsco_enum[0],
- msm_btsco_rate_get, msm_btsco_rate_put),
+ SOC_ENUM_EXT("SLIM_1_TX Channels", msm_slim_1_tx_ch_enum[0],
+ msm_slim_1_tx_ch_get, msm_slim_1_tx_ch_put),
+ SOC_ENUM_EXT("SLIM_1 SampleRate", msm_slim_1_rate_enum[0],
+ msm_slim_1_rate_get, msm_slim_1_rate_put),
SOC_SINGLE_EXT("Incall Rec Mode", SND_SOC_NOPM, 0, 1, 0,
msm_incall_rec_mode_get, msm_incall_rec_mode_put),
SOC_ENUM_EXT("SLIM_3_RX Channels", msm_enum[1],
@@ -1001,7 +1036,7 @@
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret = 0;
- unsigned int rx_ch = SLIM_1_RX_1, tx_ch = SLIM_1_TX_1;
+ unsigned int rx_ch = SLIM_1_RX_1, tx_ch[2] = {SLIM_1_TX_1, SLIM_1_TX_2};
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
pr_debug("%s: APQ BT/USB TX -> SLIMBUS_1_RX -> MDM TX shared ch %d\n",
@@ -1015,10 +1050,11 @@
goto end;
}
} else {
- pr_debug("%s: MDM RX -> SLIMBUS_1_TX -> APQ BT/USB Rx shared ch %d\n",
- __func__, tx_ch);
+ pr_debug("%s: MDM RX ->SLIMBUS_1_TX ->APQ BT/USB Rx shared ch %d %d\n",
+ __func__, tx_ch[0], tx_ch[1]);
- ret = snd_soc_dai_set_channel_map(cpu_dai, 1, &tx_ch, 0, 0);
+ ret = snd_soc_dai_set_channel_map(cpu_dai, msm_slim_1_tx_ch,
+ tx_ch, 0, 0);
if (ret < 0) {
pr_err("%s: Erorr %d setting SLIM_1 TX channel map\n",
__func__, ret);
@@ -1358,16 +1394,46 @@
struct snd_pcm_hw_params *params)
{
struct snd_interval *rate = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_RATE);
+ SNDRV_PCM_HW_PARAM_RATE);
struct snd_interval *channels = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_CHANNELS);
+ SNDRV_PCM_HW_PARAM_CHANNELS);
- rate->min = rate->max = msm_btsco_rate;
+ rate->min = rate->max = msm_slim_1_rate;
channels->min = channels->max = msm_btsco_ch;
return 0;
}
+static int msm_slim_1_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ rate->min = rate->max = msm_slim_1_rate;
+ channels->min = channels->max = msm_slim_1_rx_ch;
+
+ return 0;
+}
+
+static int msm_slim_1_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ rate->min = rate->max = msm_slim_1_rate;
+ channels->min = channels->max = msm_slim_1_tx_ch;
+
+ return 0;
+}
+
static int msm_auxpcm_be_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
@@ -1728,20 +1794,18 @@
.codec_name = "snd-soc-dummy",
},
{
- .name = "VoLTE",
- .stream_name = "VoLTE",
- .cpu_dai_name = "VoLTE",
- .platform_name = "msm-pcm-voice",
+ .name = "VoLTE Stub",
+ .stream_name = "VoLTE Stub",
+ .cpu_dai_name = "VOLTE_STUB",
+ .platform_name = "msm-pcm-hostless",
.dynamic = 1,
.trigger = {SND_SOC_DPCM_TRIGGER_POST,
- SND_SOC_DPCM_TRIGGER_POST},
+ SND_SOC_DPCM_TRIGGER_POST},
.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
.ignore_suspend = 1,
- /* this dainlink has playback support */
.ignore_pmdown_time = 1,
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
- .be_id = MSM_FRONTEND_DAI_VOLTE,
},
{
.name = "MSM8960 LowLatency",
@@ -1800,6 +1864,21 @@
.ignore_pmdown_time = 1, /* this dailink has playback support */
.be_id = MSM_FRONTEND_DAI_MULTIMEDIA8,
},
+ {
+ .name = "Voice2 Stub",
+ .stream_name = "Voice2 Stub",
+ .cpu_dai_name = "VOICE2_STUB",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* this dainlink has playback support */
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
/* Backend DAI Links */
{
.name = LPASS_BE_SLIMBUS_0_RX,
@@ -1971,7 +2050,7 @@
.codec_dai_name = "msm-stub-rx",
.no_pcm = 1,
.be_id = MSM_BACKEND_DAI_SLIMBUS_1_RX,
- .be_hw_params_fixup = msm_btsco_be_hw_params_fixup,
+ .be_hw_params_fixup = msm_slim_1_rx_be_hw_params_fixup,
.ops = &msm_slimbus_1_be_ops,
.ignore_pmdown_time = 1, /* this dainlink has playback support */
@@ -1985,7 +2064,7 @@
.codec_dai_name = "msm-stub-tx",
.no_pcm = 1,
.be_id = MSM_BACKEND_DAI_SLIMBUS_1_TX,
- .be_hw_params_fixup = msm_btsco_be_hw_params_fixup,
+ .be_hw_params_fixup = msm_slim_1_tx_be_hw_params_fixup,
.ops = &msm_slimbus_1_be_ops,
},
/* Ultrasound TX Back End DAI Link */
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index 96709be..734bd39 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -550,8 +550,8 @@
},
{
.playback = {
- .stream_name = "SGLTE Playback",
- .aif_name = "SGLTE_DL",
+ .stream_name = "Voice2 Playback",
+ .aif_name = "VOICE2_DL",
.rates = SNDRV_PCM_RATE_8000_48000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.channels_min = 1,
@@ -560,8 +560,8 @@
.rate_max = 48000,
},
.capture = {
- .stream_name = "SGLTE Capture",
- .aif_name = "SGLTE_UL",
+ .stream_name = "Voice2 Capture",
+ .aif_name = "VOICE2_UL",
.rates = SNDRV_PCM_RATE_8000_48000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.channels_min = 1,
@@ -570,7 +570,7 @@
.rate_max = 48000,
},
.ops = &msm_fe_dai_ops,
- .name = "SGLTE",
+ .name = "Voice2",
},
{
.playback = {
@@ -612,6 +612,68 @@
.ops = &msm_fe_dai_ops,
.name = "DTMF_RX_HOSTLESS",
},
+ {
+ .capture = {
+ .stream_name = "Listen Audio Service Capture",
+ .aif_name = "LSM_UL_HL",
+ .rates = SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 1,
+ .rate_min = 16000,
+ .rate_max = 16000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "LSM",
+ },
+ {
+ .playback = {
+ .stream_name = "VoLTE Stub Playback",
+ .aif_name = "VOLTE_STUB_DL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .capture = {
+ .stream_name = "VoLTE Stub Capture",
+ .aif_name = "VOLTE_STUB_UL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "VOLTE_STUB",
+ },
+ {
+ .playback = {
+ .stream_name = "Voice2 Stub Playback",
+ .aif_name = "VOICE2_STUB_DL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .capture = {
+ .stream_name = "Voice2 Stub Capture",
+ .aif_name = "VOICE2_STUB_UL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "VOICE2_STUB",
+ },
};
static __devinit int msm_fe_dai_dev_probe(struct platform_device *pdev)
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index 6cf74d5..c5cb560 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -733,8 +733,8 @@
session_id = voc_get_session_id(VOICE_SESSION_NAME);
else if (val == MSM_FRONTEND_DAI_VOLTE)
session_id = voc_get_session_id(VOLTE_SESSION_NAME);
- else if (val == MSM_FRONTEND_DAI_SGLTE)
- session_id = voc_get_session_id(SGLTE_SESSION_NAME);
+ else if (val == MSM_FRONTEND_DAI_VOICE2)
+ session_id = voc_get_session_id(VOICE2_SESSION_NAME);
else
session_id = voc_get_session_id(VOIP_SESSION_NAME);
@@ -1768,12 +1768,18 @@
SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_PRI_I2S_RX,
MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
- SOC_SINGLE_EXT("SGLTE", MSM_BACKEND_DAI_PRI_I2S_RX,
- MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
+ SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_PRI_I2S_RX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_PRI_I2S_RX,
MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("VoLTE Stub", MSM_BACKEND_DAI_PRI_I2S_RX,
+ MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("Voice2 Stub", MSM_BACKEND_DAI_PRI_I2S_RX,
+ MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_PRI_I2S_RX,
MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
@@ -1789,8 +1795,8 @@
SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_SEC_I2S_RX,
MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
- SOC_SINGLE_EXT("SGLTE", MSM_BACKEND_DAI_SEC_I2S_RX,
- MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
+ SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_SEC_I2S_RX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_SEC_I2S_RX,
MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
@@ -1807,8 +1813,8 @@
SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_SLIMBUS_0_RX ,
MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
- SOC_SINGLE_EXT("SGLTE", MSM_BACKEND_DAI_SLIMBUS_0_RX ,
- MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
+ SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_SLIMBUS_0_RX ,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_SLIMBUS_0_RX ,
MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
@@ -1825,11 +1831,17 @@
SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_INT_BT_SCO_RX,
MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("VoLTE Stub", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("Voice2 Stub", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_INT_BT_SCO_RX ,
MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
- SOC_SINGLE_EXT("SGLTE", MSM_BACKEND_DAI_INT_BT_SCO_RX ,
- MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
+ SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_INT_BT_SCO_RX ,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_INT_BT_SCO_RX ,
MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
@@ -1846,8 +1858,14 @@
SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_MI2S_RX,
MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
msm_routing_put_voice_stub_mixer),
- SOC_SINGLE_EXT("SGLTE", MSM_BACKEND_DAI_MI2S_RX,
- MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
+ SOC_SINGLE_EXT("VoLTE Stub", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("Voice2 Stub", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_MI2S_RX,
MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
@@ -1864,11 +1882,17 @@
SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_AFE_PCM_RX,
MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("VoLTE Stub", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("Voice2 Stub", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_AFE_PCM_RX,
MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
- SOC_SINGLE_EXT("SGLTE", MSM_BACKEND_DAI_AFE_PCM_RX,
- MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
+ SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_AFE_PCM_RX,
MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
@@ -1885,11 +1909,17 @@
SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_AUXPCM_RX,
MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("VoLTE Stub", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("Voice2 Stub", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_AUXPCM_RX,
MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
- SOC_SINGLE_EXT("SGLTE", MSM_BACKEND_DAI_AUXPCM_RX,
- MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
+ SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_AUXPCM_RX,
MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
@@ -1906,8 +1936,8 @@
SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
- SOC_SINGLE_EXT("SGLTE", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
- MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
+ SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
@@ -1927,8 +1957,14 @@
SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_HDMI_RX,
MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
msm_routing_put_voice_stub_mixer),
- SOC_SINGLE_EXT("SGLTE", MSM_BACKEND_DAI_HDMI_RX,
- MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
+ SOC_SINGLE_EXT("VoLTE Stub", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("Voice2 Stub", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_HDMI_RX,
MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
@@ -1939,18 +1975,36 @@
SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_EXTPROC_RX,
MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("VoLTE Stub", MSM_BACKEND_DAI_EXTPROC_RX,
+ MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("Voice2 Stub", MSM_BACKEND_DAI_EXTPROC_RX,
+ MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
};
static const struct snd_kcontrol_new slimbus_1_rx_mixer_controls[] = {
SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_SLIMBUS_1_RX,
MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("VoLTE Stub", MSM_BACKEND_DAI_SLIMBUS_1_RX,
+ MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("Voice2 Stub", MSM_BACKEND_DAI_SLIMBUS_1_RX,
+ MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
};
static const struct snd_kcontrol_new slimbus_3_rx_mixer_controls[] = {
SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_SLIMBUS_3_RX,
MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("VoLTE Stub", MSM_BACKEND_DAI_SLIMBUS_3_RX,
+ MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("Voice2 Stub", MSM_BACKEND_DAI_SLIMBUS_3_RX,
+ MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
};
static const struct snd_kcontrol_new tx_voice_mixer_controls[] = {
@@ -2004,30 +2058,30 @@
msm_routing_put_voice_mixer),
};
-static const struct snd_kcontrol_new tx_sglte_mixer_controls[] = {
- SOC_SINGLE_EXT("PRI_TX_SGLTE", MSM_BACKEND_DAI_PRI_I2S_TX,
- MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
+static const struct snd_kcontrol_new tx_voice2_mixer_controls[] = {
+ SOC_SINGLE_EXT("PRI_TX_Voice2", MSM_BACKEND_DAI_PRI_I2S_TX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
- SOC_SINGLE_EXT("SEC_TX_SGLTE", MSM_BACKEND_DAI_SEC_I2S_TX,
- MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
+ SOC_SINGLE_EXT("SEC_TX_Voice2", MSM_BACKEND_DAI_SEC_I2S_TX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
- SOC_SINGLE_EXT("MI2S_TX_SGLTE", MSM_BACKEND_DAI_MI2S_TX,
- MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
+ SOC_SINGLE_EXT("MI2S_TX_Voice2", MSM_BACKEND_DAI_MI2S_TX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
- SOC_SINGLE_EXT("SLIM_0_TX_SGLTE", MSM_BACKEND_DAI_SLIMBUS_0_TX,
- MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
+ SOC_SINGLE_EXT("SLIM_0_TX_Voice2", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
- SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX_SGLTE",
- MSM_BACKEND_DAI_INT_BT_SCO_TX, MSM_FRONTEND_DAI_SGLTE, 1, 0,
+ SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX_Voice2",
+ MSM_BACKEND_DAI_INT_BT_SCO_TX, MSM_FRONTEND_DAI_VOICE2, 1, 0,
msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
- SOC_SINGLE_EXT("AFE_PCM_TX_SGLTE", MSM_BACKEND_DAI_AFE_PCM_TX,
- MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
+ SOC_SINGLE_EXT("AFE_PCM_TX_Voice2", MSM_BACKEND_DAI_AFE_PCM_TX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
- SOC_SINGLE_EXT("AUX_PCM_TX_SGLTE", MSM_BACKEND_DAI_AUXPCM_TX,
- MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
+ SOC_SINGLE_EXT("AUX_PCM_TX_Voice2", MSM_BACKEND_DAI_AUXPCM_TX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
- SOC_SINGLE_EXT("SEC_AUX_PCM_TX_SGLTE", MSM_BACKEND_DAI_SEC_AUXPCM_TX,
- MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
+ SOC_SINGLE_EXT("SEC_AUX_PCM_TX_Voice2", MSM_BACKEND_DAI_SEC_AUXPCM_TX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new tx_voip_mixer_controls[] = {
@@ -2087,6 +2141,66 @@
msm_routing_put_voice_stub_mixer),
};
+static const struct snd_kcontrol_new tx_volte_stub_mixer_controls[] = {
+ SOC_SINGLE_EXT("STUB_TX_HL", MSM_BACKEND_DAI_EXTPROC_TX,
+ MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX,
+ MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("SLIM_1_TX", MSM_BACKEND_DAI_SLIMBUS_1_TX,
+ MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("STUB_1_TX_HL", MSM_BACKEND_DAI_EXTPROC_EC_TX,
+ MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_MI2S_TX,
+ MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("SLIM_3_TX", MSM_BACKEND_DAI_SLIMBUS_3_TX,
+ MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("PRIMARY_I2S_TX", MSM_BACKEND_DAI_PRI_I2S_TX,
+ MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("SECONDARY_I2S_TX", MSM_BACKEND_DAI_SEC_I2S_TX,
+ MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX,
+ MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+};
+
+static const struct snd_kcontrol_new tx_voice2_stub_mixer_controls[] = {
+ SOC_SINGLE_EXT("STUB_TX_HL", MSM_BACKEND_DAI_EXTPROC_TX,
+ MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX,
+ MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("SLIM_1_TX", MSM_BACKEND_DAI_SLIMBUS_1_TX,
+ MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("STUB_1_TX_HL", MSM_BACKEND_DAI_EXTPROC_EC_TX,
+ MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_MI2S_TX,
+ MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("SLIM_3_TX", MSM_BACKEND_DAI_SLIMBUS_3_TX,
+ MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("PRIMARY_I2S_TX", MSM_BACKEND_DAI_PRI_I2S_TX,
+ MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("SECONDARY_I2S_TX", MSM_BACKEND_DAI_SEC_I2S_TX,
+ MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX,
+ MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+};
+
static const struct snd_kcontrol_new sbus_0_rx_port_mixer_controls[] = {
SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX,
MSM_BACKEND_DAI_INT_FM_TX, 1, 0, msm_routing_get_port_mixer,
@@ -2553,8 +2667,8 @@
SND_SOC_DAPM_AIF_OUT("CS-VOICE_UL1", "CS-VOICE Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("VoLTE_DL", "VoLTE Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("VoLTE_UL", "VoLTE Capture", 0, 0, 0, 0),
- SND_SOC_DAPM_AIF_IN("SGLTE_DL", "SGLTE Playback", 0, 0, 0, 0),
- SND_SOC_DAPM_AIF_OUT("SGLTE_UL", "SGLTE Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("VOICE2_DL", "Voice2 Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("VOICE2_UL", "Voice2 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("VOIP_UL", "VoIP Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("SLIM0_DL_HL", "SLIMBUS0_HOSTLESS Playback",
0, 0, 0, 0),
@@ -2622,6 +2736,12 @@
0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("VOICE_STUB_DL", "VOICE_STUB Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("VOICE_STUB_UL", "VOICE_STUB Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("VOLTE_STUB_DL", "VOLTE_STUB Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("VOLTE_STUB_UL", "VOLTE_STUB Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("VOICE2_STUB_DL",
+ "VOICE2_STUB Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("VOICE2_STUB_UL",
+ "VOICE2_STUB Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("STUB_RX", "Stub Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("STUB_TX", "Stub Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("SLIMBUS_1_RX", "Slimbus1 Playback", 0, 0, 0, 0),
@@ -2712,9 +2832,9 @@
SND_SOC_DAPM_MIXER("VoLTE_Tx Mixer",
SND_SOC_NOPM, 0, 0, tx_volte_mixer_controls,
ARRAY_SIZE(tx_volte_mixer_controls)),
- SND_SOC_DAPM_MIXER("SGLTE_Tx Mixer",
- SND_SOC_NOPM, 0, 0, tx_sglte_mixer_controls,
- ARRAY_SIZE(tx_sglte_mixer_controls)),
+ SND_SOC_DAPM_MIXER("Voice2_Tx Mixer",
+ SND_SOC_NOPM, 0, 0, tx_voice2_mixer_controls,
+ ARRAY_SIZE(tx_voice2_mixer_controls)),
SND_SOC_DAPM_MIXER("INTERNAL_BT_SCO_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
int_bt_sco_rx_mixer_controls, ARRAY_SIZE(int_bt_sco_rx_mixer_controls)),
SND_SOC_DAPM_MIXER("INTERNAL_FM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
@@ -2758,7 +2878,12 @@
ARRAY_SIZE(sbus_3_rx_port_mixer_controls)),
SND_SOC_DAPM_MIXER("MI2S_RX Port Mixer", SND_SOC_NOPM, 0, 0,
mi2s_rx_port_mixer_controls, ARRAY_SIZE(mi2s_rx_port_mixer_controls)),
-
+ SND_SOC_DAPM_MIXER("VoLTE Stub Tx Mixer", SND_SOC_NOPM, 0, 0,
+ tx_volte_stub_mixer_controls,
+ ARRAY_SIZE(tx_volte_stub_mixer_controls)),
+ SND_SOC_DAPM_MIXER("Voice2 Stub Tx Mixer", SND_SOC_NOPM, 0, 0,
+ tx_voice2_stub_mixer_controls,
+ ARRAY_SIZE(tx_voice2_stub_mixer_controls)),
/* Virtual Pins to force backends ON atm */
SND_SOC_DAPM_OUTPUT("BE_OUT"),
SND_SOC_DAPM_INPUT("BE_IN"),
@@ -2890,7 +3015,7 @@
{"PRI_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
{"PRI_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
- {"PRI_RX_Voice Mixer", "SGLTE", "SGLTE_DL"},
+ {"PRI_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
{"PRI_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"PRI_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
{"PRI_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
@@ -2898,49 +3023,49 @@
{"SEC_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
{"SEC_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
- {"SEC_RX_Voice Mixer", "SGLTE", "SGLTE_DL"},
+ {"SEC_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
{"SEC_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"SEC_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
{"SEC_I2S_RX", NULL, "SEC_RX_Voice Mixer"},
{"SLIM_0_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
{"SLIM_0_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
- {"SLIM_0_RX_Voice Mixer", "SGLTE", "SGLTE_DL"},
+ {"SLIM_0_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
{"SLIM_0_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"SLIM_0_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
{"SLIMBUS_0_RX", NULL, "SLIM_0_RX_Voice Mixer"},
{"INTERNAL_BT_SCO_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
{"INTERNAL_BT_SCO_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
- {"INTERNAL_BT_SCO_RX_Voice Mixer", "SGLTE", "SGLTE_DL"},
+ {"INTERNAL_BT_SCO_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
{"INTERNAL_BT_SCO_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"INTERNAL_BT_SCO_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
{"INT_BT_SCO_RX", NULL, "INTERNAL_BT_SCO_RX_Voice Mixer"},
{"AFE_PCM_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
{"AFE_PCM_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
- {"AFE_PCM_RX_Voice Mixer", "SGLTE", "SGLTE_DL"},
+ {"AFE_PCM_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
{"AFE_PCM_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"AFE_PCM_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
{"PCM_RX", NULL, "AFE_PCM_RX_Voice Mixer"},
{"AUX_PCM_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
{"AUX_PCM_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
- {"AUX_PCM_RX_Voice Mixer", "SGLTE", "SGLTE_DL"},
+ {"AUX_PCM_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
{"AUX_PCM_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"AUX_PCM_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
{"AUX_PCM_RX", NULL, "AUX_PCM_RX_Voice Mixer"},
{"SEC_AUX_PCM_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
{"SEC_AUX_PCM_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
- {"SEC_AUX_PCM_RX_Voice Mixer", "SGLTE", "SGLTE_DL"},
+ {"SEC_AUX_PCM_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
{"SEC_AUX_PCM_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"SEC_AUX_PCM_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
{"SEC_AUX_PCM_RX", NULL, "SEC_AUX_PCM_RX_Voice Mixer"},
{"HDMI_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
{"HDMI_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
- {"HDMI_RX_Voice Mixer", "SGLTE", "SGLTE_DL"},
+ {"HDMI_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
{"HDMI_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"HDMI_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
{"HDMI", NULL, "HDMI_RX_Voice Mixer"},
@@ -2963,15 +3088,15 @@
{"VoLTE_Tx Mixer", "AUX_PCM_TX_VoLTE", "AUX_PCM_TX"},
{"VoLTE_Tx Mixer", "SEC_AUX_PCM_TX_VoLTE", "SEC_AUX_PCM_TX"},
{"VoLTE_UL", NULL, "VoLTE_Tx Mixer"},
- {"SGLTE_Tx Mixer", "PRI_TX_SGLTE", "PRI_I2S_TX"},
- {"SGLTE_Tx Mixer", "SEC_TX_SGLTE", "SEC_I2S_TX"},
- {"SGLTE_Tx Mixer", "MI2S_TX_SGLTE", "MI2S_TX"},
- {"SGLTE_Tx Mixer", "SLIM_0_TX_SGLTE", "SLIMBUS_0_TX"},
- {"SGLTE_Tx Mixer", "INTERNAL_BT_SCO_TX_SGLTE", "INT_BT_SCO_TX"},
- {"SGLTE_Tx Mixer", "AFE_PCM_TX_SGLTE", "PCM_TX"},
- {"SGLTE_Tx Mixer", "AUX_PCM_TX_SGLTE", "AUX_PCM_TX"},
- {"SGLTE_Tx Mixer", "SEC_AUX_PCM_TX_SGLTE", "SEC_AUX_PCM_TX"},
- {"SGLTE_UL", NULL, "SGLTE_Tx Mixer"},
+ {"Voice2_Tx Mixer", "PRI_TX_Voice2", "PRI_I2S_TX"},
+ {"Voice2_Tx Mixer", "SEC_TX_Voice2", "SEC_I2S_TX"},
+ {"Voice2_Tx Mixer", "MI2S_TX_Voice2", "MI2S_TX"},
+ {"Voice2_Tx Mixer", "SLIM_0_TX_Voice2", "SLIMBUS_0_TX"},
+ {"Voice2_Tx Mixer", "INTERNAL_BT_SCO_TX_Voice2", "INT_BT_SCO_TX"},
+ {"Voice2_Tx Mixer", "AFE_PCM_TX_Voice2", "PCM_TX"},
+ {"Voice2_Tx Mixer", "AUX_PCM_TX_Voice2", "AUX_PCM_TX"},
+ {"Voice2_Tx Mixer", "SEC_AUX_PCM_TX_Voice2", "SEC_AUX_PCM_TX"},
+ {"VOICE2_UL", NULL, "Voice2_Tx Mixer"},
{"Voip_Tx Mixer", "PRI_TX_Voip", "PRI_I2S_TX"},
{"Voip_Tx Mixer", "SEC_TX_Voip", "SEC_I2S_TX"},
{"Voip_Tx Mixer", "MI2S_TX_Voip", "MI2S_TX"},
@@ -3017,17 +3142,53 @@
{"Voice Stub Tx Mixer", "AFE_PCM_TX", "PCM_TX"},
{"VOICE_STUB_UL", NULL, "Voice Stub Tx Mixer"},
+ {"VoLTE Stub Tx Mixer", "STUB_TX_HL", "STUB_TX"},
+ {"VoLTE Stub Tx Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
+ {"VoLTE Stub Tx Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+ {"VoLTE Stub Tx Mixer", "STUB_1_TX_HL", "STUB_1_TX"},
+ {"VoLTE Stub Tx Mixer", "MI2S_TX", "MI2S_TX"},
+ {"VoLTE Stub Tx Mixer", "SLIM_3_TX", "SLIMBUS_3_TX"},
+ {"VoLTE Stub Tx Mixer", "PRIMARY_I2S_TX", "PRI_I2S_TX"},
+ {"VoLTE Stub Tx Mixer", "SECONDARY_I2S_TX", "SEC_I2S_TX"},
+ {"VoLTE Stub Tx Mixer", "AFE_PCM_TX", "PCM_TX"},
+ {"VOLTE_STUB_UL", NULL, "VoLTE Stub Tx Mixer"},
+
+ {"Voice2 Stub Tx Mixer", "STUB_TX_HL", "STUB_TX"},
+ {"Voice2 Stub Tx Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
+ {"Voice2 Stub Tx Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+ {"Voice2 Stub Tx Mixer", "STUB_1_TX_HL", "STUB_1_TX"},
+ {"Voice2 Stub Tx Mixer", "MI2S_TX", "MI2S_TX"},
+ {"Voice2 Stub Tx Mixer", "SLIM_3_TX", "SLIMBUS_3_TX"},
+ {"Voice2 Stub Tx Mixer", "PRIMARY_I2S_TX", "PRI_I2S_TX"},
+ {"Voice2 Stub Tx Mixer", "SECONDARY_I2S_TX", "SEC_I2S_TX"},
+ {"Voice2 Stub Tx Mixer", "AFE_PCM_TX", "PCM_TX"},
+ {"VOICE2_STUB_UL", NULL, "Voice2 Stub Tx Mixer"},
+
{"STUB_RX Mixer", "Voice Stub", "VOICE_STUB_DL"},
+ {"STUB_RX Mixer", "VoLTE Stub", "VOLTE_STUB_DL"},
+ {"STUB_RX Mixer", "Voice2 Stub", "VOICE2_STUB_DL"},
{"STUB_RX", NULL, "STUB_RX Mixer"},
{"SLIMBUS_1_RX Mixer", "Voice Stub", "VOICE_STUB_DL"},
+ {"SLIMBUS_1_RX Mixer", "VoLTE Stub", "VOLTE_STUB_DL"},
+ {"SLIMBUS_1_RX Mixer", "Voice2 Stub", "VOICE2_STUB_DL"},
{"SLIMBUS_1_RX", NULL, "SLIMBUS_1_RX Mixer"},
{"INTERNAL_BT_SCO_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
+ {"INTERNAL_BT_SCO_RX_Voice Mixer", "VoLTE Stub", "VOLTE_STUB_DL"},
+ {"INTERNAL_BT_SCO_RX_Voice Mixer", "Voice2 Stub", "VOICE2_STUB_DL"},
{"MI2S_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
+ {"MI2S_RX_Voice Mixer", "VoLTE Stub", "VOLTE_STUB_DL"},
+ {"MI2S_RX_Voice Mixer", "Voice2 Stub", "VOICE2_STUB_DL"},
{"MI2S_RX", NULL, "MI2S_RX_Voice Mixer"},
{"HDMI_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
+ {"HDMI_RX_Voice Mixer", "VoLTE Stub", "VOLTE_STUB_DL"},
+ {"HDMI_RX_Voice Mixer", "Voice2 Stub", "VOICE2_STUB_DL"},
{"AFE_PCM_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
+ {"AFE_PCM_RX_Voice Mixer", "VoLTE Stub", "VOLTE_STUB_DL"},
+ {"AFE_PCM_RX_Voice Mixer", "Voice2 Stub", "VOICE2_STUB_DL"},
{"SLIMBUS_3_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
+ {"SLIMBUS_3_RX_Voice Mixer", "VoLTE Stub", "VOLTE_STUB_DL"},
+ {"SLIMBUS_3_RX_Voice Mixer", "Voice2 Stub", "VOICE2_STUB_DL"},
{"SLIMBUS_3_RX", NULL, "SLIMBUS_3_RX_Voice Mixer"},
{"SLIMBUS_1_RX Port Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
diff --git a/sound/soc/msm/msm-pcm-routing.h b/sound/soc/msm/msm-pcm-routing.h
index b571483..c42e155 100644
--- a/sound/soc/msm/msm-pcm-routing.h
+++ b/sound/soc/msm/msm-pcm-routing.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, 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
@@ -69,8 +69,10 @@
MSM_FRONTEND_DAI_AFE_TX,
MSM_FRONTEND_DAI_VOICE_STUB,
MSM_FRONTEND_DAI_VOLTE,
- MSM_FRONTEND_DAI_SGLTE,
+ MSM_FRONTEND_DAI_VOICE2,
MSM_FRONTEND_DAI_DTMF_RX,
+ MSM_FRONTEND_DAI_VOLTE_STUB,
+ MSM_FRONTEND_DAI_VOICE2_STUB,
MSM_FRONTEND_DAI_MAX,
};
diff --git a/sound/soc/msm/msm-pcm-voice.c b/sound/soc/msm/msm-pcm-voice.c
index ac5bc34..26e6ae6 100644
--- a/sound/soc/msm/msm-pcm-voice.c
+++ b/sound/soc/msm/msm-pcm-voice.c
@@ -59,9 +59,10 @@
return false;
}
-static int is_sglte(struct msm_voice *psglte)
+static int is_voice2(struct msm_voice *pvoice2)
+
{
- if (psglte == &voice_info[SGLTE_SESSION_INDEX])
+ if (pvoice2 == &voice_info[VOICE2_SESSION_INDEX])
return true;
else
return false;
@@ -100,15 +101,15 @@
if (!strncmp("VoLTE", substream->pcm->id, 5)) {
voice = &voice_info[VOLTE_SESSION_INDEX];
pr_debug("%s: Open VoLTE Substream Id=%s\n",
- __func__, substream->pcm->id);
- } else if (!strncmp("SGLTE", substream->pcm->id, 5)) {
- voice = &voice_info[SGLTE_SESSION_INDEX];
- pr_debug("%s: Open SGLTE Substream Id=%s\n",
- __func__, substream->pcm->id);
+ __func__, substream->pcm->id);
+ } else if (!strncmp("Voice2", substream->pcm->id, 6)) {
+ voice = &voice_info[VOICE2_SESSION_INDEX];
+ pr_debug("%s: Open Voice2 Substream Id=%s\n",
+ __func__, substream->pcm->id);
} else {
voice = &voice_info[VOICE_SESSION_INDEX];
pr_debug("%s: Open VOICE Substream Id=%s\n",
- __func__, substream->pcm->id);
+ __func__, substream->pcm->id);
}
mutex_lock(&voice->lock);
@@ -174,8 +175,8 @@
pr_debug("end voice call\n");
if (is_volte(prtd))
session_id = voc_get_session_id(VOLTE_SESSION_NAME);
- else if (is_sglte(prtd))
- session_id = voc_get_session_id(SGLTE_SESSION_NAME);
+ else if (is_voice2(prtd))
+ session_id = voc_get_session_id(VOICE2_SESSION_NAME);
else
session_id = voc_get_session_id(VOICE_SESSION_NAME);
voc_end_voice_call(session_id);
@@ -201,8 +202,8 @@
if (prtd->playback_start && prtd->capture_start) {
if (is_volte(prtd))
session_id = voc_get_session_id(VOLTE_SESSION_NAME);
- else if (is_sglte(prtd))
- session_id = voc_get_session_id(SGLTE_SESSION_NAME);
+ else if (is_voice2(prtd))
+ session_id = voc_get_session_id(VOICE2_SESSION_NAME);
else
session_id = voc_get_session_id(VOICE_SESSION_NAME);
voc_start_voice_call(session_id);
@@ -233,8 +234,8 @@
pr_debug("%s: cmd = %d\n", __func__, cmd);
if (is_volte(prtd))
session_id = voc_get_session_id(VOLTE_SESSION_NAME);
- else if (is_sglte(prtd))
- session_id = voc_get_session_id(SGLTE_SESSION_NAME);
+ else if (is_voice2(prtd))
+ session_id = voc_get_session_id(VOICE2_SESSION_NAME);
else
session_id = voc_get_session_id(VOICE_SESSION_NAME);
@@ -308,19 +309,20 @@
return 0;
}
-static int msm_sglte_volume_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static int msm_voice2_volume_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
{
ucontrol->value.integer.value[0] = 0;
return 0;
}
-static int msm_sglte_volume_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static int msm_voice2_volume_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
{
int volume = ucontrol->value.integer.value[0];
pr_debug("%s: volume: %d\n", __func__, volume);
- voc_set_rx_vol_index(voc_get_session_id(SGLTE_SESSION_NAME),
+
+ voc_set_rx_vol_index(voc_get_session_id(VOICE2_SESSION_NAME),
RX_PATH, volume);
return 0;
}
@@ -401,21 +403,21 @@
return 0;
}
-static int msm_sglte_mute_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static int msm_voice2_mute_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
{
ucontrol->value.integer.value[0] = 0;
return 0;
}
-static int msm_sglte_mute_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static int msm_voice2_mute_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
{
int mute = ucontrol->value.integer.value[0];
pr_debug("%s: mute=%d\n", __func__, mute);
- voc_set_tx_mute(voc_get_session_id(SGLTE_SESSION_NAME), TX_PATH, mute);
+ voc_set_tx_mute(voc_get_session_id(VOICE2_SESSION_NAME), TX_PATH, mute);
return 0;
}
@@ -460,22 +462,22 @@
return 0;
}
-static int msm_sglte_rx_device_mute_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static int msm_voice2_rx_device_mute_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
{
ucontrol->value.integer.value[0] =
- voc_get_rx_device_mute(voc_get_session_id(SGLTE_SESSION_NAME));
+ voc_get_rx_device_mute(voc_get_session_id(VOICE2_SESSION_NAME));
return 0;
}
-static int msm_sglte_rx_device_mute_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static int msm_voice2_rx_device_mute_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
{
int mute = ucontrol->value.integer.value[0];
pr_debug("%s: mute=%d\n", __func__, mute);
- voc_set_rx_device_mute(voc_get_session_id(SGLTE_SESSION_NAME), mute);
+ voc_set_rx_device_mute(voc_get_session_id(VOICE2_SESSION_NAME), mute);
return 0;
}
@@ -502,7 +504,7 @@
voc_set_tty_mode(voc_get_session_id(VOICE_SESSION_NAME), tty_mode);
- voc_set_tty_mode(voc_get_session_id(SGLTE_SESSION_NAME), tty_mode);
+ voc_set_tty_mode(voc_get_session_id(VOICE2_SESSION_NAME), tty_mode);
return 0;
}
static int msm_voice_widevoice_put(struct snd_kcontrol *kcontrol,
@@ -514,7 +516,7 @@
voc_set_widevoice_enable(voc_get_session_id(VOICE_SESSION_NAME),
wv_enable);
- voc_set_widevoice_enable(voc_get_session_id(SGLTE_SESSION_NAME),
+ voc_set_widevoice_enable(voc_get_session_id(VOICE2_SESSION_NAME),
wv_enable);
return 0;
}
@@ -536,9 +538,9 @@
pr_debug("%s: st enable=%d\n", __func__, st_enable);
voc_set_pp_enable(voc_get_session_id(VOICE_SESSION_NAME),
- MODULE_ID_VOICE_MODULE_ST, st_enable);
- voc_set_pp_enable(voc_get_session_id(SGLTE_SESSION_NAME),
- MODULE_ID_VOICE_MODULE_ST, st_enable);
+ MODULE_ID_VOICE_MODULE_ST, st_enable);
+ voc_set_pp_enable(voc_get_session_id(VOICE2_SESSION_NAME),
+ MODULE_ID_VOICE_MODULE_ST, st_enable);
return 0;
}
@@ -560,9 +562,9 @@
pr_debug("%s: fens enable=%d\n", __func__, fens_enable);
voc_set_pp_enable(voc_get_session_id(VOICE_SESSION_NAME),
- MODULE_ID_VOICE_MODULE_FENS, fens_enable);
- voc_set_pp_enable(voc_get_session_id(SGLTE_SESSION_NAME),
- MODULE_ID_VOICE_MODULE_FENS, fens_enable);
+ MODULE_ID_VOICE_MODULE_FENS, fens_enable);
+ voc_set_pp_enable(voc_get_session_id(VOICE2_SESSION_NAME),
+ MODULE_ID_VOICE_MODULE_FENS, fens_enable);
return 0;
}
@@ -605,13 +607,13 @@
SOC_SINGLE_EXT("VoLTE Topology Disable", SND_SOC_NOPM, 0, 1, 0,
msm_volte_topology_disable_get,
msm_volte_topology_disable_put),
- SOC_SINGLE_EXT("SGLTE Rx Device Mute", SND_SOC_NOPM, 0, 1, 0,
- msm_sglte_rx_device_mute_get,
- msm_sglte_rx_device_mute_put),
- SOC_SINGLE_EXT("SGLTE Tx Mute", SND_SOC_NOPM, 0, 1, 0,
- msm_sglte_mute_get, msm_sglte_mute_put),
- SOC_SINGLE_EXT("SGLTE Rx Volume", SND_SOC_NOPM, 0, 5, 0,
- msm_sglte_volume_get, msm_sglte_volume_put),
+ SOC_SINGLE_EXT("Voice2 Rx Device Mute", SND_SOC_NOPM, 0, 1, 0,
+ msm_voice2_rx_device_mute_get,
+ msm_voice2_rx_device_mute_put),
+ SOC_SINGLE_EXT("Voice2 Tx Mute", SND_SOC_NOPM, 0, 1, 0,
+ msm_voice2_mute_get, msm_voice2_mute_put),
+ SOC_SINGLE_EXT("Voice2 Rx Volume", SND_SOC_NOPM, 0, 5, 0,
+ msm_voice2_volume_get, msm_voice2_volume_put),
};
static struct snd_pcm_ops msm_pcm_ops = {
@@ -674,7 +676,7 @@
memset(&voice_info, 0, sizeof(voice_info));
mutex_init(&voice_info[VOICE_SESSION_INDEX].lock);
mutex_init(&voice_info[VOLTE_SESSION_INDEX].lock);
- mutex_init(&voice_info[SGLTE_SESSION_INDEX].lock);
+ mutex_init(&voice_info[VOICE2_SESSION_INDEX].lock);
return platform_driver_register(&msm_pcm_driver);
}
diff --git a/sound/soc/msm/msm-pcm-voice.h b/sound/soc/msm/msm-pcm-voice.h
index 6eb2060..207e7a7 100644
--- a/sound/soc/msm/msm-pcm-voice.h
+++ b/sound/soc/msm/msm-pcm-voice.h
@@ -16,7 +16,7 @@
enum {
VOICE_SESSION_INDEX,
VOLTE_SESSION_INDEX,
- SGLTE_SESSION_INDEX,
+ VOICE2_SESSION_INDEX,
VOICE_SESSION_INDEX_MAX,
};
diff --git a/sound/soc/msm/msm8226.c b/sound/soc/msm/msm8226.c
index 328c380..4dc6505 100644
--- a/sound/soc/msm/msm8226.c
+++ b/sound/soc/msm/msm8226.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, 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
@@ -84,8 +84,9 @@
static int msm_btsco_ch = 1;
static struct mutex cdc_mclk_mutex;
-static struct q_clkdiv *codec_clk;
+static struct clk *codec_clk;
static int clk_users;
+static int vdd_spkr_gpio = -1;
static int msm_snd_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable,
bool dapm)
@@ -98,7 +99,7 @@
if (enable) {
if (!codec_clk) {
dev_err(codec->dev, "%s: did not get Taiko MCLK\n",
- __func__);
+ __func__);
ret = -EINVAL;
goto exit;
}
@@ -106,17 +107,25 @@
clk_users++;
if (clk_users != 1)
goto exit;
- /* TODO: qpnp_clkdiv_enable */
- tapan_mclk_enable(codec, 1, dapm);
+ if (codec_clk) {
+ clk_set_rate(codec_clk, TAPAN_EXT_CLK_RATE);
+ clk_prepare_enable(codec_clk);
+ tapan_mclk_enable(codec, 1, dapm);
+ } else {
+ pr_err("%s: Error setting Tapan MCLK\n", __func__);
+ clk_users--;
+ ret = -EINVAL;
+ goto exit;
+ }
} else {
if (clk_users > 0) {
clk_users--;
if (clk_users == 0) {
tapan_mclk_enable(codec, 0, dapm);
- /* TODO: qpnp_clkdiv_disable */
+ clk_disable_unprepare(codec_clk);
}
} else {
- pr_err("%s: Error releasing Tabla MCLK\n", __func__);
+ pr_err("%s: Error releasing Tapan MCLK\n", __func__);
ret = -EINVAL;
goto exit;
}
@@ -141,6 +150,30 @@
return 0;
}
+static int msm8226_vdd_spkr_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ pr_debug("%s: event = %d\n", __func__, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ if (vdd_spkr_gpio >= 0) {
+ gpio_direction_output(vdd_spkr_gpio, 1);
+ pr_debug("%s: Enabled 5V external supply for speaker\n",
+ __func__);
+ }
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ if (vdd_spkr_gpio >= 0) {
+ gpio_direction_output(vdd_spkr_gpio, 0);
+ pr_debug("%s: Disabled 5V external supply for speaker\n",
+ __func__);
+ }
+ break;
+ }
+ return 0;
+}
+
static const struct snd_soc_dapm_widget msm8226_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("MCLK", SND_SOC_NOPM, 0, 0,
@@ -157,6 +190,9 @@
SND_SOC_DAPM_MIC("Digital Mic4", NULL),
SND_SOC_DAPM_MIC("Digital Mic5", NULL),
SND_SOC_DAPM_MIC("Digital Mic6", NULL),
+
+ SND_SOC_DAPM_SUPPLY("EXT_VDD_SPKR", SND_SOC_NOPM, 0, 0,
+ msm8226_vdd_spkr_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
};
static const char *const slim0_rx_ch_text[] = {"One", "Two"};
@@ -268,23 +304,6 @@
return 0;
}
-static int msm8226_hdmi_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
- struct snd_pcm_hw_params *params)
-{
- struct snd_interval *rate = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_RATE);
-
- struct snd_interval *channels = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_CHANNELS);
-
- pr_debug("%s channels->min %u channels->max %u ()\n", __func__,
- channels->min, channels->max);
-
- rate->min = rate->max = 48000;
-
- return 0;
-}
-
static int msm_slim_0_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
@@ -335,9 +354,9 @@
};
static const struct snd_kcontrol_new msm_snd_controls[] = {
- SOC_ENUM_EXT("SLIM_0_RX Channels", msm_snd_enum[1],
+ SOC_ENUM_EXT("SLIM_0_RX Channels", msm_snd_enum[0],
msm_slim_0_rx_ch_get, msm_slim_0_rx_ch_put),
- SOC_ENUM_EXT("SLIM_0_TX Channels", msm_snd_enum[2],
+ SOC_ENUM_EXT("SLIM_0_TX Channels", msm_snd_enum[1],
msm_slim_0_tx_ch_get, msm_slim_0_tx_ch_put),
};
@@ -373,13 +392,21 @@
snd_soc_dapm_sync(dapm);
+ codec_clk = clk_get(cpu_dai->dev, "osr_clk");
+ if (codec_clk < 0)
+ pr_err("%s() Failed to get clock for %s\n",
+ __func__, dev_name(cpu_dai->dev));
+
snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch),
tx_ch, ARRAY_SIZE(rx_ch), rx_ch);
/* start mbhc */
mbhc_cfg.calibration = def_tapan_mbhc_cal();
- if (mbhc_cfg.calibration)
- err = tapan_hs_detect(codec, &mbhc_cfg);
+ if (mbhc_cfg.calibration) {
+ pr_info("%s: WCD9306: Headset detection disabled\n",
+ __func__);
+ }
+
else
err = -ENOMEM;
@@ -550,7 +577,7 @@
.name = "MSM8226 Media1",
.stream_name = "MultiMedia1",
.cpu_dai_name = "MultiMedia1",
- .platform_name = "msm-pcm-dsp",
+ .platform_name = "msm-pcm-dsp.0",
.dynamic = 1,
.trigger = {SND_SOC_DPCM_TRIGGER_POST,
SND_SOC_DPCM_TRIGGER_POST},
@@ -565,7 +592,7 @@
.name = "MSM8226 Media2",
.stream_name = "MultiMedia2",
.cpu_dai_name = "MultiMedia2",
- .platform_name = "msm-pcm-dsp",
+ .platform_name = "msm-pcm-dsp.0",
.dynamic = 1,
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
@@ -744,6 +771,37 @@
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
},
+ {
+ .name = "VoLTE",
+ .stream_name = "VoLTE",
+ .cpu_dai_name = "VoLTE",
+ .platform_name = "msm-pcm-voice",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_VOLTE,
+ },
+ {
+ .name = "MSM8226 LowLatency",
+ .stream_name = "MultiMedia5",
+ .cpu_dai_name = "MultiMedia5",
+ .platform_name = "msm-pcm-dsp.1",
+ .dynamic = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA5,
+ },
/* Backend BT/FM DAI Links */
{
.name = LPASS_BE_INT_BT_SCO_RX,
@@ -757,6 +815,7 @@
.be_hw_params_fixup = msm_btsco_be_hw_params_fixup,
/* this dainlink has playback support */
.ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
},
{
.name = LPASS_BE_INT_BT_SCO_TX,
@@ -768,6 +827,7 @@
.no_pcm = 1,
.be_id = MSM_BACKEND_DAI_INT_BT_SCO_TX,
.be_hw_params_fixup = msm_btsco_be_hw_params_fixup,
+ .ignore_suspend = 1,
},
{
.name = LPASS_BE_INT_FM_RX,
@@ -781,6 +841,7 @@
.be_hw_params_fixup = msm_be_hw_params_fixup,
/* this dainlink has playback support */
.ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
},
{
.name = LPASS_BE_INT_FM_TX,
@@ -792,6 +853,7 @@
.no_pcm = 1,
.be_id = MSM_BACKEND_DAI_INT_FM_TX,
.be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
},
/* Backend AFE DAI Links */
{
@@ -806,6 +868,7 @@
.be_hw_params_fixup = msm_proxy_be_hw_params_fixup,
/* this dainlink has playback support */
.ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
},
{
.name = LPASS_BE_AFE_PCM_TX,
@@ -817,6 +880,7 @@
.no_pcm = 1,
.be_id = MSM_BACKEND_DAI_AFE_PCM_TX,
.be_hw_params_fixup = msm_proxy_be_hw_params_fixup,
+ .ignore_suspend = 1,
},
/* HDMI Hostless */
{
@@ -833,19 +897,6 @@
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
},
- /* HDMI BACK END DAI Link */
- {
- .name = LPASS_BE_HDMI,
- .stream_name = "HDMI Playback",
- .cpu_dai_name = "msm-dai-q6-hdmi.8",
- .platform_name = "msm-pcm-routing",
- .codec_name = "msm-stub-codec.1",
- .codec_dai_name = "msm-stub-rx",
- .no_pcm = 1,
- .be_id = MSM_BACKEND_DAI_HDMI_RX,
- .be_hw_params_fixup = msm8226_hdmi_be_hw_params_fixup,
- .ignore_pmdown_time = 1,
- },
/* Backend DAI Links */
{
.name = LPASS_BE_SLIMBUS_0_RX,
@@ -860,6 +911,7 @@
.be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup,
.ops = &msm8226_be_ops,
.ignore_pmdown_time = 1, /* dai link has playback support */
+ .ignore_suspend = 1,
},
{
.name = LPASS_BE_SLIMBUS_0_TX,
@@ -872,6 +924,7 @@
.be_id = MSM_BACKEND_DAI_SLIMBUS_0_TX,
.be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
.ops = &msm8226_be_ops,
+ .ignore_suspend = 1,
},
{
.name = LPASS_BE_SLIMBUS_1_RX,
@@ -886,6 +939,7 @@
.ops = &msm8226_be_ops,
/* dai link has playback support */
.ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
},
{
.name = LPASS_BE_SLIMBUS_1_TX,
@@ -898,6 +952,7 @@
.be_id = MSM_BACKEND_DAI_SLIMBUS_1_TX,
.be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
.ops = &msm8226_be_ops,
+ .ignore_suspend = 1,
},
{
.name = LPASS_BE_SLIMBUS_3_RX,
@@ -912,6 +967,7 @@
.ops = &msm8226_be_ops,
/* dai link has playback support */
.ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
},
{
.name = LPASS_BE_SLIMBUS_3_TX,
@@ -924,6 +980,7 @@
.be_id = MSM_BACKEND_DAI_SLIMBUS_3_TX,
.be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
.ops = &msm8226_be_ops,
+ .ignore_suspend = 1,
},
{
.name = LPASS_BE_SLIMBUS_4_RX,
@@ -938,6 +995,7 @@
.ops = &msm8226_be_ops,
/* dai link has playback support */
.ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
},
{
.name = LPASS_BE_SLIMBUS_4_TX,
@@ -950,6 +1008,46 @@
.be_id = MSM_BACKEND_DAI_SLIMBUS_4_TX,
.be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
.ops = &msm8226_be_ops,
+ .ignore_suspend = 1,
+ },
+ /* Incall Record Uplink BACK END DAI Link */
+ {
+ .name = LPASS_BE_INCALL_RECORD_TX,
+ .stream_name = "Voice Uplink Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.32772",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_INCALL_RECORD_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ /* Incall Record Downlink BACK END DAI Link */
+ {
+ .name = LPASS_BE_INCALL_RECORD_RX,
+ .stream_name = "Voice Downlink Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.32771",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_INCALL_RECORD_RX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ /* Incall Music BACK END DAI Link */
+ {
+ .name = LPASS_BE_VOICE_PLAYBACK_TX,
+ .stream_name = "Voice Farend Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.32773",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
},
};
@@ -961,6 +1059,17 @@
static int msm8226_prepare_codec_mclk(struct snd_soc_card *card)
{
+ struct msm8226_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+ int ret;
+ if (pdata->mclk_gpio) {
+ ret = gpio_request(pdata->mclk_gpio, "TAPAN_CODEC_PMIC_MCLK");
+ if (ret) {
+ dev_err(card->dev,
+ "%s: Failed to request taiko mclk gpio %d\n",
+ __func__, pdata->mclk_gpio);
+ return ret;
+ }
+ }
return 0;
}
@@ -1012,22 +1121,62 @@
goto err;
}
- /* TODO: MCLK GPIO */
+ pdata->mclk_gpio = of_get_named_gpio(pdev->dev.of_node,
+ "qcom,cdc-mclk-gpios", 0);
+ if (pdata->mclk_gpio < 0) {
+ dev_err(&pdev->dev,
+ "Looking up %s property in node %s failed %d\n",
+ "qcom, cdc-mclk-gpios", pdev->dev.of_node->full_name,
+ pdata->mclk_gpio);
+ ret = -ENODEV;
+ goto err;
+ }
+
+ vdd_spkr_gpio = of_get_named_gpio(pdev->dev.of_node,
+ "qcom,cdc-vdd-spkr-gpios", 0);
+ if (vdd_spkr_gpio < 0) {
+ dev_err(&pdev->dev,
+ "Looking up %s property in node %s failed %d\n",
+ "qcom, cdc-vdd-spkr-gpios",
+ pdev->dev.of_node->full_name, vdd_spkr_gpio);
+ } else {
+ ret = gpio_request(vdd_spkr_gpio, "TAPAN_CODEC_VDD_SPKR");
+ if (ret) {
+ /* GPIO to enable EXT VDD exists, but failed request */
+ dev_err(card->dev,
+ "%s: Failed to request tapan vdd spkr gpio %d\n",
+ __func__, vdd_spkr_gpio);
+ goto err;
+ }
+ }
ret = msm8226_prepare_codec_mclk(card);
if (ret)
- goto err;
+ goto err_vdd_spkr;
ret = snd_soc_register_card(card);
if (ret) {
dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
ret);
- goto err;
+ goto err_vdd_spkr;
}
mutex_init(&cdc_mclk_mutex);
return 0;
+
+err_vdd_spkr:
+ if (vdd_spkr_gpio >= 0) {
+ gpio_free(vdd_spkr_gpio);
+ vdd_spkr_gpio = -1;
+ }
+
err:
+ if (pdata->mclk_gpio > 0) {
+ dev_dbg(&pdev->dev, "%s free gpio %d\n",
+ __func__, pdata->mclk_gpio);
+ gpio_free(pdata->mclk_gpio);
+ pdata->mclk_gpio = 0;
+ }
devm_kfree(&pdev->dev, pdata);
return ret;
}
@@ -1035,8 +1184,11 @@
static int __devexit msm8226_asoc_machine_remove(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
+ struct msm8226_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
- /* TODO: GPIO MCLK */
+ gpio_free(pdata->mclk_gpio);
+ gpio_free(vdd_spkr_gpio);
+ vdd_spkr_gpio = -1;
snd_soc_unregister_card(card);
return 0;
diff --git a/sound/soc/msm/msm8930.c b/sound/soc/msm/msm8930.c
index ae9468f..2bd5c88 100644
--- a/sound/soc/msm/msm8930.c
+++ b/sound/soc/msm/msm8930.c
@@ -1105,9 +1105,9 @@
.be_id = MSM_FRONTEND_DAI_VOLTE,
},
{
- .name = "SGLTE",
- .stream_name = "SGLTE",
- .cpu_dai_name = "SGLTE",
+ .name = "Voice2",
+ .stream_name = "Voice2",
+ .cpu_dai_name = "Voice2",
.platform_name = "msm-pcm-voice",
.dynamic = 1,
.trigger = {SND_SOC_DPCM_TRIGGER_POST,
@@ -1118,7 +1118,7 @@
.ignore_pmdown_time = 1,
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
- .be_id = MSM_FRONTEND_DAI_SGLTE,
+ .be_id = MSM_FRONTEND_DAI_VOICE2,
},
{
.name = "MSM8960 LowLatency",
diff --git a/sound/soc/msm/msm8960.c b/sound/soc/msm/msm8960.c
index f987eb4..8c0d1a9 100644
--- a/sound/soc/msm/msm8960.c
+++ b/sound/soc/msm/msm8960.c
@@ -1361,9 +1361,9 @@
.be_id = MSM_FRONTEND_DAI_VOLTE,
},
{
- .name = "SGLTE",
- .stream_name = "SGLTE",
- .cpu_dai_name = "SGLTE",
+ .name = "Voice2",
+ .stream_name = "Voice2",
+ .cpu_dai_name = "Voice2",
.platform_name = "msm-pcm-voice",
.dynamic = 1,
.trigger = {SND_SOC_DPCM_TRIGGER_POST,
@@ -1373,7 +1373,7 @@
.ignore_pmdown_time = 1,/* this dainlink has playback support */
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
- .be_id = MSM_FRONTEND_DAI_SGLTE,
+ .be_id = MSM_FRONTEND_DAI_VOICE2,
},
{
.name = "MSM8960 LowLatency",
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index 747e027..0dbe3f7 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -24,6 +24,7 @@
#include <sound/soc-dapm.h>
#include <sound/pcm.h>
#include <sound/jack.h>
+#include <sound/q6afe-v2.h>
#include <asm/mach-types.h>
#include <mach/socinfo.h>
#include <sound/pcm_params.h>
@@ -1003,6 +1004,33 @@
return 0;
}
+static int msm_slim_5_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ int rc;
+ void *config;
+ struct snd_soc_codec *codec = rtd->codec;
+ struct snd_interval *rate =
+ hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+ struct snd_interval *channels =
+ hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ pr_debug("%s enter\n", __func__);
+ rate->min = rate->max = 16000;
+ channels->min = channels->max = 1;
+
+ config = taiko_get_afe_config(codec, AFE_SLIMBUS_SLAVE_PORT_CONFIG);
+ rc = afe_set_config(AFE_SLIMBUS_SLAVE_PORT_CONFIG, config,
+ SLIMBUS_5_TX);
+ if (rc) {
+ pr_err("%s: Failed to set slimbus slave port config %d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ return 0;
+}
+
static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
@@ -1054,6 +1082,7 @@
static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
{
int err;
+ void *config_data;
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
@@ -1108,6 +1137,23 @@
snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch),
tx_ch, ARRAY_SIZE(rx_ch), rx_ch);
+
+ config_data = taiko_get_afe_config(codec, AFE_CDC_REGISTERS_CONFIG);
+ err = afe_set_config(AFE_CDC_REGISTERS_CONFIG, config_data, 0);
+ if (err) {
+ pr_err("%s: Failed to set codec registers config %d\n",
+ __func__, err);
+ return err;
+ }
+
+ config_data = taiko_get_afe_config(codec, AFE_SLIMBUS_SLAVE_CONFIG);
+ err = afe_set_config(AFE_SLIMBUS_SLAVE_CONFIG, config_data, 0);
+ if (err) {
+ pr_err("%s: Failed to set slimbus slave config %d\n", __func__,
+ err);
+ return err;
+ }
+
/* start mbhc */
mbhc_cfg.calibration = def_taiko_mbhc_cal();
if (mbhc_cfg.calibration)
@@ -1574,6 +1620,22 @@
.ignore_pmdown_time = 1,
.be_id = MSM_FRONTEND_DAI_MULTIMEDIA5,
},
+ /* LSM FE */
+ {
+ .name = "Listen Audio Service",
+ .stream_name = "Listen Audio Service",
+ .cpu_dai_name = "LSM",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .trigger = { SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM1,
+ },
/* Backend BT/FM DAI Links */
{
.name = LPASS_BE_INT_BT_SCO_RX,
@@ -1837,6 +1899,19 @@
.be_hw_params_fixup = msm_be_hw_params_fixup,
.ignore_suspend = 1,
},
+ /* MAD BE */
+ {
+ .name = LPASS_BE_SLIMBUS_5_TX,
+ .stream_name = "Slimbus5 Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16395",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "taiko_codec",
+ .codec_dai_name = "taiko_mad1",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_5_TX,
+ .be_hw_params_fixup = msm_slim_5_tx_be_hw_params_fixup,
+ .ops = &msm8974_be_ops,
+ },
/* Incall Music BACK END DAI Link */
{
.name = LPASS_BE_VOICE_PLAYBACK_TX,
diff --git a/sound/soc/msm/qdsp6/q6voice.c b/sound/soc/msm/qdsp6/q6voice.c
index f04947c..17f2d03 100644
--- a/sound/soc/msm/qdsp6/q6voice.c
+++ b/sound/soc/msm/qdsp6/q6voice.c
@@ -31,11 +31,6 @@
#define CMD_STATUS_SUCCESS 0
#define CMD_STATUS_FAIL 1
-#define VOC_PATH_PASSIVE 0
-#define VOC_PATH_FULL 1
-#define VOC_PATH_VOLTE_PASSIVE 2
-#define VOC_PATH_SGLTE_PASSIVE 3
-
#define CAL_BUFFER_SIZE 4096
#define NUM_CVP_CAL_BLOCKS 75
#define NUM_CVS_CAL_BLOCKS 15
@@ -173,9 +168,9 @@
else if (!strncmp(name, "VoLTE session", 13))
session_id =
common.voice[VOC_PATH_VOLTE_PASSIVE].session_id;
- else if (!strncmp(name, "SGLTE session", 13))
+ else if (!strncmp(name, "Voice2 session", 14))
session_id =
- common.voice[VOC_PATH_SGLTE_PASSIVE].session_id;
+ common.voice[VOC_PATH_VOICE2_PASSIVE].session_id;
else
session_id = common.voice[VOC_PATH_FULL].session_id;
@@ -216,9 +211,9 @@
return (session_id == common.voice[VOC_PATH_VOLTE_PASSIVE].session_id);
}
-static bool is_sglte_session(u16 session_id)
+static bool is_voice2_session(u16 session_id)
{
- return (session_id == common.voice[VOC_PATH_SGLTE_PASSIVE].session_id);
+ return (session_id == common.voice[VOC_PATH_VOICE2_PASSIVE].session_id);
}
/* Only for memory allocated in the voice driver */
@@ -373,9 +368,9 @@
pr_err("%s: apr_mvm is NULL.\n", __func__);
return -EINVAL;
}
- pr_debug("%s: VoLTE/SGLTE command to MVM\n", __func__);
+ pr_debug("%s: VoLTE/Voice2 command to MVM\n", __func__);
if (is_volte_session(v->session_id) ||
- is_sglte_session(v->session_id)) {
+ is_voice2_session(v->session_id)) {
mvm_handle = voice_get_mvm_handle(v);
mvm_voice_ctl_cmd.hdr.hdr_field = APR_HDR_FIELD(
@@ -451,7 +446,7 @@
if (!mvm_handle) {
if (is_voice_session(v->session_id) ||
is_volte_session(v->session_id) ||
- is_sglte_session(v->session_id)) {
+ is_voice2_session(v->session_id)) {
mvm_session_cmd.hdr.hdr_field = APR_HDR_FIELD(
APR_MSG_TYPE_SEQ_CMD,
APR_HDR_LEN(APR_HDR_SIZE),
@@ -471,7 +466,7 @@
strlcpy(mvm_session_cmd.mvm_session.name,
"default volte voice",
sizeof(mvm_session_cmd.mvm_session.name) - 1);
- } else if (is_sglte_session(v->session_id)) {
+ } else if (is_voice2_session(v->session_id)) {
strlcpy(mvm_session_cmd.mvm_session.name,
"default modem voice2",
sizeof(mvm_session_cmd.mvm_session.name));
@@ -538,7 +533,7 @@
if (!cvs_handle) {
if (is_voice_session(v->session_id) ||
is_volte_session(v->session_id) ||
- is_sglte_session(v->session_id)) {
+ is_voice2_session(v->session_id)) {
pr_debug("%s: creating CVS passive session\n",
__func__);
@@ -559,7 +554,7 @@
strlcpy(cvs_session_cmd.cvs_session.name,
"default volte voice",
sizeof(cvs_session_cmd.cvs_session.name) - 1);
- } else if (is_sglte_session(v->session_id)) {
+ } else if (is_voice2_session(v->session_id)) {
strlcpy(cvs_session_cmd.cvs_session.name,
"default modem voice2",
sizeof(cvs_session_cmd.cvs_session.name));
diff --git a/sound/soc/msm/qdsp6/q6voice.h b/sound/soc/msm/qdsp6/q6voice.h
index 8df6c38..0bae384 100644
--- a/sound/soc/msm/qdsp6/q6voice.h
+++ b/sound/soc/msm/qdsp6/q6voice.h
@@ -1314,12 +1314,12 @@
#define VOICE_SESSION_NAME "Voice session"
#define VOIP_SESSION_NAME "VoIP session"
#define VOLTE_SESSION_NAME "VoLTE session"
-#define SGLTE_SESSION_NAME "SGLTE session"
+#define VOICE2_SESSION_NAME "Voice2 session"
#define VOC_PATH_PASSIVE 0
#define VOC_PATH_FULL 1
#define VOC_PATH_VOLTE_PASSIVE 2
-#define VOC_PATH_SGLTE_PASSIVE 3
+#define VOC_PATH_VOICE2_PASSIVE 3
uint16_t voc_get_session_id(char *name);
diff --git a/sound/soc/msm/qdsp6v2/Makefile b/sound/soc/msm/qdsp6v2/Makefile
index 69c0976..391b3da 100644
--- a/sound/soc/msm/qdsp6v2/Makefile
+++ b/sound/soc/msm/qdsp6v2/Makefile
@@ -1,6 +1,11 @@
-snd-soc-qdsp6v2-objs += msm-dai-q6-v2.o msm-pcm-q6-v2.o msm-pcm-routing-v2.o msm-compr-q6-v2.o msm-multi-ch-pcm-q6-v2.o
-snd-soc-qdsp6v2-objs += msm-pcm-lpa-v2.o msm-pcm-afe-v2.o msm-pcm-voip-v2.o msm-pcm-voice-v2.o msm-dai-q6-hdmi-v2.o
-obj-$(CONFIG_SND_SOC_QDSP6V2) += snd-soc-qdsp6v2.o msm-pcm-dtmf-v2.o msm-dai-stub-v2.o
-obj-y += q6adm.o q6afe.o q6asm.o q6audio-v2.o q6voice.o q6core.o audio_acdb.o rtac.o
+snd-soc-qdsp6v2-objs += msm-dai-q6-v2.o msm-pcm-q6-v2.o msm-pcm-routing-v2.o \
+ msm-compr-q6-v2.o msm-multi-ch-pcm-q6-v2.o \
+ msm-pcm-lpa-v2.o msm-pcm-afe-v2.o msm-pcm-voip-v2.o \
+ msm-pcm-voice-v2.o msm-dai-q6-hdmi-v2.o \
+ msm-lsm-client.o
+obj-$(CONFIG_SND_SOC_QDSP6V2) += snd-soc-qdsp6v2.o msm-pcm-dtmf-v2.o \
+ msm-dai-stub-v2.o
+obj-y += q6adm.o q6afe.o q6asm.o q6audio-v2.o q6voice.o q6core.o audio_acdb.o \
+ rtac.o q6lsm.o
ocmem-audio-objs += audio_ocmem.o
obj-$(CONFIG_AUDIO_OCMEM) += ocmem-audio.o
diff --git a/sound/soc/msm/qdsp6v2/audio_acdb.c b/sound/soc/msm/qdsp6v2/audio_acdb.c
index ccaf39d..259f3ed 100644
--- a/sound/soc/msm/qdsp6v2/audio_acdb.c
+++ b/sound/soc/msm/qdsp6v2/audio_acdb.c
@@ -839,7 +839,7 @@
{
int result;
int i;
- unsigned long paddr;
+ ion_phys_addr_t paddr;
void *kvptr;
unsigned long kvaddr;
unsigned long mem_len;
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
index 387af59..5b18311 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
@@ -485,7 +485,7 @@
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
- case SNDRV_PCM_FMTBIT_SPECIAL:
+ case SNDRV_PCM_FORMAT_SPECIAL:
dai_data->port_config.i2s.bit_width = 16;
break;
case SNDRV_PCM_FORMAT_S24_LE:
@@ -561,7 +561,7 @@
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
- case SNDRV_PCM_FMTBIT_SPECIAL:
+ case SNDRV_PCM_FORMAT_SPECIAL:
dai_data->port_config.slim_sch.bit_width = 16;
break;
case SNDRV_PCM_FORMAT_S24_LE:
@@ -701,6 +701,7 @@
case SLIMBUS_2_TX:
case SLIMBUS_3_TX:
case SLIMBUS_4_TX:
+ case SLIMBUS_5_TX:
rc = msm_dai_q6_slim_bus_hw_params(params, dai,
substream->stream);
break;
@@ -831,6 +832,7 @@
case SLIMBUS_2_TX:
case SLIMBUS_3_TX:
case SLIMBUS_4_TX:
+ case SLIMBUS_5_TX:
/*
* channel number to be between 128 and 255.
* For TX port use channel numbers
@@ -1980,6 +1982,7 @@
break;
case SLIMBUS_0_TX:
case SLIMBUS_2_TX:
+ case SLIMBUS_5_TX:
rc = snd_soc_register_dai(&pdev->dev,
&msm_dai_q6_slimbus_tx_dai);
break;
diff --git a/sound/soc/msm/qdsp6v2/msm-lsm-client.c b/sound/soc/msm/qdsp6v2/msm-lsm-client.c
new file mode 100644
index 0000000..ea6f390
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-lsm-client.c
@@ -0,0 +1,370 @@
+/*
+ * Copyright (c) 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/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/android_pmem.h>
+#include <linux/of.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/timer.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <sound/q6lsm.h>
+#include <sound/lsm_params.h>
+#include "msm-pcm-routing-v2.h"
+
+struct lsm_priv {
+ struct snd_pcm_substream *substream;
+ struct lsm_client *lsm_client;
+
+ struct snd_lsm_event_status *event_status;
+ spinlock_t event_lock;
+ wait_queue_head_t event_wait;
+ unsigned long event_avail;
+ atomic_t event_wait_stop;
+};
+
+static void lsm_event_handler(uint32_t opcode, uint32_t token,
+ void *payload, void *priv)
+{
+ unsigned long flags;
+ struct snd_lsm_event_status *event_status;
+ struct lsm_priv *prtd = priv;
+ struct snd_pcm_substream *substream = prtd->substream;
+
+ pr_debug("%s: enter opcode 0x%x\n", __func__, opcode);
+ switch (opcode) {
+ case LSM_SESSION_EVENT_DETECTION_STATUS:
+ event_status = payload;
+
+ spin_lock_irqsave(&prtd->event_lock, flags);
+ prtd->event_status = krealloc(prtd->event_status,
+ sizeof(*event_status) +
+ event_status->payload_size,
+ GFP_ATOMIC);
+ if (likely(prtd->event_status)) {
+ memcpy(prtd->event_status, event_status,
+ sizeof(*event_status) +
+ event_status->payload_size);
+ prtd->event_avail = 1;
+ spin_unlock_irqrestore(&prtd->event_lock, flags);
+ wake_up(&prtd->event_wait);
+ } else {
+ spin_unlock_irqrestore(&prtd->event_lock, flags);
+ pr_err("%s: Couldn't allocate %d bytes of memory\n",
+ __func__, event_status->payload_size);
+ }
+ if (substream->timer_running)
+ snd_timer_interrupt(substream->timer, 1);
+ break;
+ default:
+ pr_debug("%s: Unsupported Event opcode 0x%x\n", __func__,
+ opcode);
+ break;
+ }
+}
+
+static int msm_lsm_ioctl(struct snd_pcm_substream *substream,
+ unsigned int cmd, void *arg)
+{
+ unsigned long flags;
+ int ret;
+ struct snd_lsm_sound_model snd_model;
+ int rc = 0;
+ int xchg = 0;
+ int size = 0;
+ struct snd_lsm_event_status *event_status = NULL;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct lsm_priv *prtd = runtime->private_data;
+ struct snd_lsm_event_status *user = arg;
+
+ pr_debug("%s: enter cmd %x\n", __func__, cmd);
+ switch (cmd) {
+ case SNDRV_LSM_REG_SND_MODEL:
+ pr_debug("%s: Registering sound model\n", __func__);
+ if (copy_from_user(&snd_model, (void *)arg,
+ sizeof(struct snd_lsm_sound_model))) {
+ rc = -EFAULT;
+ pr_err("%s: copy from user failed, size %d\n", __func__,
+ sizeof(struct snd_lsm_sound_model));
+ break;
+ }
+
+ rc = q6lsm_snd_model_buf_alloc(prtd->lsm_client,
+ snd_model.data_size);
+ if (rc) {
+ pr_err("%s: q6lsm buffer alloc failed, size %d\n",
+ __func__, snd_model.data_size);
+ break;
+ }
+
+ if (copy_from_user(prtd->lsm_client->sound_model.data,
+ snd_model.data, snd_model.data_size)) {
+ pr_err("%s: copy from user data failed size %d\n",
+ __func__, snd_model.data_size);
+ rc = -EFAULT;
+ break;
+ }
+
+ rc = q6lsm_register_sound_model(prtd->lsm_client,
+ snd_model.detection_mode,
+ snd_model.min_keyw_confidence,
+ snd_model.min_user_confidence,
+ snd_model.detect_failure);
+ if (rc < 0)
+ pr_err("%s: q6lsm_register_sound_model failed =%d\n",
+ __func__, rc);
+ break;
+
+ case SNDRV_LSM_DEREG_SND_MODEL:
+ pr_debug("%s: Deregistering sound model\n", __func__);
+ rc = q6lsm_deregister_sound_model(prtd->lsm_client);
+ break;
+
+ case SNDRV_LSM_EVENT_STATUS:
+ pr_debug("%s: Get event status\n", __func__);
+ atomic_set(&prtd->event_wait_stop, 0);
+ rc = wait_event_interruptible(prtd->event_wait,
+ (cmpxchg(&prtd->event_avail, 1, 0) ||
+ (xchg = atomic_cmpxchg(&prtd->event_wait_stop,
+ 1, 0))));
+ pr_debug("%s: wait_event_interruptible %d event_wait_stop %d\n",
+ __func__, rc, xchg);
+ if (!rc && !xchg) {
+ pr_debug("%s: New event available %ld\n", __func__,
+ prtd->event_avail);
+ spin_lock_irqsave(&prtd->event_lock, flags);
+ if (prtd->event_status) {
+ size = sizeof(*event_status) +
+ prtd->event_status->payload_size;
+ event_status = kmemdup(prtd->event_status, size,
+ GFP_ATOMIC);
+ }
+ spin_unlock_irqrestore(&prtd->event_lock, flags);
+ if (!event_status) {
+ pr_err("%s: Couldn't allocate %d bytes\n",
+ __func__, size);
+ /*
+ * Don't use -ENOMEM as userspace will check
+ * it for increasing buffer
+ */
+ rc = -EFAULT;
+ } else {
+ if (user->payload_size <
+ event_status->payload_size) {
+ pr_debug("%s: provided %dbytes isn't enough, needs %dbytes\n",
+ __func__, user->payload_size,
+ size);
+ rc = -ENOMEM;
+ } else if (!access_ok(VERIFY_WRITE, arg,
+ size)) {
+ rc = -EFAULT;
+ } else {
+ rc = copy_to_user(arg, event_status,
+ size);
+ if (rc)
+ pr_err("%s: copy to user failed %d\n",
+ __func__, rc);
+ }
+ kfree(event_status);
+ }
+ } else if (xchg) {
+ pr_debug("%s: Wait aborted\n", __func__);
+ rc = 0;
+ }
+ break;
+
+ case SNDRV_LSM_ABORT_EVENT:
+ pr_debug("%s: Aborting event status wait\n", __func__);
+ atomic_set(&prtd->event_wait_stop, 1);
+ wake_up(&prtd->event_wait);
+ break;
+
+ case SNDRV_LSM_START:
+ pr_debug("%s: Starting LSM client session\n", __func__);
+ if (!prtd->lsm_client->started) {
+ ret = q6lsm_start(prtd->lsm_client, true);
+ if (!ret) {
+ prtd->lsm_client->started = true;
+ pr_debug("%s: LSM client session started\n",
+ __func__);
+ }
+ }
+ break;
+
+ case SNDRV_LSM_STOP:
+ pr_debug("%s: Stopping LSM client session\n", __func__);
+ if (prtd->lsm_client->started) {
+ ret = q6lsm_stop(prtd->lsm_client, true);
+ if (!ret) {
+ prtd->lsm_client->started = false;
+ pr_debug("%s: LSM client session stopped\n",
+ __func__);
+ }
+ }
+ break;
+
+ default:
+ pr_debug("%s: Falling into default snd_lib_ioctl cmd 0x%x\n",
+ __func__, cmd);
+ rc = snd_pcm_lib_ioctl(substream, cmd, arg);
+ break;
+ }
+
+ if (!rc)
+ pr_debug("%s: leave (%d)\n", __func__, rc);
+ else
+ pr_err("%s: cmd 0x%x failed %d\n", __func__, cmd, rc);
+
+ return rc;
+}
+
+static int msm_lsm_open(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct lsm_priv *prtd;
+ int ret = 0;
+
+ pr_debug("%s\n", __func__);
+ prtd = kzalloc(sizeof(struct lsm_priv), GFP_KERNEL);
+ if (!prtd) {
+ pr_err("%s: Failed to allocate memory for lsm_priv\n",
+ __func__);
+ return -ENOMEM;
+ }
+ prtd->substream = substream;
+ prtd->lsm_client = q6lsm_client_alloc((app_cb)lsm_event_handler, prtd);
+ if (!prtd->lsm_client) {
+ pr_err("%s: Could not allocate memory\n", __func__);
+ kfree(prtd);
+ return -ENOMEM;
+ }
+ ret = q6lsm_open(prtd->lsm_client);
+ if (ret < 0) {
+ pr_err("%s: lsm out open failed\n", __func__);
+ q6lsm_client_free(prtd->lsm_client);
+ kfree(prtd);
+ return -ENOMEM;
+ }
+
+ pr_debug("%s: Session ID %d\n", __func__, prtd->lsm_client->session);
+ prtd->lsm_client->started = false;
+ spin_lock_init(&prtd->event_lock);
+ init_waitqueue_head(&prtd->event_wait);
+ runtime->private_data = prtd;
+
+ return 0;
+}
+
+static int msm_lsm_close(struct snd_pcm_substream *substream)
+{
+ unsigned long flags;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct lsm_priv *prtd = runtime->private_data;
+
+ pr_debug("%s\n", __func__);
+
+ q6lsm_close(prtd->lsm_client);
+ q6lsm_client_free(prtd->lsm_client);
+
+ spin_lock_irqsave(&prtd->event_lock, flags);
+ kfree(prtd->event_status);
+ prtd->event_status = NULL;
+ spin_unlock_irqrestore(&prtd->event_lock, flags);
+ kfree(prtd);
+
+ return 0;
+}
+
+static struct snd_pcm_ops msm_lsm_ops = {
+ .open = msm_lsm_open,
+ .close = msm_lsm_close,
+ .ioctl = msm_lsm_ioctl,
+};
+
+static int msm_asoc_lsm_new(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_card *card = rtd->card->snd_card;
+
+ if (!card->dev->coherent_dma_mask)
+ card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+
+ return 0;
+}
+
+static int msm_asoc_lsm_probe(struct snd_soc_platform *platform)
+{
+ pr_debug("enter %s\n", __func__);
+
+ return 0;
+}
+
+static struct snd_soc_platform_driver msm_soc_platform = {
+ .ops = &msm_lsm_ops,
+ .pcm_new = msm_asoc_lsm_new,
+ .probe = msm_asoc_lsm_probe,
+};
+
+static __devinit int msm_lsm_probe(struct platform_device *pdev)
+{
+ if (pdev->dev.of_node)
+ dev_set_name(&pdev->dev, "%s", "msm-lsm-client");
+
+ return snd_soc_register_platform(&pdev->dev, &msm_soc_platform);
+}
+
+static int msm_lsm_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_platform(&pdev->dev);
+
+ return 0;
+}
+
+static const struct of_device_id msm_lsm_client_dt_match[] = {
+ {.compatible = "qcom,msm-lsm-client" },
+ { }
+};
+
+static struct platform_driver msm_lsm_driver = {
+ .driver = {
+ .name = "msm-lsm-client",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(msm_lsm_client_dt_match),
+ },
+ .probe = msm_lsm_probe,
+ .remove = __devexit_p(msm_lsm_remove),
+};
+
+static int __init msm_soc_platform_init(void)
+{
+ return platform_driver_register(&msm_lsm_driver);
+}
+module_init(msm_soc_platform_init);
+
+static void __exit msm_soc_platform_exit(void)
+{
+ platform_driver_unregister(&msm_lsm_driver);
+}
+module_exit(msm_soc_platform_exit);
+
+MODULE_DESCRIPTION("LSM client platform driver");
+MODULE_DEVICE_TABLE(of, msm_lsm_client_dt_match);
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 9fe438c..819512d 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -55,6 +55,27 @@
static int fm_switch_enable;
static int fm_pcmrx_switch_enable;
static int srs_alsa_ctrl_ever_called;
+static int lsm_mux_slim_port;
+
+enum {
+ MADNONE,
+ MADAUDIO,
+ MADBEACON,
+ MADULTRASOUND
+};
+
+#define SLIMBUS_0_TX_TEXT "SLIMBUS_0_TX"
+#define SLIMBUS_1_TX_TEXT "SLIMBUS_1_TX"
+#define SLIMBUS_2_TX_TEXT "SLIMBUS_2_TX"
+#define SLIMBUS_3_TX_TEXT "SLIMBUS_3_TX"
+#define SLIMBUS_4_TX_TEXT "SLIMBUS_4_TX"
+#define SLIMBUS_5_TX_TEXT "SLIMBUS_5_TX"
+#define LSM_FUNCTION_TEXT "LSM Function"
+static const char * const mad_audio_mux_text[] = {
+ "None",
+ SLIMBUS_0_TX_TEXT, SLIMBUS_1_TX_TEXT, SLIMBUS_2_TX_TEXT,
+ SLIMBUS_3_TX_TEXT, SLIMBUS_4_TX_TEXT, SLIMBUS_5_TX_TEXT
+};
#define INT_RX_VOL_MAX_STEPS 0x2000
#define INT_RX_VOL_GAIN 0x2000
@@ -190,6 +211,7 @@
{ SLIMBUS_4_TX, 0, 0, 0, 0, 0},
{ SLIMBUS_3_RX, 0, 0, 0, 0, 0},
{ SLIMBUS_3_TX, 0, 0, 0, 0, 0},
+ { SLIMBUS_5_TX, 0, 0, 0, 0, 0 },
{ SLIMBUS_EXTPROC_RX, 0, 0, 0, 0, 0},
{ SLIMBUS_EXTPROC_RX, 0, 0, 0, 0, 0},
{ SLIMBUS_EXTPROC_RX, 0, 0, 0, 0, 0},
@@ -731,6 +753,118 @@
return 1;
}
+static int msm_routing_lsm_mux_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = lsm_mux_slim_port;
+ return 0;
+}
+
+static int msm_routing_lsm_mux_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ int mux = ucontrol->value.enumerated.item[0];
+
+ pr_debug("%s: LSM enable %ld\n", __func__,
+ ucontrol->value.integer.value[0]);
+ if (ucontrol->value.integer.value[0]) {
+ lsm_mux_slim_port = ucontrol->value.integer.value[0];
+ snd_soc_dapm_mux_update_power(widget, kcontrol, 1, mux, e);
+ } else {
+ snd_soc_dapm_mux_update_power(widget, kcontrol, 1, mux, e);
+ lsm_mux_slim_port = ucontrol->value.integer.value[0];
+ }
+
+ return 0;
+}
+
+static int msm_routing_lsm_func_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int i;
+ u16 port_id;
+ enum afe_mad_type mad_type;
+
+ pr_debug("%s: enter\n", __func__);
+ for (i = 0; i < ARRAY_SIZE(mad_audio_mux_text); i++)
+ if (!strncmp(kcontrol->id.name, mad_audio_mux_text[i],
+ strlen(mad_audio_mux_text[i])))
+ break;
+
+ if (i-- == ARRAY_SIZE(mad_audio_mux_text)) {
+ WARN(1, "Invalid id name %s\n", kcontrol->id.name);
+ return -EINVAL;
+ }
+
+ port_id = i * 2 + 1 + SLIMBUS_0_RX;
+ mad_type = afe_port_get_mad_type(port_id);
+ pr_debug("%s: port_id 0x%x, mad_type %d\n", __func__, port_id,
+ mad_type);
+ switch (mad_type) {
+ case MAD_HW_NONE:
+ ucontrol->value.integer.value[0] = MADNONE;
+ break;
+ case MAD_HW_AUDIO:
+ ucontrol->value.integer.value[0] = MADAUDIO;
+ break;
+ case MAD_HW_BEACON:
+ ucontrol->value.integer.value[0] = MADBEACON;
+ break;
+ case MAD_HW_ULTRASOUND:
+ ucontrol->value.integer.value[0] = MADULTRASOUND;
+ break;
+ default:
+ WARN(1, "Unknown\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int msm_routing_lsm_func_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int i;
+ u16 port_id;
+ enum afe_mad_type mad_type;
+
+ pr_debug("%s: enter\n", __func__);
+ for (i = 0; i < ARRAY_SIZE(mad_audio_mux_text); i++)
+ if (!strncmp(kcontrol->id.name, mad_audio_mux_text[i],
+ strlen(mad_audio_mux_text[i])))
+ break;
+
+ if (i-- == ARRAY_SIZE(mad_audio_mux_text)) {
+ WARN(1, "Invalid id name %s\n", kcontrol->id.name);
+ return -EINVAL;
+ }
+
+ port_id = i * 2 + 1 + SLIMBUS_0_RX;
+ switch (ucontrol->value.integer.value[0]) {
+ case MADNONE:
+ mad_type = MAD_HW_NONE;
+ break;
+ case MADAUDIO:
+ mad_type = MAD_HW_AUDIO;
+ break;
+ case MADBEACON:
+ mad_type = MAD_HW_BEACON;
+ break;
+ case MADULTRASOUND:
+ mad_type = MAD_HW_ULTRASOUND;
+ break;
+ default:
+ WARN(1, "Unknown\n");
+ return -EINVAL;
+ }
+
+ pr_debug("%s: port_id 0x%x, mad_type %d\n", __func__, port_id,
+ mad_type);
+ return afe_port_set_mad_type(port_id, mad_type);
+}
+
static int msm_routing_get_port_mixer(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -1734,6 +1868,33 @@
0, 1, 0, msm_routing_get_fm_pcmrx_switch_mixer,
msm_routing_put_fm_pcmrx_switch_mixer);
+static const struct soc_enum lsm_mux_enum =
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mad_audio_mux_text), mad_audio_mux_text);
+static const struct snd_kcontrol_new lsm_mux =
+ SOC_DAPM_ENUM_EXT("LSM1 MUX", lsm_mux_enum,
+ msm_routing_lsm_mux_get,
+ msm_routing_lsm_mux_put);
+
+static const char * const lsm_func_text[] = {
+ "None", "AUDIO", "BEACON", "ULTRASOUND"
+};
+static const struct soc_enum lsm_func_enum =
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(lsm_func_text), lsm_func_text);
+static const struct snd_kcontrol_new lsm_function[] = {
+ SOC_ENUM_EXT(SLIMBUS_0_TX_TEXT" "LSM_FUNCTION_TEXT, lsm_func_enum,
+ msm_routing_lsm_func_get, msm_routing_lsm_func_put),
+ SOC_ENUM_EXT(SLIMBUS_1_TX_TEXT" "LSM_FUNCTION_TEXT, lsm_func_enum,
+ msm_routing_lsm_func_get, msm_routing_lsm_func_put),
+ SOC_ENUM_EXT(SLIMBUS_2_TX_TEXT" "LSM_FUNCTION_TEXT, lsm_func_enum,
+ msm_routing_lsm_func_get, msm_routing_lsm_func_put),
+ SOC_ENUM_EXT(SLIMBUS_3_TX_TEXT" "LSM_FUNCTION_TEXT, lsm_func_enum,
+ msm_routing_lsm_func_get, msm_routing_lsm_func_put),
+ SOC_ENUM_EXT(SLIMBUS_4_TX_TEXT" "LSM_FUNCTION_TEXT, lsm_func_enum,
+ msm_routing_lsm_func_get, msm_routing_lsm_func_put),
+ SOC_ENUM_EXT(SLIMBUS_5_TX_TEXT" "LSM_FUNCTION_TEXT, lsm_func_enum,
+ msm_routing_lsm_func_get, msm_routing_lsm_func_put),
+};
+
static const struct snd_kcontrol_new int_fm_vol_mixer_controls[] = {
SOC_SINGLE_EXT_TLV("Internal FM RX Volume", SND_SOC_NOPM, 0,
INT_RX_VOL_GAIN, 0, msm_routing_get_fm_vol_mixer,
@@ -2111,6 +2272,9 @@
0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("DTMF_DL_HL", "DTMF_RX_HOSTLESS Playback",
0, 0, 0, 0),
+ /* LSM */
+ SND_SOC_DAPM_AIF_OUT("LSM_UL_HL", "Listen Audio Service Capture",
+ 0, 0, 0, 0),
/* Backend AIF */
/* Stream name equals to backend dai link stream name
*/
@@ -2156,6 +2320,7 @@
0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("SLIMBUS_4_TX", "Slimbus4 Capture",
0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SLIMBUS_5_TX", "Slimbus5 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("AUX_PCM_RX", "AUX PCM Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("AUX_PCM_TX", "AUX PCM Capture", 0, 0, 0, 0),
@@ -2180,6 +2345,10 @@
&fm_switch_mixer_controls),
SND_SOC_DAPM_SWITCH("PCM_RX_DL_HL", SND_SOC_NOPM, 0, 0,
&pcm_rx_switch_mixer_controls),
+
+ /* Mux Definitions */
+ SND_SOC_DAPM_MUX("LSM1 MUX", SND_SOC_NOPM, 0, 0, &lsm_mux),
+
/* Mixer definitions */
SND_SOC_DAPM_MIXER("PRI_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
pri_i2s_rx_mixer_controls, ARRAY_SIZE(pri_i2s_rx_mixer_controls)),
@@ -2514,6 +2683,14 @@
{"SLIM1_UL_HL", NULL, "SLIMBUS_1_TX"},
{"SLIM3_UL_HL", NULL, "SLIMBUS_3_TX"},
{"SLIM4_UL_HL", NULL, "SLIMBUS_4_TX"},
+
+ {"LSM1 MUX", "SLIMBUS_0_TX", "SLIMBUS_0_TX"},
+ {"LSM1 MUX", "SLIMBUS_1_TX", "SLIMBUS_1_TX"},
+ {"LSM1 MUX", "SLIMBUS_3_TX", "SLIMBUS_3_TX"},
+ {"LSM1 MUX", "SLIMBUS_4_TX", "SLIMBUS_4_TX"},
+ {"LSM1 MUX", "SLIMBUS_5_TX", "SLIMBUS_5_TX"},
+ {"LSM_UL_HL", NULL, "LSM1 MUX"},
+
{"INT_FM_RX", NULL, "INTFM_DL_HL"},
{"INTFM_UL_HL", NULL, "INT_FM_TX"},
{"AUX_PCM_RX", NULL, "AUXPCM_DL_HL"},
@@ -2600,6 +2777,7 @@
{"SLIMBUS_1_TX", NULL, "BE_IN" },
{"SLIMBUS_3_TX", NULL, "BE_IN" },
{"SLIMBUS_4_TX", NULL, "BE_IN" },
+ {"SLIMBUS_5_TX", NULL, "BE_IN" },
{"BE_OUT", NULL, "INT_BT_SCO_RX"},
{"INT_BT_SCO_TX", NULL, "BE_IN"},
{"BE_OUT", NULL, "INT_FM_RX"},
@@ -2821,6 +2999,9 @@
snd_soc_add_platform_controls(platform,
multi_ch_channel_map_mixer_controls,
ARRAY_SIZE(multi_ch_channel_map_mixer_controls));
+
+ snd_soc_add_platform_controls(platform, lsm_function,
+ ARRAY_SIZE(lsm_function));
return 0;
}
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
index 7ecdff3..798f676 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
@@ -51,6 +51,7 @@
#define LPASS_BE_SLIMBUS_3_TX "SLIMBUS_3_TX"
#define LPASS_BE_SLIMBUS_4_RX "SLIMBUS_4_RX"
#define LPASS_BE_SLIMBUS_4_TX "SLIMBUS_4_TX"
+#define LPASS_BE_SLIMBUS_5_TX "SLIMBUS_5_TX"
/* For multimedia front-ends, asm session is allocated dynamically.
* Hence, asm session/multimedia front-end mapping has to be maintained.
@@ -71,6 +72,7 @@
MSM_FRONTEND_DAI_VOICE_STUB,
MSM_FRONTEND_DAI_VOLTE,
MSM_FRONTEND_DAI_DTMF_RX,
+ MSM_FRONTEND_DAI_LSM1,
MSM_FRONTEND_DAI_MAX,
};
@@ -103,6 +105,7 @@
MSM_BACKEND_DAI_SLIMBUS_4_TX,
MSM_BACKEND_DAI_SLIMBUS_3_RX,
MSM_BACKEND_DAI_SLIMBUS_3_TX,
+ MSM_BACKEND_DAI_SLIMBUS_5_TX,
MSM_BACKEND_DAI_EXTPROC_RX,
MSM_BACKEND_DAI_EXTPROC_TX,
MSM_BACKEND_DAI_EXTPROC_EC_TX,
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.h
index d0b119c..a25fb2a 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, 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
@@ -11,7 +11,7 @@
*/
#ifndef _MSM_PCM_VOICE_H
#define _MSM_PCM_VOICE_H
-#include <sound/apr_audio.h>
+#include <sound/apr_audio-v2.h>
enum {
VOICE_SESSION_INDEX,
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index 5e1da59..97cd3fc 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -9,7 +9,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
-
#include <linux/slab.h>
#include <linux/debugfs.h>
#include <linux/kernel.h>
@@ -22,6 +21,7 @@
#include <sound/apr_audio-v2.h>
#include <sound/q6afe-v2.h>
#include <sound/q6audio-v2.h>
+#include "msm-pcm-routing-v2.h"
#include "audio_acdb.h"
@@ -47,6 +47,8 @@
int vi_tx_port;
};
+static atomic_t afe_ports_mad_type[SLIMBUS_PORT_LAST - SLIMBUS_0_RX];
+
static struct afe_ctl this_afe;
#define TIMEOUT_MS 1000
@@ -121,6 +123,7 @@
case AFE_SERVICE_CMD_SHARED_MEM_UNMAP_REGIONS:
case AFE_SERVICE_CMD_UNREGISTER_RT_PORT_DRIVER:
case AFE_PORTS_CMD_DTMF_CTL:
+ case AFE_SVC_CMD_SET_PARAM:
atomic_set(&this_afe.state, 0);
wake_up(&this_afe.wait[data->token]);
break;
@@ -218,6 +221,7 @@
case SLIMBUS_2_TX:
case SLIMBUS_3_TX:
case SLIMBUS_4_TX:
+ case SLIMBUS_5_TX:
case INT_FM_TX:
case VOICE_RECORD_RX:
case INT_BT_SCO_TX:
@@ -298,6 +302,37 @@
return ret;
}
+/*
+ * afe_apr_send_pkt : returns 0 on success, negative otherwise.
+ */
+static int afe_apr_send_pkt(void *data, wait_queue_head_t *wait)
+{
+ int ret;
+
+ atomic_set(&this_afe.state, 1);
+ atomic_set(&this_afe.status, 0);
+ ret = apr_send_pkt(this_afe.apr, data);
+ if (ret > 0) {
+ if (wait) {
+ ret = wait_event_timeout(*wait,
+ (atomic_read(&this_afe.state) == 0),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (ret)
+ ret = 0;
+ else
+ ret = -ETIMEDOUT;
+ } else {
+ ret = 0;
+ }
+ } else if (ret == 0) {
+ /* apr_send_pkt can return 0 when nothing is transmitted */
+ ret = -EINVAL;
+ }
+
+ pr_debug("%s: leave %d\n", __func__, ret);
+ return ret;
+}
+
static void afe_send_cal_block(int32_t path, u16 port_id)
{
int result = 0;
@@ -350,22 +385,13 @@
__func__, port_id, path,
cal_block.cal_size, cal_block.cal_paddr);
- atomic_set(&this_afe.state, 1);
- result = apr_send_pkt(this_afe.apr, (uint32_t *) &afe_cal);
- if (result < 0) {
- pr_err("%s: AFE cal for port %d failed\n",
- __func__, port_id);
- }
-
- result = wait_event_timeout(this_afe.wait[index],
- (atomic_read(&this_afe.state) == 0),
- msecs_to_jiffies(TIMEOUT_MS));
- if (!result) {
- pr_err("%s: wait_event timeout SET AFE CAL\n", __func__);
- goto done;
- }
-
- pr_debug("%s: AFE cal sent for path %d device!\n", __func__, path);
+ result = afe_apr_send_pkt(&afe_cal, &this_afe.wait[index]);
+ if (result)
+ pr_err("%s: AFE cal for port %d failed %d\n",
+ __func__, port_id, result);
+ else
+ pr_debug("%s: AFE cal sent for path %d device!\n", __func__,
+ path);
done:
return;
}
@@ -506,14 +532,319 @@
}
}
+int afe_turn_onoff_hw_mad(u16 mad_type, u16 enable)
+{
+ int ret;
+ struct afe_cmd_hw_mad_ctrl config;
+
+ pr_debug("%s: enter\n", __func__);
+ memset(&config, 0, sizeof(config));
+ config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ config.hdr.pkt_size = sizeof(config);
+ config.hdr.src_port = 0;
+ config.hdr.dest_port = 0;
+ config.hdr.token = IDX_GLOBAL_CFG;
+ config.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+ config.param.port_id = SLIMBUS_5_TX;
+ config.param.payload_size = sizeof(config) - sizeof(struct apr_hdr) -
+ sizeof(config.param);
+ config.param.payload_address_lsw = 0x00;
+ config.param.payload_address_msw = 0x00;
+ config.param.mem_map_handle = 0x00;
+ config.pdata.module_id = AFE_MODULE_HW_MAD;
+ config.pdata.param_id = AFE_PARAM_ID_HW_MAD_CTRL;
+ config.pdata.param_size = sizeof(config.payload);
+ config.payload.minor_version = 1;
+ config.payload.mad_type = mad_type;
+ config.payload.mad_enable = enable;
+
+ ret = afe_apr_send_pkt(&config, &this_afe.wait[IDX_GLOBAL_CFG]);
+ if (ret)
+ pr_err("%s: AFE_PARAM_ID_HW_MAD_CTRL failed %d\n", __func__,
+ ret);
+ return ret;
+}
+
+static int afe_send_slimbus_slave_cfg(
+ struct afe_param_cdc_slimbus_slave_cfg *sb_slave_cfg)
+{
+ int ret;
+ struct afe_svc_cmd_sb_slave_cfg config;
+
+ pr_debug("%s: enter\n", __func__);
+
+ config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ config.hdr.pkt_size = sizeof(config);
+ config.hdr.src_port = 0;
+ config.hdr.dest_port = 0;
+ config.hdr.token = IDX_GLOBAL_CFG;
+ config.hdr.opcode = AFE_SVC_CMD_SET_PARAM;
+ config.param.payload_size = sizeof(config) - sizeof(struct apr_hdr) -
+ sizeof(config.param);
+ config.param.payload_address_lsw = 0x00;
+ config.param.payload_address_msw = 0x00;
+ config.param.mem_map_handle = 0x00;
+ config.pdata.module_id = AFE_MODULE_CDC_DEV_CFG;
+ config.pdata.param_id = AFE_PARAM_ID_CDC_SLIMBUS_SLAVE_CFG;
+ config.pdata.param_size =
+ sizeof(struct afe_param_cdc_slimbus_slave_cfg);
+ config.sb_slave_cfg = *sb_slave_cfg;
+
+ ret = afe_apr_send_pkt(&config, &this_afe.wait[IDX_GLOBAL_CFG]);
+ if (ret)
+ pr_err("%s: AFE_PARAM_ID_CDC_SLIMBUS_SLAVE_CFG failed %d\n",
+ __func__, ret);
+
+ pr_debug("%s: leave %d\n", __func__, ret);
+ return ret;
+}
+
+static int afe_send_codec_reg_config(
+ struct afe_param_cdc_reg_cfg_data *cdc_reg_cfg)
+{
+ int i, ret;
+ int pkt_size, payload_size;
+ struct afe_svc_cmd_cdc_reg_cfg *config;
+ struct afe_svc_cmd_set_param *param;
+
+ pr_debug("%s: enter\n", __func__);
+ payload_size = sizeof(struct afe_param_cdc_reg_cfg_payload) *
+ cdc_reg_cfg->num_registers;
+ pkt_size = sizeof(*config) + payload_size;
+
+ pr_debug("%s: pkt_size %d, payload %d\n", __func__, pkt_size,
+ payload_size);
+ config = kzalloc(pkt_size, GFP_KERNEL);
+ if (!config) {
+ pr_warn("%s: Not enought memory, pkt_size %d\n", __func__,
+ pkt_size);
+ return -ENOMEM;
+ }
+
+ config->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ config->hdr.pkt_size = pkt_size;
+ config->hdr.src_port = 0;
+ config->hdr.dest_port = 0;
+ config->hdr.token = IDX_GLOBAL_CFG;
+ config->hdr.opcode = AFE_SVC_CMD_SET_PARAM;
+
+ param = &config->param;
+ param->payload_size = payload_size;
+ param->payload_address_lsw = 0x00;
+ param->payload_address_msw = 0x00;
+ param->mem_map_handle = 0x00;
+
+ for (i = 0; i < cdc_reg_cfg->num_registers; i++) {
+ config->reg_data[i].common.module_id = AFE_MODULE_CDC_DEV_CFG;
+ config->reg_data[i].common.param_id = AFE_PARAM_ID_CDC_REG_CFG;
+ config->reg_data[i].common.param_size =
+ sizeof(config->reg_data[i].reg_cfg);
+ config->reg_data[i].reg_cfg = cdc_reg_cfg->reg_data[i];
+ }
+
+ ret = afe_apr_send_pkt(config, &this_afe.wait[IDX_GLOBAL_CFG]);
+ if (ret)
+ pr_err("%s: AFE_PARAM_ID_CDC_REG_CFG failed %d\n", __func__,
+ ret);
+
+ kfree(config);
+ pr_debug("%s: leave ret %d\n", __func__, ret);
+ return ret;
+}
+
+static int afe_init_cdc_reg_config(void)
+{
+ int ret;
+ struct afe_svc_cmd_init_cdc_reg_cfg config;
+
+ pr_debug("%s: enter\n", __func__);
+ config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ config.hdr.pkt_size = sizeof(config);
+ config.hdr.src_port = 0;
+ config.hdr.dest_port = 0;
+ config.hdr.token = IDX_GLOBAL_CFG;
+ config.hdr.opcode = AFE_SVC_CMD_SET_PARAM;
+
+ config.param.payload_size = sizeof(struct afe_port_param_data_v2);
+ config.param.payload_address_lsw = 0x00;
+ config.param.payload_address_msw = 0x00;
+ config.param.mem_map_handle = 0x00;
+
+ config.init.module_id = AFE_MODULE_CDC_DEV_CFG;
+ config.init.param_id = AFE_PARAM_ID_CDC_REG_CFG_INIT;
+ config.init.param_size = 0;
+
+ ret = afe_apr_send_pkt(&config, &this_afe.wait[IDX_GLOBAL_CFG]);
+ if (ret) {
+ pr_err("%s: AFE_PARAM_ID_CDC_INIT_REG_CFG failed %d\n",
+ __func__, ret);
+ } else if (atomic_read(&this_afe.status) != 0) {
+ pr_err("%s: config cmd failed\n", __func__);
+ ret = -EINVAL;
+ }
+
+ pr_debug("%s: leave ret %d\n", __func__, 0);
+ return ret;
+}
+
+static int afe_send_slimbus_slave_port_cfg(
+ struct afe_param_slimbus_slave_port_cfg *port_config, u16 port_id)
+{
+ int ret, index;
+ struct afe_cmd_hw_mad_slimbus_slave_port_cfg config;
+
+ pr_debug("%s: enter, port_id %u\n", __func__, port_id);
+ index = q6audio_get_port_index(port_id);
+ if (q6audio_validate_port(port_id) < 0) {
+ pr_err("%s: port id: %#x\n", __func__, port_id);
+ return -EINVAL;
+ }
+
+ config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ config.hdr.pkt_size = sizeof(config);
+ config.hdr.src_port = 0;
+ config.hdr.dest_port = 0;
+ config.hdr.token = index;
+ config.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+ config.param.port_id = port_id;
+ config.param.payload_size = sizeof(config) - sizeof(struct apr_hdr) -
+ sizeof(config.param);
+ config.param.payload_address_lsw = 0x00;
+ config.param.payload_address_msw = 0x00;
+ config.param.mem_map_handle = 0x00;
+ config.pdata.module_id = AFE_MODULE_HW_MAD;
+ config.pdata.param_id = AFE_PARAM_ID_SLIMBUS_SLAVE_PORT_CFG;
+ config.pdata.param_size = sizeof(*port_config);
+ config.sb_port_cfg = *port_config;
+
+ ret = afe_apr_send_pkt(&config, &this_afe.wait[index]);
+ if (ret) {
+ pr_err("%s: AFE_PARAM_ID_SLIMBUS_SLAVE_PORT_CFG failed %d\n",
+ __func__, ret);
+ } else if (atomic_read(&this_afe.status) != 0) {
+ pr_err("%s: config cmd failed\n", __func__);
+ ret = -EINVAL;
+ }
+ pr_debug("%s: leave %d\n", __func__, ret);
+ return ret;
+}
+
+int afe_port_set_mad_type(u16 port_id, enum afe_mad_type mad_type)
+{
+ int i;
+
+ i = port_id - SLIMBUS_0_RX;
+ if (i < 0 || i > ARRAY_SIZE(afe_ports_mad_type)) {
+ pr_err("%s: Invalid port_id 0x%x\n", __func__, port_id);
+ return -EINVAL;
+ }
+ atomic_set(&afe_ports_mad_type[i], mad_type);
+ return 0;
+}
+
+enum afe_mad_type afe_port_get_mad_type(u16 port_id)
+{
+ int i;
+
+ i = port_id - SLIMBUS_0_RX;
+ if (i < 0 || i > ARRAY_SIZE(afe_ports_mad_type)) {
+ pr_err("%s: Invalid port_id 0x%x\n", __func__, port_id);
+ return MAD_HW_NONE;
+ }
+ return (enum afe_mad_type) atomic_read(&afe_ports_mad_type[i]);
+}
+
+int afe_set_config(enum afe_config_type config_type, void *config_data, int arg)
+{
+ int ret;
+
+ pr_debug("%s: enter config_type %d\n", __func__, config_type);
+ ret = afe_q6_interface_prepare();
+ if (ret) {
+ pr_err("%s: Q6 interface prepare failed %d\n", __func__, ret);
+ return ret;
+ }
+
+ switch (config_type) {
+ case AFE_SLIMBUS_SLAVE_CONFIG:
+ ret = afe_send_slimbus_slave_cfg(config_data);
+ if (!ret)
+ ret = afe_init_cdc_reg_config();
+ else
+ pr_err("%s: Sending slimbus slave config failed %d\n",
+ __func__, ret);
+ break;
+ case AFE_CDC_REGISTERS_CONFIG:
+ ret = afe_send_codec_reg_config(config_data);
+ break;
+ case AFE_SLIMBUS_SLAVE_PORT_CONFIG:
+ ret = afe_send_slimbus_slave_port_cfg(config_data, arg);
+ break;
+ default:
+ pr_err("%s: unknown configuration type", __func__);
+ ret = -EINVAL;
+ }
+
+ pr_debug("%s: leave ret %d\n", __func__, ret);
+ return ret;
+}
+
+static int afe_send_cmd_port_start(u16 port_id)
+{
+ struct afe_port_cmd_device_start start;
+ int ret, index;
+
+ pr_debug("%s: enter\n", __func__);
+ index = q6audio_get_port_index(port_id);
+ if (q6audio_validate_port(port_id) < 0) {
+ pr_err("%s: port id: %#x\n", __func__, port_id);
+ return -EINVAL;
+ }
+
+ start.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ start.hdr.pkt_size = sizeof(start);
+ start.hdr.src_port = 0;
+ start.hdr.dest_port = 0;
+ start.hdr.token = index;
+ start.hdr.opcode = AFE_PORT_CMD_DEVICE_START;
+ start.port_id = q6audio_get_port_id(port_id);
+ pr_debug("%s: cmd device start opcode[0x%x] port id[0x%x]\n",
+ __func__, start.hdr.opcode, start.port_id);
+
+ ret = afe_apr_send_pkt(&start, &this_afe.wait[index]);
+ if (ret) {
+ pr_err("%s: AFE enable for port %#x failed %d\n", __func__,
+ port_id, ret);
+ } else if (this_afe.task != current) {
+ this_afe.task = current;
+ pr_debug("task_name = %s pid = %d\n",
+ this_afe.task->comm, this_afe.task->pid);
+ }
+
+ pr_debug("%s: leave %d\n", __func__, ret);
+ return ret;
+}
+
int afe_port_start(u16 port_id, union afe_port_config *afe_config,
u32 rate) /* This function is no blocking */
{
- struct afe_port_cmd_device_start start;
struct afe_audioif_config_command config;
- int ret;
+ int ret = 0;
int cfg_type;
int index = 0;
+ enum afe_mad_type mad_type;
if (!afe_config) {
pr_err("%s: Error, no configuration data\n", __func__);
@@ -529,6 +860,7 @@
port_id = VIRTUAL_ID_TO_PORTID(port_id);
pr_debug("%s: port id: %#x\n", __func__, port_id);
+
index = q6audio_get_port_index(port_id);
if (q6audio_validate_port(port_id) < 0) {
pr_err("%s: port id: %#x\n", __func__, port_id);
@@ -539,11 +871,19 @@
if (IS_ERR_VALUE(ret))
return ret;
- if (q6audio_validate_port(port_id) < 0) {
- pr_err("%s: Failed : Invalid Port id = %#x\n", __func__,
- port_id);
- ret = -EINVAL;
- goto fail_cmd;
+ afe_send_cal(port_id);
+
+ /* Start SW MAD module */
+ mad_type = afe_port_get_mad_type(port_id);
+ pr_debug("%s: port_id 0x%x, mad_type %d\n", __func__, port_id,
+ mad_type);
+ if (mad_type != MAD_HW_NONE) {
+ ret = afe_turn_onoff_hw_mad(mad_type, true);
+ if (ret) {
+ pr_err("%s: afe_turn_onoff_hw_mad failed %d\n",
+ __func__, ret);
+ return ret;
+ }
}
config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
@@ -593,6 +933,7 @@
case SLIMBUS_3_TX:
case SLIMBUS_4_RX:
case SLIMBUS_4_TX:
+ case SLIMBUS_5_TX:
cfg_type = AFE_PARAM_ID_SLIMBUS_CONFIG;
break;
case RT_PROXY_PORT_001_RX:
@@ -623,69 +964,17 @@
config.port = *afe_config;
- atomic_set(&this_afe.state, 1);
- atomic_set(&this_afe.status, 0);
- ret = apr_send_pkt(this_afe.apr, (uint32_t *) &config);
- if (ret < 0) {
+ ret = afe_apr_send_pkt(&config, &this_afe.wait[index]);
+ if (ret) {
pr_err("%s: AFE enable for port %#x failed\n", __func__,
port_id);
- ret = -EINVAL;
goto fail_cmd;
- }
- ret = wait_event_timeout(this_afe.wait[index],
- (atomic_read(&this_afe.state) == 0),
- msecs_to_jiffies(TIMEOUT_MS));
-
- if (!ret) {
- pr_err("%s: wait_event timeout IF CONFIG\n", __func__);
- ret = -EINVAL;
- goto fail_cmd;
- }
- if (atomic_read(&this_afe.status) != 0) {
+ } else if (atomic_read(&this_afe.status) != 0) {
pr_err("%s: config cmd failed\n", __func__);
ret = -EINVAL;
goto fail_cmd;
}
- /* send AFE cal */
- afe_send_cal(port_id);
-
- start.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
- APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
- start.hdr.pkt_size = sizeof(start);
- start.hdr.src_port = 0;
- start.hdr.dest_port = 0;
- start.hdr.token = index;
- start.hdr.opcode = AFE_PORT_CMD_DEVICE_START;
- start.port_id = q6audio_get_port_id(port_id);
- pr_debug("%s: cmd device start opcode[0x%x] port id[0x%x]\n",
- __func__, start.hdr.opcode, start.port_id);
-
- atomic_set(&this_afe.state, 1);
- ret = apr_send_pkt(this_afe.apr, (uint32_t *) &start);
-
- if (IS_ERR_VALUE(ret)) {
- pr_err("%s: AFE enable for port %#x failed\n", __func__,
- port_id);
- ret = -EINVAL;
- goto fail_cmd;
- }
-
- ret = wait_event_timeout(this_afe.wait[index],
- (atomic_read(&this_afe.state) == 0),
- msecs_to_jiffies(TIMEOUT_MS));
-
- if (!ret) {
- pr_err("%s: wait_event timeout PORT START\n", __func__);
- ret = -EINVAL;
- goto fail_cmd;
- }
- if (this_afe.task != current)
- this_afe.task = current;
-
- pr_debug("task_name = %s pid = %d\n",
- this_afe.task->comm, this_afe.task->pid);
-
- return 0;
+ return afe_send_cmd_port_start(port_id);
fail_cmd:
return ret;
@@ -725,6 +1014,7 @@
case RT_PROXY_PORT_001_TX: return IDX_RT_PROXY_PORT_001_TX;
case SLIMBUS_4_RX: return IDX_SLIMBUS_4_RX;
case SLIMBUS_4_TX: return IDX_SLIMBUS_4_TX;
+ case SLIMBUS_5_TX: return IDX_SLIMBUS_5_TX;
case AFE_PORT_ID_PRIMARY_MI2S_RX:
return IDX_AFE_PORT_ID_PRIMARY_MI2S_RX;
case AFE_PORT_ID_QUATERNARY_MI2S_RX:
@@ -837,25 +1127,13 @@
__func__, config.param.payload_size, config.pdata.param_size,
sizeof(config), sizeof(config.param), sizeof(config.port),
sizeof(struct apr_hdr), config.pdata.param_id);
- atomic_set(&this_afe.state, 1);
- atomic_set(&this_afe.status, 0);
- ret = apr_send_pkt(this_afe.apr, (uint32_t *) &config);
- if (ret < 0) {
+
+ ret = afe_apr_send_pkt(&config, &this_afe.wait[index]);
+ if (ret) {
pr_err("%s: AFE enable for port %d opcode[0x%x]failed\n",
__func__, port_id, cfg_type);
- ret = -EINVAL;
goto fail_cmd;
- }
-
- ret = wait_event_timeout(this_afe.wait[index],
- (atomic_read(&this_afe.state) == 0),
- msecs_to_jiffies(TIMEOUT_MS));
- if (!ret) {
- pr_err("%s: wait_event timeout\n", __func__);
- ret = -EINVAL;
- goto fail_cmd;
- }
- if (atomic_read(&this_afe.status) != 0) {
+ } else if (atomic_read(&this_afe.status) != 0) {
pr_err("%s: config cmd failed\n", __func__);
ret = -EINVAL;
goto fail_cmd;
@@ -870,24 +1148,14 @@
start.port_id = q6audio_get_port_id(port_id);
pr_debug("%s: cmd device start opcode[0x%x] port id[0x%x]\n",
__func__, start.hdr.opcode, start.port_id);
- atomic_set(&this_afe.state, 1);
- ret = apr_send_pkt(this_afe.apr, (uint32_t *) &start);
- if (ret < 0) {
+
+ ret = afe_apr_send_pkt(&start, &this_afe.wait[index]);
+ if (ret) {
pr_err("%s: AFE enable for port %d failed\n", __func__,
port_id);
- ret = -EINVAL;
- goto fail_cmd;
- }
- ret = wait_event_timeout(this_afe.wait[index],
- (atomic_read(&this_afe.state) == 0),
- msecs_to_jiffies(TIMEOUT_MS));
- if (!ret) {
- pr_err("%s: wait_event timeout\n", __func__);
- ret = -EINVAL;
goto fail_cmd;
}
- return 0;
fail_cmd:
return ret;
}
@@ -934,23 +1202,10 @@
lb_cmd.routing_mode = LB_MODE_DEFAULT;
lb_cmd.enable = (enable ? 1 : 0);
lb_cmd.loopback_cfg_minor_version = AFE_API_VERSION_LOOPBACK_CONFIG;
- atomic_set(&this_afe.state, 1);
- ret = apr_send_pkt(this_afe.apr, (uint32_t *) &lb_cmd);
- if (ret < 0) {
- pr_err("%s: AFE loopback failed\n", __func__);
- ret = -EINVAL;
- goto done;
- }
- pr_debug("%s: waiting for this_afe.wait[%d]\n", __func__, index);
- ret = wait_event_timeout(this_afe.wait[index],
- (atomic_read(&this_afe.state) == 0),
- msecs_to_jiffies(TIMEOUT_MS));
- if (!ret) {
- pr_err("%s: wait_event timeout\n", __func__);
- ret = -EINVAL;
- }
-done:
+ ret = afe_apr_send_pkt(&lb_cmd, &this_afe.wait[index]);
+ if (ret)
+ pr_err("%s: AFE loopback failed %d\n", __func__, ret);
return ret;
}
@@ -1016,24 +1271,13 @@
set_param.rx_port_id = port_id;
set_param.gain = volume;
- atomic_set(&this_afe.state, 1);
- ret = apr_send_pkt(this_afe.apr, (uint32_t *) &set_param);
- if (ret < 0) {
+ ret = afe_apr_send_pkt(&set_param, &this_afe.wait[index]);
+ if (ret) {
pr_err("%s: AFE param set failed for port %d\n",
__func__, port_id);
- ret = -EINVAL;
goto fail_cmd;
}
- ret = wait_event_timeout(this_afe.wait[index],
- (atomic_read(&this_afe.state) == 0),
- msecs_to_jiffies(TIMEOUT_MS));
- if (ret < 0) {
- pr_err("%s: wait_event timeout\n", __func__);
- ret = -EINVAL;
- goto fail_cmd;
- }
- return 0;
fail_cmd:
return ret;
}
@@ -1060,9 +1304,8 @@
start.port_id = port_id;
start.timing = 1;
- atomic_set(&this_afe.state, 1);
- ret = apr_send_pkt(this_afe.apr, (uint32_t *) &start);
- if (ret < 0) {
+ ret = afe_apr_send_pkt(&start, NULL);
+ if (ret) {
pr_err("%s: AFE enable for port %d failed %d\n",
__func__, port_id, ret);
return -EINVAL;
@@ -1095,25 +1338,13 @@
start.hdr.opcode = AFE_PSEUDOPORT_CMD_START;
start.port_id = port_id;
start.timing = 1;
-
start.hdr.token = index;
- atomic_set(&this_afe.state, 1);
- ret = apr_send_pkt(this_afe.apr, (uint32_t *) &start);
- if (ret < 0) {
+
+ ret = afe_apr_send_pkt(&start, &this_afe.wait[index]);
+ if (ret)
pr_err("%s: AFE enable for port %d failed %d\n",
__func__, port_id, ret);
- return -EINVAL;
- }
-
- ret = wait_event_timeout(this_afe.wait[index],
- (atomic_read(&this_afe.state) == 0),
- msecs_to_jiffies(TIMEOUT_MS));
- if (!ret) {
- pr_err("%s: wait_event timeout\n", __func__);
- return -EINVAL;
- }
-
- return 0;
+ return ret;
}
int afe_pseudo_port_stop_nowait(u16 port_id)
@@ -1141,17 +1372,13 @@
stop.hdr.opcode = AFE_PSEUDOPORT_CMD_STOP;
stop.port_id = port_id;
stop.reserved = 0;
-
stop.hdr.token = index;
- atomic_set(&this_afe.state, 1);
- ret = apr_send_pkt(this_afe.apr, (uint32_t *) &stop);
- if (ret < 0) {
+
+ ret = afe_apr_send_pkt(&stop, NULL);
+ if (ret)
pr_err("%s: AFE close failed %d\n", __func__, ret);
- return -EINVAL;
- }
- return 0;
-
+ return ret;
}
int afe_stop_pseudo_port(u16 port_id)
@@ -1180,24 +1407,13 @@
stop.hdr.opcode = AFE_PSEUDOPORT_CMD_STOP;
stop.port_id = port_id;
stop.reserved = 0;
-
stop.hdr.token = index;
- atomic_set(&this_afe.state, 1);
- ret = apr_send_pkt(this_afe.apr, (uint32_t *) &stop);
- if (ret < 0) {
+
+ ret = afe_apr_send_pkt(&stop, &this_afe.wait[index]);
+ if (ret)
pr_err("%s: AFE close failed %d\n", __func__, ret);
- return -EINVAL;
- }
- ret = wait_event_timeout(this_afe.wait[index],
- (atomic_read(&this_afe.state) == 0),
- msecs_to_jiffies(TIMEOUT_MS));
- if (!ret) {
- pr_err("%s: wait_event timeout\n", __func__);
- return -EINVAL;
- }
-
- return 0;
+ return ret;
}
uint32_t afe_req_mmap_handle(struct afe_audio_client *ac)
@@ -1480,15 +1696,11 @@
mregion_pl->shm_addr_msw = 0x00;
mregion_pl->mem_size_bytes = dma_buf_sz;
- atomic_set(&this_afe.state, 1);
- ret = apr_send_pkt(this_afe.apr, (uint32_t *) mmap_region_cmd);
- if (ret < 0) {
+ ret = afe_apr_send_pkt(mmap_region_cmd, NULL);
+ if (ret)
pr_err("%s: AFE memory map cmd failed %d\n",
__func__, ret);
- ret = -EINVAL;
- return ret;
- }
- return 0;
+ return ret;
}
int q6afe_audio_client_buf_free_contiguous(unsigned int dir,
struct afe_audio_client *ac)
@@ -1576,24 +1788,11 @@
/* Todo */
index = mregion.hdr.token = IDX_RSVD_2;
- atomic_set(&this_afe.state, 1);
- ret = apr_send_pkt(this_afe.apr, (uint32_t *) &mregion);
- if (ret < 0) {
+ ret = afe_apr_send_pkt(&mregion, &this_afe.wait[index]);
+ if (ret)
pr_err("%s: AFE memory unmap cmd failed %d\n",
__func__, ret);
- ret = -EINVAL;
- return ret;
- }
-
- ret = wait_event_timeout(this_afe.wait[index],
- (atomic_read(&this_afe.state) == 0),
- msecs_to_jiffies(TIMEOUT_MS));
- if (!ret) {
- pr_err("%s: wait_event timeout\n", __func__);
- ret = -EINVAL;
- return ret;
- }
- return 0;
+ return ret;
}
int afe_cmd_memory_unmap_nowait(u32 mem_map_handle)
@@ -1623,13 +1822,11 @@
mregion.hdr.opcode = AFE_SERVICE_CMD_SHARED_MEM_UNMAP_REGIONS;
mregion.mem_map_handle = mem_map_handle;
- ret = apr_send_pkt(this_afe.apr, (uint32_t *) &mregion);
- if (ret < 0) {
+ ret = afe_apr_send_pkt(&mregion, NULL);
+ if (ret)
pr_err("%s: AFE memory unmap cmd failed %d\n",
__func__, ret);
- ret = -EINVAL;
- }
- return 0;
+ return ret;
}
int afe_register_get_events(u16 port_id,
@@ -1675,14 +1872,11 @@
rtproxy.port_id = port_id;
rtproxy.reserved = 0;
- ret = apr_send_pkt(this_afe.apr, (uint32_t *) &rtproxy);
- if (ret < 0) {
+ ret = afe_apr_send_pkt(&rtproxy, NULL);
+ if (ret)
pr_err("%s: AFE reg. rtproxy_event failed %d\n",
__func__, ret);
- ret = -EINVAL;
- return ret;
- }
- return 0;
+ return ret;
}
int afe_unregister_get_events(u16 port_id)
@@ -1734,24 +1928,11 @@
this_afe.rx_private_data = NULL;
}
- atomic_set(&this_afe.state, 1);
- ret = apr_send_pkt(this_afe.apr, (uint32_t *) &rtproxy);
- if (ret < 0) {
+ ret = afe_apr_send_pkt(&rtproxy, &this_afe.wait[index]);
+ if (ret)
pr_err("%s: AFE enable Unreg. rtproxy_event failed %d\n",
__func__, ret);
- ret = -EINVAL;
- return ret;
- }
-
- ret = wait_event_timeout(this_afe.wait[index],
- (atomic_read(&this_afe.state) == 0),
- msecs_to_jiffies(TIMEOUT_MS));
- if (!ret) {
- pr_err("%s: wait_event timeout\n", __func__);
- ret = -EINVAL;
- return ret;
- }
- return 0;
+ return ret;
}
int afe_rt_proxy_port_write(u32 buf_addr_p, u32 mem_map_handle, int bytes)
@@ -1781,14 +1962,11 @@
afecmd_wr.available_bytes = bytes;
afecmd_wr.reserved = 0;
- ret = apr_send_pkt(this_afe.apr, (uint32_t *) &afecmd_wr);
- if (ret < 0) {
+ ret = afe_apr_send_pkt(&afecmd_wr, NULL);
+ if (ret)
pr_err("%s: AFE rtproxy write to port 0x%x failed %d\n",
__func__, afecmd_wr.port_id, ret);
- ret = -EINVAL;
- return ret;
- }
- return 0;
+ return ret;
}
@@ -1818,14 +1996,11 @@
afecmd_rd.available_bytes = bytes;
afecmd_rd.mem_map_handle = mem_map_handle;
- ret = apr_send_pkt(this_afe.apr, (uint32_t *) &afecmd_rd);
- if (ret < 0) {
+ ret = afe_apr_send_pkt(&afecmd_rd, NULL);
+ if (ret)
pr_err("%s: AFE rtproxy read cmd to port 0x%x failed %d\n",
__func__, afecmd_rd.port_id, ret);
- ret = -EINVAL;
- return ret;
- }
- return 0;
+ return ret;
}
#ifdef CONFIG_DEBUG_FS
@@ -2102,25 +2277,10 @@
cmd_sidetone.routing_mode = LB_MODE_SIDETONE;
cmd_sidetone.enable = enable;
- atomic_set(&this_afe.state, 1);
- ret = apr_send_pkt(this_afe.apr, (uint32_t *) &cmd_sidetone);
- if (ret < 0) {
+ ret = afe_apr_send_pkt(&cmd_sidetone, &this_afe.wait[index]);
+ if (ret)
pr_err("%s: AFE sidetone failed for tx_port:%d rx_port:%d\n",
__func__, tx_port_id, rx_port_id);
- ret = -EINVAL;
- goto fail_cmd;
- }
-
- ret = wait_event_timeout(this_afe.wait[index],
- (atomic_read(&this_afe.state) == 0),
- msecs_to_jiffies(TIMEOUT_MS));
- if (ret < 0) {
- pr_err("%s: wait_event timeout\n", __func__);
- ret = -EINVAL;
- goto fail_cmd;
- }
- return 0;
-fail_cmd:
return ret;
}
@@ -2217,12 +2377,9 @@
stop.port_id = port_id;
stop.reserved = 0;
- ret = apr_send_pkt(this_afe.apr, (uint32_t *) &stop);
-
- if (IS_ERR_VALUE(ret)) {
+ ret = afe_apr_send_pkt(&stop, NULL);
+ if (ret)
pr_err("%s: AFE close failed\n", __func__);
- ret = -EINVAL;
- }
fail_cmd:
return ret;
@@ -2232,10 +2389,10 @@
int afe_close(int port_id)
{
struct afe_port_cmd_device_stop stop;
+ enum afe_mad_type mad_type;
int ret = 0;
int index = 0;
-
if (this_afe.apr == NULL) {
pr_err("AFE is already closed\n");
ret = -EINVAL;
@@ -2245,9 +2402,25 @@
port_id = q6audio_convert_virtual_to_portid(port_id);
index = q6audio_get_port_index(port_id);
- if (q6audio_validate_port(port_id) < 0)
+ if (q6audio_validate_port(port_id) < 0) {
+ pr_warn("%s: Not a valid port id 0x0%x\n", __func__, port_id);
return -EINVAL;
+ }
+ mad_type = afe_port_get_mad_type(port_id);
+ pr_debug("%s: port_id 0x%x, mad_type %d\n", __func__, port_id,
+ mad_type);
+ if (mad_type != MAD_HW_NONE) {
+ pr_debug("%s: Turn off MAD\n", __func__);
+ ret = afe_turn_onoff_hw_mad(mad_type, false);
+ if (ret) {
+ pr_err("%s: afe_turn_onoff_hw_mad failed %d\n",
+ __func__, ret);
+ return ret;
+ }
+ } else {
+ pr_debug("%s: Not a MAD port\n", __func__);
+ }
stop.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
@@ -2259,23 +2432,10 @@
stop.port_id = q6audio_get_port_id(port_id);
stop.reserved = 0;
- atomic_set(&this_afe.state, 1);
- ret = apr_send_pkt(this_afe.apr, (uint32_t *) &stop);
+ ret = afe_apr_send_pkt(&stop, &this_afe.wait[index]);
+ if (ret)
+ pr_err("%s: AFE close failed %d\n", __func__, ret);
- if (ret < 0) {
- pr_err("%s: AFE close failed\n", __func__);
- ret = -EINVAL;
- goto fail_cmd;
- }
-
- ret = wait_event_timeout(this_afe.wait[index],
- (atomic_read(&this_afe.state) == 0),
- msecs_to_jiffies(TIMEOUT_MS));
- if (!ret) {
- pr_err("%s: wait_event timeout\n", __func__);
- ret = -EINVAL;
- goto fail_cmd;
- }
fail_cmd:
return ret;
}
diff --git a/sound/soc/msm/qdsp6v2/q6audio-v2.c b/sound/soc/msm/qdsp6v2/q6audio-v2.c
index 4ed0fb7..d3d335d 100644
--- a/sound/soc/msm/qdsp6v2/q6audio-v2.c
+++ b/sound/soc/msm/qdsp6v2/q6audio-v2.c
@@ -44,6 +44,7 @@
case SLIMBUS_2_RX: return IDX_SLIMBUS_2_RX;
case SLIMBUS_2_TX: return IDX_SLIMBUS_2_TX;
case SLIMBUS_4_TX: return IDX_SLIMBUS_4_TX;
+ case SLIMBUS_5_TX: return IDX_SLIMBUS_5_TX;
case INT_BT_SCO_RX: return IDX_INT_BT_SCO_RX;
case INT_BT_SCO_TX: return IDX_INT_BT_SCO_TX;
case INT_BT_A2DP_RX: return IDX_INT_BT_A2DP_RX;
@@ -91,6 +92,7 @@
case SLIMBUS_2_RX: return AFE_PORT_ID_SLIMBUS_MULTI_CHAN_2_RX;
case SLIMBUS_2_TX: return AFE_PORT_ID_SLIMBUS_MULTI_CHAN_2_TX;
case SLIMBUS_4_TX: return AFE_PORT_ID_SLIMBUS_MULTI_CHAN_4_TX;
+ case SLIMBUS_5_TX: return AFE_PORT_ID_SLIMBUS_MULTI_CHAN_5_TX;
case INT_BT_SCO_RX: return AFE_PORT_ID_INTERNAL_BT_SCO_RX;
case INT_BT_SCO_TX: return AFE_PORT_ID_INTERNAL_BT_SCO_TX;
case INT_BT_A2DP_RX: return AFE_PORT_ID_INTERNAL_BT_A2DP_RX;
@@ -109,7 +111,9 @@
case AFE_PORT_ID_SECONDARY_MI2S_TX:
return AFE_PORT_ID_SECONDARY_MI2S_TX;
- default: return -EINVAL;
+ default:
+ pr_warn("%s: Invalid port_id %d\n", __func__, port_id);
+ return -EINVAL;
}
}
int q6audio_convert_virtual_to_portid(u16 port_id)
@@ -185,6 +189,7 @@
case SLIMBUS_2_RX:
case SLIMBUS_2_TX:
case SLIMBUS_4_TX:
+ case SLIMBUS_5_TX:
case INT_BT_SCO_RX:
case INT_BT_SCO_TX:
case INT_BT_A2DP_RX:
diff --git a/sound/soc/msm/qdsp6v2/q6lsm.c b/sound/soc/msm/qdsp6v2/q6lsm.c
new file mode 100644
index 0000000..f2b531a
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/q6lsm.c
@@ -0,0 +1,813 @@
+/*
+ * Copyright (c) 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/fs.h>
+#include <linux/mutex.h>
+#include <linux/wait.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/miscdevice.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/memory_alloc.h>
+#include <linux/debugfs.h>
+#include <linux/time.h>
+#include <linux/atomic.h>
+#include <sound/apr_audio-v2.h>
+#include <sound/lsm_params.h>
+#include <sound/q6lsm.h>
+#include <asm/ioctls.h>
+#include <mach/memory.h>
+#include <mach/debug_mm.h>
+#include <mach/msm_subsystem_map.h>
+#include "audio_acdb.h"
+
+#define APR_TIMEOUT (5 * HZ)
+#define LSM_CAL_SIZE 4096
+
+enum {
+ CMD_STATE_CLEARED = 0,
+ CMD_STATE_WAIT_RESP = 1,
+};
+
+enum {
+ LSM_INVALID_SESSION_ID = 0,
+ LSM_MIN_SESSION_ID = 1,
+ LSM_MAX_SESSION_ID = 8,
+};
+
+struct lsm_common {
+ void *apr;
+ atomic_t apr_users;
+ uint32_t lsm_cal_addr;
+ uint32_t lsm_cal_size;
+ uint32_t mmap_handle_for_cal;
+ struct mutex apr_lock;
+};
+
+static struct lsm_common lsm_common;
+
+/*
+ * mmap_handle_p can point either client->sound_model.mem_map_handle or
+ * lsm_common.mmap_handle_for_cal.
+ * mmap_lock must be held while accessing this.
+ */
+static spinlock_t mmap_lock;
+static uint32_t *mmap_handle_p;
+
+static spinlock_t lsm_session_lock;
+static struct lsm_client *lsm_session[LSM_MAX_SESSION_ID + 1];
+
+static int q6lsm_mmapcallback(struct apr_client_data *data, void *priv);
+static int q6lsm_send_cal(struct lsm_client *client);
+static int q6lsm_snd_model_buf_free(struct lsm_client *client);
+
+static int q6lsm_callback(struct apr_client_data *data, void *priv)
+{
+ struct lsm_client *client = (struct lsm_client *)priv;
+ uint32_t token;
+ uint32_t *payload;
+
+ if (!client || !data) {
+ WARN_ON(1);
+ return -EINVAL;
+ }
+
+ payload = data->payload;
+ pr_debug("%s: Session %d opcode 0x%x token 0x%x payload size %d\n",
+ __func__, client->session,
+ data->opcode, data->token, data->payload_size);
+
+ if (data->opcode == APR_BASIC_RSP_RESULT) {
+ token = data->token;
+ switch (payload[0]) {
+ case LSM_SESSION_CMD_START:
+ case LSM_SESSION_CMD_STOP:
+ case LSM_SESSION_CMD_SET_PARAMS:
+ case LSM_SESSION_CMD_OPEN_TX:
+ case LSM_SESSION_CMD_CLOSE_TX:
+ case LSM_SESSION_CMD_REGISTER_SOUND_MODEL:
+ case LSM_SESSION_CMD_DEREGISTER_SOUND_MODEL:
+ case LSM_SESSION_CMD_SHARED_MEM_UNMAP_REGIONS:
+ if (token != client->session &&
+ payload[0] !=
+ LSM_SESSION_CMD_DEREGISTER_SOUND_MODEL) {
+ pr_err("%s: Invalid session %d receivced expected %d\n",
+ __func__, token, client->session);
+ return -EINVAL;
+ }
+ if (atomic_cmpxchg(&client->cmd_state,
+ CMD_STATE_WAIT_RESP,
+ CMD_STATE_CLEARED) ==
+ CMD_STATE_WAIT_RESP)
+ wake_up(&client->cmd_wait);
+ break;
+ default:
+ pr_debug("%s: Unknown command 0x%x\n",
+ __func__, payload[0]);
+ break;
+ }
+ return 0;
+ }
+
+ if (client->cb)
+ client->cb(data->opcode, data->token, data->payload,
+ client->priv);
+
+ return 0;
+}
+
+static int q6lsm_session_alloc(struct lsm_client *client)
+{
+ unsigned long flags;
+ int n, ret = -ENOMEM;
+
+ spin_lock_irqsave(&lsm_session_lock, flags);
+ for (n = LSM_MIN_SESSION_ID; n <= LSM_MAX_SESSION_ID; n++) {
+ if (!lsm_session[n]) {
+ lsm_session[n] = client;
+ ret = n;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&lsm_session_lock, flags);
+ return ret;
+}
+
+static void q6lsm_session_free(struct lsm_client *client)
+{
+ unsigned long flags;
+
+ pr_debug("%s: Freeing session ID %d\n", __func__, client->session);
+ spin_lock_irqsave(&lsm_session_lock, flags);
+ lsm_session[client->session] = LSM_INVALID_SESSION_ID;
+ spin_unlock_irqrestore(&lsm_session_lock, flags);
+ client->session = LSM_INVALID_SESSION_ID;
+}
+
+static void *q6lsm_mmap_apr_reg(void)
+{
+ if (atomic_inc_return(&lsm_common.apr_users) == 1) {
+ lsm_common.apr =
+ apr_register("ADSP", "LSM", q6lsm_mmapcallback,
+ 0x0FFFFFFFF, &lsm_common);
+ if (!lsm_common.apr) {
+ pr_debug("%s Unable to register APR LSM common port\n",
+ __func__);
+ atomic_dec(&lsm_common.apr_users);
+ }
+ }
+
+ return lsm_common.apr;
+}
+
+static int q6lsm_mmap_apr_dereg(void)
+{
+ if (atomic_read(&lsm_common.apr_users) <= 0) {
+ WARN("%s: APR common port already closed\n", __func__);
+ } else {
+ if (atomic_dec_return(&lsm_common.apr_users) == 0) {
+ apr_deregister(lsm_common.apr);
+ pr_debug("%s:APR De-Register common port\n", __func__);
+ }
+ }
+ return 0;
+}
+
+struct lsm_client *q6lsm_client_alloc(app_cb cb, void *priv)
+{
+ struct lsm_client *client;
+ int n;
+
+ pr_debug("%s: enter\n", __func__);
+ client = kzalloc(sizeof(struct lsm_client), GFP_KERNEL);
+ if (!client)
+ return NULL;
+ n = q6lsm_session_alloc(client);
+ if (n <= 0) {
+ kfree(client);
+ return NULL;
+ }
+
+ pr_debug("%s: New client session %d\n", __func__, client->session);
+ client->session = n;
+ client->cb = cb;
+ client->priv = priv;
+ client->apr = apr_register("ADSP", "LSM", q6lsm_callback,
+ ((client->session) << 8 | 0x0001), client);
+
+ if (client->apr == NULL) {
+ pr_err("%s: Registration with APR failed\n", __func__);
+ goto fail;
+ }
+
+ pr_debug("%s Registering the common port with APR\n", __func__);
+ client->mmap_apr = q6lsm_mmap_apr_reg();
+ if (!client->mmap_apr) {
+ pr_err("%s: APR registration failed\n", __func__);
+ goto fail;
+ }
+
+ init_waitqueue_head(&client->cmd_wait);
+ mutex_init(&client->cmd_lock);
+ atomic_set(&client->cmd_state, CMD_STATE_CLEARED);
+ pr_debug("%s: New client allocated\n", __func__);
+ return client;
+fail:
+ q6lsm_client_free(client);
+ return NULL;
+}
+
+void q6lsm_client_free(struct lsm_client *client)
+{
+ if (!client || !client->session)
+ return;
+
+ apr_deregister(client->apr);
+ client->mmap_apr = NULL;
+ q6lsm_session_free(client);
+ q6lsm_mmap_apr_dereg();
+ mutex_destroy(&client->cmd_lock);
+ kfree(client);
+}
+
+/*
+ * q6lsm_apr_send_pkt : If wait == true, hold mutex to prevent from preempting
+ * other thread's wait.
+ * If mmap_handle_p != NULL, disable irq and spin lock to
+ * protect mmap_handle_p
+ */
+static int q6lsm_apr_send_pkt(struct lsm_client *client, void *handle,
+ void *data, bool wait, uint32_t *mmap_p)
+{
+ int ret;
+ unsigned long flags = 0;
+
+ pr_debug("%s: enter wait %d\n", __func__, wait);
+ if (wait)
+ mutex_lock(&lsm_common.apr_lock);
+ if (mmap_p) {
+ WARN_ON(!wait);
+ spin_lock_irqsave(&mmap_lock, flags);
+ mmap_handle_p = mmap_p;
+ }
+ atomic_set(&client->cmd_state, CMD_STATE_WAIT_RESP);
+ ret = apr_send_pkt(client->apr, data);
+ if (mmap_p)
+ spin_unlock_irqrestore(&mmap_lock, flags);
+
+ if (ret < 0) {
+ pr_err("%s: apr_send_pkt failed %d\n", __func__, ret);
+ } else if (wait) {
+ ret = wait_event_timeout(client->cmd_wait,
+ (atomic_read(&client->cmd_state) ==
+ CMD_STATE_CLEARED),
+ APR_TIMEOUT);
+ if (likely(ret))
+ ret = 0;
+ else
+ pr_err("%s: wait timedout\n", __func__);
+ } else {
+ ret = 0;
+ }
+ if (wait)
+ mutex_unlock(&lsm_common.apr_lock);
+
+ pr_debug("%s: leave ret %d\n", __func__, ret);
+ return ret;
+}
+
+static void q6lsm_add_hdr(struct lsm_client *client, struct apr_hdr *hdr,
+ uint32_t pkt_size, bool cmd_flg)
+{
+ pr_debug("%s: pkt_size %d cmd_flg %d session %d\n", __func__,
+ pkt_size, cmd_flg, client->session);
+ hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(sizeof(struct apr_hdr)),
+ APR_PKT_VER);
+ hdr->src_svc = APR_SVC_LSM;
+ hdr->src_domain = APR_DOMAIN_APPS;
+ hdr->dest_svc = APR_SVC_LSM;
+ hdr->dest_domain = APR_DOMAIN_ADSP;
+ hdr->src_port = ((client->session << 8) & 0xFF00) | 0x01;
+ hdr->dest_port = ((client->session << 8) & 0xFF00) | 0x01;
+ hdr->pkt_size = pkt_size;
+ if (cmd_flg)
+ hdr->token = client->session;
+}
+
+int q6lsm_open(struct lsm_client *client)
+{
+ int rc;
+ struct lsm_stream_cmd_open_tx open;
+
+ memset(&open, 0, sizeof(open));
+ q6lsm_add_hdr(client, &open.hdr, sizeof(open), true);
+
+ open.hdr.opcode = LSM_SESSION_CMD_OPEN_TX;
+ open.app_id = 1;
+ open.sampling_rate = 16000;
+
+ rc = q6lsm_apr_send_pkt(client, client->apr, &open, true, NULL);
+ if (rc)
+ pr_err("%s: Open failed opcode 0x%x, rc %d\n",
+ __func__, open.hdr.opcode, rc);
+
+ pr_debug("%s: leave %d\n", __func__, rc);
+ return rc;
+}
+
+static int q6lsm_set_params(struct lsm_client *client)
+{
+ int rc;
+ struct lsm_cmd_set_params params;
+ struct lsm_params_payload *payload = ¶ms.payload;
+
+ pr_debug("%s: enter\n", __func__);
+ q6lsm_add_hdr(client, ¶ms.hdr, sizeof(params), true);
+
+ params.hdr.opcode = LSM_SESSION_CMD_SET_PARAMS;
+ params.data_payload_addr_lsw = 0;
+ params.data_payload_addr_msw = 0;
+ params.mem_map_handle = 0;
+ params.data_payload_size = sizeof(struct lsm_params_payload);
+
+ payload->op_mode.common.module_id = LSM_MODULE_ID_VOICE_WAKEUP;
+ payload->op_mode.common.param_id = LSM_PARAM_ID_OPERATION_MODE;
+ payload->op_mode.common.param_size =
+ sizeof(struct lsm_param_op_mode) - sizeof(payload->op_mode.common);
+ payload->op_mode.common.reserved = 0;
+ payload->op_mode.minor_version = 1;
+ payload->op_mode.mode = client->mode;
+ payload->op_mode.reserved = 0;
+
+ payload->connect_to_port.common.module_id = LSM_MODULE_ID_VOICE_WAKEUP;
+ payload->connect_to_port.common.param_id = LSM_PARAM_ID_CONNECT_TO_PORT;
+ payload->connect_to_port.common.param_size =
+ sizeof(payload->connect_to_port) - sizeof(payload->op_mode.common);
+ payload->connect_to_port.common.reserved = 0;
+ payload->connect_to_port.minor_version = 1;
+ payload->connect_to_port.port_id = client->connect_to_port;
+ payload->connect_to_port.reserved = 0;
+
+ payload->kwds.common.module_id = LSM_MODULE_ID_VOICE_WAKEUP;
+ payload->kwds.common.param_id = LSM_PARAM_ID_KEYWORD_DETECT_SENSITIVITY;
+ payload->kwds.common.param_size =
+ sizeof(payload->kwds) - sizeof(payload->op_mode.common);
+ payload->kwds.common.reserved = 0;
+ payload->kwds.minor_version = 1;
+ payload->kwds.keyword_sensitivity = client->kw_sensitivity;
+ payload->kwds.reserved = 0;
+
+ payload->uds.common.module_id = LSM_MODULE_ID_VOICE_WAKEUP;
+ payload->uds.common.param_id = LSM_PARAM_ID_USER_DETECT_SENSITIVITY;
+ payload->uds.common.param_size =
+ sizeof(payload->uds) - sizeof(payload->op_mode.common);
+ payload->uds.common.reserved = 0;
+ payload->uds.minor_version = 1;
+ payload->uds.user_sensitivity = client->user_sensitivity;
+ payload->uds.reserved = 0;
+
+ rc = q6lsm_apr_send_pkt(client, client->apr, ¶ms, true, NULL);
+ if (rc)
+ pr_err("%s: Failed set_params opcode 0x%x, rc %d\n",
+ __func__, params.hdr.opcode, rc);
+
+ pr_debug("%s: leave %d\n", __func__, rc);
+ return rc;
+}
+
+int q6lsm_register_sound_model(struct lsm_client *client,
+ enum lsm_detection_mode mode, u16 minkeyword,
+ u16 minuser, bool detectfailure)
+{
+ int rc;
+ struct lsm_cmd_reg_snd_model cmd;
+
+ memset(&cmd, 0, sizeof(cmd));
+ if (mode == LSM_MODE_KEYWORD_ONLY_DETECTION) {
+ client->mode = 0x01;
+ } else if (mode == LSM_MODE_USER_KEYWORD_DETECTION) {
+ client->mode = 0x03;
+ } else {
+ pr_err("%s: Incorrect detection mode %d\n", __func__, mode);
+ return -EINVAL;
+ }
+ client->mode |= detectfailure << 2;
+ client->kw_sensitivity = minkeyword;
+ client->user_sensitivity = minuser;
+ client->connect_to_port = AFE_PORT_ID_SLIMBUS_MULTI_CHAN_5_TX;
+
+ rc = q6lsm_set_params(client);
+ if (rc < 0) {
+ pr_err("%s: Failed to set lsm config params\n", __func__);
+ return rc;
+ }
+ rc = q6lsm_send_cal(client);
+ if (rc < 0) {
+ pr_err("%s: Failed to send calibration data\n", __func__);
+ return rc;
+ }
+
+ q6lsm_add_hdr(client, &cmd.hdr, sizeof(cmd), true);
+ cmd.hdr.opcode = LSM_SESSION_CMD_REGISTER_SOUND_MODEL;
+ cmd.model_addr_lsw = client->sound_model.phys;
+ cmd.model_addr_msw = 0;
+ cmd.model_size = client->sound_model.size;
+ /* read updated mem_map_handle by q6lsm_mmapcallback */
+ rmb();
+ cmd.mem_map_handle = client->sound_model.mem_map_handle;
+
+ pr_debug("%s: lsw %x, size %d, handle %x\n", __func__,
+ cmd.model_addr_lsw, cmd.model_size, cmd.mem_map_handle);
+ rc = q6lsm_apr_send_pkt(client, client->apr, &cmd, true, NULL);
+ if (rc)
+ pr_err("%s: Failed cmd op[0x%x]rc[%d]\n", __func__,
+ cmd.hdr.opcode, rc);
+ else
+ pr_debug("%s: Register sound model succeeded\n", __func__);
+
+ return rc;
+}
+
+int q6lsm_deregister_sound_model(struct lsm_client *client)
+{
+ int rc;
+ struct lsm_cmd_reg_snd_model cmd;
+
+ if (!client || !client->apr) {
+ pr_err("APR handle NULL\n");
+ return -EINVAL;
+ }
+ pr_debug("%s: session[%d]", __func__, client->session);
+
+ memset(&cmd, 0, sizeof(cmd));
+ q6lsm_add_hdr(client, &cmd.hdr, sizeof(cmd.hdr), false);
+ cmd.hdr.opcode = LSM_SESSION_CMD_DEREGISTER_SOUND_MODEL;
+
+ rc = q6lsm_apr_send_pkt(client, client->apr, &cmd.hdr, true, NULL);
+ if (rc < 0) {
+ pr_err("%s: Failed cmd opcode 0x%x, rc %d\n", __func__,
+ cmd.hdr.opcode, rc);
+ } else {
+ pr_debug("%s: Deregister sound model succeeded\n", __func__);
+ q6lsm_snd_model_buf_free(client);
+ }
+
+ return rc;
+}
+
+static void q6lsm_add_mmaphdr(struct lsm_client *client, struct apr_hdr *hdr,
+ u32 pkt_size, u32 cmd_flg, u32 token)
+{
+ pr_debug("%s:pkt size=%d cmd_flg=%d session=%d\n", __func__, pkt_size,
+ cmd_flg, client->session);
+ hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ hdr->src_port = 0x00;
+ hdr->dest_port = client->session;
+ if (cmd_flg)
+ hdr->token = token;
+ hdr->pkt_size = pkt_size;
+ return;
+}
+
+static int q6lsm_memory_map_regions(struct lsm_client *client,
+ uint32_t dma_addr_p, uint32_t dma_buf_sz,
+ uint32_t *mmap_p)
+{
+ struct avs_cmd_shared_mem_map_regions *mmap_regions = NULL;
+ struct avs_shared_map_region_payload *mregions = NULL;
+ void *mmap_region_cmd = NULL;
+ void *payload = NULL;
+ int rc;
+ int cmd_size = 0;
+
+ pr_debug("%s: dma_addr_p 0x%x, dma_buf_sz %d, session %d\n",
+ __func__, dma_addr_p, dma_buf_sz, client->session);
+
+ cmd_size = sizeof(struct avs_cmd_shared_mem_map_regions) +
+ sizeof(struct avs_shared_map_region_payload);
+
+ mmap_region_cmd = kzalloc(cmd_size, GFP_KERNEL);
+ if (!mmap_region_cmd)
+ return -ENOMEM;
+
+ mmap_regions = (struct avs_cmd_shared_mem_map_regions *)mmap_region_cmd;
+ q6lsm_add_mmaphdr(client, &mmap_regions->hdr, cmd_size, true,
+ (client->session << 8));
+
+ mmap_regions->hdr.opcode = LSM_SESSION_CMD_SHARED_MEM_MAP_REGIONS;
+ mmap_regions->mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL;
+ mmap_regions->num_regions = 1;
+ mmap_regions->property_flag = 0x00;
+ payload = ((u8 *)mmap_region_cmd +
+ sizeof(struct avs_cmd_shared_mem_map_regions));
+ mregions = (struct avs_shared_map_region_payload *)payload;
+
+ mregions->shm_addr_lsw = dma_addr_p;
+ mregions->shm_addr_msw = 0;
+ mregions->mem_size_bytes = dma_buf_sz;
+
+ rc = q6lsm_apr_send_pkt(client, client->mmap_apr, mmap_region_cmd,
+ true, mmap_p);
+ if (rc)
+ pr_err("%s: Failed mmap_regions opcode 0x%x, rc %d\n",
+ __func__, mmap_regions->hdr.opcode, rc);
+
+ pr_debug("%s: leave %d\n", __func__, rc);
+ kfree(mmap_region_cmd);
+ return rc;
+}
+
+static int q6lsm_send_cal(struct lsm_client *client)
+{
+ int rc;
+
+ struct lsm_cmd_set_params params;
+ struct acdb_cal_block lsm_cal;
+
+ pr_debug("%s: enter\n", __func__);
+
+ memset(&lsm_cal, 0, sizeof(lsm_cal));
+ get_lsm_cal(&lsm_cal);
+ if (!lsm_cal.cal_size) {
+ pr_err("%s: Could not get LSM calibration data\n", __func__);
+ rc = -EINVAL;
+ goto bail;
+ }
+
+ /* Cache mmap address, only map once or if new addr */
+ if ((lsm_common.lsm_cal_addr != lsm_cal.cal_paddr) ||
+ (lsm_cal.cal_size > lsm_common.lsm_cal_size)) {
+ if (lsm_common.lsm_cal_addr != 0)
+ afe_cmd_memory_unmap(lsm_cal.cal_paddr);
+
+ rc = q6lsm_memory_map_regions(client, lsm_cal.cal_paddr,
+ LSM_CAL_SIZE,
+ &lsm_common.mmap_handle_for_cal);
+ if (rc < 0) {
+ pr_err("%s: Calibration data memory map failed\n",
+ __func__);
+ goto bail;
+ }
+ lsm_common.lsm_cal_addr = lsm_cal.cal_paddr;
+ lsm_common.lsm_cal_size = LSM_CAL_SIZE;
+ }
+
+ q6lsm_add_hdr(client, ¶ms.hdr, sizeof(params), true);
+ params.hdr.opcode = LSM_SESSION_CMD_SET_PARAMS;
+ params.data_payload_addr_lsw = lsm_cal.cal_paddr;
+ params.data_payload_addr_msw = 0;
+ /* read updated mem_map_handle by q6lsm_mmapcallback */
+ rmb();
+ params.mem_map_handle = lsm_common.mmap_handle_for_cal;
+ params.data_payload_size = lsm_cal.cal_size;
+
+ rc = q6lsm_apr_send_pkt(client, client->apr, ¶ms, true, NULL);
+ if (rc)
+ pr_err("%s: Failed set_params opcode 0x%x, rc %d\n",
+ __func__, params.hdr.opcode, rc);
+bail:
+ return rc;
+}
+
+static int q6lsm_memory_unmap_regions(struct lsm_client *client)
+{
+ struct avs_cmd_shared_mem_unmap_regions unmap;
+ int rc = 0;
+ int cmd_size = 0;
+
+ cmd_size = sizeof(struct avs_cmd_shared_mem_unmap_regions);
+ q6lsm_add_mmaphdr(client, &unmap.hdr, cmd_size,
+ true, (client->session << 8));
+ unmap.hdr.opcode = LSM_SESSION_CMD_SHARED_MEM_UNMAP_REGIONS;
+ unmap.mem_map_handle = client->sound_model.mem_map_handle;
+
+ pr_debug("%s: unmap handle 0x%x\n", __func__, unmap.mem_map_handle);
+ rc = q6lsm_apr_send_pkt(client, client->mmap_apr, &unmap, true,
+ NULL);
+ if (rc)
+ pr_err("%s: Failed mmap_regions opcode 0x%x rc %d\n",
+ __func__, unmap.hdr.opcode, rc);
+
+ return rc;
+}
+
+static int q6lsm_snd_model_buf_free(struct lsm_client *client)
+{
+ int rc;
+
+ pr_debug("%s: Session id %d\n", __func__, client->session);
+ mutex_lock(&client->cmd_lock);
+ rc = q6lsm_memory_unmap_regions(client);
+ if (rc < 0) {
+ pr_err("%s CMD Memory_unmap_regions failed\n", __func__);
+ } else if (client->sound_model.data) {
+ ion_unmap_kernel(client->sound_model.client,
+ client->sound_model.handle);
+ ion_free(client->sound_model.client,
+ client->sound_model.handle);
+ ion_client_destroy(client->sound_model.client);
+ client->sound_model.data = NULL;
+ client->sound_model.phys = 0;
+ }
+ mutex_unlock(&client->cmd_lock);
+ return rc;
+}
+
+static struct lsm_client *q6lsm_get_lsm_client(int session_id)
+{
+ unsigned long flags;
+ struct lsm_client *client = NULL;
+
+ spin_lock_irqsave(&lsm_session_lock, flags);
+ if (session_id < LSM_MIN_SESSION_ID || session_id > LSM_MAX_SESSION_ID)
+ pr_err("%s: Invalid session %d\n", __func__, session_id);
+ else if (!lsm_session[session_id])
+ pr_err("%s: Not an active session %d\n", __func__, session_id);
+ else
+ client = lsm_session[session_id];
+ spin_unlock_irqrestore(&lsm_session_lock, flags);
+
+ return client;
+}
+
+/*
+ * q6lsm_mmapcallback : atomic context
+ */
+static int q6lsm_mmapcallback(struct apr_client_data *data, void *priv)
+{
+ unsigned long flags;
+ uint32_t sid = 0;
+ const uint32_t *payload = data->payload;
+ const uint32_t command = payload[0];
+ const uint32_t retcode = payload[1];
+ struct lsm_client *client = NULL;
+
+ pr_debug("%s: opcode 0x%x command 0x%x return code 0x%x\n", __func__,
+ data->opcode, command, retcode);
+
+ sid = (data->token >> 8) & 0x0F;
+ client = q6lsm_get_lsm_client(sid);
+ if (!client) {
+ pr_debug("%s: Session %d already freed\n", __func__, sid);
+ return 0;
+ }
+
+ switch (data->opcode) {
+ case LSM_SESSION_CMDRSP_SHARED_MEM_MAP_REGIONS:
+ if (atomic_read(&client->cmd_state) == CMD_STATE_WAIT_RESP) {
+ spin_lock_irqsave(&mmap_lock, flags);
+ *mmap_handle_p = command;
+ /* spin_unlock_irqrestore implies barrier */
+ spin_unlock_irqrestore(&mmap_lock, flags);
+ atomic_set(&client->cmd_state, CMD_STATE_CLEARED);
+ wake_up(&client->cmd_wait);
+ }
+ break;
+ case APR_BASIC_RSP_RESULT:
+ if (command == LSM_SESSION_CMD_SHARED_MEM_UNMAP_REGIONS) {
+ atomic_set(&client->cmd_state, CMD_STATE_CLEARED);
+ wake_up(&client->cmd_wait);
+ } else {
+ pr_warn("%s: Unexpected command 0x%x\n", __func__,
+ command);
+ }
+ break;
+ default:
+ pr_debug("%s: command 0x%x return code 0x%x\n",
+ __func__, command, retcode);
+ break;
+ }
+ if (client->cb)
+ client->cb(data->opcode, data->token,
+ data->payload, client->priv);
+ return 0;
+}
+
+int q6lsm_snd_model_buf_alloc(struct lsm_client *client, uint32_t len)
+{
+ int rc = -EINVAL;
+
+ if (!client)
+ goto fail;
+
+ mutex_lock(&client->cmd_lock);
+ if (!client->sound_model.data) {
+ client->sound_model.client =
+ msm_ion_client_create(UINT_MAX, "lsm_client");
+ if (IS_ERR_OR_NULL(client->sound_model.client)) {
+ pr_err("%s: ION create client for AUDIO failed\n",
+ __func__);
+ goto fail;
+ }
+ client->sound_model.handle =
+ ion_alloc(client->sound_model.client,
+ len, SZ_4K, (0x1 << ION_AUDIO_HEAP_ID), 0);
+ if (IS_ERR_OR_NULL(client->sound_model.handle)) {
+ pr_err("%s: ION memory allocation for AUDIO failed\n",
+ __func__);
+ goto fail;
+ }
+
+ rc = ion_phys(client->sound_model.client,
+ client->sound_model.handle,
+ (ion_phys_addr_t *)&client->sound_model.phys,
+ (size_t *)&len);
+ if (rc) {
+ pr_err("%s: ION get physical mem failed, rc%d\n",
+ __func__, rc);
+ goto fail;
+ }
+
+ client->sound_model.data =
+ ion_map_kernel(client->sound_model.client,
+ client->sound_model.handle);
+ if (IS_ERR_OR_NULL(client->sound_model.data)) {
+ pr_err("%s: ION memory mapping failed\n", __func__);
+ goto fail;
+ }
+ memset(client->sound_model.data, 0, len);
+ client->sound_model.size = len;
+ } else {
+ rc = -EBUSY;
+ goto fail;
+ }
+ mutex_unlock(&client->cmd_lock);
+
+ rc = q6lsm_memory_map_regions(client, client->sound_model.phys,
+ client->sound_model.size,
+ &client->sound_model.mem_map_handle);
+ if (rc < 0) {
+ pr_err("%s:CMD Memory_map_regions failed\n", __func__);
+ goto fail;
+ }
+
+ return 0;
+fail:
+ q6lsm_snd_model_buf_free(client);
+ return rc;
+}
+
+static int q6lsm_cmd(struct lsm_client *client, int opcode, bool wait)
+{
+ struct apr_hdr hdr;
+ int rc;
+
+ pr_debug("%s: enter opcode %d wait %d\n", __func__, opcode, wait);
+ q6lsm_add_hdr(client, &hdr, sizeof(hdr), true);
+ switch (opcode) {
+ case LSM_SESSION_CMD_START:
+ case LSM_SESSION_CMD_STOP:
+ case LSM_SESSION_CMD_CLOSE_TX:
+ hdr.opcode = opcode;
+ break;
+ default:
+ pr_err("%s: Invalid opcode %d\n", __func__, opcode);
+ return -EINVAL;
+ }
+ rc = q6lsm_apr_send_pkt(client, client->apr, &hdr, wait, NULL);
+ if (rc)
+ pr_err("%s: Failed commmand 0x%x\n", __func__, hdr.opcode);
+
+ pr_debug("%s: leave %d\n", __func__, rc);
+ return rc;
+}
+
+int q6lsm_start(struct lsm_client *client, bool wait)
+{
+ return q6lsm_cmd(client, LSM_SESSION_CMD_START, wait);
+}
+
+int q6lsm_stop(struct lsm_client *client, bool wait)
+{
+ return q6lsm_cmd(client, LSM_SESSION_CMD_STOP, wait);
+}
+
+int q6lsm_close(struct lsm_client *client)
+{
+ return q6lsm_cmd(client, LSM_SESSION_CMD_CLOSE_TX, true);
+}
+
+static int __init q6lsm_init(void)
+{
+ pr_debug("%s\n", __func__);
+ spin_lock_init(&lsm_session_lock);
+ spin_lock_init(&mmap_lock);
+ mutex_init(&lsm_common.apr_lock);
+ return 0;
+}
+
+device_initcall(q6lsm_init);