summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/arm/msm/remote_debug_drv.txt468
-rw-r--r--Documentation/devicetree/bindings/arm/msm/msm.txt1
-rw-r--r--Documentation/devicetree/bindings/power/qcom-charger/qpnp-fg-gen3.txt14
-rw-r--r--Documentation/devicetree/bindings/ufs/ufs-qcom.txt4
-rw-r--r--arch/arm/boot/dts/qcom/Makefile3
-rw-r--r--arch/arm/boot/dts/qcom/fg-gen3-batterydata-ascent-3450mah.dtsi2
-rw-r--r--arch/arm/boot/dts/qcom/fg-gen3-batterydata-demo-6000mah.dtsi2
-rw-r--r--arch/arm/boot/dts/qcom/fg-gen3-batterydata-itech-3000mah.dtsi2
-rw-r--r--arch/arm/boot/dts/qcom/fg-gen3-batterydata-qrd-skuk-4v4-3000mah.dtsi (renamed from arch/arm/boot/dts/qcom/batterydata-qrd-skuk-4v4-3000mah.dtsi)2
-rw-r--r--arch/arm/boot/dts/qcom/msm-pm2falcon.dtsi7
-rw-r--r--arch/arm/boot/dts/qcom/msm-pmfalcon.dtsi10
-rw-r--r--arch/arm/boot/dts/qcom/msm-pmi8998.dtsi1
-rw-r--r--arch/arm/boot/dts/qcom/msm8996-camera.dtsi2
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-cdp.dtsi43
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-mtp.dtsi43
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-qrd.dtsi511
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-qrd-skuk.dtsi3
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-qrd-vr1.dtsi3
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-msmfalcon-cdp.dts17
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-msmfalcon-mtp.dts17
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-msmfalcon-qrd.dts2
-rw-r--r--arch/arm/boot/dts/qcom/msm8998.dtsi8
-rw-r--r--arch/arm/boot/dts/qcom/msmfalcon-cdp.dtsi21
-rw-r--r--arch/arm/boot/dts/qcom/msmfalcon-gpu.dtsi20
-rw-r--r--arch/arm/boot/dts/qcom/msmfalcon-mtp.dtsi21
-rw-r--r--arch/arm/boot/dts/qcom/msmfalcon-pinctrl.dtsi28
-rw-r--r--arch/arm/boot/dts/qcom/msmfalcon-qrd.dts23
-rw-r--r--arch/arm/boot/dts/qcom/msmfalcon-qrd.dtsi24
-rw-r--r--arch/arm/boot/dts/qcom/msmfalcon-rumi.dts20
-rw-r--r--arch/arm/boot/dts/qcom/msmfalcon-sim.dts21
-rw-r--r--arch/arm/boot/dts/qcom/msmfalcon.dtsi130
-rw-r--r--arch/arm/boot/dts/qcom/msmtriton-regulator.dtsi810
-rw-r--r--arch/arm/boot/dts/qcom/msmtriton.dtsi31
-rw-r--r--arch/arm/configs/msmfalcon-perf_defconfig6
-rw-r--r--arch/arm/configs/msmfalcon_defconfig9
-rw-r--r--arch/arm64/configs/msm-perf_defconfig3
-rw-r--r--arch/arm64/configs/msm_defconfig3
-rw-r--r--arch/arm64/configs/msmcortex-perf_defconfig2
-rw-r--r--arch/arm64/configs/msmfalcon-perf_defconfig2
-rw-r--r--arch/arm64/configs/msmfalcon_defconfig3
-rw-r--r--drivers/char/Kconfig21
-rw-r--r--drivers/char/Makefile1
-rw-r--r--drivers/char/rdbg.c1165
-rw-r--r--drivers/clk/clk.c6
-rw-r--r--drivers/clk/clk.h2
-rw-r--r--drivers/clk/qcom/Kconfig2
-rw-r--r--drivers/clk/qcom/Makefile2
-rw-r--r--drivers/clk/qcom/common.c218
-rw-r--r--drivers/clk/qcom/common.h91
-rw-r--r--drivers/clk/qcom/gcc-msmfalcon.c16
-rw-r--r--drivers/clk/qcom/mdss/Kconfig3
-rw-r--r--drivers/clk/qcom/mdss/Makefile9
-rw-r--r--drivers/clk/qcom/mdss/mdss-dsi-pll-14nm-util.c (renamed from drivers/clk/qcom/mdss/mdss-dsi-pll-8996-util.c)344
-rw-r--r--drivers/clk/qcom/mdss/mdss-dsi-pll-14nm.c614
-rw-r--r--drivers/clk/qcom/mdss/mdss-dsi-pll-14nm.h (renamed from drivers/clk/qcom/mdss/mdss-dsi-pll-8996.h)54
-rw-r--r--drivers/clk/qcom/mdss/mdss-dsi-pll-8996.c566
-rw-r--r--drivers/clk/qcom/mdss/mdss-dsi-pll.h65
-rw-r--r--drivers/clk/qcom/mdss/mdss-pll-util.c1
-rw-r--r--drivers/clk/qcom/mdss/mdss-pll.c25
-rw-r--r--drivers/clk/qcom/mdss/mdss-pll.h27
-rw-r--r--drivers/clk/qcom/mmcc-msmfalcon.c11
-rw-r--r--drivers/gpu/msm/adreno_dispatch.c127
-rw-r--r--drivers/gpu/msm/adreno_drawctxt.c3
-rw-r--r--drivers/gpu/msm/kgsl.c152
-rw-r--r--drivers/gpu/msm/kgsl.h3
-rw-r--r--drivers/gpu/msm/kgsl_compat.c2
-rw-r--r--drivers/gpu/msm/kgsl_device.h15
-rw-r--r--drivers/gpu/msm/kgsl_drawobj.c187
-rw-r--r--drivers/gpu/msm/kgsl_drawobj.h33
-rw-r--r--drivers/gpu/msm/kgsl_ioctl.c2
-rw-r--r--drivers/hwtracing/coresight/Kconfig3
-rw-r--r--drivers/media/platform/msm/camera_v2/common/cam_smmu_api.c5
-rw-r--r--drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c81
-rw-r--r--drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.h6
-rw-r--r--drivers/media/platform/msm/camera_v2/fd/msm_fd_hw.c56
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp47.c2
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c4
-rw-r--r--drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c137
-rw-r--r--drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h21
-rw-r--r--drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c6
-rw-r--r--drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c16
-rw-r--r--drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c4
-rw-r--r--drivers/media/platform/msm/vidc/hfi_response_handler.c16
-rw-r--r--drivers/media/platform/msm/vidc/msm_vidc_common.c50
-rw-r--r--drivers/media/platform/msm/vidc/venus_hfi.c5
-rw-r--r--drivers/media/platform/msm/vidc/vidc_hfi_api.h1
-rw-r--r--drivers/nfc/nq-nci.c135
-rw-r--r--drivers/nfc/nq-nci.h2
-rw-r--r--drivers/phy/Makefile1
-rw-r--r--drivers/phy/phy-qcom-ufs-qmp-v3-falcon.c260
-rw-r--r--drivers/phy/phy-qcom-ufs-qmp-v3-falcon.h283
-rw-r--r--drivers/power/qcom-charger/fg-core.h12
-rw-r--r--drivers/power/qcom-charger/fg-reg.h4
-rw-r--r--drivers/power/qcom-charger/qpnp-fg-gen3.c174
-rw-r--r--drivers/power/qcom-charger/smb-lib.c11
-rw-r--r--drivers/soc/qcom/glink.c8
-rw-r--r--drivers/soc/qcom/icnss.c10
-rw-r--r--drivers/soc/qcom/pil-msa.c3
-rw-r--r--drivers/soc/qcom/pil-q6v5.c6
-rw-r--r--drivers/soc/qcom/smcinvoke.c10
-rw-r--r--drivers/soc/qcom/spcom.c79
-rw-r--r--drivers/staging/android/ion/msm/msm_ion.c25
-rw-r--r--drivers/staging/android/ion/msm/msm_ion.h26
-rw-r--r--drivers/usb/dwc3/dbm.c20
-rw-r--r--drivers/usb/dwc3/dwc3-msm.c211
-rw-r--r--drivers/usb/dwc3/gadget.c3
-rw-r--r--drivers/usb/gadget/composite.c2
-rw-r--r--drivers/usb/gadget/function/f_gsi.c4
-rw-r--r--drivers/usb/gadget/function/u_data_ipa.c4
-rw-r--r--drivers/usb/gadget/function/u_qdss.c3
-rw-r--r--drivers/video/fbdev/msm/mdss_compat_utils.c8
-rw-r--r--include/dt-bindings/clock/mdss-pll-clk.h42
-rw-r--r--include/linux/clk-provider.h1
-rw-r--r--include/linux/usb/msm_hsusb.h6
-rw-r--r--include/soc/qcom/icnss.h3
-rw-r--r--include/uapi/linux/msm_kgsl.h32
-rw-r--r--mm/cma.c3
-rw-r--r--sound/soc/msm/msmfalcon-common.c2
118 files changed, 6385 insertions, 1530 deletions
diff --git a/Documentation/arm/msm/remote_debug_drv.txt b/Documentation/arm/msm/remote_debug_drv.txt
new file mode 100644
index 000000000000..13a35f43e86b
--- /dev/null
+++ b/Documentation/arm/msm/remote_debug_drv.txt
@@ -0,0 +1,468 @@
+Introduction
+============
+
+The goal of this debug feature is to provide a reliable, responsive,
+accurate and secure debug capability to developers interested in
+debugging MSM subsystem processor images without the use of a hardware
+debugger.
+
+The Debug Agent along with the Remote Debug Driver implements a shared
+memory based transport mechanism that allows for a debugger (ex. GDB)
+running on a host PC to communicate with a remote stub running on
+peripheral subsystems such as the ADSP, MODEM etc.
+
+The diagram below depicts end to end the components involved to
+support remote debugging:
+
+
+: :
+: HOST (PC) : MSM
+: ,--------, : ,-------,
+: | | : | Debug | ,--------,
+: |Debugger|<--:-->| Agent | | Remote |
+: | | : | App | +----->| Debug |
+: `--------` : |-------| ,--------, | | Stub |
+: : | Remote| | |<---+ `--------`
+: : | Debug |<-->|--------|
+: : | Driver| | |<---+ ,--------,
+: : `-------` `--------` | | Remote |
+: : LA Shared +----->| Debug |
+: : Memory | Stub |
+: : `--------`
+: : Peripheral Subsystems
+: : (ADSP, MODEM, ...)
+
+
+Debugger: Debugger application running on the host PC that
+ communicates with the remote stub.
+ Examples: GDB, LLDB
+
+Debug Agent: Software that runs on the Linux Android platform
+ that provides connectivity from the MSM to the
+ host PC. This involves two portions:
+ 1) User mode Debug Agent application that discovers
+ processes running on the subsystems and creates
+ TCP/IP sockets for the host to connect to. In addition
+ to this, it creates an info (or meta) port that
+ users can connect to discover the various
+ processes and their corresponding debug ports.
+
+Remote Debug A character based driver that the Debug
+Driver: Agent uses to transport the payload received from the
+ host to the debug stub running on the subsystem
+ processor over shared memory and vice versa.
+
+Shared Memory: Shared memory from the SMEM pool that is accessible
+ from the Applications Processor (AP) and the
+ subsystem processors.
+
+Remote Debug Privileged code that runs in the kernels of the
+Stub: subsystem processors that receives debug commands
+ from the debugger running on the host and
+ acts on these commands. These commands include reading
+ and writing to registers and memory belonging to the
+ subsystem's address space, setting breakpoints,
+ single stepping etc.
+
+Hardware description
+====================
+
+The Remote Debug Driver interfaces with the Remote Debug stubs
+running on the subsystem processors and does not drive or
+manage any hardware resources.
+
+Software description
+====================
+
+The debugger and the remote stubs use Remote Serial Protocol (RSP)
+to communicate with each other. This is widely used protocol by both
+software and hardware debuggers. RSP is an ASCII based protocol
+and used when it is not possible to run GDB server on the target under
+debug.
+
+The Debug Agent application along with the Remote Debug Driver
+is responsible for establishing a bi-directional connection from
+the debugger application running on the host to the remote debug
+stub running on a subsystem. The Debug Agent establishes connectivity
+to the host PC via TCP/IP sockets.
+
+This feature uses ADB port forwarding to establish connectivity
+between the debugger running on the host and the target under debug.
+
+Please note the Debug Agent does not expose HLOS memory to the
+remote subsystem processors.
+
+Design
+======
+
+Here is the overall flow:
+
+1) When the Debug Agent application starts up, it opens up a shared memory
+based transport channel to the various subsystem processor images.
+
+2) The Debug Agent application sends messages across to the remote stubs
+to discover the various processes that are running on the subsystem and
+creates debug sockets for each of them.
+
+3) Whenever a process running on a subsystem exits, the Debug Agent
+is notified by the stub so that the debug port and other resources
+can be reclaimed.
+
+4) The Debug Agent uses the services of the Remote Debug Driver to
+transport payload from the host debugger to the remote stub and vice versa.
+
+5) Communication between the Remote Debug Driver and the Remote Debug stub
+running on the subsystem processor is done over shared memory (see figure).
+SMEM services are used to allocate the shared memory that will
+be readable and writeable by the AP and the subsystem image under debug.
+
+A separate SMEM allocation takes place for each subsystem processor
+involved in remote debugging. The remote stub running on each of the
+subsystems allocates a SMEM buffer using a unique identifier so that both
+the AP and subsystem get the same physical block of memory. It should be
+noted that subsystem images can be restarted at any time.
+However, when a subsystem comes back up, its stub uses the same unique
+SMEM identifier to allocate the SMEM block. This would not result in a
+new allocation rather the same block of memory in the first bootup instance
+is provided back to the stub running on the subsystem.
+
+An 8KB chunk of shared memory is allocated and used for communication
+per subsystem. For multi-process capable subsystems, 16KB chunk of shared
+memory is allocated to allow for simultaneous debugging of more than one
+process running on a single subsystem.
+
+The shared memory is used as a circular ring buffer in each direction.
+Thus we have a bi-directional shared memory channel between the AP
+and a subsystem. We call this SMQ. Each memory channel contains a header,
+data and a control mechanism that is used to synchronize read and write
+of data between the AP and the remote subsystem.
+
+Overall SMQ memory view:
+:
+: +------------------------------------------------+
+: | SMEM buffer |
+: |-----------------------+------------------------|
+: |Producer: LA | Producer: Remote |
+: |Consumer: Remote | subsystem |
+: | subsystem | Consumer: LA |
+: | | |
+: | Producer| Consumer|
+: +-----------------------+------------------------+
+: | |
+: | |
+: | +--------------------------------------+
+: | |
+: | |
+: v v
+: +--------------------------------------------------------------+
+: | Header | Data | Control |
+: +-----------+---+---+---+-----+----+--+--+-----+---+--+--+-----+
+: | | b | b | b | | S |n |n | | S |n |n | |
+: | Producer | l | l | l | | M |o |o | | M |o |o | |
+: | Ver | o | o | o | | Q |d |d | | Q |d |d | |
+: |-----------| c | c | c | ... | |e |e | ... | |e |e | ... |
+: | | k | k | k | | O | | | | I | | | |
+: | Consumer | | | | | u |0 |1 | | n |0 |1 | |
+: | Ver | 0 | 1 | 2 | | t | | | | | | | |
+: +-----------+---+---+---+-----+----+--+--+-----+---+--+--+-----+
+: | |
+: + |
+: |
+: +------------------------+
+: |
+: v
+: +----+----+----+----+
+: | SMQ Nodes |
+: |----|----|----|----|
+: Node # | 0 | 1 | 2 | ...|
+: |----|----|----|----|
+: Starting Block Index # | 0 | 3 | 8 | ...|
+: |----|----|----|----|
+: # of blocks | 3 | 5 | 1 | ...|
+: +----+----+----+----+
+:
+
+Header: Contains version numbers for software compatibility to ensure
+that both producers and consumers on the AP and subsystems know how to
+read from and write to the queue.
+Both the producer and consumer versions are 1.
+: +---------+-------------------+
+: | Size | Field |
+: +---------+-------------------+
+: | 1 byte | Producer Version |
+: +---------+-------------------+
+: | 1 byte | Consumer Version |
+: +---------+-------------------+
+
+
+Data: The data portion contains multiple blocks [0..N] of a fixed size.
+The block size SM_BLOCKSIZE is fixed to 128 bytes for header version #1.
+Payload sent from the debug agent app is split (if necessary) and placed
+in these blocks. The first data block is placed at the next 8 byte aligned
+address after the header.
+
+The number of blocks for a given SMEM allocation is derived as follows:
+ Number of Blocks = ((Total Size - Alignment - Size of Header
+ - Size of SMQIn - Size of SMQOut)/(SM_BLOCKSIZE))
+
+The producer maintains a private block map of each of these blocks to
+determine which of these blocks in the queue is available and which are free.
+
+Control:
+The control portion contains a list of nodes [0..N] where N is number
+of available data blocks. Each node identifies the data
+block indexes that contain a particular debug message to be transferred,
+and the number of blocks it took to hold the contents of the message.
+
+Each node has the following structure:
+: +---------+-------------------+
+: | Size | Field |
+: +---------+-------------------+
+: | 2 bytes |Staring Block Index|
+: +---------+-------------------+
+: | 2 bytes |Number of Blocks |
+: +---------+-------------------+
+
+The producer and the consumer update different parts of the control channel
+(SMQOut / SMQIn) respectively. Each of these control data structures contains
+information about the last node that was written / read, and the actual nodes
+that were written/read.
+
+SMQOut Structure (R/W by producer, R by consumer):
+: +---------+-------------------+
+: | Size | Field |
+: +---------+-------------------+
+: | 4 bytes | Magic Init Number |
+: +---------+-------------------+
+: | 4 bytes | Reset |
+: +---------+-------------------+
+: | 4 bytes | Last Sent Index |
+: +---------+-------------------+
+: | 4 bytes | Index Free Read |
+: +---------+-------------------+
+
+SMQIn Structure (R/W by consumer, R by producer):
+: +---------+-------------------+
+: | Size | Field |
+: +---------+-------------------+
+: | 4 bytes | Magic Init Number |
+: +---------+-------------------+
+: | 4 bytes | Reset ACK |
+: +---------+-------------------+
+: | 4 bytes | Last Read Index |
+: +---------+-------------------+
+: | 4 bytes | Index Free Write |
+: +---------+-------------------+
+
+Magic Init Number:
+Both SMQ Out and SMQ In initialize this field with a predefined magic
+number so as to make sure that both the consumer and producer blocks
+have fully initialized and have valid data in the shared memory control area.
+ Producer Magic #: 0xFF00FF01
+ Consumer Magic #: 0xFF00FF02
+
+SMQ Out's Last Sent Index and Index Free Read:
+ Only a producer can write to these indexes and they are updated whenever
+ there is new payload to be inserted into the SMQ in order to be sent to a
+ consumer.
+
+ The number of blocks required for the SMQ allocation is determined as:
+ (payload size + SM_BLOCKSIZE - 1) / SM_BLOCKSIZE
+
+ The private block map is searched for a large enough continuous set of blocks
+ and the user data is copied into the data blocks.
+
+ The starting index of the free block(s) is updated in the SMQOut's Last Sent
+ Index. This update keeps track of which index was last written to and the
+ producer uses it to determine where the the next allocation could be done.
+
+ Every allocation, a producer updates the Index Free Read from its
+ collaborating consumer's Index Free Write field (if they are unequal).
+ This index value indicates that the consumer has read all blocks associated
+ with allocation on the SMQ and that the producer can reuse these blocks for
+ subsquent allocations since this is a circular queue.
+
+ At cold boot and restart, these indexes are initialized to zero and all
+ blocks are marked as available for allocation.
+
+SMQ In's Last Read Index and Index Free Write:
+ These indexes are written to only by a consumer and are updated whenever
+ there is new payload to be read from the SMQ. The Last Read Index keeps
+ track of which index was last read by the consumer and using this, it
+ determines where the next read should be done.
+ After completing a read, Last Read Index is incremented to the
+ next block index. A consumer updates Index Free Write to the starting
+ index of an allocation whenever it has completed processing the blocks.
+ This is an optimization that can be used to prevent an additional copy
+ of data from the queue into a client's data buffer and the data in the queue
+ itself can be used.
+ Once Index Free Write is updated, the collaborating producer (on the next
+ data allocation) reads the updated Index Free Write value and it then
+ updates its corresponding SMQ Out's Index Free Read and marks the blocks
+ associated with that index as available for allocation. At cold boot and
+ restart, these indexes are initialized to zero.
+
+SMQ Out Reset# and SMQ In Reset ACK #:
+ Since subsystems can restart at anytime, the data blocks and control channel
+ can be in an inconsistent state when a producer or consumer comes up.
+ We use Reset and Reset ACK to manage this. At cold boot, the producer
+ initializes the Reset# to a known number ex. 1. Every other reset that the
+ producer undergoes, the Reset#1 is simply incremented by 1. All the producer
+ indexes are reset.
+ When the producer notifies the consumer of data availability, the consumer
+ reads the producers Reset # and copies that into its SMQ In Reset ACK#
+ field when they differ. When that occurs, the consumer resets its
+ indexes to 0.
+
+6) Asynchronous notifications between a producer and consumer are
+done using the SMP2P service which is interrupt based.
+
+Power Management
+================
+
+None
+
+SMP/multi-core
+==============
+
+The driver uses completion to wake up the Debug Agent client threads.
+
+Security
+========
+
+From the perspective of the subsystem, the AP is untrusted. The remote
+stubs consult the secure debug fuses to determine whether or not the
+remote debugging will be enabled at the subsystem.
+
+If the hardware debug fuses indicate that debugging is disabled, the
+remote stubs will not be functional on the subsystem. Writes to the
+queue will only be done if the driver sees that the remote stub has been
+initialized on the subsystem.
+
+Therefore even if any untrusted software running on the AP requests
+the services of the Remote Debug Driver and inject RSP messages
+into the shared memory buffer, these RSP messages will be discarded and
+an appropriate error code will be sent up to the invoking application.
+
+Performance
+===========
+
+During operation, the Remote Debug Driver copies RSP messages
+asynchronously sent from the host debugger to the remote stub and vice
+versa. The debug messages are ASCII based and relatively short
+(<25 bytes) and may once in a while go up to a maximum 700 bytes
+depending on the command the user requested. Thus we do not
+anticipate any major performance impact. Moreover, in a typical
+functional debug scenario performance should not be a concern.
+
+Interface
+=========
+
+The Remote Debug Driver is a character based device that manages
+a piece of shared memory that is used as a bi-directional
+single producer/consumer circular queue using a next fit allocator.
+Every subsystem, has its own shared memory buffer that is managed
+like a separate device.
+
+The driver distinguishes each subsystem processor's buffer by
+registering a node with a different minor number.
+
+For each subsystem that is supported, the driver exposes a user space
+interface through the following node:
+ - /dev/rdbg-<subsystem>
+ Ex. /dev/rdbg-adsp (for the ADSP subsystem)
+
+The standard open(), close(), read() and write() API set is
+implemented.
+
+The open() syscall will fail if a subsystem is not present or supported
+by the driver or a shared memory buffer cannot be allocated for the
+AP - subsystem communication. It will also fail if the subsytem has
+not initialized the queue on its side. Here are the error codes returned
+in case a call to open() fails:
+ENODEV - memory was not yet allocated for the device
+EEXIST - device is already opened
+ENOMEM - SMEM allocation failed
+ECOMM - Subsytem queue is not yet setup
+ENOMEM - Failure to initialize SMQ
+
+read() is a blocking call that will return with the number of bytes written
+by the subsystem whenever the subsystem sends it some payload. Here are the
+error codes returned in case a call to read() fails:
+EINVAL - Invalid input
+ENODEV - Device has not been opened yet
+ERESTARTSYS - call to wait_for_completion_interruptible is interrupted
+ENODATA - call to smq_receive failed
+
+write() attempts to send user mode payload out to the subsystem. It can fail
+if the SMQ is full. The number of bytes written is returned back to the user.
+Here are the error codes returned in case a call to write() fails:
+EINVAL - Invalid input
+ECOMM - SMQ send failed
+
+In the close() syscall, the control information state of the SMQ is
+initialized to zero thereby preventing any further communication between
+the AP and the subsystem. Here is the error code returned in case
+a call to close() fails:
+ENODEV - device wasn't opened/initialized
+
+The Remote Debug driver uses SMP2P for bi-directional AP to subsystem
+notification. Notifications are sent to indicate that there are new
+debug messages available for processing. Each subsystem that is
+supported will need to add a device tree entry per the usage
+specification of SMP2P driver.
+
+In case the remote stub becomes non operational or the security configuration
+on the subsystem does not permit debugging, any messages put in the SMQ will
+not be responded to. It is the responsibility of the Debug Agent app and the
+host debugger application such as GDB to timeout and notify the user of the
+non availability of remote debugging.
+
+Driver parameters
+=================
+
+None
+
+Config options
+==============
+
+The driver is configured with a device tree entry to map an SMP2P entry
+to the device. The SMP2P entry name used is "rdbg". Please see
+kernel\Documentation\arm\msm\msm_smp2p.txt for information about the
+device tree entry required to configure SMP2P.
+
+The driver uses the SMEM allocation type SMEM_LC_DEBUGGER to allocate memory
+for the queue that is used to share data with the subsystems.
+
+Dependencies
+============
+
+The Debug Agent driver requires services of SMEM to
+allocate shared memory buffers.
+
+SMP2P is used as a bi-directional notification
+mechanism between the AP and a subsystem processor.
+
+User space utilities
+====================
+
+This driver is meant to be used in conjunction with the user mode
+Remote Debug Agent application.
+
+Other
+=====
+
+None
+
+Known issues
+============
+For targets with an external subsystem, we cannot use
+shared memory for communication and would have to use the prevailing
+transport mechanisms that exists between the AP and the external subsystem.
+
+This driver cannot be leveraged for such targets.
+
+To do
+=====
+
+None
diff --git a/Documentation/devicetree/bindings/arm/msm/msm.txt b/Documentation/devicetree/bindings/arm/msm/msm.txt
index ce7bfa24490a..6e1ac697a751 100644
--- a/Documentation/devicetree/bindings/arm/msm/msm.txt
+++ b/Documentation/devicetree/bindings/arm/msm/msm.txt
@@ -264,6 +264,7 @@ compatible = "qcom,msmfalcon-sim"
compatible = "qcom,msmfalcon-rumi"
compatible = "qcom,msmfalcon-cdp"
compatible = "qcom,msmfalcon-mtp"
+compatible = "qcom,msmfalcon-qrd"
compatible = "qcom,msmtriton-rumi"
compatible = "qcom,msm8952-rumi"
compatible = "qcom,msm8952-sim"
diff --git a/Documentation/devicetree/bindings/power/qcom-charger/qpnp-fg-gen3.txt b/Documentation/devicetree/bindings/power/qcom-charger/qpnp-fg-gen3.txt
index 808e18b495d5..ac63b3c3bf01 100644
--- a/Documentation/devicetree/bindings/power/qcom-charger/qpnp-fg-gen3.txt
+++ b/Documentation/devicetree/bindings/power/qcom-charger/qpnp-fg-gen3.txt
@@ -36,6 +36,12 @@ First Level Node - FG Gen3 device
Definition: For details about IIO bindings see:
Documentation/devicetree/bindings/iio/iio-bindings.txt
+- qcom,rradc-base
+ Usage: required
+ Value type: <u32>
+ Definition: Should specify the base address of RR_ADC peripheral. This
+ is used for reading certain peripheral registers under it.
+
- qcom,fg-cutoff-voltage
Usage: optional
Value type: <u32>
@@ -260,6 +266,13 @@ First Level Node - FG Gen3 device
is specified to make it fully functional. Value has no
unit. Allowed range is 0 to 62200 in micro units.
+- qcom,fg-rconn-mohms
+ Usage: optional
+ Value type: <u32>
+ Definition: Battery connector resistance (Rconn) in milliohms. If Rconn
+ is specified, then ESR to Rslow scaling factors will be
+ updated to account it for an accurate ESR.
+
==========================================================
Second Level Nodes - Peripherals managed by FG Gen3 driver
==========================================================
@@ -290,6 +303,7 @@ pmi8998_fg: qpnp,fg {
qcom,pmic-revid = <&pmi8998_revid>;
io-channels = <&pmi8998_rradc 3>;
io-channel-names = "rradc_batt_id";
+ qcom,rradc-base = <0x4500>;
qcom,ki-coeff-soc-dischg = <30 60 90>;
qcom,ki-coeff-med-dischg = <800 1000 1400>;
qcom,ki-coeff-hi-dischg = <1200 1500 2100>;
diff --git a/Documentation/devicetree/bindings/ufs/ufs-qcom.txt b/Documentation/devicetree/bindings/ufs/ufs-qcom.txt
index 80488c802df2..66142b4cd880 100644
--- a/Documentation/devicetree/bindings/ufs/ufs-qcom.txt
+++ b/Documentation/devicetree/bindings/ufs/ufs-qcom.txt
@@ -9,7 +9,9 @@ contain a phandle reference to UFS PHY node.
Required properties:
- compatible : compatible list, contains "qcom,ufs-phy-qmp-20nm"
or "qcom,ufs-phy-qmp-14nm" or "qcom,ufs-phy-qmp-v3"
- or "qcom,ufs-phy-qrbtc-v2" according to the relevant phy in use.
+ or "qcom,ufs-phy-qrbtc-v2" or
+ "qcom,ufs-phy-qmp-v3-falcon"
+ according to the relevant phy in use.
- reg : should contain PHY register address space (mandatory),
- reg-names : indicates various resources passed to driver (via reg proptery) by name.
Required "reg-names" is "phy_mem".
diff --git a/arch/arm/boot/dts/qcom/Makefile b/arch/arm/boot/dts/qcom/Makefile
index 4d82f51be778..bc918a9a6402 100644
--- a/arch/arm/boot/dts/qcom/Makefile
+++ b/arch/arm/boot/dts/qcom/Makefile
@@ -138,7 +138,8 @@ dtb-$(CONFIG_ARCH_MSMFALCON) += msmfalcon-sim.dtb \
msmfalcon-rumi.dtb \
msmfalcon-cdp.dtb \
msmfalcon-mtp.dtb \
- msmfalcon-rcm.dtb
+ msmfalcon-rcm.dtb \
+ msmfalcon-qrd.dtb
dtb-$(CONFIG_ARCH_MSMTRITON) += msmtriton-rumi.dtb
diff --git a/arch/arm/boot/dts/qcom/fg-gen3-batterydata-ascent-3450mah.dtsi b/arch/arm/boot/dts/qcom/fg-gen3-batterydata-ascent-3450mah.dtsi
index 364b83320015..76f7c498d2cd 100644
--- a/arch/arm/boot/dts/qcom/fg-gen3-batterydata-ascent-3450mah.dtsi
+++ b/arch/arm/boot/dts/qcom/fg-gen3-batterydata-ascent-3450mah.dtsi
@@ -14,7 +14,7 @@ qcom,ascent_3450mah {
/* Ascent_with_connector_3450mAh_averaged_MasterSlave_Nov28th2016 */
qcom,max-voltage-uv = <4350000>;
qcom,fg-cc-cv-threshold-mv = <4340>;
- qcom,nom-batt-capacity-mah = <3450>;
+ qcom,fastchg-current-ma = <3450>;
qcom,batt-id-kohm = <60>;
qcom,battery-beta = <3435>;
qcom,battery-type = "ascent_3450mah_averaged_masterslave_nov28th2016";
diff --git a/arch/arm/boot/dts/qcom/fg-gen3-batterydata-demo-6000mah.dtsi b/arch/arm/boot/dts/qcom/fg-gen3-batterydata-demo-6000mah.dtsi
index b107918a8e98..bc43fb0549cb 100644
--- a/arch/arm/boot/dts/qcom/fg-gen3-batterydata-demo-6000mah.dtsi
+++ b/arch/arm/boot/dts/qcom/fg-gen3-batterydata-demo-6000mah.dtsi
@@ -13,7 +13,7 @@
qcom,demo_6000mah {
qcom,max-voltage-uv = <4350000>;
qcom,fg-cc-cv-threshold-mv = <4340>;
- qcom,nom-batt-capacity-mah = <6000>;
+ qcom,fastchg-current-ma = <6000>;
qcom,batt-id-kohm = <75>;
qcom,battery-beta = <3435>;
qcom,battery-type = "Demo_battery_6000mah";
diff --git a/arch/arm/boot/dts/qcom/fg-gen3-batterydata-itech-3000mah.dtsi b/arch/arm/boot/dts/qcom/fg-gen3-batterydata-itech-3000mah.dtsi
index c3f23b75fa9c..d196a8074d8a 100644
--- a/arch/arm/boot/dts/qcom/fg-gen3-batterydata-itech-3000mah.dtsi
+++ b/arch/arm/boot/dts/qcom/fg-gen3-batterydata-itech-3000mah.dtsi
@@ -14,7 +14,7 @@ qcom,itech_3000mah {
/* #Itech_B00826LF_3000mAh_ver1660_averaged_MasterSlave_Jul20th2016*/
qcom,max-voltage-uv = <4350000>;
qcom,fg-cc-cv-threshold-mv = <4340>;
- qcom,nom-batt-capacity-mah = <3000>;
+ qcom,fastchg-current-ma = <3000>;
qcom,batt-id-kohm = <100>;
qcom,battery-beta = <3450>;
qcom,battery-type = "itech_b00826lf_3000mah_ver1660";
diff --git a/arch/arm/boot/dts/qcom/batterydata-qrd-skuk-4v4-3000mah.dtsi b/arch/arm/boot/dts/qcom/fg-gen3-batterydata-qrd-skuk-4v4-3000mah.dtsi
index ba3b33361ba1..e023a7700437 100644
--- a/arch/arm/boot/dts/qcom/batterydata-qrd-skuk-4v4-3000mah.dtsi
+++ b/arch/arm/boot/dts/qcom/fg-gen3-batterydata-qrd-skuk-4v4-3000mah.dtsi
@@ -12,7 +12,7 @@
qcom,qrd_msm8998_skuk_3000mah {
qcom,max-voltage-uv = <4400000>;
- qcom,nom-batt-capacity-mah = <3000>;
+ qcom,fastchg-current-ma = <3000>;
qcom,batt-id-kohm = <68>;
qcom,battery-beta = <3380>;
qcom,battery-type = "qrd_msm8998_skuk_300mah";
diff --git a/arch/arm/boot/dts/qcom/msm-pm2falcon.dtsi b/arch/arm/boot/dts/qcom/msm-pm2falcon.dtsi
index 8ec542d953e2..0f5c12856cc0 100644
--- a/arch/arm/boot/dts/qcom/msm-pm2falcon.dtsi
+++ b/arch/arm/boot/dts/qcom/msm-pm2falcon.dtsi
@@ -34,6 +34,13 @@
<PON_POWER_OFF_SHUTDOWN>;
};
+ qcom,temp-alarm@2400 {
+ compatible = "qcom,qpnp-temp-alarm";
+ reg = <0x2400 0x100>;
+ interrupts = <0x0 0x24 0x0 IRQ_TYPE_EDGE_RISING>;
+ label = "pm2falcon_tz";
+ };
+
pm2falcon_gpios: gpios {
compatible = "qcom,qpnp-pin";
gpio-controller;
diff --git a/arch/arm/boot/dts/qcom/msm-pmfalcon.dtsi b/arch/arm/boot/dts/qcom/msm-pmfalcon.dtsi
index 1cc31380604b..0168cb2cddb3 100644
--- a/arch/arm/boot/dts/qcom/msm-pmfalcon.dtsi
+++ b/arch/arm/boot/dts/qcom/msm-pmfalcon.dtsi
@@ -51,6 +51,15 @@
};
};
+ qcom,temp-alarm@2400 {
+ compatible = "qcom,qpnp-temp-alarm";
+ reg = <0x2400 0x100>;
+ interrupts = <0x0 0x24 0x0 IRQ_TYPE_EDGE_RISING>;
+ label = "pmfalcon_tz";
+ qcom,channel-num = <6>;
+ qcom,temp_alarm-vadc = <&pmfalcon_vadc>;
+ };
+
pmfalcon_gpios: gpios {
compatible = "qcom,qpnp-pin";
gpio-controller;
@@ -497,6 +506,7 @@
qcom,pmic-revid = <&pmfalcon_revid>;
io-channels = <&pmfalcon_rradc 0>;
io-channel-names = "rradc_batt_id";
+ qcom,rradc-base = <0x4500>;
qcom,fg-esr-timer-awake = <96>;
qcom,fg-esr-timer-asleep = <256>;
qcom,cycle-counter-en;
diff --git a/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi b/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi
index 0dc9da9289e2..3fa85d918f6c 100644
--- a/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi
+++ b/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi
@@ -321,6 +321,7 @@
qcom,pmic-revid = <&pmi8998_revid>;
io-channels = <&pmi8998_rradc 0>;
io-channel-names = "rradc_batt_id";
+ qcom,rradc-base = <0x4500>;
qcom,fg-esr-timer-awake = <96>;
qcom,fg-esr-timer-asleep = <256>;
qcom,cycle-counter-en;
diff --git a/arch/arm/boot/dts/qcom/msm8996-camera.dtsi b/arch/arm/boot/dts/qcom/msm8996-camera.dtsi
index 282e6bcb713b..ec07030092ca 100644
--- a/arch/arm/boot/dts/qcom/msm8996-camera.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8996-camera.dtsi
@@ -642,6 +642,8 @@
<106 512 0 0>,
<106 512 0 0>;
qcom,msm-bus-vector-dyn-vote;
+ qcom,src-clock-rates = <100000000 200000000 320000000
+ 480000000 640000000>;
qcom,cpp-fw-payload-info {
qcom,stripe-base = <553>;
qcom,plane-base = <481>;
diff --git a/arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-cdp.dtsi b/arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-cdp.dtsi
index 1a7f759f4b63..505b13aeb342 100644
--- a/arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-cdp.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-cdp.dtsi
@@ -327,6 +327,49 @@
qcom,clock-rates = <24000000 0>;
};
+ qcom,camera@1 {
+ cell-index = <1>;
+ compatible = "qcom,camera";
+ reg = <0x1>;
+ qcom,csiphy-sd-index = <1>;
+ qcom,csid-sd-index = <2>;
+ qcom,mount-angle = <90>;
+ cam_vio-supply = <&pmfalcon_l11>;
+ cam_vana-supply = <&pm2falcon_bob>;
+ cam_vdig-supply = <&pmfalcon_s5>;
+ qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig";
+ qcom,cam-vreg-min-voltage = <1780000 3300000 1350000>;
+ qcom,cam-vreg-max-voltage = <1950000 3600000 1350000>;
+ qcom,cam-vreg-op-mode = <105000 80000 105000>;
+ qcom,gpio-no-mux = <0>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk2_active
+ &cam_sensor_rear2_active>;
+ pinctrl-1 = <&cam_sensor_mclk2_suspend
+ &cam_sensor_rear2_suspend>;
+ gpios = <&tlmm 15 0>,
+ <&tlmm 9 0>,
+ <&pm2falcon_gpios 3 0>,
+ <&tlmm 8 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-vdig = <2>;
+ qcom,gpio-vana = <3>;
+ qcom,gpio-req-tbl-num = <0 1 2 3>;
+ qcom,gpio-req-tbl-flags = <1 0 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+ "CAM_RESET",
+ "CAM_VDIG",
+ "CAM_VANA";
+ qcom,sensor-position = <0>;
+ qcom,sensor-mode = <0>;
+ qcom,cci-master = <1>;
+ status = "ok";
+ clocks = <&clock_mmss clk_mclk2_clk_src>,
+ <&clock_mmss clk_mmss_camss_mclk2_clk>;
+ clock-names = "cam_src_clk", "cam_clk";
+ qcom,clock-rates = <24000000 0>;
+ };
+
qcom,camera@2 {
cell-index = <2>;
compatible = "qcom,camera";
diff --git a/arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-mtp.dtsi
index 1a7f759f4b63..505b13aeb342 100644
--- a/arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-mtp.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-mtp.dtsi
@@ -327,6 +327,49 @@
qcom,clock-rates = <24000000 0>;
};
+ qcom,camera@1 {
+ cell-index = <1>;
+ compatible = "qcom,camera";
+ reg = <0x1>;
+ qcom,csiphy-sd-index = <1>;
+ qcom,csid-sd-index = <2>;
+ qcom,mount-angle = <90>;
+ cam_vio-supply = <&pmfalcon_l11>;
+ cam_vana-supply = <&pm2falcon_bob>;
+ cam_vdig-supply = <&pmfalcon_s5>;
+ qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig";
+ qcom,cam-vreg-min-voltage = <1780000 3300000 1350000>;
+ qcom,cam-vreg-max-voltage = <1950000 3600000 1350000>;
+ qcom,cam-vreg-op-mode = <105000 80000 105000>;
+ qcom,gpio-no-mux = <0>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk2_active
+ &cam_sensor_rear2_active>;
+ pinctrl-1 = <&cam_sensor_mclk2_suspend
+ &cam_sensor_rear2_suspend>;
+ gpios = <&tlmm 15 0>,
+ <&tlmm 9 0>,
+ <&pm2falcon_gpios 3 0>,
+ <&tlmm 8 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-vdig = <2>;
+ qcom,gpio-vana = <3>;
+ qcom,gpio-req-tbl-num = <0 1 2 3>;
+ qcom,gpio-req-tbl-flags = <1 0 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+ "CAM_RESET",
+ "CAM_VDIG",
+ "CAM_VANA";
+ qcom,sensor-position = <0>;
+ qcom,sensor-mode = <0>;
+ qcom,cci-master = <1>;
+ status = "ok";
+ clocks = <&clock_mmss clk_mclk2_clk_src>,
+ <&clock_mmss clk_mmss_camss_mclk2_clk>;
+ clock-names = "cam_src_clk", "cam_clk";
+ qcom,clock-rates = <24000000 0>;
+ };
+
qcom,camera@2 {
cell-index = <2>;
compatible = "qcom,camera";
diff --git a/arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-qrd.dtsi b/arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-qrd.dtsi
new file mode 100644
index 000000000000..d10c2a25b301
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-qrd.dtsi
@@ -0,0 +1,511 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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.
+ */
+
+&soc {
+ tlmm: pinctrl@03400000 {
+ cam_sensor_rear_active: cam_sensor_rear_active {
+ /* RESET, STANDBY */
+ mux {
+ pins = "gpio9", "gpio8";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio9", "gpio8";
+ bias-disable; /* No PULL */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+
+ cam_sensor_rear_suspend: cam_sensor_rear_suspend {
+ /* RESET, STANDBY */
+ mux {
+ pins = "gpio9", "gpio8";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio9", "gpio8";
+ bias-disable; /* No PULL */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+
+ cam_sensor_rear2_active: cam_sensor_rear2_active {
+ /* RESET, STANDBY */
+ mux {
+ pins = "gpio30", "gpio8";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio30", "gpio8";
+ bias-disable; /* No PULL */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+
+ cam_sensor_rear2_suspend: cam_sensor_rear2_suspend {
+ /* RESET, STANDBY */
+ mux {
+ pins = "gpio30", "gpio8";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio30", "gpio8";
+ bias-disable; /* No PULL */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+
+ cam_sensor_front_active: cam_sensor_front_active {
+ /* RESET */
+ mux {
+ pins = "gpio28","gpio8";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio28","gpio8";
+ bias-disable; /* No PULL */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+ cam_sensor_front_suspend: cam_sensor_front_suspend {
+ /* RESET */
+ mux {
+ pins = "gpio28","gpio8";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio28","gpio8";
+ bias-disable; /* No PULL */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+
+ };
+
+ qcom,csiphy@ca34000 {
+ qcom,clock-rates = <0 0 0 0 0 0 384000000 0 0 269333333 0
+ 0 384000000 0>;
+ };
+
+ qcom,csiphy@ca35000 {
+ qcom,clock-rates = <0 0 0 0 0 0 384000000 0 0 269333333 0
+ 0 384000000 0>;
+ };
+
+ qcom,csiphy@ca36000 {
+ qcom,clock-rates = <0 0 0 0 0 0 384000000 0 0 269333333 0
+ 0 384000000 0>;
+ };
+
+ qcom,csid@ca30000 {
+ qcom,csi-vdd-voltage = <1200000>;
+ qcom,mipi-csi-vdd-supply = <&pmfalcon_l1>;
+ gdscr-supply = <&gdsc_camss_top>;
+ vdd_sec-supply = <&pm2falcon_l1>;
+ bimc_smmu-supply = <&gdsc_bimc_smmu>;
+ qcom,cam-vreg-name = "vdd_sec", "gdscr", "bimc_smmu";
+ qcom,cam-vreg-min-voltage = <925000 0 0>;
+ qcom,cam-vreg-max-voltage = <925000 0 0>;
+ qcom,cam-vreg-op-mode = <0 0 0>;
+ qcom,clock-rates = <0 0 0 0 0 0 0 384000000 384000000
+ 0 0 0 0 0>;
+ };
+
+ qcom,csid@ca30400 {
+ qcom,csi-vdd-voltage = <1200000>;
+ qcom,mipi-csi-vdd-supply = <&pmfalcon_l1>;
+ gdscr-supply = <&gdsc_camss_top>;
+ vdd_sec-supply = <&pm2falcon_l1>;
+ bimc_smmu-supply = <&gdsc_bimc_smmu>;
+ qcom,cam-vreg-name = "vdd_sec", "gdscr", "bimc_smmu";
+ qcom,cam-vreg-min-voltage = <925000 0 0>;
+ qcom,cam-vreg-max-voltage = <925000 0 0>;
+ qcom,cam-vreg-op-mode = <0 0 0>;
+ qcom,clock-rates = <0 0 0 0 0 0 0 384000000 384000000
+ 0 0 0 0 0>;
+ };
+
+ qcom,csid@ca30800 {
+ qcom,csi-vdd-voltage = <1200000>;
+ qcom,mipi-csi-vdd-supply = <&pmfalcon_l1>;
+ gdscr-supply = <&gdsc_camss_top>;
+ vdd_sec-supply = <&pm2falcon_l1>;
+ bimc_smmu-supply = <&gdsc_bimc_smmu>;
+ qcom,cam-vreg-name = "vdd_sec", "gdscr", "bimc_smmu";
+ qcom,cam-vreg-min-voltage = <925000 0 0>;
+ qcom,cam-vreg-max-voltage = <925000 0 0>;
+ qcom,cam-vreg-op-mode = <0 0 0>;
+ qcom,clock-rates = <0 0 0 0 0 0 0 384000000 384000000
+ 0 0 0 0 0>;
+ };
+
+ qcom,csid@ca30c00 {
+ qcom,csi-vdd-voltage = <1200000>;
+ qcom,mipi-csi-vdd-supply = <&pmfalcon_l1>;
+ gdscr-supply = <&gdsc_camss_top>;
+ vdd_sec-supply = <&pm2falcon_l1>;
+ bimc_smmu-supply = <&gdsc_bimc_smmu>;
+ qcom,cam-vreg-name = "vdd_sec", "gdscr", "bimc_smmu";
+ qcom,cam-vreg-min-voltage = <925000 0 0>;
+ qcom,cam-vreg-max-voltage = <925000 0 0>;
+ qcom,cam-vreg-op-mode = <0 0 0>;
+ qcom,clock-rates = <0 0 0 0 0 0 0 384000000 384000000
+ 0 0 0 0 0>;
+ };
+};
+
+&cci {
+ /delete-node/qcom,camera@0;
+ /delete-node/qcom,camera@1;
+ /delete-node/qcom,camera@2;
+ /delete-node/qcom,eeprom@0;
+ /delete-node/qcom,eeprom@1;
+ /delete-node/qcom,eeprom@2;
+ /delete-node/qcom,actuator@0;
+ /delete-node/qcom,actuator@1;
+ /delete-node/qcom,ois@0;
+};
+
+&cci {
+ actuator0: qcom,actuator@0 {
+ cell-index = <0>;
+ reg = <0x0>;
+ compatible = "qcom,actuator";
+ qcom,cci-master = <0>;
+ gpios = <&tlmm 27 0>;
+ qcom,gpio-vaf = <0>;
+ qcom,gpio-req-tbl-num = <0>;
+ qcom,gpio-req-tbl-flags = <0>;
+ qcom,gpio-req-tbl-label = "CAM_VAF";
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_actuator_vaf_active>;
+ pinctrl-1 = <&cam_actuator_vaf_suspend>;
+ };
+
+ actuator1: qcom,actuator@1 {
+ cell-index = <1>;
+ reg = <0x1>;
+ compatible = "qcom,actuator";
+ qcom,cci-master = <0>;
+ gpios = <&tlmm 27 0>;
+ qcom,gpio-vaf = <0>;
+ qcom,gpio-req-tbl-num = <0>;
+ qcom,gpio-req-tbl-flags = <0>;
+ qcom,gpio-req-tbl-label = "CAM_VAF";
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_actuator_vaf_active>;
+ pinctrl-1 = <&cam_actuator_vaf_suspend>;
+ };
+
+ ois0: qcom,ois@0 {
+ cell-index = <0>;
+ reg = <0x0>;
+ compatible = "qcom,ois";
+ qcom,cci-master = <0>;
+ gpios = <&tlmm 27 0>;
+ qcom,gpio-vaf = <0>;
+ qcom,gpio-req-tbl-num = <0>;
+ qcom,gpio-req-tbl-flags = <0>;
+ qcom,gpio-req-tbl-label = "CAM_VAF";
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_actuator_vaf_active>;
+ pinctrl-1 = <&cam_actuator_vaf_suspend>;
+ status = "disabled";
+ };
+
+ eeprom0: qcom,eeprom@0 {
+ cell-index = <0>;
+ reg = <0>;
+ compatible = "qcom,eeprom";
+ cam_vio-supply = <&pmfalcon_l11>;
+ cam_vana-supply = <&pm2falcon_bob>;
+ cam_vdig-supply = <&pmfalcon_s5>;
+ qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig";
+ qcom,cam-vreg-min-voltage = <1750000 3300000 1352000>;
+ qcom,cam-vreg-max-voltage = <1980000 3600000 1352000>;
+ qcom,cam-vreg-op-mode = <105000 80000 105000>;
+ qcom,gpio-no-mux = <0>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk0_active
+ &cam_sensor_rear_active>;
+ pinctrl-1 = <&cam_sensor_mclk0_suspend
+ &cam_sensor_rear_suspend>;
+ gpios = <&tlmm 13 0>,
+ <&tlmm 9 0>,
+ <&pm2falcon_gpios 4 0>,
+ <&tlmm 8 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-vdig = <2>;
+ qcom,gpio-vana = <3>;
+ qcom,gpio-req-tbl-num = <0 1 2 3>;
+ qcom,gpio-req-tbl-flags = <1 0 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK0",
+ "CAM_RESET0",
+ "CAM_VDIG",
+ "CAM_VANA";
+ qcom,sensor-position = <0>;
+ qcom,sensor-mode = <0>;
+ qcom,cci-master = <0>;
+ status = "ok";
+ clocks = <&clock_mmss clk_mclk0_clk_src>,
+ <&clock_mmss clk_mmss_camss_mclk0_clk>;
+ clock-names = "cam_src_clk", "cam_clk";
+ qcom,clock-rates = <24000000 0>;
+ };
+
+ eeprom1: qcom,eeprom@1 {
+ cell-index = <1>;
+ reg = <0x1>;
+ compatible = "qcom,eeprom";
+ cam_vio-supply = <&pmfalcon_l11>;
+ cam_vana-supply = <&pm2falcon_bob>;
+ cam_vdig-supply = <&pmfalcon_s5>;
+ qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig";
+ qcom,cam-vreg-min-voltage = <1750000 3300000 1350000>;
+ qcom,cam-vreg-max-voltage = <1980000 3600000 1350000>;
+ qcom,cam-vreg-op-mode = <105000 80000 105000>;
+ qcom,gpio-no-mux = <0>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk2_active
+ &cam_sensor_rear2_active>;
+ pinctrl-1 = <&cam_sensor_mclk2_suspend
+ &cam_sensor_rear2_suspend>;
+ gpios = <&tlmm 15 0>,
+ <&tlmm 30 0>,
+ <&pm2falcon_gpios 4 0>,
+ <&tlmm 8 0>,
+ <&tlmm 27 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-vdig = <2>;
+ qcom,gpio-vana = <3>;
+ qcom,gpio-vaf = <4>;
+ qcom,gpio-req-tbl-num = <0 1 2 3 4>;
+ qcom,gpio-req-tbl-flags = <1 0 0 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK1",
+ "CAM_RESET1",
+ "CAM_VDIG1",
+ "CAM_VANA1",
+ "CAM_VAF";
+ qcom,sensor-position = <0>;
+ qcom,sensor-mode = <0>;
+ qcom,cci-master = <0>;
+ status = "ok";
+ clocks = <&clock_mmss clk_mclk2_clk_src>,
+ <&clock_mmss clk_mmss_camss_mclk2_clk>;
+ clock-names = "cam_src_clk", "cam_clk";
+ qcom,clock-rates = <24000000 0>;
+ };
+
+ eeprom2: qcom,eeprom@2 {
+ cell-index = <2>;
+ reg = <0x2>;
+ compatible = "qcom,eeprom";
+ cam_vio-supply = <&pmfalcon_l11>;
+ cam_vana-supply = <&pm2falcon_bob>;
+ cam_vdig-supply = <&pmfalcon_s5>;
+ qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig";
+ qcom,cam-vreg-min-voltage = <1780000 33000000 1352000>;
+ qcom,cam-vreg-max-voltage = <1950000 36000000 1352000>;
+ qcom,cam-vreg-op-mode = <105000 80000 105000>;
+ qcom,gpio-no-mux = <0>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk1_active
+ &cam_sensor_front_active>;
+ pinctrl-1 = <&cam_sensor_mclk1_suspend
+ &cam_sensor_front_suspend>;
+ gpios = <&tlmm 14 0>,
+ <&tlmm 28 0>,
+ <&pm2falcon_gpios 3 0>,
+ <&tlmm 8 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-vdig = <2>;
+ qcom,gpio-vana = <3>;
+ qcom,gpio-req-tbl-num = <0 1 2 3>;
+ qcom,gpio-req-tbl-flags = <1 0 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK2",
+ "CAM_RESET2",
+ "CAM_VDIG",
+ "CAM_VANA";
+ qcom,sensor-position = <1>;
+ qcom,sensor-mode = <0>;
+ qcom,cci-master = <1>;
+ status = "ok";
+ clocks = <&clock_mmss clk_mclk1_clk_src>,
+ <&clock_mmss clk_mmss_camss_mclk1_clk>;
+ clock-names = "cam_src_clk", "cam_clk";
+ qcom,clock-rates = <24000000 0>;
+ };
+
+ qcom,camera@0 {
+ cell-index = <0>;
+ compatible = "qcom,camera";
+ reg = <0x0>;
+ qcom,csiphy-sd-index = <0>;
+ qcom,csid-sd-index = <0>;
+ qcom,mount-angle = <90>;
+ qcom,actuator-src = <&actuator0>;
+ /*qcom,ois-src = <&ois0>;*/
+ qcom,eeprom-src = <&eeprom0>;
+ cam_vio-supply = <&pmfalcon_l11>;
+ cam_vana-supply = <&pm2falcon_bob>;
+ cam_vdig-supply = <&pmfalcon_s5>;
+ qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig";
+ qcom,cam-vreg-min-voltage = <1780000 3300000 1350000>;
+ qcom,cam-vreg-max-voltage = <1950000 3600000 1350000>;
+ qcom,cam-vreg-op-mode = <105000 80000 105000>;
+ qcom,gpio-no-mux = <0>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk0_active
+ &cam_sensor_rear_active>;
+ pinctrl-1 = <&cam_sensor_mclk0_suspend
+ &cam_sensor_rear_suspend>;
+ gpios = <&tlmm 13 0>,
+ <&tlmm 9 0>,
+ <&pm2falcon_gpios 4 0>,
+ <&tlmm 8 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-vdig = <2>;
+ qcom,gpio-vana = <3>;
+ qcom,gpio-req-tbl-num = <0 1 2 3>;
+ qcom,gpio-req-tbl-flags = <1 0 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK2",
+ "CAM_RESET0",
+ "CAM_VDIG",
+ "CAM_VANA";
+ qcom,sensor-position = <0>;
+ qcom,sensor-mode = <0>;
+ qcom,cci-master = <0>;
+ status = "ok";
+ clocks = <&clock_mmss clk_mclk0_clk_src>,
+ <&clock_mmss clk_mmss_camss_mclk0_clk>;
+ clock-names = "cam_src_clk", "cam_clk";
+ qcom,clock-rates = <24000000 0>;
+ };
+
+ qcom,camera@1 {
+ cell-index = <1>;
+ compatible = "qcom,camera";
+ reg = <0x1>;
+ qcom,csiphy-sd-index = <1>;
+ qcom,csid-sd-index = <1>;
+ qcom,mount-angle = <90>;
+ qcom,actuator-src = <&actuator1>;
+ qcom,eeprom-src = <&eeprom1>;
+ cam_vio-supply = <&pmfalcon_l11>;
+ cam_vana-supply = <&pm2falcon_bob>;
+ cam_vdig-supply = <&pmfalcon_s5>;
+ qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig";
+ qcom,cam-vreg-min-voltage = <1780000 3300000 1350000>;
+ qcom,cam-vreg-max-voltage = <1950000 3600000 1350000>;
+ qcom,cam-vreg-op-mode = <105000 80000 105000>;
+ qcom,gpio-no-mux = <0>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk2_active
+ &cam_sensor_rear2_active>;
+ pinctrl-1 = <&cam_sensor_mclk2_suspend
+ &cam_sensor_rear2_suspend>;
+ gpios = <&tlmm 15 0>,
+ <&tlmm 30 0>,
+ <&pm2falcon_gpios 4 0>,
+ <&tlmm 8 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-vdig = <2>;
+ qcom,gpio-vana = <3>;
+ qcom,gpio-req-tbl-num = <0 1 2 3>;
+ qcom,gpio-req-tbl-flags = <1 0 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK1",
+ "CAM_RESET1",
+ "CAM_VDIG1",
+ "CAM_VANA1";
+ qcom,sensor-position = <0>;
+ qcom,sensor-mode = <0>;
+ qcom,cci-master = <0>;
+ status = "ok";
+ clocks = <&clock_mmss clk_mclk2_clk_src>,
+ <&clock_mmss clk_mmss_camss_mclk2_clk>;
+ clock-names = "cam_src_clk", "cam_clk";
+ qcom,clock-rates = <24000000 0>;
+ };
+
+ qcom,camera@2 {
+ cell-index = <2>;
+ compatible = "qcom,camera";
+ reg = <0x02>;
+ qcom,csiphy-sd-index = <2>;
+ qcom,csid-sd-index = <2>;
+ qcom,mount-angle = <270>;
+ /*qcom,eeprom-src = <&eeprom2>;*/
+ cam_vio-supply = <&pmfalcon_l11>;
+ cam_vana-supply = <&pm2falcon_bob>;
+ cam_vdig-supply = <&pmfalcon_s5>;
+ qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig";
+ qcom,cam-vreg-min-voltage = <1780000 3300000 1350000>;
+ qcom,cam-vreg-max-voltage = <1950000 3600000 1350000>;
+ qcom,cam-vreg-op-mode = <105000 80000 105000>;
+ qcom,gpio-no-mux = <0>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk1_active
+ &cam_sensor_front_active>;
+ pinctrl-1 = <&cam_sensor_mclk1_suspend
+ &cam_sensor_front_suspend>;
+ gpios = <&tlmm 14 0>,
+ <&tlmm 28 0>,
+ <&pm2falcon_gpios 3 0>,
+ <&tlmm 8 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-vdig = <2>;
+ qcom,gpio-vana = <3>;
+ qcom,gpio-req-tbl-num = <0 1 2 3>;
+ qcom,gpio-req-tbl-flags = <1 0 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK2",
+ "CAM_RESET2",
+ "CAM_VDIG",
+ "CAM_VANA";
+ qcom,sensor-position = <1>;
+ qcom,sensor-mode = <0>;
+ qcom,cci-master = <1>;
+ status = "ok";
+ clocks = <&clock_mmss clk_mclk1_clk_src>,
+ <&clock_mmss clk_mmss_camss_mclk1_clk>;
+ clock-names = "cam_src_clk", "cam_clk";
+ qcom,clock-rates = <24000000 0>;
+ };
+};
+
+&pm2falcon_gpios {
+ gpio@c300 { /* GPIO4 -CAMERA SENSOR 0 VDIG*/
+ qcom,mode = <1>; /* Output */
+ qcom,pull = <5>; /* No Pull */
+ qcom,vin-sel = <0>; /* VIN1 GPIO_LV */
+ qcom,src-sel = <0>; /* GPIO */
+ qcom,invert = <0>; /* Invert */
+ qcom,master-en = <1>; /* Enable GPIO */
+ status = "ok";
+ };
+
+ gpio@c200 { /* GPIO3 -CAMERA SENSOR 2 VDIG*/
+ qcom,mode = <1>; /* Output */
+ qcom,pull = <5>; /* No Pull */
+ qcom,vin-sel = <0>; /* VIN1 GPIO_LV */
+ qcom,src-sel = <0>; /* GPIO */
+ qcom,invert = <0>; /* Invert */
+ qcom,master-en = <1>; /* Enable GPIO */
+ status = "ok";
+ };
+};
diff --git a/arch/arm/boot/dts/qcom/msm8998-qrd-skuk.dtsi b/arch/arm/boot/dts/qcom/msm8998-qrd-skuk.dtsi
index f60fd10b92f8..dcd84e79ba1b 100644
--- a/arch/arm/boot/dts/qcom/msm8998-qrd-skuk.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-qrd-skuk.dtsi
@@ -243,8 +243,7 @@
/{
qrd_batterydata: qcom,battery-data {
qcom,batt-id-range-pct = <15>;
-
- #include "batterydata-qrd-skuk-4v4-3000mah.dtsi"
+ #include "fg-gen3-batterydata-qrd-skuk-4v4-3000mah.dtsi"
};
};
diff --git a/arch/arm/boot/dts/qcom/msm8998-qrd-vr1.dtsi b/arch/arm/boot/dts/qcom/msm8998-qrd-vr1.dtsi
index bd9d8147dd82..2d1616412caa 100644
--- a/arch/arm/boot/dts/qcom/msm8998-qrd-vr1.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-qrd-vr1.dtsi
@@ -159,8 +159,7 @@
/{
qrd_batterydata: qcom,battery-data {
qcom,batt-id-range-pct = <15>;
-
- #include "batterydata-qrd-skuk-4v4-3000mah.dtsi"
+ #include "fg-gen3-batterydata-qrd-skuk-4v4-3000mah.dtsi"
};
};
diff --git a/arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-msmfalcon-cdp.dts b/arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-msmfalcon-cdp.dts
index aae66d41966f..e88ee107e280 100644
--- a/arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-msmfalcon-cdp.dts
+++ b/arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-msmfalcon-cdp.dts
@@ -87,6 +87,23 @@
status = "ok";
};
+&usb3 {
+ extcon = <&pmfalcon_pdphy>;
+};
+
+&qusb_phy0 {
+ vdd-supply = <&pm2falcon_l1>;
+ vdda18-supply = <&pmfalcon_l10>;
+ qcom,vdd-voltage-level = <0 925000 925000>;
+ vdda33-supply = <&pm2falcon_l7>;
+};
+
+&ssphy {
+ vdd-supply = <&pm2falcon_l1>;
+ qcom,vdd-voltage-level = <0 925000 925000>;
+ core-supply = <&pmfalcon_l1>;
+};
+
&mdss_dsi {
hw-config = "split_dsi";
vdda-1p2-supply = <&pmfalcon_l1>;
diff --git a/arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-msmfalcon-mtp.dts b/arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-msmfalcon-mtp.dts
index b0e687f967be..ccc94307277d 100644
--- a/arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-msmfalcon-mtp.dts
+++ b/arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-msmfalcon-mtp.dts
@@ -133,6 +133,23 @@
qcom,panel-mode-gpio = <&tlmm 91 0>;
};
+&usb3 {
+ extcon = <&pmfalcon_pdphy>;
+};
+
+&qusb_phy0 {
+ vdd-supply = <&pm2falcon_l1>;
+ vdda18-supply = <&pmfalcon_l10>;
+ qcom,vdd-voltage-level = <0 925000 925000>;
+ vdda33-supply = <&pm2falcon_l7>;
+};
+
+&ssphy {
+ vdd-supply = <&pm2falcon_l1>;
+ qcom,vdd-voltage-level = <0 925000 925000>;
+ core-supply = <&pmfalcon_l1>;
+};
+
&pm2falcon_gpios {
/* GPIO 7 for VOL_UP */
gpio@c600 {
diff --git a/arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-msmfalcon-qrd.dts b/arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-msmfalcon-qrd.dts
index 013c849c4936..cf313cfea768 100644
--- a/arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-msmfalcon-qrd.dts
+++ b/arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-msmfalcon-qrd.dts
@@ -16,7 +16,7 @@
#include "msm8998-v2.1-interposer-msmfalcon-qrd.dtsi"
#include "msm8998-interposer-pmfalcon.dtsi"
#include "msm8998-interposer-msmfalcon-audio.dtsi"
-#include "msm8998-interposer-camera-sensor-mtp.dtsi"
+#include "msm8998-interposer-camera-sensor-qrd.dtsi"
/ {
model =
diff --git a/arch/arm/boot/dts/qcom/msm8998.dtsi b/arch/arm/boot/dts/qcom/msm8998.dtsi
index c265eafcdd30..8deeafccb89b 100644
--- a/arch/arm/boot/dts/qcom/msm8998.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998.dtsi
@@ -2037,10 +2037,9 @@
clock-names = "xo", "iface_clk", "bus_clk",
"mem_clk", "gpll0_mss_clk", "snoc_axi_clk",
"mnoc_axi_clk", "qdss_clk";
- qcom,proxy-clock-names = "xo", "qdss_clk";
- qcom,active-clock-names = "iface_clk", "bus_clk", "mem_clk",
- "gpll0_mss_clk", "snoc_axi_clk",
- "mnoc_axi_clk";
+ qcom,proxy-clock-names = "xo", "qdss_clk", "mem_clk";
+ qcom,active-clock-names = "iface_clk", "bus_clk",
+ "gpll0_mss_clk", "snoc_axi_clk", "mnoc_axi_clk";
interrupts = <0 448 1>;
vdd_cx-supply = <&pm8998_s1_level>;
@@ -2051,7 +2050,6 @@
qcom,pil-self-auth;
qcom,sysmon-id = <0>;
qcom,ssctl-instance-id = <0x12>;
- qcom,override-acc;
qcom,qdsp6v62-1-2;
status = "ok";
memory-region = <&modem_mem>;
diff --git a/arch/arm/boot/dts/qcom/msmfalcon-cdp.dtsi b/arch/arm/boot/dts/qcom/msmfalcon-cdp.dtsi
index 3ec991b82bba..ff14003877d1 100644
--- a/arch/arm/boot/dts/qcom/msmfalcon-cdp.dtsi
+++ b/arch/arm/boot/dts/qcom/msmfalcon-cdp.dtsi
@@ -20,5 +20,26 @@
pinctrl-0 = <&uart_console_active>;
};
+&ufsphy1 {
+ vdda-phy-supply = <&pm2falcon_l1>;
+ vdda-pll-supply = <&pmfalcon_l10>;
+ vddp-ref-clk-supply = <&pmfalcon_l1>;
+ vdda-phy-max-microamp = <51400>;
+ vdda-pll-max-microamp = <14200>;
+ vddp-ref-clk-max-microamp = <100>;
+ vddp-ref-clk-always-on;
+ status = "ok";
+};
+
+&ufs1 {
+ vdd-hba-supply = <&gdsc_ufs>;
+ vdd-hba-fixed-regulator;
+ vcc-supply = <&pm2falcon_l4>;
+ vccq2-supply = <&pmfalcon_l8>;
+ vcc-max-microamp = <500000>;
+ vccq2-max-microamp = <600000>;
+ status = "ok";
+};
+
&soc {
};
diff --git a/arch/arm/boot/dts/qcom/msmfalcon-gpu.dtsi b/arch/arm/boot/dts/qcom/msmfalcon-gpu.dtsi
index 76fc9f9c5e31..111eca7aef22 100644
--- a/arch/arm/boot/dts/qcom/msmfalcon-gpu.dtsi
+++ b/arch/arm/boot/dts/qcom/msmfalcon-gpu.dtsi
@@ -111,6 +111,26 @@
vddcx-supply = <&gdsc_gpu_cx>;
vdd-supply = <&gdsc_gpu_gx>;
+ /* GPU Mempools */
+ qcom,gpu-mempools {
+ #address-cells= <1>;
+ #size-cells = <0>;
+ compatible = "qcom,gpu-mempools";
+
+ qcom,mempool-max-pages = <32768>;
+
+ /* 4K Page Pool configuration */
+ qcom,gpu-mempool@0 {
+ reg = <0>;
+ qcom,mempool-page-size = <4096>;
+ };
+ /* 64K Page Pool configuration */
+ qcom,gpu-mempool@1 {
+ reg = <1>;
+ qcom,mempool-page-size = <65536>;
+ };
+ };
+
/* Power levels */
qcom,gpu-pwrlevels {
#address-cells = <1>;
diff --git a/arch/arm/boot/dts/qcom/msmfalcon-mtp.dtsi b/arch/arm/boot/dts/qcom/msmfalcon-mtp.dtsi
index 3ec991b82bba..ff14003877d1 100644
--- a/arch/arm/boot/dts/qcom/msmfalcon-mtp.dtsi
+++ b/arch/arm/boot/dts/qcom/msmfalcon-mtp.dtsi
@@ -20,5 +20,26 @@
pinctrl-0 = <&uart_console_active>;
};
+&ufsphy1 {
+ vdda-phy-supply = <&pm2falcon_l1>;
+ vdda-pll-supply = <&pmfalcon_l10>;
+ vddp-ref-clk-supply = <&pmfalcon_l1>;
+ vdda-phy-max-microamp = <51400>;
+ vdda-pll-max-microamp = <14200>;
+ vddp-ref-clk-max-microamp = <100>;
+ vddp-ref-clk-always-on;
+ status = "ok";
+};
+
+&ufs1 {
+ vdd-hba-supply = <&gdsc_ufs>;
+ vdd-hba-fixed-regulator;
+ vcc-supply = <&pm2falcon_l4>;
+ vccq2-supply = <&pmfalcon_l8>;
+ vcc-max-microamp = <500000>;
+ vccq2-max-microamp = <600000>;
+ status = "ok";
+};
+
&soc {
};
diff --git a/arch/arm/boot/dts/qcom/msmfalcon-pinctrl.dtsi b/arch/arm/boot/dts/qcom/msmfalcon-pinctrl.dtsi
index a029d8689111..6951cdf96815 100644
--- a/arch/arm/boot/dts/qcom/msmfalcon-pinctrl.dtsi
+++ b/arch/arm/boot/dts/qcom/msmfalcon-pinctrl.dtsi
@@ -760,5 +760,33 @@
bias-disable;
};
};
+
+ tlmm_gpio_key {
+ gpio_key_active: gpio_key_active {
+ mux {
+ pins = "gpio64", "gpio113";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio64", "gpio113";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+
+ gpio_key_suspend: gpio_key_suspend {
+ mux {
+ pins = "gpio64", "gpio113";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio64", "gpio113";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+ };
};
};
diff --git a/arch/arm/boot/dts/qcom/msmfalcon-qrd.dts b/arch/arm/boot/dts/qcom/msmfalcon-qrd.dts
new file mode 100644
index 000000000000..229676f17456
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/msmfalcon-qrd.dts
@@ -0,0 +1,23 @@
+/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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 "msmfalcon.dtsi"
+#include "msmfalcon-qrd.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. MSM FALCON QRD";
+ compatible = "qcom,msmfalcon-qrd", "qcom,msmfalcon", "qcom,qrd";
+ qcom,board-id = <0x1000b 0>;
+};
diff --git a/arch/arm/boot/dts/qcom/msmfalcon-qrd.dtsi b/arch/arm/boot/dts/qcom/msmfalcon-qrd.dtsi
new file mode 100644
index 000000000000..3ec991b82bba
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/msmfalcon-qrd.dtsi
@@ -0,0 +1,24 @@
+/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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 "msmfalcon-pinctrl.dtsi"
+/ {
+};
+
+&uartblsp1dm1 {
+ status = "ok";
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart_console_active>;
+};
+
+&soc {
+};
diff --git a/arch/arm/boot/dts/qcom/msmfalcon-rumi.dts b/arch/arm/boot/dts/qcom/msmfalcon-rumi.dts
index d952c3b5e299..ab61ee115782 100644
--- a/arch/arm/boot/dts/qcom/msmfalcon-rumi.dts
+++ b/arch/arm/boot/dts/qcom/msmfalcon-rumi.dts
@@ -117,3 +117,23 @@
compatible = "qcom,dummycc";
clock-output-names = "mmss_clocks";
};
+
+&ufsphy1 {
+ vdda-phy-supply = <&pm2falcon_l1>;
+ vdda-pll-supply = <&pmfalcon_l10>;
+ vddp-ref-clk-supply = <&pmfalcon_l1>;
+ vdda-phy-max-microamp = <51400>;
+ vdda-pll-max-microamp = <14200>;
+ vddp-ref-clk-max-microamp = <100>;
+ vddp-ref-clk-always-on;
+};
+
+&ufs1 {
+ vdd-hba-supply = <&gdsc_ufs>;
+ vdd-hba-fixed-regulator;
+ vcc-supply = <&pm2falcon_l4>;
+ vccq2-supply = <&pmfalcon_l8>;
+ vcc-max-microamp = <500000>;
+ vccq2-max-microamp = <600000>;
+ qcom,disable-lpm;
+};
diff --git a/arch/arm/boot/dts/qcom/msmfalcon-sim.dts b/arch/arm/boot/dts/qcom/msmfalcon-sim.dts
index fe92f40d786f..80772bab86e4 100644
--- a/arch/arm/boot/dts/qcom/msmfalcon-sim.dts
+++ b/arch/arm/boot/dts/qcom/msmfalcon-sim.dts
@@ -86,3 +86,24 @@
&pmfalcon_pdphy {
status = "disabled";
};
+
+&ufsphy1 {
+ vdda-phy-supply = <&pm2falcon_l1>;
+ vdda-pll-supply = <&pmfalcon_l10>;
+ vddp-ref-clk-supply = <&pmfalcon_l1>;
+ vdda-phy-max-microamp = <51400>;
+ vdda-pll-max-microamp = <14200>;
+ vddp-ref-clk-max-microamp = <100>;
+ vddp-ref-clk-always-on;
+ status = "ok";
+};
+
+&ufs1 {
+ vdd-hba-supply = <&gdsc_ufs>;
+ vdd-hba-fixed-regulator;
+ vcc-supply = <&pm2falcon_l4>;
+ vccq2-supply = <&pmfalcon_l8>;
+ vcc-max-microamp = <500000>;
+ vccq2-max-microamp = <600000>;
+ status = "ok";
+};
diff --git a/arch/arm/boot/dts/qcom/msmfalcon.dtsi b/arch/arm/boot/dts/qcom/msmfalcon.dtsi
index 572a896ad795..ce6c5cf6c9b1 100644
--- a/arch/arm/boot/dts/qcom/msmfalcon.dtsi
+++ b/arch/arm/boot/dts/qcom/msmfalcon.dtsi
@@ -322,6 +322,25 @@
size = <0x0 0x5c00000>;
};
};
+
+ bluetooth: bt_wcn3990 {
+ compatible = "qca,wcn3990";
+ qca,bt-vdd-core-supply = <&pmfalcon_l9_pin_ctrl>;
+ qca,bt-vdd-pa-supply = <&pmfalcon_l6_pin_ctrl>;
+ qca,bt-vdd-ldo-supply = <&pmfalcon_l19_pin_ctrl>;
+ qca,bt-chip-pwd-supply = <&pm2falcon_bob_pin1>;
+ clocks = <&clock_rpmcc RPM_RF_CLK1>;
+ clock-names = "rf_clk1";
+
+ qca,bt-vdd-core-voltage-level = <1800000 1900000>;
+ qca,bt-vdd-pa-voltage-level = <1304000 1370000>;
+ qca,bt-vdd-ldo-voltage-level = <3312000 3400000>;
+ qca,bt-chip-pwd-voltage-level = <3600000 3600000>;
+
+ qca,bt-vdd-core-current-level = <1>; /* LPM/PFM */
+ qca,bt-vdd-pa-current-level = <1>; /* LPM/PFM */
+ qca,bt-vdd-ldo-current-level = <1>; /* LPM/PFM */
+ };
};
#include "msmfalcon-smp2p.dtsi"
@@ -706,6 +725,11 @@
};
};
+ qcom,lmh {
+ compatible = "qcom,lmh_v1";
+ interrupts = <GIC_SPI 134 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
qcom,msm-core@780000 {
compatible = "qcom,apss-core-ea";
reg = <0x780000 0x1000>;
@@ -1353,7 +1377,6 @@
qcom,pil-self-auth;
qcom,sysmon-id = <0>;
qcom,ssctl-instance-id = <0x12>;
- qcom,override-acc;
qcom,qdsp6v62-1-5;
memory-region = <&modem_fw_mem>;
qcom,mem-protect-id = <0xF>;
@@ -1413,6 +1436,11 @@
compatible = "qcom,msm-imem-pil";
reg = <0x94c 200>;
};
+
+ diag_dload@c8 {
+ compatible = "qcom,msm-imem-diag-dload";
+ reg = <0xc8 200>;
+ };
};
qcom,ghd {
@@ -1565,6 +1593,85 @@
qcom,config-arr = <0x178880b8 0x178980b8
0x178a80b8 0x178b80b8>;
};
+
+ ufsphy1: ufsphy@1da7000 {
+ compatible = "qcom,ufs-phy-qmp-v3-falcon";
+ reg = <0x1da7000 0xdb8>;
+ reg-names = "phy_mem";
+ #phy-cells = <0>;
+ clock-names = "ref_clk_src",
+ "ref_clk",
+ "ref_aux_clk";
+ clocks = <&clock_rpmcc RPM_LN_BB_CLK1>,
+ <&clock_gcc GCC_UFS_CLKREF_CLK>,
+ <&clock_gcc GCC_UFS_PHY_AUX_CLK>;
+ status = "disabled";
+ };
+
+ ufs1: ufshc@1da4000 {
+ compatible = "qcom,ufshc";
+ reg = <0x1da4000 0x3000>;
+ interrupts = <0 265 0>;
+ phys = <&ufsphy1>;
+ phy-names = "ufsphy";
+
+ clock-names =
+ "core_clk",
+ "bus_aggr_clk",
+ "iface_clk",
+ "core_clk_unipro",
+ "core_clk_ice",
+ "ref_clk",
+ "tx_lane0_sync_clk",
+ "rx_lane0_sync_clk";
+ clocks =
+ <&clock_gcc GCC_UFS_AXI_CLK>,
+ <&clock_gcc GCC_AGGRE2_UFS_AXI_CLK>,
+ <&clock_gcc GCC_UFS_AHB_CLK>,
+ <&clock_gcc GCC_UFS_UNIPRO_CORE_CLK>,
+ <&clock_gcc GCC_UFS_ICE_CORE_CLK>,
+ <&clock_rpmcc RPM_LN_BB_CLK1>,
+ <&clock_gcc GCC_UFS_TX_SYMBOL_0_CLK>,
+ <&clock_gcc GCC_UFS_RX_SYMBOL_0_CLK>;
+ freq-table-hz =
+ <50000000 200000000>,
+ <0 0>,
+ <0 0>,
+ <37500000 150000000>,
+ <75000000 300000000>,
+ <0 0>,
+ <0 0>,
+ <0 0>;
+
+ lanes-per-direction = <1>;
+
+ qcom,msm-bus,name = "ufs1";
+ qcom,msm-bus,num-cases = <12>;
+ qcom,msm-bus,num-paths = <2>;
+ qcom,msm-bus,vectors-KBps =
+ <95 512 0 0>, <1 650 0 0>, /* No vote */
+ <95 512 922 0>, <1 650 1000 0>, /* PWM G1 */
+ <95 512 1844 0>, <1 650 1000 0>, /* PWM G2 */
+ <95 512 3688 0>, <1 650 1000 0>, /* PWM G3 */
+ <95 512 7376 0>, <1 650 1000 0>, /* PWM G4 */
+ <95 512 127796 0>, <1 650 1000 0>, /* HS G1 RA */
+ <95 512 255591 0>, <1 650 1000 0>, /* HS G2 RA */
+ <95 512 2097152 0>, <1 650 102400 0>, /* HS G3 RA */
+ <95 512 149422 0>, <1 650 1000 0>, /* HS G1 RB */
+ <95 512 298189 0>, <1 650 1000 0>, /* HS G2 RB */
+ <95 512 2097152 0>, <1 650 102400 0>, /* HS G3 RB */
+ <95 512 7643136 0>, <1 650 307200 0>; /* Max. bandwidth */
+ qcom,bus-vector-names = "MIN",
+ "PWM_G1_L1", "PWM_G2_L1", "PWM_G3_L1", "PWM_G4_L1",
+ "HS_RA_G1_L1", "HS_RA_G2_L1", "HS_RA_G3_L1",
+ "HS_RB_G1_L1", "HS_RB_G2_L1", "HS_RB_G3_L1",
+ "MAX";
+
+ resets = <&clock_gcc GCC_UFS_BCR>;
+ reset-names = "core_reset";
+
+ status = "disabled";
+ };
};
#include "msmfalcon-ion.dtsi"
@@ -1672,9 +1779,28 @@
&soc {
gpio_keys {
+ status = "okay";
compatible = "gpio-keys";
input-name = "gpio-keys";
- status = "okay";
+ pinctrl-names = "tlmm_gpio_key_active","tlmm_gpio_key_suspend";
+ pinctrl-0 = <&gpio_key_active>;
+ pinctrl-1 = <&gpio_key_suspend>;
+
+ camera_focus {
+ label = "camera_focus";
+ gpios = <&tlmm 64 0x1>;
+ linux,input-type = <1>;
+ linux,code = <0x210>;
+ debounce-interval = <15>;
+ };
+
+ camera_snapshot {
+ label = "camera_snapshot";
+ gpios = <&tlmm 113 0x1>;
+ linux,input-type = <1>;
+ linux,code = <0x2fe>;
+ debounce-interval = <15>;
+ };
vol_up {
label = "volume_up";
diff --git a/arch/arm/boot/dts/qcom/msmtriton-regulator.dtsi b/arch/arm/boot/dts/qcom/msmtriton-regulator.dtsi
index 323024278406..2201a04cfbc1 100644
--- a/arch/arm/boot/dts/qcom/msmtriton-regulator.dtsi
+++ b/arch/arm/boot/dts/qcom/msmtriton-regulator.dtsi
@@ -10,351 +10,483 @@
* GNU General Public License for more details.
*/
-/* Stub regulators */
-
-/ {
- /* PMFALCON S1 - VDD_APC0 supply */
- pmfalcon_s1: regulator-pmfalcon-s1 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pmfalcon_s1";
- qcom,hpm-min-load = <100000>;
- regulator-min-microvolt = <565000>;
- regulator-max-microvolt = <1170000>;
- };
-
- /* PMFALCON S2 + S3 = VDD_APC1 supply */
- pmfalcon_s2: regulator-pmfalcon-s2 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pmfalcon_s2";
- qcom,hpm-min-load = <100000>;
- regulator-min-microvolt = <565000>;
- regulator-max-microvolt = <1170000>;
- };
-
- pmfalcon_s4: regulator-pmfalcon-s4 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pmfalcon_s4";
- qcom,hpm-min-load = <100000>;
- regulator-min-microvolt = <1805000>;
- regulator-max-microvolt = <2040000>;
- };
-
- pmfalcon_s5: regulator-pmfalcon-s5 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pmfalcon_s5";
- qcom,hpm-min-load = <100000>;
- regulator-min-microvolt = <1350000>;
- regulator-max-microvolt = <1350000>;
- };
-
- pmfalcon_s6: regulator-pmfalcon-s6 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pmfalcon_s6";
- qcom,hpm-min-load = <100000>;
- regulator-min-microvolt = <504000>;
- regulator-max-microvolt = <992000>;
- };
-
- pm2falcon_s1: regulator-pm2falcon-s1 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm2falcon_s1";
- qcom,hpm-min-load = <100000>;
- regulator-min-microvolt = <1125000>;
- regulator-max-microvolt = <1125000>;
- };
-
- pm2falcon_s2: regulator-pm2falcon-s2 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm2falcon_s2";
- qcom,hpm-min-load = <100000>;
- regulator-min-microvolt = <1050000>;
- regulator-max-microvolt = <1050000>;
- };
-
- /* PMFALCON S3 + S4 - VDD_CX supply */
- pm2falcon_s3_level: regulator-pm2falcon-s3-level {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm2falcon_s3_level";
- qcom,hpm-min-load = <100000>;
- regulator-min-microvolt = <RPM_SMD_REGULATOR_LEVEL_RETENTION>;
- regulator-max-microvolt = <RPM_SMD_REGULATOR_LEVEL_TURBO>;
- };
-
- pm2falcon_s3_floor_level: regulator-pm2falcon-s3-floor-level {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm2falcon_s3_floor_level";
- qcom,hpm-min-load = <100000>;
- regulator-min-microvolt = <RPM_SMD_REGULATOR_LEVEL_RETENTION>;
- regulator-max-microvolt = <RPM_SMD_REGULATOR_LEVEL_TURBO>;
- };
-
- pm2falcon_s3_level_ao: regulator-pm2falcon-s3-level-ao {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm2falcon_s3_level_ao";
- qcom,hpm-min-load = <100000>;
- regulator-min-microvolt = <RPM_SMD_REGULATOR_LEVEL_RETENTION>;
- regulator-max-microvolt = <RPM_SMD_REGULATOR_LEVEL_TURBO>;
- };
-
- /* PMFALCON S5 - VDD_MX supply */
- pm2falcon_s5_level: regulator-pm2falcon-s5-level {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm2falcon_s5_level";
- qcom,hpm-min-load = <100000>;
- regulator-min-microvolt = <RPM_SMD_REGULATOR_LEVEL_RETENTION>;
- regulator-max-microvolt = <RPM_SMD_REGULATOR_LEVEL_TURBO>;
- };
-
- pm2falcon_s5_floor_level: regulator-pm2falcon-s5-floor-level {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm2falcon_s5_floor_level";
- qcom,hpm-min-load = <100000>;
- regulator-min-microvolt = <RPM_SMD_REGULATOR_LEVEL_RETENTION>;
- regulator-max-microvolt = <RPM_SMD_REGULATOR_LEVEL_TURBO>;
- };
-
- pm2falcon_s5_level_ao: regulator-pm2falcon-s5-level-ao {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm2falcon_s5_level_ao";
- qcom,hpm-min-load = <100000>;
- regulator-min-microvolt = <RPM_SMD_REGULATOR_LEVEL_RETENTION>;
- regulator-max-microvolt = <RPM_SMD_REGULATOR_LEVEL_TURBO>;
- };
-
- pmfalcon_l1: regulator-pmfalcon-l1 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pmfalcon_l1";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1150000>;
- regulator-max-microvolt = <1250000>;
- };
-
- pmfalcon_l2: regulator-pmfalcon-l2 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pmfalcon_l2";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <950000>;
- regulator-max-microvolt = <1010000>;
- };
-
- pmfalcon_l3: regulator-pmfalcon-l3 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pmfalcon_l3";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <950000>;
- regulator-max-microvolt = <1010000>;
- };
-
- /* TODO: remove if ADRASTEA CX/MX not voted from APPS */
- pmfalcon_l5: regulator-pmfalcon-l5 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pmfalcon_l5";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <525000>;
- regulator-max-microvolt = <950000>;
- };
-
- pmfalcon_l6: regulator-pmfalcon-l6 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pmfalcon_l6";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1200000>;
- regulator-max-microvolt = <1370000>;
- };
-
- pmfalcon_l7: regulator-pmfalcon-l7 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pmfalcon_l7";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1200000>;
- regulator-max-microvolt = <1200000>;
- };
-
- pmfalcon_l8: regulator-pmfalcon-l8 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pmfalcon_l8";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1750000>;
- regulator-max-microvolt = <1900000>;
- };
-
- pmfalcon_l9: regulator-pmfalcon-l9 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pmfalcon_l9";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1750000>;
- regulator-max-microvolt = <1900000>;
- };
-
- pmfalcon_l10: regulator-pmfalcon-l10 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pmfalcon_l10";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1780000>;
- regulator-max-microvolt = <1950000>;
- };
-
- pmfalcon_l11: regulator-pmfalcon-l11 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pmfalcon_l11";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1780000>;
- regulator-max-microvolt = <1950000>;
- };
-
- pmfalcon_l12: regulator-pmfalcon-l12 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pmfalcon_l12";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1780000>;
- regulator-max-microvolt = <1950000>;
- };
-
- pmfalcon_l13: regulator-pmfalcon-l13 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pmfalcon_l13";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1750000>;
- regulator-max-microvolt = <1950000>;
- };
-
- pmfalcon_l14: regulator-pmfalcon-l14 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pmfalcon_l14";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1710000>;
- regulator-max-microvolt = <1900000>;
- };
-
- pmfalcon_l15: regulator-pmfalcon-l15 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pmfalcon_l15";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1650000>;
- regulator-max-microvolt = <2950000>;
- };
-
- pmfalcon_l17: regulator-pmfalcon-l17 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pmfalcon_l17";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1650000>;
- regulator-max-microvolt = <2950000>;
- };
-
- pmfalcon_l19: regulator-pmfalcon-l19 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pmfalcon_l19";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <3200000>;
- regulator-max-microvolt = <3400000>;
- };
-
- pm2falcon_l1: regulator-pm2falcon-l1 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm2falcon_l1";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <800000>;
- regulator-max-microvolt = <925000>;
- };
-
- pm2falcon_l2: regulator-pm2falcon-l2 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm2falcon_l2";
- qcom,hpm-min-load = <5000>;
- regulator-min-microvolt = <350000>;
- regulator-max-microvolt = <3100000>;
- };
-
- pm2falcon_l3: regulator-pm2falcon-l3 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm2falcon_l3";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1710000>;
- regulator-max-microvolt = <3600000>;
- };
-
- pm2falcon_l4: regulator-pm2falcon-l4 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm2falcon_l4";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1700000>;
- regulator-max-microvolt = <2950000>;
- };
-
- pm2falcon_l5: regulator-pm2falcon-l5 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm2falcon_l5";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1721000>;
- regulator-max-microvolt = <3600000>;
- };
-
- pm2falcon_l6: regulator-pm2falcon-l6 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm2falcon_l6";
- qcom,hpm-min-load = <5000>;
- regulator-min-microvolt = <1700000>;
- regulator-max-microvolt = <3300000>;
- };
-
- pm2falcon_l7: regulator-pm2falcon-l7 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm2falcon_l7";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <2700000>;
- regulator-max-microvolt = <3125000>;
- };
-
- pm2falcon_l8: regulator-pm2falcon-l8 {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm2falcon_l8";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <3200000>;
- regulator-max-microvolt = <3400000>;
- };
-
- /* PMFALCON L9 = VDD_SSC_CX supply */
- pm2falcon_l9_level: regulator-pm2falcon-l9-level {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm2falcon_l9_level";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <RPM_SMD_REGULATOR_LEVEL_RETENTION>;
- regulator-max-microvolt = <RPM_SMD_REGULATOR_LEVEL_TURBO>;
- };
-
- pm2falcon_l9_floor_level: regulator-pm2falcon-l9-floor-level {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm2falcon_l9_floor_level";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <RPM_SMD_REGULATOR_LEVEL_RETENTION>;
- regulator-max-microvolt = <RPM_SMD_REGULATOR_LEVEL_TURBO>;
- };
-
- /* PMFALCON L10 = VDD_SSC_MX supply */
- pm2falcon_l10_level: regulator-pm2falcon-l10-level {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm2falcon_l10_level";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <RPM_SMD_REGULATOR_LEVEL_RETENTION>;
- regulator-max-microvolt = <RPM_SMD_REGULATOR_LEVEL_TURBO>;
+&rpm_bus {
+ rpm-regulator-smpa4 {
+ status = "okay";
+ pmfalcon_s4: regulator-s4 {
+ regulator-min-microvolt = <1805000>;
+ regulator-max-microvolt = <2040000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-smpa5 {
+ status = "okay";
+ pmfalcon_s5: regulator-s5 {
+ regulator-min-microvolt = <1350000>;
+ regulator-max-microvolt = <1350000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-smpa6 {
+ status = "okay";
+ pmfalcon_s6: regulator-s6 {
+ regulator-min-microvolt = <504000>;
+ regulator-max-microvolt = <992000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-smpb1 {
+ status = "okay";
+ pm2falcon_s1: regulator-s1 {
+ regulator-min-microvolt = <1125000>;
+ regulator-max-microvolt = <1125000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-smpb2 {
+ status = "okay";
+ pm2falcon_s2: regulator-s2 {
+ regulator-min-microvolt = <1050000>;
+ regulator-max-microvolt = <1050000>;
+ status = "okay";
+ };
+ };
+
+ /* PM2FALCON S3 + S4 - VDD_CX supply */
+ rpm-regulator-smpb3 {
+ status = "okay";
+ pm2falcon_s3_level: regulator-s3-level {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm2falcon_s3_level";
+ qcom,set = <3>;
+ regulator-min-microvolt =
+ <RPM_SMD_REGULATOR_LEVEL_RETENTION>;
+ regulator-max-microvolt =
+ <RPM_SMD_REGULATOR_LEVEL_TURBO>;
+ qcom,use-voltage-level;
+ };
+
+ pm2falcon_s3_floor_level: regulator-s3-floor-level {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm2falcon_s3_floor_level";
+ qcom,set = <3>;
+ regulator-min-microvolt =
+ <RPM_SMD_REGULATOR_LEVEL_RETENTION>;
+ regulator-max-microvolt =
+ <RPM_SMD_REGULATOR_LEVEL_TURBO>;
+ qcom,use-voltage-floor-level;
+ qcom,always-send-voltage;
+ };
+
+ pm2falcon_s3_level_ao: regulator-s3-level-ao {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm2falcon_s3_level_ao";
+ qcom,set = <1>;
+ regulator-min-microvolt =
+ <RPM_SMD_REGULATOR_LEVEL_RETENTION>;
+ regulator-max-microvolt =
+ <RPM_SMD_REGULATOR_LEVEL_TURBO>;
+ qcom,use-voltage-level;
+ };
+ };
+
+ /* PM2FALCON S5 - VDD_MX supply */
+ rpm-regulator-smpb5 {
+ status = "okay";
+ pm2falcon_s5_level: regulator-s5-level {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm2falcon_s5_level";
+ qcom,set = <3>;
+ regulator-min-microvolt =
+ <RPM_SMD_REGULATOR_LEVEL_RETENTION>;
+ regulator-max-microvolt =
+ <RPM_SMD_REGULATOR_LEVEL_TURBO>;
+ qcom,use-voltage-level;
+ };
+
+ pm2falcon_s5_floor_level: regulator-s5-floor-level {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm2falcon_s5_floor_level";
+ qcom,set = <3>;
+ regulator-min-microvolt =
+ <RPM_SMD_REGULATOR_LEVEL_RETENTION>;
+ regulator-max-microvolt =
+ <RPM_SMD_REGULATOR_LEVEL_TURBO>;
+ qcom,use-voltage-floor-level;
+ qcom,always-send-voltage;
+ };
+
+ pm2falcon_s5_level_ao: regulator-s5-level-ao {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm2falcon_s5_level_ao";
+ qcom,set = <1>;
+ regulator-min-microvolt =
+ <RPM_SMD_REGULATOR_LEVEL_RETENTION>;
+ regulator-max-microvolt =
+ <RPM_SMD_REGULATOR_LEVEL_TURBO>;
+ qcom,use-voltage-level;
+ };
+ };
+
+ rpm-regulator-ldoa1 {
+ status = "okay";
+ pmfalcon_l1: regulator-l1 {
+ regulator-min-microvolt = <1150000>;
+ regulator-max-microvolt = <1250000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa2 {
+ status = "okay";
+ pmfalcon_l2: regulator-l2 {
+ regulator-min-microvolt = <950000>;
+ regulator-max-microvolt = <1010000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa3 {
+ status = "okay";
+ pmfalcon_l3: regulator-l3 {
+ regulator-min-microvolt = <950000>;
+ regulator-max-microvolt = <1010000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa5 {
+ status = "okay";
+ pmfalcon_l5: regulator-l5 {
+ regulator-min-microvolt = <525000>;
+ regulator-max-microvolt = <950000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa6 {
+ status = "okay";
+ pmfalcon_l6: regulator-l6 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1370000>;
+ status = "okay";
+ };
+
+ pmfalcon_l6_pin_ctrl: regulator-l6-pin-ctrl {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pmfalcon_l6_pin_ctrl";
+ qcom,set = <3>;
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1370000>;
+ /* Force NPM follows HW_EN1 */
+ qcom,init-pin-ctrl-mode = <2>;
+ /* Enable follows HW_EN1 */
+ qcom,enable-with-pin-ctrl = <0 2>;
+ };
+ };
+
+ rpm-regulator-ldoa7 {
+ status = "okay";
+ pmfalcon_l7: regulator-l7 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa8 {
+ status = "okay";
+ pmfalcon_l8: regulator-l8 {
+ regulator-min-microvolt = <1750000>;
+ regulator-max-microvolt = <1900000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa9 {
+ status = "okay";
+ pmfalcon_l9: regulator-l9 {
+ regulator-min-microvolt = <1750000>;
+ regulator-max-microvolt = <1900000>;
+ status = "okay";
+ };
+
+ pmfalcon_l9_pin_ctrl: regulator-l9-pin-ctrl {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pmfalcon_l9_pin_ctrl";
+ qcom,set = <3>;
+ regulator-min-microvolt = <1750000>;
+ regulator-max-microvolt = <1900000>;
+ /* Force NPM follows HW_EN1 */
+ qcom,init-pin-ctrl-mode = <2>;
+ /* Enable follows HW_EN1 */
+ qcom,enable-with-pin-ctrl = <0 2>;
+ };
+ };
+
+ rpm-regulator-ldoa10 {
+ status = "okay";
+ pmfalcon_l10: regulator-l10 {
+ regulator-min-microvolt = <1780000>;
+ regulator-max-microvolt = <1950000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa11 {
+ status = "okay";
+ pmfalcon_l11: regulator-l11 {
+ regulator-min-microvolt = <1780000>;
+ regulator-max-microvolt = <1950000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa12 {
+ status = "okay";
+ pmfalcon_l12: regulator-l12 {
+ regulator-min-microvolt = <1780000>;
+ regulator-max-microvolt = <1950000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa13 {
+ status = "okay";
+ pmfalcon_l13: regulator-l13 {
+ regulator-min-microvolt = <1780000>;
+ regulator-max-microvolt = <1950000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa14 {
+ status = "okay";
+ pmfalcon_l14: regulator-l14 {
+ regulator-min-microvolt = <1710000>;
+ regulator-max-microvolt = <1900000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa15 {
+ status = "okay";
+ pmfalcon_l15: regulator-l15 {
+ regulator-min-microvolt = <1650000>;
+ regulator-max-microvolt = <2950000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa17 {
+ status = "okay";
+ pmfalcon_l17: regulator-l17 {
+ regulator-min-microvolt = <1650000>;
+ regulator-max-microvolt = <2950000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa19 {
+ status = "okay";
+ pmfalcon_l19: regulator-l19 {
+ regulator-min-microvolt = <3200000>;
+ regulator-max-microvolt = <3400000>;
+ status = "okay";
+ };
+
+ pmfalcon_l19_pin_ctrl: regulator-l19-pin-ctrl {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pmfalcon_l19_pin_ctrl";
+ qcom,set = <3>;
+ regulator-min-microvolt = <3200000>;
+ regulator-max-microvolt = <3400000>;
+ /* Force NPM follows HW_EN1 */
+ qcom,init-pin-ctrl-mode = <2>;
+ /* Enable follows HW_EN1 */
+ qcom,enable-with-pin-ctrl = <0 2>;
+ };
+ };
+
+ rpm-regulator-ldob1 {
+ status = "okay";
+ pm2falcon_l1: regulator-l1 {
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <925000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldob2 {
+ status = "okay";
+ pm2falcon_l2: regulator-l2 {
+ regulator-min-microvolt = <350000>;
+ regulator-max-microvolt = <3100000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldob3 {
+ status = "okay";
+ pm2falcon_l3: regulator-l3 {
+ regulator-min-microvolt = <1710000>;
+ regulator-max-microvolt = <3600000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldob4 {
+ status = "okay";
+ pm2falcon_l4: regulator-l4 {
+ regulator-min-microvolt = <1700000>;
+ regulator-max-microvolt = <2950000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldob5 {
+ status = "okay";
+ pm2falcon_l5: regulator-l5 {
+ regulator-min-microvolt = <1721000>;
+ regulator-max-microvolt = <3600000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldob6 {
+ status = "okay";
+ pm2falcon_l6: regulator-l6 {
+ regulator-min-microvolt = <1700000>;
+ regulator-max-microvolt = <3300000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldob7 {
+ status = "okay";
+ pm2falcon_l7: regulator-l7 {
+ regulator-min-microvolt = <2700000>;
+ regulator-max-microvolt = <3125000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldob8 {
+ status = "okay";
+ pm2falcon_l8: regulator-l8 {
+ regulator-min-microvolt = <3200000>;
+ regulator-max-microvolt = <3400000>;
+ status = "okay";
+ };
+ };
+
+ /* PM2FALCON L9 = VDD_SSC_CX supply */
+ rpm-regulator-ldob9 {
+ status = "okay";
+ pm2falcon_l9_level: regulator-l9-level {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm2falcon_l9_level";
+ qcom,set = <3>;
+ regulator-min-microvolt =
+ <RPM_SMD_REGULATOR_LEVEL_RETENTION>;
+ regulator-max-microvolt =
+ <RPM_SMD_REGULATOR_LEVEL_TURBO>;
+ qcom,use-voltage-level;
+ };
+
+ pm2falcon_l9_floor_level: regulator-l9-floor-level {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm2falcon_l9_floor_level";
+ qcom,set = <3>;
+ regulator-min-microvolt =
+ <RPM_SMD_REGULATOR_LEVEL_RETENTION>;
+ regulator-max-microvolt =
+ <RPM_SMD_REGULATOR_LEVEL_TURBO>;
+ qcom,use-voltage-floor-level;
+ qcom,always-send-voltage;
+ };
+ };
+
+ /* PM2FALCON L10 = VDD_SSC_MX supply */
+ rpm-regulator-ldob10 {
+ status = "okay";
+ pm2falcon_l10_level: regulator-l10-level {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm2falcon_l10_level";
+ qcom,set = <3>;
+ regulator-min-microvolt =
+ <RPM_SMD_REGULATOR_LEVEL_RETENTION>;
+ regulator-max-microvolt =
+ <RPM_SMD_REGULATOR_LEVEL_TURBO>;
+ qcom,use-voltage-level;
+ };
+
+ pm2falcon_l10_floor_level: regulator-l10-floor-level {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm2falcon_l10_floor_level";
+ qcom,set = <3>;
+ regulator-min-microvolt =
+ <RPM_SMD_REGULATOR_LEVEL_RETENTION>;
+ regulator-max-microvolt =
+ <RPM_SMD_REGULATOR_LEVEL_TURBO>;
+ qcom,use-voltage-floor-level;
+ qcom,always-send-voltage;
+ };
+ };
+
+ rpm-regulator-bobb {
+ status = "okay";
+ pm2falcon_bob: regulator-bob {
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3600000>;
+ status = "okay";
+ };
+
+ pm2falcon_bob_pin1: regulator-bob-pin1 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm2falcon_bob_pin1";
+ qcom,set = <3>;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3600000>;
+ qcom,use-pin-ctrl-voltage1;
+ };
+
+ pm2falcon_bob_pin2: regulator-bob-pin2 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm2falcon_bob_pin2";
+ qcom,set = <3>;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3600000>;
+ qcom,use-pin-ctrl-voltage2;
+ };
+
+ pm2falcon_bob_pin3: regulator-bob-pin3 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm2falcon_bob_pin3";
+ qcom,set = <3>;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3600000>;
+ qcom,use-pin-ctrl-voltage3;
+ };
};
+};
- pm2falcon_l10_floor_level: regulator-pm2falcon-l10-floor-level {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm2falcon_l10_floor_level";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <RPM_SMD_REGULATOR_LEVEL_RETENTION>;
- regulator-max-microvolt = <RPM_SMD_REGULATOR_LEVEL_TURBO>;
+&pmfalcon_charger {
+ smb2_vbus: qcom,smb2-vbus {
+ regulator-name = "smb2-vbus";
};
- pm2falcon_bob: regulator-pm2falcon-bob {
- compatible = "qcom,stub-regulator";
- regulator-name = "pm2falcon_bob";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
+ smb2_vconn: qcom,smb2-vconn {
+ regulator-name = "smb2-vconn";
};
+};
+/* Stub regulators */
+/ {
/* GFX Supply */
gfx_vreg_corner: regulator-gfx-corner {
compatible = "qcom,stub-regulator";
diff --git a/arch/arm/boot/dts/qcom/msmtriton.dtsi b/arch/arm/boot/dts/qcom/msmtriton.dtsi
index dfa592c16643..e577a5692d90 100644
--- a/arch/arm/boot/dts/qcom/msmtriton.dtsi
+++ b/arch/arm/boot/dts/qcom/msmtriton.dtsi
@@ -902,7 +902,6 @@
qcom,pil-self-auth;
qcom,sysmon-id = <0>;
qcom,ssctl-instance-id = <0x12>;
- qcom,override-acc;
qcom,qdsp6v62-1-5;
memory-region = <&modem_fw_mem>;
qcom,mem-protect-id = <0xF>;
@@ -961,6 +960,11 @@
compatible = "qcom,msm-imem-pil";
reg = <0x94c 200>;
};
+
+ diag_dload@c8 {
+ compatible = "qcom,msm-imem-diag-dload";
+ reg = <0xc8 200>;
+ };
};
qcom,ghd {
@@ -1003,9 +1007,34 @@
qcom,config-arr = <0x178880b8 0x178980b8
0x178a80b8 0x178b80b8>;
};
+
+ spmi_bus: qcom,spmi@800f000 {
+ compatible = "qcom,spmi-pmic-arb";
+ reg = <0x800f000 0x1000>,
+ <0x8400000 0x1000000>,
+ <0x9400000 0x1000000>,
+ <0xa400000 0x220000>,
+ <0x800a000 0x3000>;
+ reg-names = "core", "chnls", "obsrvr", "intr", "cnfg";
+ interrupt-names = "periph_irq";
+ interrupts = <GIC_SPI 326 IRQ_TYPE_NONE>;
+ qcom,ee = <0>;
+ qcom,channel = <0>;
+ #address-cells = <2>;
+ #size-cells = <0>;
+ interrupt-controller;
+ #interrupt-cells = <4>;
+ cell-index = <0>;
+ qcom,not-wakeup; /* Needed until Full-boot-chain enabled */
+ status = "ok";
+ };
};
#include "msmtriton-ion.dtsi"
+#include "msm-pmfalcon.dtsi"
+#include "msm-pm2falcon.dtsi"
+#include "msm-pmfalcon-rpm-regulator.dtsi"
+#include "msm-pm2falcon-rpm-regulator.dtsi"
#include "msmtriton-regulator.dtsi"
#include "msm-gdsc-falcon.dtsi"
#include "msmfalcon-common.dtsi"
diff --git a/arch/arm/configs/msmfalcon-perf_defconfig b/arch/arm/configs/msmfalcon-perf_defconfig
index 6f26912a318d..b47866ae1826 100644
--- a/arch/arm/configs/msmfalcon-perf_defconfig
+++ b/arch/arm/configs/msmfalcon-perf_defconfig
@@ -94,6 +94,7 @@ CONFIG_INET_AH=y
CONFIG_INET_ESP=y
CONFIG_INET_IPCOMP=y
# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG_DESTROY=y
CONFIG_IPV6_ROUTER_PREF=y
CONFIG_IPV6_ROUTE_INFO=y
CONFIG_IPV6_OPTIMISTIC_DAD=y
@@ -274,6 +275,7 @@ CONFIG_PPPOLAC=y
CONFIG_PPPOPNS=y
CONFIG_PPP_ASYNC=y
CONFIG_PPP_SYNC_TTY=y
+CONFIG_USB_USBNET=y
CONFIG_WCNSS_MEM_PRE_ALLOC=y
CONFIG_ATH_CARDS=y
CONFIG_CLD_LL_CORE=y
@@ -415,6 +417,8 @@ CONFIG_USB_GADGET=y
CONFIG_USB_GADGET_VBUS_DRAW=500
CONFIG_USB_CONFIGFS=y
CONFIG_USB_CONFIGFS_NCM=y
+CONFIG_USB_CONFIGFS_QCRNDIS=y
+CONFIG_USB_CONFIGFS_RMNET_BAM=y
CONFIG_USB_CONFIGFS_MASS_STORAGE=y
CONFIG_USB_CONFIGFS_F_FS=y
CONFIG_USB_CONFIGFS_F_MTP=y
@@ -527,6 +531,7 @@ CONFIG_MSM_SERVICE_NOTIFIER=y
CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y
CONFIG_MSM_RPM_LOG=y
CONFIG_MSM_RPM_STATS_LOG=y
+CONFIG_QCOM_SMCINVOKE=y
CONFIG_MEM_SHARE_QMI_SERVICE=y
CONFIG_QCOM_BIMC_BWMON=y
CONFIG_ARM_MEMLAT_MON=y
@@ -587,7 +592,6 @@ CONFIG_PID_IN_CONTEXTIDR=y
CONFIG_DEBUG_SET_MODULE_RONX=y
CONFIG_CORESIGHT=y
CONFIG_CORESIGHT_EVENT=y
-CONFIG_CORESIGHT_LINKS_AND_SINKS=y
CONFIG_CORESIGHT_QCOM_REPLICATOR=y
CONFIG_CORESIGHT_STM=y
CONFIG_CORESIGHT_HWEVENT=y
diff --git a/arch/arm/configs/msmfalcon_defconfig b/arch/arm/configs/msmfalcon_defconfig
index 7ff481c87614..693588045aed 100644
--- a/arch/arm/configs/msmfalcon_defconfig
+++ b/arch/arm/configs/msmfalcon_defconfig
@@ -93,6 +93,7 @@ CONFIG_INET_AH=y
CONFIG_INET_ESP=y
CONFIG_INET_IPCOMP=y
# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG_DESTROY=y
CONFIG_IPV6_ROUTER_PREF=y
CONFIG_IPV6_ROUTE_INFO=y
CONFIG_IPV6_OPTIMISTIC_DAD=y
@@ -273,6 +274,7 @@ CONFIG_PPPOLAC=y
CONFIG_PPPOPNS=y
CONFIG_PPP_ASYNC=y
CONFIG_PPP_SYNC_TTY=y
+CONFIG_USB_USBNET=y
CONFIG_WCNSS_MEM_PRE_ALLOC=y
CONFIG_ATH_CARDS=y
CONFIG_CLD_LL_CORE=y
@@ -416,6 +418,8 @@ CONFIG_USB_GADGET=y
CONFIG_USB_GADGET_VBUS_DRAW=500
CONFIG_USB_CONFIGFS=y
CONFIG_USB_CONFIGFS_NCM=y
+CONFIG_USB_CONFIGFS_QCRNDIS=y
+CONFIG_USB_CONFIGFS_RMNET_BAM=y
CONFIG_USB_CONFIGFS_MASS_STORAGE=y
CONFIG_USB_CONFIGFS_F_FS=y
CONFIG_USB_CONFIGFS_F_MTP=y
@@ -516,6 +520,7 @@ CONFIG_PANIC_ON_GLADIATOR_ERROR_V2=y
CONFIG_MSM_GLADIATOR_HANG_DETECT=y
CONFIG_MSM_CORE_HANG_DETECT=y
CONFIG_MSM_RUN_QUEUE_STATS=y
+# CONFIG_MSM_JTAGV8 is not set
CONFIG_MSM_BOOT_STATS=y
CONFIG_QCOM_CPUSS_DUMP=y
CONFIG_MSM_QDSP6_APRV2_GLINK=y
@@ -535,6 +540,7 @@ CONFIG_MSM_SERVICE_NOTIFIER=y
CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y
CONFIG_MSM_RPM_LOG=y
CONFIG_MSM_RPM_STATS_LOG=y
+CONFIG_QCOM_SMCINVOKE=y
CONFIG_QCOM_EARLY_RANDOM=y
CONFIG_MEM_SHARE_QMI_SERVICE=y
CONFIG_QCOM_BIMC_BWMON=y
@@ -625,7 +631,8 @@ CONFIG_PID_IN_CONTEXTIDR=y
CONFIG_DEBUG_SET_MODULE_RONX=y
CONFIG_CORESIGHT=y
CONFIG_CORESIGHT_EVENT=y
-CONFIG_CORESIGHT_LINKS_AND_SINKS=y
+CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y
+CONFIG_CORESIGHT_SOURCE_ETM4X=y
CONFIG_CORESIGHT_REMOTE_ETM=y
CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0
CONFIG_CORESIGHT_QCOM_REPLICATOR=y
diff --git a/arch/arm64/configs/msm-perf_defconfig b/arch/arm64/configs/msm-perf_defconfig
index 42eb9054513a..4226060cb6fc 100644
--- a/arch/arm64/configs/msm-perf_defconfig
+++ b/arch/arm64/configs/msm-perf_defconfig
@@ -258,6 +258,7 @@ CONFIG_BONDING=y
CONFIG_DUMMY=y
CONFIG_TUN=y
CONFIG_MSM_RMNET_MHI=y
+CONFIG_RNDIS_IPA=y
CONFIG_PPP=y
CONFIG_PPP_BSDCOMP=y
CONFIG_PPP_DEFLATE=y
@@ -434,7 +435,9 @@ CONFIG_USB_CONFIGFS=y
CONFIG_USB_CONFIGFS_SERIAL=y
CONFIG_USB_CONFIGFS_NCM=y
CONFIG_USB_CONFIGFS_ECM=y
+CONFIG_USB_CONFIGFS_QCRNDIS=y
CONFIG_USB_CONFIGFS_RNDIS=y
+CONFIG_USB_CONFIGFS_RMNET_BAM=y
CONFIG_USB_CONFIGFS_MASS_STORAGE=y
CONFIG_USB_CONFIGFS_F_FS=y
CONFIG_USB_CONFIGFS_F_MTP=y
diff --git a/arch/arm64/configs/msm_defconfig b/arch/arm64/configs/msm_defconfig
index 37f9f5e985ca..720dc8ba3be4 100644
--- a/arch/arm64/configs/msm_defconfig
+++ b/arch/arm64/configs/msm_defconfig
@@ -250,6 +250,7 @@ CONFIG_BONDING=y
CONFIG_DUMMY=y
CONFIG_TUN=y
CONFIG_MSM_RMNET_MHI=y
+CONFIG_RNDIS_IPA=y
CONFIG_PPP=y
CONFIG_PPP_BSDCOMP=y
CONFIG_PPP_DEFLATE=y
@@ -419,7 +420,9 @@ CONFIG_USB_CONFIGFS=y
CONFIG_USB_CONFIGFS_SERIAL=y
CONFIG_USB_CONFIGFS_NCM=y
CONFIG_USB_CONFIGFS_ECM=y
+CONFIG_USB_CONFIGFS_QCRNDIS=y
CONFIG_USB_CONFIGFS_RNDIS=y
+CONFIG_USB_CONFIGFS_RMNET_BAM=y
CONFIG_USB_CONFIGFS_MASS_STORAGE=y
CONFIG_USB_CONFIGFS_F_FS=y
CONFIG_USB_CONFIGFS_F_MTP=y
diff --git a/arch/arm64/configs/msmcortex-perf_defconfig b/arch/arm64/configs/msmcortex-perf_defconfig
index 60bb033be6df..85ce3e119ebc 100644
--- a/arch/arm64/configs/msmcortex-perf_defconfig
+++ b/arch/arm64/configs/msmcortex-perf_defconfig
@@ -592,8 +592,6 @@ CONFIG_DEBUG_RODATA=y
CONFIG_DEBUG_ALIGN_RODATA=y
CONFIG_CORESIGHT=y
CONFIG_CORESIGHT_EVENT=y
-CONFIG_CORESIGHT_LINKS_AND_SINKS=y
-CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y
CONFIG_CORESIGHT_QCOM_REPLICATOR=y
CONFIG_CORESIGHT_STM=y
CONFIG_CORESIGHT_HWEVENT=y
diff --git a/arch/arm64/configs/msmfalcon-perf_defconfig b/arch/arm64/configs/msmfalcon-perf_defconfig
index c02d63f57b8f..10c988472268 100644
--- a/arch/arm64/configs/msmfalcon-perf_defconfig
+++ b/arch/arm64/configs/msmfalcon-perf_defconfig
@@ -443,6 +443,8 @@ CONFIG_USB_GADGET=y
CONFIG_USB_GADGET_VBUS_DRAW=500
CONFIG_USB_CONFIGFS=y
CONFIG_USB_CONFIGFS_NCM=y
+CONFIG_USB_CONFIGFS_QCRNDIS=y
+CONFIG_USB_CONFIGFS_RMNET_BAM=y
CONFIG_USB_CONFIGFS_MASS_STORAGE=y
CONFIG_USB_CONFIGFS_F_FS=y
CONFIG_USB_CONFIGFS_F_MTP=y
diff --git a/arch/arm64/configs/msmfalcon_defconfig b/arch/arm64/configs/msmfalcon_defconfig
index e812762562ab..702952ceafa0 100644
--- a/arch/arm64/configs/msmfalcon_defconfig
+++ b/arch/arm64/configs/msmfalcon_defconfig
@@ -271,6 +271,7 @@ CONFIG_PPPOLAC=y
CONFIG_PPPOPNS=y
CONFIG_PPP_ASYNC=y
CONFIG_PPP_SYNC_TTY=y
+CONFIG_USB_USBNET=y
CONFIG_WCNSS_MEM_PRE_ALLOC=y
CONFIG_ATH_CARDS=y
CONFIG_WIL6210=m
@@ -444,6 +445,8 @@ CONFIG_USB_GADGET=y
CONFIG_USB_GADGET_VBUS_DRAW=500
CONFIG_USB_CONFIGFS=y
CONFIG_USB_CONFIGFS_NCM=y
+CONFIG_USB_CONFIGFS_QCRNDIS=y
+CONFIG_USB_CONFIGFS_RMNET_BAM=y
CONFIG_USB_CONFIGFS_MASS_STORAGE=y
CONFIG_USB_CONFIGFS_F_FS=y
CONFIG_USB_CONFIGFS_F_MTP=y
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 1046c262b46b..8e3bff9c7fe9 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -606,13 +606,20 @@ config TILE_SROM
source "drivers/char/xillybus/Kconfig"
config MSM_ADSPRPC
- tristate "Qualcomm ADSP RPC driver"
- depends on MSM_SMD
- help
- Provides a communication mechanism that allows for clients to
- make remote method invocations across processor boundary to
- applications DSP processor. Say M if you want to enable this
- module.
+ tristate "QTI ADSP RPC driver"
+ depends on MSM_SMD
+ help
+ Provides a communication mechanism that allows for clients to
+ make remote method invocations across processor boundary to
+ applications DSP processor. Say M if you want to enable this
+ module.
+
+config MSM_RDBG
+ tristate "QTI Remote debug driver"
+ help
+ Implements a shared memory based transport mechanism that allows
+ for a debugger running on a host PC to communicate with a remote
+ stub running on peripheral subsystems such as the ADSP, MODEM etc.
endmenu
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index e180562c725e..7b0bd5408324 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -65,3 +65,4 @@ obj-$(CONFIG_MSM_ADSPRPC) += adsprpc.o
ifdef CONFIG_COMPAT
obj-$(CONFIG_MSM_ADSPRPC) += adsprpc_compat.o
endif
+obj-$(CONFIG_MSM_RDBG) += rdbg.o
diff --git a/drivers/char/rdbg.c b/drivers/char/rdbg.c
new file mode 100644
index 000000000000..0823ed78485e
--- /dev/null
+++ b/drivers/char/rdbg.c
@@ -0,0 +1,1165 @@
+/*
+ * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/of_gpio.h>
+#include <soc/qcom/smsm.h>
+#include <linux/uaccess.h>
+#include <linux/interrupt.h>
+
+#define SMP2P_NUM_PROCS 8
+#define MAX_RETRIES 20
+
+#define SM_VERSION 1
+#define SM_BLOCKSIZE 128
+
+#define SMQ_MAGIC_INIT 0xFF00FF00
+#define SMQ_MAGIC_PRODUCER (SMQ_MAGIC_INIT | 0x1)
+#define SMQ_MAGIC_CONSUMER (SMQ_MAGIC_INIT | 0x2)
+
+enum SMQ_STATUS {
+ SMQ_SUCCESS = 0,
+ SMQ_ENOMEMORY = -1,
+ SMQ_EBADPARM = -2,
+ SMQ_UNDERFLOW = -3,
+ SMQ_OVERFLOW = -4
+};
+
+enum smq_type {
+ PRODUCER = 1,
+ CONSUMER = 2,
+ INVALID = 3
+};
+
+struct smq_block_map {
+ uint32_t index_read;
+ uint32_t num_blocks;
+ uint8_t *map;
+};
+
+struct smq_node {
+ uint16_t index_block;
+ uint16_t num_blocks;
+} __attribute__ ((__packed__));
+
+struct smq_hdr {
+ uint8_t producer_version;
+ uint8_t consumer_version;
+} __attribute__ ((__packed__));
+
+struct smq_out_state {
+ uint32_t init;
+ uint32_t index_check_queue_for_reset;
+ uint32_t index_sent_write;
+ uint32_t index_free_read;
+} __attribute__ ((__packed__));
+
+struct smq_out {
+ struct smq_out_state s;
+ struct smq_node sent[1];
+};
+
+struct smq_in_state {
+ uint32_t init;
+ uint32_t index_check_queue_for_reset_ack;
+ uint32_t index_sent_read;
+ uint32_t index_free_write;
+} __attribute__ ((__packed__));
+
+struct smq_in {
+ struct smq_in_state s;
+ struct smq_node free[1];
+};
+
+struct smq {
+ struct smq_hdr *hdr;
+ struct smq_out *out;
+ struct smq_in *in;
+ uint8_t *blocks;
+ uint32_t num_blocks;
+ struct mutex *lock;
+ uint32_t initialized;
+ struct smq_block_map block_map;
+ enum smq_type type;
+};
+
+struct gpio_info {
+ int gpio_base_id;
+ int irq_base_id;
+};
+
+struct rdbg_data {
+ struct device *device;
+ struct completion work;
+ struct gpio_info in;
+ struct gpio_info out;
+ bool device_initialized;
+ int gpio_out_offset;
+ bool device_opened;
+ void *smem_addr;
+ size_t smem_size;
+ struct smq producer_smrb;
+ struct smq consumer_smrb;
+ struct mutex write_mutex;
+};
+
+struct rdbg_device {
+ struct cdev cdev;
+ struct class *class;
+ dev_t dev_no;
+ int num_devices;
+ struct rdbg_data *rdbg_data;
+};
+
+static struct rdbg_device g_rdbg_instance = {
+ { {0} },
+ NULL,
+ 0,
+ SMP2P_NUM_PROCS,
+ NULL
+};
+
+struct processor_specific_info {
+ char *name;
+ unsigned int smem_buffer_addr;
+ size_t smem_buffer_size;
+};
+
+static struct processor_specific_info proc_info[SMP2P_NUM_PROCS] = {
+ {0}, /*APPS*/
+ {"rdbg_modem", 0, 0}, /*MODEM*/
+ {"rdbg_adsp", SMEM_LC_DEBUGGER, 16*1024}, /*ADSP*/
+ {0}, /*SMP2P_RESERVED_PROC_1*/
+ {"rdbg_wcnss", 0, 0}, /*WCNSS*/
+ {0}, /*SMP2P_RESERVED_PROC_2*/
+ {0}, /*SMP2P_POWER_PROC*/
+ {0} /*SMP2P_REMOTE_MOCK_PROC*/
+};
+
+static int smq_blockmap_get(struct smq_block_map *block_map,
+ uint32_t *block_index, uint32_t n)
+{
+ uint32_t start;
+ uint32_t mark = 0;
+ uint32_t found = 0;
+ uint32_t i = 0;
+
+ start = block_map->index_read;
+
+ if (n == 1) {
+ do {
+ if (!block_map->map[block_map->index_read]) {
+ *block_index = block_map->index_read;
+ block_map->map[block_map->index_read] = 1;
+ block_map->index_read++;
+ block_map->index_read %= block_map->num_blocks;
+ return SMQ_SUCCESS;
+ }
+ block_map->index_read++;
+ } while (start != (block_map->index_read %=
+ block_map->num_blocks));
+ } else {
+ mark = block_map->num_blocks;
+
+ do {
+ if (!block_map->map[block_map->index_read]) {
+ if (mark > block_map->index_read) {
+ mark = block_map->index_read;
+ start = block_map->index_read;
+ found = 0;
+ }
+
+ found++;
+ if (found == n) {
+ *block_index = mark;
+ for (i = 0; i < n; i++)
+ block_map->map[mark + i] =
+ (uint8_t)(n - i);
+ block_map->index_read += block_map->map
+ [block_map->index_read] - 1;
+ return SMQ_SUCCESS;
+ }
+ } else {
+ found = 0;
+ block_map->index_read += block_map->map
+ [block_map->index_read] - 1;
+ mark = block_map->num_blocks;
+ }
+ block_map->index_read++;
+ } while (start != (block_map->index_read %=
+ block_map->num_blocks));
+ }
+
+ return SMQ_ENOMEMORY;
+}
+
+static void smq_blockmap_put(struct smq_block_map *block_map, uint32_t i)
+{
+ uint32_t num_blocks = block_map->map[i];
+
+ while (num_blocks--) {
+ block_map->map[i] = 0;
+ i++;
+ }
+}
+
+static int smq_blockmap_reset(struct smq_block_map *block_map)
+{
+ if (!block_map->map)
+ return SMQ_ENOMEMORY;
+ memset(block_map->map, 0, block_map->num_blocks + 1);
+ block_map->index_read = 0;
+
+ return SMQ_SUCCESS;
+}
+
+static int smq_blockmap_ctor(struct smq_block_map *block_map,
+ uint32_t num_blocks)
+{
+ if (num_blocks <= 1)
+ return SMQ_ENOMEMORY;
+
+ block_map->map = kcalloc(num_blocks, sizeof(uint8_t), GFP_KERNEL);
+ if (!block_map->map)
+ return SMQ_ENOMEMORY;
+
+ block_map->num_blocks = num_blocks - 1;
+ smq_blockmap_reset(block_map);
+
+ return SMQ_SUCCESS;
+}
+
+static void smq_blockmap_dtor(struct smq_block_map *block_map)
+{
+ kfree(block_map->map);
+ block_map->map = NULL;
+}
+
+static int smq_free(struct smq *smq, void *data)
+{
+ struct smq_node node;
+ uint32_t index_block;
+ int err = SMQ_SUCCESS;
+
+ if (smq->lock)
+ mutex_lock(smq->lock);
+
+ if ((smq->hdr->producer_version != SM_VERSION) &&
+ (smq->out->s.init != SMQ_MAGIC_PRODUCER)) {
+ err = SMQ_UNDERFLOW;
+ goto bail;
+ }
+
+ index_block = ((uint8_t *)data - smq->blocks) / SM_BLOCKSIZE;
+ if (index_block >= smq->num_blocks) {
+ err = SMQ_EBADPARM;
+ goto bail;
+ }
+
+ node.index_block = (uint16_t)index_block;
+ node.num_blocks = 0;
+ *((struct smq_node *)(smq->in->free + smq->in->
+ s.index_free_write)) = node;
+
+ smq->in->s.index_free_write = (smq->in->s.index_free_write + 1)
+ % smq->num_blocks;
+
+bail:
+ if (smq->lock)
+ mutex_unlock(smq->lock);
+ return err;
+}
+
+static int smq_receive(struct smq *smq, void **pp, int *pnsize, int *pbmore)
+{
+ struct smq_node *node;
+ int err = SMQ_SUCCESS;
+ int more = 0;
+
+ if ((smq->hdr->producer_version != SM_VERSION) &&
+ (smq->out->s.init != SMQ_MAGIC_PRODUCER))
+ return SMQ_UNDERFLOW;
+
+ if (smq->in->s.index_sent_read == smq->out->s.index_sent_write) {
+ err = SMQ_UNDERFLOW;
+ goto bail;
+ }
+
+ node = (struct smq_node *)(smq->out->sent + smq->in->s.index_sent_read);
+ if (node->index_block >= smq->num_blocks) {
+ err = SMQ_EBADPARM;
+ goto bail;
+ }
+
+ smq->in->s.index_sent_read = (smq->in->s.index_sent_read + 1)
+ % smq->num_blocks;
+
+ *pp = smq->blocks + (node->index_block * SM_BLOCKSIZE);
+ *pnsize = SM_BLOCKSIZE * node->num_blocks;
+
+ /* Ensure that the reads and writes are updated in the memory
+ * when they are done and not cached. Also, ensure that the reads
+ * and writes are not reordered as they are shared between two cores.
+ */
+ rmb();
+ if (smq->in->s.index_sent_read != smq->out->s.index_sent_write)
+ more = 1;
+
+bail:
+ *pbmore = more;
+ return err;
+}
+
+static int smq_alloc_send(struct smq *smq, const uint8_t *pcb, int nsize)
+{
+ void *pv = 0;
+ int num_blocks;
+ uint32_t index_block = 0;
+ int err = SMQ_SUCCESS;
+ struct smq_node *node = NULL;
+
+ mutex_lock(smq->lock);
+
+ if ((smq->in->s.init == SMQ_MAGIC_CONSUMER) &&
+ (smq->hdr->consumer_version == SM_VERSION)) {
+ if (smq->out->s.index_check_queue_for_reset ==
+ smq->in->s.index_check_queue_for_reset_ack) {
+ while (smq->out->s.index_free_read !=
+ smq->in->s.index_free_write) {
+ node = (struct smq_node *)(
+ smq->in->free +
+ smq->out->s.index_free_read);
+ if (node->index_block >= smq->num_blocks) {
+ err = SMQ_EBADPARM;
+ goto bail;
+ }
+
+ smq->out->s.index_free_read =
+ (smq->out->s.index_free_read + 1)
+ % smq->num_blocks;
+
+ smq_blockmap_put(&smq->block_map,
+ node->index_block);
+ /* Ensure that the reads and writes are
+ * updated in the memory when they are done
+ * and not cached. Also, ensure that the reads
+ * and writes are not reordered as they are
+ * shared between two cores.
+ */
+ rmb();
+ }
+ }
+ }
+
+ num_blocks = ALIGN(nsize, SM_BLOCKSIZE)/SM_BLOCKSIZE;
+ err = smq_blockmap_get(&smq->block_map, &index_block, num_blocks);
+ if (err != SMQ_SUCCESS)
+ goto bail;
+
+ pv = smq->blocks + (SM_BLOCKSIZE * index_block);
+
+ err = copy_from_user((void *)pv, (void *)pcb, nsize);
+ if (err != 0)
+ goto bail;
+
+ ((struct smq_node *)(smq->out->sent +
+ smq->out->s.index_sent_write))->index_block
+ = (uint16_t)index_block;
+ ((struct smq_node *)(smq->out->sent +
+ smq->out->s.index_sent_write))->num_blocks
+ = (uint16_t)num_blocks;
+
+ smq->out->s.index_sent_write = (smq->out->s.index_sent_write + 1)
+ % smq->num_blocks;
+
+bail:
+ if (err != SMQ_SUCCESS) {
+ if (pv)
+ smq_blockmap_put(&smq->block_map, index_block);
+ }
+ mutex_unlock(smq->lock);
+ return err;
+}
+
+static int smq_reset_producer_queue_internal(struct smq *smq,
+ uint32_t reset_num)
+{
+ int retval = 0;
+ uint32_t i;
+
+ if (smq->type != PRODUCER)
+ goto bail;
+
+ mutex_lock(smq->lock);
+ if (smq->out->s.index_check_queue_for_reset != reset_num) {
+ smq->out->s.index_check_queue_for_reset = reset_num;
+ for (i = 0; i < smq->num_blocks; i++)
+ (smq->out->sent + i)->index_block = 0xFFFF;
+
+ smq_blockmap_reset(&smq->block_map);
+ smq->out->s.index_sent_write = 0;
+ smq->out->s.index_free_read = 0;
+ retval = 1;
+ }
+ mutex_unlock(smq->lock);
+
+bail:
+ return retval;
+}
+
+static int smq_check_queue_reset(struct smq *p_cons, struct smq *p_prod)
+{
+ int retval = 0;
+ uint32_t reset_num, i;
+
+ if ((p_cons->type != CONSUMER) ||
+ (p_cons->out->s.init != SMQ_MAGIC_PRODUCER) ||
+ (p_cons->hdr->producer_version != SM_VERSION))
+ goto bail;
+
+ reset_num = p_cons->out->s.index_check_queue_for_reset;
+ if (p_cons->in->s.index_check_queue_for_reset_ack != reset_num) {
+ p_cons->in->s.index_check_queue_for_reset_ack = reset_num;
+ for (i = 0; i < p_cons->num_blocks; i++)
+ (p_cons->in->free + i)->index_block = 0xFFFF;
+
+ p_cons->in->s.index_sent_read = 0;
+ p_cons->in->s.index_free_write = 0;
+
+ retval = smq_reset_producer_queue_internal(p_prod, reset_num);
+ }
+
+bail:
+ return retval;
+}
+
+static int check_subsystem_debug_enabled(void *base_addr, int size)
+{
+ int num_blocks;
+ uint8_t *pb_orig;
+ uint8_t *pb;
+ struct smq smq;
+ int err = 0;
+
+ pb = pb_orig = (uint8_t *)base_addr;
+ pb += sizeof(struct smq_hdr);
+ pb = PTR_ALIGN(pb, 8);
+ size -= pb - (uint8_t *)pb_orig;
+ num_blocks = (int)((size - sizeof(struct smq_out_state) -
+ sizeof(struct smq_in_state))/(SM_BLOCKSIZE +
+ sizeof(struct smq_node) * 2));
+ if (num_blocks <= 0) {
+ err = SMQ_EBADPARM;
+ goto bail;
+ }
+
+ pb += num_blocks * SM_BLOCKSIZE;
+ smq.out = (struct smq_out *)pb;
+ pb += sizeof(struct smq_out_state) + (num_blocks *
+ sizeof(struct smq_node));
+ smq.in = (struct smq_in *)pb;
+
+ if (smq.in->s.init != SMQ_MAGIC_CONSUMER) {
+ pr_err("%s, smq in consumer not initialized", __func__);
+ err = -ECOMM;
+ }
+
+bail:
+ return err;
+}
+
+static void smq_dtor(struct smq *smq)
+{
+ if (smq->initialized == SMQ_MAGIC_INIT) {
+ switch (smq->type) {
+ case PRODUCER:
+ smq->out->s.init = 0;
+ smq_blockmap_dtor(&smq->block_map);
+ break;
+ case CONSUMER:
+ smq->in->s.init = 0;
+ break;
+ default:
+ case INVALID:
+ break;
+ }
+
+ smq->initialized = 0;
+ }
+}
+
+/*
+ * The shared memory is used as a circular ring buffer in each direction.
+ * Thus we have a bi-directional shared memory channel between the AP
+ * and a subsystem. We call this SMQ. Each memory channel contains a header,
+ * data and a control mechanism that is used to synchronize read and write
+ * of data between the AP and the remote subsystem.
+ *
+ * Overall SMQ memory view:
+ *
+ * +------------------------------------------------+
+ * | SMEM buffer |
+ * |-----------------------+------------------------|
+ * |Producer: LA | Producer: Remote |
+ * |Consumer: Remote | subsystem |
+ * | subsystem | Consumer: LA |
+ * | | |
+ * | Producer| Consumer|
+ * +-----------------------+------------------------+
+ * | |
+ * | |
+ * | +--------------------------------------+
+ * | |
+ * | |
+ * v v
+ * +--------------------------------------------------------------+
+ * | Header | Data | Control |
+ * +-----------+---+---+---+-----+----+--+--+-----+---+--+--+-----+
+ * | | b | b | b | | S |n |n | | S |n |n | |
+ * | Producer | l | l | l | | M |o |o | | M |o |o | |
+ * | Ver | o | o | o | | Q |d |d | | Q |d |d | |
+ * |-----------| c | c | c | ... | |e |e | ... | |e |e | ... |
+ * | | k | k | k | | O | | | | I | | | |
+ * | Consumer | | | | | u |0 |1 | | n |0 |1 | |
+ * | Ver | 0 | 1 | 2 | | t | | | | | | | |
+ * +-----------+---+---+---+-----+----+--+--+-----+---+--+--+-----+
+ * | |
+ * + |
+ * |
+ * +------------------------+
+ * |
+ * v
+ * +----+----+----+----+
+ * | SMQ Nodes |
+ * |----|----|----|----|
+ * Node # | 0 | 1 | 2 | ...|
+ * |----|----|----|----|
+ * Starting Block Index # | 0 | 3 | 8 | ...|
+ * |----|----|----|----|
+ * # of blocks | 3 | 5 | 1 | ...|
+ * +----+----+----+----+
+ *
+ * Header: Contains version numbers for software compatibility to ensure
+ * that both producers and consumers on the AP and subsystems know how to
+ * read from and write to the queue.
+ * Both the producer and consumer versions are 1.
+ * +---------+-------------------+
+ * | Size | Field |
+ * +---------+-------------------+
+ * | 1 byte | Producer Version |
+ * +---------+-------------------+
+ * | 1 byte | Consumer Version |
+ * +---------+-------------------+
+ *
+ * Data: The data portion contains multiple blocks [0..N] of a fixed size.
+ * The block size SM_BLOCKSIZE is fixed to 128 bytes for header version #1.
+ * Payload sent from the debug agent app is split (if necessary) and placed
+ * in these blocks. The first data block is placed at the next 8 byte aligned
+ * address after the header.
+ *
+ * The number of blocks for a given SMEM allocation is derived as follows:
+ * Number of Blocks = ((Total Size - Alignment - Size of Header
+ * - Size of SMQIn - Size of SMQOut)/(SM_BLOCKSIZE))
+ *
+ * The producer maintains a private block map of each of these blocks to
+ * determine which of these blocks in the queue is available and which are free.
+ *
+ * Control:
+ * The control portion contains a list of nodes [0..N] where N is number
+ * of available data blocks. Each node identifies the data
+ * block indexes that contain a particular debug message to be transferred,
+ * and the number of blocks it took to hold the contents of the message.
+ *
+ * Each node has the following structure:
+ * +---------+-------------------+
+ * | Size | Field |
+ * +---------+-------------------+
+ * | 2 bytes |Staring Block Index|
+ * +---------+-------------------+
+ * | 2 bytes |Number of Blocks |
+ * +---------+-------------------+
+ *
+ * The producer and the consumer update different parts of the control channel
+ * (SMQOut / SMQIn) respectively. Each of these control data structures contains
+ * information about the last node that was written / read, and the actual nodes
+ * that were written/read.
+ *
+ * SMQOut Structure (R/W by producer, R by consumer):
+ * +---------+-------------------+
+ * | Size | Field |
+ * +---------+-------------------+
+ * | 4 bytes | Magic Init Number |
+ * +---------+-------------------+
+ * | 4 bytes | Reset |
+ * +---------+-------------------+
+ * | 4 bytes | Last Sent Index |
+ * +---------+-------------------+
+ * | 4 bytes | Index Free Read |
+ * +---------+-------------------+
+ *
+ * SMQIn Structure (R/W by consumer, R by producer):
+ * +---------+-------------------+
+ * | Size | Field |
+ * +---------+-------------------+
+ * | 4 bytes | Magic Init Number |
+ * +---------+-------------------+
+ * | 4 bytes | Reset ACK |
+ * +---------+-------------------+
+ * | 4 bytes | Last Read Index |
+ * +---------+-------------------+
+ * | 4 bytes | Index Free Write |
+ * +---------+-------------------+
+ *
+ * Magic Init Number:
+ * Both SMQ Out and SMQ In initialize this field with a predefined magic
+ * number so as to make sure that both the consumer and producer blocks
+ * have fully initialized and have valid data in the shared memory control area.
+ * Producer Magic #: 0xFF00FF01
+ * Consumer Magic #: 0xFF00FF02
+ */
+static int smq_ctor(struct smq *smq, void *base_addr, int size,
+ enum smq_type type, struct mutex *lock_ptr)
+{
+ int num_blocks;
+ uint8_t *pb_orig;
+ uint8_t *pb;
+ uint32_t i;
+ int err;
+
+ if (smq->initialized == SMQ_MAGIC_INIT) {
+ err = SMQ_EBADPARM;
+ goto bail;
+ }
+
+ if (!base_addr || !size) {
+ err = SMQ_EBADPARM;
+ goto bail;
+ }
+
+ if (type == PRODUCER)
+ smq->lock = lock_ptr;
+
+ pb_orig = (uint8_t *)base_addr;
+ smq->hdr = (struct smq_hdr *)pb_orig;
+ pb = pb_orig;
+ pb += sizeof(struct smq_hdr);
+ pb = PTR_ALIGN(pb, 8);
+ size -= pb - (uint8_t *)pb_orig;
+ num_blocks = (int)((size - sizeof(struct smq_out_state) -
+ sizeof(struct smq_in_state))/(SM_BLOCKSIZE +
+ sizeof(struct smq_node) * 2));
+ if (num_blocks <= 0) {
+ err = SMQ_ENOMEMORY;
+ goto bail;
+ }
+
+ smq->blocks = pb;
+ smq->num_blocks = num_blocks;
+ pb += num_blocks * SM_BLOCKSIZE;
+ smq->out = (struct smq_out *)pb;
+ pb += sizeof(struct smq_out_state) + (num_blocks *
+ sizeof(struct smq_node));
+ smq->in = (struct smq_in *)pb;
+ smq->type = type;
+ if (type == PRODUCER) {
+ smq->hdr->producer_version = SM_VERSION;
+ for (i = 0; i < smq->num_blocks; i++)
+ (smq->out->sent + i)->index_block = 0xFFFF;
+
+ err = smq_blockmap_ctor(&smq->block_map, smq->num_blocks);
+ if (err != SMQ_SUCCESS)
+ goto bail;
+
+ smq->out->s.index_sent_write = 0;
+ smq->out->s.index_free_read = 0;
+ if (smq->out->s.init == SMQ_MAGIC_PRODUCER) {
+ smq->out->s.index_check_queue_for_reset += 1;
+ } else {
+ smq->out->s.index_check_queue_for_reset = 1;
+ smq->out->s.init = SMQ_MAGIC_PRODUCER;
+ }
+ } else {
+ smq->hdr->consumer_version = SM_VERSION;
+ for (i = 0; i < smq->num_blocks; i++)
+ (smq->in->free + i)->index_block = 0xFFFF;
+
+ smq->in->s.index_sent_read = 0;
+ smq->in->s.index_free_write = 0;
+ if (smq->out->s.init == SMQ_MAGIC_PRODUCER) {
+ smq->in->s.index_check_queue_for_reset_ack =
+ smq->out->s.index_check_queue_for_reset;
+ } else {
+ smq->in->s.index_check_queue_for_reset_ack = 0;
+ }
+
+ smq->in->s.init = SMQ_MAGIC_CONSUMER;
+ }
+ smq->initialized = SMQ_MAGIC_INIT;
+ err = SMQ_SUCCESS;
+
+bail:
+ return err;
+}
+
+static void send_interrupt_to_subsystem(struct rdbg_data *rdbgdata)
+{
+ int offset = rdbgdata->gpio_out_offset;
+ int val = 1 ^ gpio_get_value(rdbgdata->out.gpio_base_id + offset);
+
+ gpio_set_value(rdbgdata->out.gpio_base_id + offset, val);
+ rdbgdata->gpio_out_offset = (offset + 1) % 32;
+
+ dev_dbg(rdbgdata->device, "%s: sent interrupt %d to subsystem",
+ __func__, val);
+}
+
+static irqreturn_t on_interrupt_from(int irq, void *ptr)
+{
+ struct rdbg_data *rdbgdata = (struct rdbg_data *) ptr;
+
+ dev_dbg(rdbgdata->device, "%s: Received interrupt %d from subsystem",
+ __func__, irq);
+
+ complete(&(rdbgdata->work));
+ return IRQ_HANDLED;
+}
+
+static int initialize_smq(struct rdbg_data *rdbgdata)
+{
+ int err = 0;
+ unsigned char *smem_consumer_buffer = rdbgdata->smem_addr;
+
+ smem_consumer_buffer += (rdbgdata->smem_size/2);
+
+ if (smq_ctor(&(rdbgdata->producer_smrb), (void *)(rdbgdata->smem_addr),
+ ((rdbgdata->smem_size)/2), PRODUCER, &rdbgdata->write_mutex)) {
+ dev_err(rdbgdata->device, "%s: smq producer allocation failed",
+ __func__);
+ err = -ENOMEM;
+ goto bail;
+ }
+
+ if (smq_ctor(&(rdbgdata->consumer_smrb), (void *)smem_consumer_buffer,
+ ((rdbgdata->smem_size)/2), CONSUMER, NULL)) {
+ dev_err(rdbgdata->device, "%s: smq conmsumer allocation failed",
+ __func__);
+ err = -ENOMEM;
+ }
+
+bail:
+ return err;
+
+}
+
+static int rdbg_open(struct inode *inode, struct file *filp)
+{
+ int device_id = -1;
+ struct rdbg_device *device = &g_rdbg_instance;
+ struct rdbg_data *rdbgdata = NULL;
+ int err = 0;
+
+ if (!inode || !device->rdbg_data) {
+ pr_err("Memory not allocated yet");
+ err = -ENODEV;
+ goto bail;
+ }
+
+ device_id = MINOR(inode->i_rdev);
+ rdbgdata = &device->rdbg_data[device_id];
+
+ if (rdbgdata->device_opened) {
+ dev_err(rdbgdata->device, "%s: Device already opened",
+ __func__);
+ err = -EEXIST;
+ goto bail;
+ }
+
+ rdbgdata->smem_size = proc_info[device_id].smem_buffer_size;
+ if (!rdbgdata->smem_size) {
+ dev_err(rdbgdata->device, "%s: smem not initialized", __func__);
+ err = -ENOMEM;
+ goto bail;
+ }
+
+ rdbgdata->smem_addr = smem_find(proc_info[device_id].smem_buffer_addr,
+ rdbgdata->smem_size, 0, SMEM_ANY_HOST_FLAG);
+ if (!rdbgdata->smem_addr) {
+ dev_err(rdbgdata->device, "%s: Could not allocate smem memory",
+ __func__);
+ err = -ENOMEM;
+ goto bail;
+ }
+ dev_dbg(rdbgdata->device, "%s: SMEM address=0x%lx smem_size=%d",
+ __func__, (unsigned long)rdbgdata->smem_addr,
+ (unsigned int)rdbgdata->smem_size);
+
+ if (check_subsystem_debug_enabled(rdbgdata->smem_addr,
+ rdbgdata->smem_size/2)) {
+ dev_err(rdbgdata->device, "%s: Subsystem %s is not debug enabled",
+ __func__, proc_info[device_id].name);
+ err = -ECOMM;
+ goto bail;
+ }
+
+ init_completion(&rdbgdata->work);
+
+ err = request_irq(rdbgdata->in.irq_base_id, on_interrupt_from,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ proc_info[device_id].name,
+ (void *)&device->rdbg_data[device_id]);
+ if (err) {
+ dev_err(rdbgdata->device,
+ "%s: Failed to register interrupt.Err=%d,irqid=%d.",
+ __func__, err, rdbgdata->in.irq_base_id);
+ goto irq_bail;
+ }
+
+ err = enable_irq_wake(rdbgdata->in.irq_base_id);
+ if (err < 0) {
+ dev_dbg(rdbgdata->device, "enable_irq_wake() failed with err=%d",
+ err);
+ err = 0;
+ }
+
+ mutex_init(&rdbgdata->write_mutex);
+
+ err = initialize_smq(rdbgdata);
+ if (err) {
+ dev_err(rdbgdata->device, "Error initializing smq. Err=%d",
+ err);
+ goto smq_bail;
+ }
+
+ rdbgdata->device_opened = 1;
+
+ filp->private_data = (void *)rdbgdata;
+
+ return 0;
+
+smq_bail:
+ smq_dtor(&(rdbgdata->producer_smrb));
+ smq_dtor(&(rdbgdata->consumer_smrb));
+ mutex_destroy(&rdbgdata->write_mutex);
+irq_bail:
+ free_irq(rdbgdata->in.irq_base_id, (void *)
+ &device->rdbg_data[device_id]);
+bail:
+ return err;
+}
+
+static int rdbg_release(struct inode *inode, struct file *filp)
+{
+ int device_id = -1;
+ struct rdbg_device *rdbgdevice = &g_rdbg_instance;
+ struct rdbg_data *rdbgdata = NULL;
+ int err = 0;
+
+ if (!inode || !rdbgdevice->rdbg_data) {
+ pr_err("Memory not allocated yet");
+ err = -ENODEV;
+ goto bail;
+ }
+
+ device_id = MINOR(inode->i_rdev);
+ rdbgdata = &rdbgdevice->rdbg_data[device_id];
+
+ if (rdbgdata->device_opened == 1) {
+ dev_dbg(rdbgdata->device, "%s: Destroying %s.", __func__,
+ proc_info[device_id].name);
+ rdbgdata->device_opened = 0;
+ complete(&(rdbgdata->work));
+ free_irq(rdbgdata->in.irq_base_id, (void *)
+ &rdbgdevice->rdbg_data[device_id]);
+ if (rdbgdevice->rdbg_data[device_id].producer_smrb.initialized)
+ smq_dtor(&(rdbgdevice->rdbg_data[device_id].
+ producer_smrb));
+ if (rdbgdevice->rdbg_data[device_id].consumer_smrb.initialized)
+ smq_dtor(&(rdbgdevice->rdbg_data[device_id].
+ consumer_smrb));
+ mutex_destroy(&rdbgdata->write_mutex);
+ }
+
+ filp->private_data = NULL;
+
+bail:
+ return err;
+}
+
+static ssize_t rdbg_read(struct file *filp, char __user *buf, size_t size,
+ loff_t *offset)
+{
+ int err = 0;
+ struct rdbg_data *rdbgdata = filp->private_data;
+ void *p_sent_buffer = NULL;
+ int nsize = 0;
+ int more = 0;
+
+ if (!rdbgdata) {
+ pr_err("Invalid argument");
+ err = -EINVAL;
+ goto bail;
+ }
+
+ dev_dbg(rdbgdata->device, "%s: In receive", __func__);
+ err = wait_for_completion_interruptible(&(rdbgdata->work));
+ if (err) {
+ dev_err(rdbgdata->device, "%s: Error in wait", __func__);
+ goto bail;
+ }
+
+ smq_check_queue_reset(&(rdbgdata->consumer_smrb),
+ &(rdbgdata->producer_smrb));
+ if (smq_receive(&(rdbgdata->consumer_smrb), &p_sent_buffer,
+ &nsize, &more) != SMQ_SUCCESS) {
+ dev_err(rdbgdata->device, "%s: Error in smq_recv(). Err code = %d",
+ __func__, err);
+ err = -ENODATA;
+ goto bail;
+ }
+
+ size = ((size < nsize) ? size : nsize);
+ err = copy_to_user(buf, p_sent_buffer, size);
+ if (err != 0) {
+ dev_err(rdbgdata->device, "%s: Error in copy_to_user(). Err code = %d",
+ __func__, err);
+ err = -ENODATA;
+ goto bail;
+ }
+
+ smq_free(&(rdbgdata->consumer_smrb), p_sent_buffer);
+ err = size;
+ dev_dbg(rdbgdata->device, "%s: Read data to buffer with address 0x%lx",
+ __func__, (unsigned long) buf);
+
+bail:
+ return err;
+}
+
+static ssize_t rdbg_write(struct file *filp, const char __user *buf,
+ size_t size, loff_t *offset)
+{
+ int err = 0;
+ int num_retries = 0;
+ struct rdbg_data *rdbgdata = filp->private_data;
+
+ if (!rdbgdata) {
+ pr_err("Invalid argument");
+ err = -EINVAL;
+ goto bail;
+ }
+
+ do {
+ err = smq_alloc_send(&(rdbgdata->producer_smrb), buf, size);
+ dev_dbg(rdbgdata->device, "%s, smq_alloc_send returned %d.",
+ __func__, err);
+ } while (err != 0 && num_retries++ < MAX_RETRIES);
+
+ if (err != 0) {
+ err = -ECOMM;
+ goto bail;
+ }
+
+ send_interrupt_to_subsystem(rdbgdata);
+
+ err = size;
+
+bail:
+ return err;
+}
+
+
+static const struct file_operations rdbg_fops = {
+ .open = rdbg_open,
+ .read = rdbg_read,
+ .write = rdbg_write,
+ .release = rdbg_release,
+};
+
+static int register_smp2p(char *node_name, struct gpio_info *gpio_info_ptr)
+{
+ struct device_node *node = NULL;
+ int cnt = 0;
+ int id = 0;
+
+ node = of_find_compatible_node(NULL, NULL, node_name);
+ if (node) {
+ cnt = of_gpio_count(node);
+ if (cnt && gpio_info_ptr) {
+ id = of_get_gpio(node, 0);
+ gpio_info_ptr->gpio_base_id = id;
+ gpio_info_ptr->irq_base_id = gpio_to_irq(id);
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+
+static int __init rdbg_init(void)
+{
+ int err = 0;
+ struct rdbg_device *rdbgdevice = &g_rdbg_instance;
+ int minor = 0;
+ int major = 0;
+ int minor_nodes_created = 0;
+
+ char *rdbg_compatible_string = "qcom,smp2pgpio_client_rdbg_";
+ int max_len = strlen(rdbg_compatible_string) + strlen("xx_out");
+
+ char *node_name = kcalloc(max_len, sizeof(char), GFP_KERNEL);
+
+ if (!node_name) {
+ err = -ENOMEM;
+ goto bail;
+ }
+
+ if (rdbgdevice->num_devices < 1 ||
+ rdbgdevice->num_devices > SMP2P_NUM_PROCS) {
+ pr_err("rgdb: invalid num_devices");
+ err = -EDOM;
+ goto name_bail;
+ }
+
+ rdbgdevice->rdbg_data = kcalloc(rdbgdevice->num_devices,
+ sizeof(struct rdbg_data), GFP_KERNEL);
+ if (!rdbgdevice->rdbg_data) {
+ err = -ENOMEM;
+ goto name_bail;
+ }
+
+ err = alloc_chrdev_region(&rdbgdevice->dev_no, 0,
+ rdbgdevice->num_devices, "rdbgctl");
+ if (err) {
+ pr_err("Error in alloc_chrdev_region.");
+ goto data_bail;
+ }
+ major = MAJOR(rdbgdevice->dev_no);
+
+ cdev_init(&rdbgdevice->cdev, &rdbg_fops);
+ rdbgdevice->cdev.owner = THIS_MODULE;
+ err = cdev_add(&rdbgdevice->cdev, MKDEV(major, 0),
+ rdbgdevice->num_devices);
+ if (err) {
+ pr_err("Error in cdev_add");
+ goto chrdev_bail;
+ }
+
+ rdbgdevice->class = class_create(THIS_MODULE, "rdbg");
+ if (IS_ERR(rdbgdevice->class)) {
+ err = PTR_ERR(rdbgdevice->class);
+ pr_err("Error in class_create");
+ goto cdev_bail;
+ }
+
+ for (minor = 0; minor < rdbgdevice->num_devices; minor++) {
+ if (!proc_info[minor].name)
+ continue;
+
+ if (snprintf(node_name, max_len, "%s%d_in",
+ rdbg_compatible_string, minor) <= 0) {
+ pr_err("Error in snprintf");
+ err = -ENOMEM;
+ goto device_bail;
+ }
+
+ if (register_smp2p(node_name,
+ &rdbgdevice->rdbg_data[minor].in)) {
+ pr_debug("No incoming device tree entry found for %s",
+ proc_info[minor].name);
+ continue;
+ }
+
+ if (snprintf(node_name, max_len, "%s%d_out",
+ rdbg_compatible_string, minor) <= 0) {
+ pr_err("Error in snprintf");
+ err = -ENOMEM;
+ goto device_bail;
+ }
+
+ if (register_smp2p(node_name,
+ &rdbgdevice->rdbg_data[minor].out)) {
+ pr_err("No outgoing device tree entry found for %s",
+ proc_info[minor].name);
+ err = -EINVAL;
+ goto device_bail;
+ }
+
+ rdbgdevice->rdbg_data[minor].device = device_create(
+ rdbgdevice->class, NULL, MKDEV(major, minor),
+ NULL, "%s", proc_info[minor].name);
+ if (IS_ERR(rdbgdevice->rdbg_data[minor].device)) {
+ err = PTR_ERR(rdbgdevice->rdbg_data[minor].device);
+ pr_err("Error in device_create");
+ goto device_bail;
+ }
+ rdbgdevice->rdbg_data[minor].device_initialized = 1;
+ minor_nodes_created++;
+ dev_dbg(rdbgdevice->rdbg_data[minor].device,
+ "%s: created /dev/%s c %d %d'", __func__,
+ proc_info[minor].name, major, minor);
+ }
+
+ if (!minor_nodes_created) {
+ pr_err("No device tree entries found");
+ err = -EINVAL;
+ goto class_bail;
+ }
+
+ goto name_bail;
+
+device_bail:
+ for (--minor; minor >= 0; minor--) {
+ if (rdbgdevice->rdbg_data[minor].device_initialized)
+ device_destroy(rdbgdevice->class,
+ MKDEV(MAJOR(rdbgdevice->dev_no), minor));
+ }
+class_bail:
+ class_destroy(rdbgdevice->class);
+cdev_bail:
+ cdev_del(&rdbgdevice->cdev);
+chrdev_bail:
+ unregister_chrdev_region(rdbgdevice->dev_no, rdbgdevice->num_devices);
+data_bail:
+ kfree(rdbgdevice->rdbg_data);
+name_bail:
+ kfree(node_name);
+bail:
+ return err;
+}
+
+static void __exit rdbg_exit(void)
+{
+ struct rdbg_device *rdbgdevice = &g_rdbg_instance;
+ int minor;
+
+ for (minor = 0; minor < rdbgdevice->num_devices; minor++) {
+ if (rdbgdevice->rdbg_data[minor].device_initialized) {
+ device_destroy(rdbgdevice->class,
+ MKDEV(MAJOR(rdbgdevice->dev_no), minor));
+ }
+ }
+ class_destroy(rdbgdevice->class);
+ cdev_del(&rdbgdevice->cdev);
+ unregister_chrdev_region(rdbgdevice->dev_no, 1);
+ kfree(rdbgdevice->rdbg_data);
+}
+
+module_init(rdbg_init);
+module_exit(rdbg_exit);
+
+MODULE_DESCRIPTION("rdbg module");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index eb44cf9ddd17..c4aec62d1014 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -2801,6 +2801,8 @@ static int clk_debug_create_one(struct clk_core *core, struct dentry *pdentry)
goto err_out;
}
+ clk_debug_measure_add(core->hw, core->dentry);
+
ret = 0;
goto out;
@@ -2930,8 +2932,10 @@ static int __init clk_debug_init(void)
return -ENOMEM;
mutex_lock(&clk_debug_lock);
- hlist_for_each_entry(core, &clk_debug_list, debug_node)
+ hlist_for_each_entry(core, &clk_debug_list, debug_node) {
+ clk_register_debug(core->hw, core->dentry);
clk_debug_create_one(core, rootdir);
+ }
inited = 1;
mutex_unlock(&clk_debug_lock);
diff --git a/drivers/clk/clk.h b/drivers/clk/clk.h
index 179b27c08022..c95a327a9301 100644
--- a/drivers/clk/clk.h
+++ b/drivers/clk/clk.h
@@ -23,6 +23,8 @@ void __clk_free_clk(struct clk *clk);
/* Debugfs API to print the enabled clocks */
void clock_debug_print_enabled(void);
+int clk_register_debug(struct clk_hw *hw, struct dentry *dentry);
+void clk_debug_measure_add(struct clk_hw *hw, struct dentry *dentry);
#else
/* All these casts to avoid ifdefs in clkdev... */
diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
index 36ab5cf68740..2148dad33e87 100644
--- a/drivers/clk/qcom/Kconfig
+++ b/drivers/clk/qcom/Kconfig
@@ -218,3 +218,5 @@ config QCOM_A53
Support for the A53 clock controller on MSM devices.
Say Y if you want to support CPU frequency scaling on devices
such as MSM8916.
+
+source "drivers/clk/qcom/mdss/Kconfig"
diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile
index 595254f69db1..176dc3103cdb 100644
--- a/drivers/clk/qcom/Makefile
+++ b/drivers/clk/qcom/Makefile
@@ -37,3 +37,5 @@ obj-$(CONFIG_KRAITCC) += krait-cc.o
obj-$(CONFIG_QCOM_A53) += clk-a53.o
obj-$(CONFIG_QCOM_CLK_RPM) += clk-rpm.o
obj-$(CONFIG_QCOM_CLK_SMD_RPM) += clk-smd-rpm.o
+
+obj-y += mdss/
diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c
index 423e975dffee..c762a387068b 100644
--- a/drivers/clk/qcom/common.c
+++ b/drivers/clk/qcom/common.c
@@ -11,6 +11,7 @@
* GNU General Public License for more details.
*/
+#include <linux/clk.h>
#include <linux/export.h>
#include <linux/module.h>
#include <linux/regmap.h>
@@ -286,4 +287,221 @@ int qcom_cc_probe(struct platform_device *pdev, const struct qcom_cc_desc *desc)
}
EXPORT_SYMBOL_GPL(qcom_cc_probe);
+/* Debugfs Support */
+static struct clk_hw *measure;
+
+DEFINE_SPINLOCK(clk_reg_lock);
+
+/* Sample clock for 'ticks' reference clock ticks. */
+static u32 run_measurement(unsigned ticks, struct regmap *regmap,
+ u32 ctl_reg, u32 status_reg)
+{
+ u32 regval;
+
+ /* Stop counters and set the XO4 counter start value. */
+ regmap_write(regmap, ctl_reg, ticks);
+
+ regmap_read(regmap, status_reg, &regval);
+
+ /* Wait for timer to become ready. */
+ while ((regval & BIT(25)) != 0) {
+ cpu_relax();
+ regmap_read(regmap, status_reg, &regval);
+ }
+
+ /* Run measurement and wait for completion. */
+ regmap_write(regmap, ctl_reg, (BIT(20)|ticks));
+ regmap_read(regmap, ctl_reg, &regval);
+
+ regmap_read(regmap, status_reg, &regval);
+
+ while ((regval & BIT(25)) == 0) {
+ cpu_relax();
+ regmap_read(regmap, status_reg, &regval);
+ }
+
+ /* Return measured ticks. */
+ regmap_read(regmap, status_reg, &regval);
+ regval &= BM(24, 0);
+
+ return regval;
+}
+
+/*
+ * Perform a hardware rate measurement for a given clock.
+ * FOR DEBUG USE ONLY: Measurements take ~15 ms!
+ */
+static unsigned long clk_debug_mux_measure_rate(struct clk_hw *hw)
+{
+ unsigned long flags, ret = 0;
+ u32 gcc_xo4_reg, sample_ticks = 0x10000, multiplier = 1;
+ u64 raw_count_short, raw_count_full;
+ struct clk_debug_mux *meas = to_clk_measure(hw);
+ struct measure_clk_data *data = meas->priv;
+
+ spin_lock_irqsave(&clk_reg_lock, flags);
+
+ clk_prepare_enable(data->cxo);
+
+ /* Enable CXO/4 and RINGOSC branch. */
+ regmap_read(meas->regmap[GCC], data->xo_div4_cbcr, &gcc_xo4_reg);
+ gcc_xo4_reg |= BIT(0);
+ regmap_write(meas->regmap[GCC], data->xo_div4_cbcr, gcc_xo4_reg);
+
+ /*
+ * The ring oscillator counter will not reset if the measured clock
+ * is not running. To detect this, run a short measurement before
+ * the full measurement. If the raw results of the two are the same
+ * then the clock must be off.
+ */
+
+ /* Run a short measurement. (~1 ms) */
+ raw_count_short = run_measurement(0x1000, meas->regmap[GCC],
+ data->ctl_reg, data->status_reg);
+
+ /* Run a full measurement. (~14 ms) */
+ raw_count_full = run_measurement(sample_ticks, meas->regmap[GCC],
+ data->ctl_reg, data->status_reg);
+
+ gcc_xo4_reg &= ~BIT(0);
+ regmap_write(meas->regmap[GCC], data->xo_div4_cbcr, gcc_xo4_reg);
+
+ /* Return 0 if the clock is off. */
+ if (raw_count_full == raw_count_short)
+ ret = 0;
+ else {
+ /* Compute rate in Hz. */
+ raw_count_full = ((raw_count_full * 10) + 15) * 4800000;
+ do_div(raw_count_full, ((sample_ticks * 10) + 35));
+ ret = (raw_count_full * multiplier);
+ }
+
+ clk_disable_unprepare(data->cxo);
+
+ spin_unlock_irqrestore(&clk_reg_lock, flags);
+
+ return ret;
+}
+
+static u8 clk_debug_mux_get_parent(struct clk_hw *hw)
+{
+ struct clk_debug_mux *meas = to_clk_measure(hw);
+ int i, num_parents = clk_hw_get_num_parents(hw);
+
+ for (i = 0; i < num_parents; i++) {
+ if (!strcmp(meas->parent[i].parents,
+ hw->init->parent_names[i])) {
+ pr_debug("%s :Clock name %s index %d\n", __func__,
+ hw->init->name, i);
+ return i;
+ }
+ }
+
+ return 0;
+}
+
+static int clk_debug_mux_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct clk_debug_mux *meas = to_clk_measure(hw);
+ u32 regval = 0;
+ int dbg_cc = 0;
+
+ dbg_cc = meas->parent[index].dbg_cc;
+
+ if (dbg_cc != GCC) {
+ regmap_read(meas->regmap[dbg_cc], 0x0, &regval);
+
+ if (meas->parent[index].mask)
+ regval &= ~meas->parent[index].mask <<
+ meas->parent[index].shift;
+ else
+ regval &= ~meas->mask;
+
+ regval |= (meas->parent[index].next_sel & meas->mask);
+
+ if (meas->parent[index].en_mask == 0xFF)
+ /* Skip en_mask */
+ regval = regval;
+ else if (meas->parent[index].en_mask)
+ regval |= meas->parent[index].en_mask;
+ else
+ regval |= meas->en_mask;
+
+ regmap_write(meas->regmap[dbg_cc], 0x0, regval);
+ }
+
+ /* update the debug sel for GCC */
+ regmap_read(meas->regmap[GCC], meas->debug_offset, &regval);
+
+ /* clear post divider bits */
+ regval &= ~BM(15, 12);
+ regval &= ~meas->mask;
+ regval |= (meas->parent[index].sel & meas->mask);
+ regval |= meas->en_mask;
+
+ regmap_write(meas->regmap[GCC], meas->debug_offset, regval);
+
+ return 0;
+}
+
+const struct clk_ops clk_debug_mux_ops = {
+ .get_parent = clk_debug_mux_get_parent,
+ .set_parent = clk_debug_mux_set_parent,
+};
+EXPORT_SYMBOL_GPL(clk_debug_mux_ops);
+
+static int clk_debug_measure_get(void *data, u64 *val)
+{
+ struct clk_hw *hw = data, *par;
+ int ret = 0;
+ unsigned long meas_rate, sw_rate;
+
+ ret = clk_set_parent(measure->clk, hw->clk);
+ if (!ret) {
+ par = measure;
+ while (par && par != hw) {
+ if (par->init->ops->enable)
+ par->init->ops->enable(par);
+ par = clk_hw_get_parent(par);
+ }
+ *val = clk_debug_mux_measure_rate(measure);
+ }
+
+ meas_rate = clk_get_rate(hw->clk);
+ sw_rate = clk_get_rate(clk_hw_get_parent(measure)->clk);
+ if (sw_rate && meas_rate >= (sw_rate * 2))
+ *val *= DIV_ROUND_CLOSEST(meas_rate, sw_rate);
+
+ return ret;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(clk_measure_fops, clk_debug_measure_get,
+ NULL, "%lld\n");
+
+void clk_debug_measure_add(struct clk_hw *hw, struct dentry *dentry)
+{
+ if (IS_ERR_OR_NULL(measure))
+ return;
+
+ if (clk_set_parent(measure->clk, hw->clk))
+ return;
+
+ debugfs_create_file("measure", S_IRUGO, dentry, hw,
+ &clk_measure_fops);
+}
+EXPORT_SYMBOL_GPL(clk_debug_measure_add);
+
+int clk_register_debug(struct clk_hw *hw, struct dentry *dentry)
+{
+ if (IS_ERR_OR_NULL(measure)) {
+ if (hw->init->flags & CLK_IS_MEASURE)
+ measure = hw;
+ if (!IS_ERR_OR_NULL(measure))
+ clk_debug_measure_add(hw, dentry);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(clk_register_debug);
+
MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/qcom/common.h b/drivers/clk/qcom/common.h
index e3f450533470..841367eb21ff 100644
--- a/drivers/clk/qcom/common.h
+++ b/drivers/clk/qcom/common.h
@@ -51,4 +51,95 @@ extern int qcom_cc_really_probe(struct platform_device *pdev,
extern int qcom_cc_probe(struct platform_device *pdev,
const struct qcom_cc_desc *desc);
extern struct clk_ops clk_dummy_ops;
+
+/* Debugfs Measure Clocks */
+
+/**
+ * struct measure_clk_data - Structure of clk measure
+ *
+ * @cxo: XO clock.
+ * @xo_div4_cbcr: offset of debug XO/4 div register.
+ * @ctl_reg: offset of debug control register.
+ * @status_reg: offset of debug status register.
+ *
+ */
+struct measure_clk_data {
+ struct clk *cxo;
+ u32 xo_div4_cbcr;
+ u32 ctl_reg;
+ u32 status_reg;
+};
+
+/**
+ * List of Debug clock controllers.
+ */
+enum debug_cc {
+ GCC,
+ MMCC,
+ GPU,
+ CPU,
+};
+
+/**
+ * struct clk_src - Struture of clock source for debug mux
+ *
+ * @parents: clock name to be used as parent for debug mux.
+ * @sel: debug mux index at global clock controller.
+ * @dbg_cc: indicates the clock controller for recursive debug clock
+ * controllers.
+ * @next_sel: indicates the debug mux index at recursive debug mux.
+ * @mask: indicates the mask required at recursive debug mux.
+ * @shift: indicates the shift required at recursive debug mux.
+ * @en_mask: indicates the enable bit mask at recursive debug mux.
+ * Incase the recursive debug mux does not have a enable bit,
+ * 0xFF should be used to indicate the same, otherwise global
+ * enable bit would be used.
+ */
+struct clk_src {
+ const char *parents;
+ int sel;
+ enum debug_cc dbg_cc;
+ int next_sel;
+ u32 mask;
+ u32 shift;
+ u32 en_mask;
+};
+
+#define MUX_SRC_LIST(...) \
+ .parent = (struct clk_src[]){__VA_ARGS__}, \
+ .num_parents = ARRAY_SIZE(((struct clk_src[]){__VA_ARGS__}))
+
+/**
+ * struct clk_debug_mux - Struture of clock debug mux
+ *
+ * @parent: structure of clk_src
+ * @num_parents: number of parents
+ * @regmap: regmaps of debug mux
+ * @num_parent_regmap: number of regmap of debug mux
+ * @priv: private measure_clk_data to be used by debug mux
+ * @en_mask: indicates the enable bit mask at global clock
+ * controller debug mux.
+ * @mask: indicates the mask to be used at global clock
+ * controller debug mux.
+ * @debug_offset: Start of debug mux offset.
+ * @hw: handle between common and hardware-specific interfaces.
+ */
+struct clk_debug_mux {
+ struct clk_src *parent;
+ int num_parents;
+ struct regmap **regmap;
+ int num_parent_regmap;
+ void *priv;
+ u32 en_mask;
+ u32 mask;
+ u32 debug_offset;
+ struct clk_hw hw;
+};
+
+#define BM(msb, lsb) (((((uint32_t)-1) << (31-msb)) >> (31-msb+lsb)) << lsb)
+
+#define to_clk_measure(_hw) container_of((_hw), struct clk_debug_mux, hw)
+
+extern const struct clk_ops clk_debug_mux_ops;
+
#endif
diff --git a/drivers/clk/qcom/gcc-msmfalcon.c b/drivers/clk/qcom/gcc-msmfalcon.c
index b5f7e18cf495..5a48fb79c8b2 100644
--- a/drivers/clk/qcom/gcc-msmfalcon.c
+++ b/drivers/clk/qcom/gcc-msmfalcon.c
@@ -705,6 +705,7 @@ static const struct freq_tbl ftbl_hmss_ahb_clk_src[] = {
F(19200000, P_XO, 1, 0, 0),
F(37500000, P_GPLL0_OUT_MAIN, 16, 0, 0),
F(75000000, P_GPLL0_OUT_MAIN, 8, 0, 0),
+ F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0),
{ }
};
@@ -820,7 +821,7 @@ static const struct freq_tbl ftbl_qspi_ser_clk_src[] = {
F(19200000, P_XO, 1, 0, 0),
F(80200000, P_PLL1_EARLY_DIV_CLK_SRC, 5, 0, 0),
F(160400000, P_GPLL1_OUT_MAIN, 5, 0, 0),
- F(320800000, P_GPLL1_OUT_MAIN, 2.5, 0, 0),
+ F(267333333, P_GPLL1_OUT_MAIN, 3, 0, 0),
{ }
};
@@ -838,7 +839,7 @@ static struct clk_rcg2 qspi_ser_clk_src = {
VDD_DIG_FMAX_MAP3(
LOWER, 80200000,
LOW, 160400000,
- NOMINAL, 320800000),
+ NOMINAL, 267333333),
},
};
@@ -876,6 +877,7 @@ static const struct freq_tbl ftbl_sdcc1_ice_core_clk_src[] = {
F(75000000, P_PLL0_EARLY_DIV_CLK_SRC, 4, 0, 0),
F(150000000, P_GPLL0_OUT_MAIN, 4, 0, 0),
F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0),
+ F(300000000, P_GPLL0_OUT_MAIN, 2, 0, 0),
{ }
};
@@ -905,6 +907,7 @@ static const struct freq_tbl ftbl_sdcc2_apps_clk_src[] = {
F(50000000, P_PLL0_EARLY_DIV_CLK_SRC, 6, 0, 0),
F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0),
F(192000000, P_GPLL4_OUT_MAIN, 8, 0, 0),
+ F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0),
{ }
};
@@ -929,6 +932,7 @@ static struct clk_rcg2 sdcc2_apps_clk_src = {
static const struct freq_tbl ftbl_ufs_axi_clk_src[] = {
F(50000000, P_PLL0_EARLY_DIV_CLK_SRC, 6, 0, 0),
F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0),
+ F(150000000, P_GPLL0_OUT_MAIN, 4, 0, 0),
F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0),
F(240000000, P_GPLL0_OUT_MAIN, 2.5, 0, 0),
{ }
@@ -1045,12 +1049,18 @@ static struct clk_rcg2 usb20_master_clk_src = {
},
};
+static const struct freq_tbl ftbl_usb20_mock_utmi_clk_src[] = {
+ F(19200000, P_XO, 1, 0, 0),
+ F(60000000, P_GPLL0_OUT_MAIN, 10, 0, 0),
+ { }
+};
+
static struct clk_rcg2 usb20_mock_utmi_clk_src = {
.cmd_rcgr = 0x2f024,
.mnd_width = 0,
.hid_width = 5,
.parent_map = gcc_parent_map_0,
- .freq_tbl = ftbl_hmss_rbcpr_clk_src,
+ .freq_tbl = ftbl_usb20_mock_utmi_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "usb20_mock_utmi_clk_src",
.parent_names = gcc_parent_names_0,
diff --git a/drivers/clk/qcom/mdss/Kconfig b/drivers/clk/qcom/mdss/Kconfig
index 229780e45bb8..7213e375f1ef 100644
--- a/drivers/clk/qcom/mdss/Kconfig
+++ b/drivers/clk/qcom/mdss/Kconfig
@@ -1,5 +1,6 @@
-config MSM_MDSS_PLL
+config QCOM_MDSS_PLL
bool "MDSS pll programming"
+ depends on COMMON_CLK_QCOM
---help---
It provides support for DSI, eDP and HDMI interface pll programming on MDSS
hardware. It also handles the pll specific resources and turn them on/off when
diff --git a/drivers/clk/qcom/mdss/Makefile b/drivers/clk/qcom/mdss/Makefile
index 75891dc10dda..6a0a1de1e942 100644
--- a/drivers/clk/qcom/mdss/Makefile
+++ b/drivers/clk/qcom/mdss/Makefile
@@ -1,5 +1,4 @@
-obj-$(CONFIG_MSM_MDSS_PLL) += mdss-pll-util.o
-obj-$(CONFIG_MSM_MDSS_PLL) += mdss-pll.o
-obj-$(CONFIG_MSM_MDSS_PLL) += mdss-dsi-pll-8996.o
-obj-$(CONFIG_MSM_MDSS_PLL) += mdss-dsi-pll-8996-util.o
-obj-$(CONFIG_MSM_MDSS_PLL) += mdss-hdmi-pll-8996.o
+obj-$(CONFIG_QCOM_MDSS_PLL) += mdss-pll-util.o
+obj-$(CONFIG_QCOM_MDSS_PLL) += mdss-pll.o
+obj-$(CONFIG_QCOM_MDSS_PLL) += mdss-dsi-pll-14nm.o
+obj-$(CONFIG_QCOM_MDSS_PLL) += mdss-dsi-pll-14nm-util.o
diff --git a/drivers/clk/qcom/mdss/mdss-dsi-pll-8996-util.c b/drivers/clk/qcom/mdss/mdss-dsi-pll-14nm-util.c
index 6d2694d5a2e9..a4044955c68f 100644
--- a/drivers/clk/qcom/mdss/mdss-dsi-pll-8996-util.c
+++ b/drivers/clk/qcom/mdss/mdss-dsi-pll-14nm-util.c
@@ -16,37 +16,18 @@
#include <linux/err.h>
#include <linux/iopoll.h>
#include <linux/delay.h>
-#include <linux/clk/msm-clock-generic.h>
#include "mdss-pll.h"
#include "mdss-dsi-pll.h"
-#include "mdss-dsi-pll-8996.h"
+#include "mdss-dsi-pll-14nm.h"
#define DSI_PLL_POLL_MAX_READS 15
#define DSI_PLL_POLL_TIMEOUT_US 1000
#define MSM8996_DSI_PLL_REVISION_2 2
-#define CEIL(x, y) (((x) + ((y)-1)) / (y))
-
-int set_mdss_byte_mux_sel_8996(struct mux_clk *clk, int sel)
-{
- return 0;
-}
-
-int get_mdss_byte_mux_sel_8996(struct mux_clk *clk)
-{
- return 0;
-}
-
-int set_mdss_pixel_mux_sel_8996(struct mux_clk *clk, int sel)
-{
- return 0;
-}
+#define VCO_REF_CLK_RATE 19200000
-int get_mdss_pixel_mux_sel_8996(struct mux_clk *clk)
-{
- return 0;
-}
+#define CEIL(x, y) (((x) + ((y)-1)) / (y))
static int mdss_pll_read_stored_trim_codes(
struct mdss_pll_resources *dsi_pll_res, s64 vco_clk_rate)
@@ -94,9 +75,9 @@ end_read:
return rc;
}
-int post_n1_div_set_div(struct div_clk *clk, int div)
+int post_n1_div_set_div(void *context, unsigned int reg, unsigned int div)
{
- struct mdss_pll_resources *pll = clk->priv;
+ struct mdss_pll_resources *pll = context;
struct dsi_pll_db *pdb;
struct dsi_pll_output *pout;
int rc;
@@ -108,6 +89,9 @@ int post_n1_div_set_div(struct div_clk *clk, int div)
return rc;
}
+ /* in common clock framework the divider value provided is one less */
+ div++;
+
pdb = (struct dsi_pll_db *)pll->priv;
pout = &pdb->out;
@@ -120,8 +104,6 @@ int post_n1_div_set_div(struct div_clk *clk, int div)
* support bit_clk above 86.67Mhz
*/
- /* this is for vco/bit clock */
- pout->pll_postdiv = 1; /* fixed, divided by 1 */
pout->pll_n1div = div;
n1div = MDSS_PLL_REG_R(pll->pll_base, DSIPHY_CMN_CLK_CFG0);
@@ -138,11 +120,15 @@ int post_n1_div_set_div(struct div_clk *clk, int div)
return 0;
}
-int post_n1_div_get_div(struct div_clk *clk)
+int post_n1_div_get_div(void *context, unsigned int reg, unsigned int *div)
{
- u32 div;
int rc;
- struct mdss_pll_resources *pll = clk->priv;
+ struct mdss_pll_resources *pll = context;
+ struct dsi_pll_db *pdb;
+ struct dsi_pll_output *pout;
+
+ pdb = (struct dsi_pll_db *)pll->priv;
+ pout = &pdb->out;
if (is_gdsc_disabled(pll))
return 0;
@@ -159,20 +145,33 @@ int post_n1_div_get_div(struct div_clk *clk)
* fot the time being, assume postdiv = 1
*/
- div = MDSS_PLL_REG_R(pll->pll_base, DSIPHY_CMN_CLK_CFG0);
- div &= 0xF;
- pr_debug("n1 div = %d\n", div);
+ *div = MDSS_PLL_REG_R(pll->pll_base, DSIPHY_CMN_CLK_CFG0);
+ *div &= 0xF;
+
+ /*
+ * initialize n1div here, it will get updated when
+ * corresponding set_div is called.
+ */
+ pout->pll_n1div = *div;
+
+ /* common clock framework will add one to the divider value sent */
+ if (*div == 0)
+ *div = 1; /* value of zero means div is 2 as per SWI */
+ else
+ *div -= 1;
+
+ pr_debug("post n1 get div = %d\n", *div);
mdss_pll_resource_enable(pll, false);
- return div;
+ return rc;
}
-int n2_div_set_div(struct div_clk *clk, int div)
+int n2_div_set_div(void *context, unsigned int reg, unsigned int div)
{
int rc;
u32 n2div;
- struct mdss_pll_resources *pll = clk->priv;
+ struct mdss_pll_resources *pll = context;
struct dsi_pll_db *pdb;
struct dsi_pll_output *pout;
struct mdss_pll_resources *slave;
@@ -183,6 +182,12 @@ int n2_div_set_div(struct div_clk *clk, int div)
return rc;
}
+ /*
+ * in common clock framework the actual divider value
+ * provided is one less.
+ */
+ div++;
+
pdb = (struct dsi_pll_db *)pll->priv;
pout = &pdb->out;
@@ -208,9 +213,9 @@ int n2_div_set_div(struct div_clk *clk, int div)
return rc;
}
-int shadow_n2_div_set_div(struct div_clk *clk, int div)
+int shadow_n2_div_set_div(void *context, unsigned int reg, unsigned int div)
{
- struct mdss_pll_resources *pll = clk->priv;
+ struct mdss_pll_resources *pll = context;
struct dsi_pll_db *pdb;
struct dsi_pll_output *pout;
u32 data;
@@ -218,6 +223,12 @@ int shadow_n2_div_set_div(struct div_clk *clk, int div)
pdb = pll->priv;
pout = &pdb->out;
+ /*
+ * in common clock framework the actual divider value
+ * provided is one less.
+ */
+ div++;
+
pout->pll_n2div = div;
data = (pout->pll_n1div | (pout->pll_n2div << 4));
@@ -228,15 +239,20 @@ int shadow_n2_div_set_div(struct div_clk *clk, int div)
return 0;
}
-int n2_div_get_div(struct div_clk *clk)
+int n2_div_get_div(void *context, unsigned int reg, unsigned int *div)
{
int rc;
u32 n2div;
- struct mdss_pll_resources *pll = clk->priv;
+ struct mdss_pll_resources *pll = context;
+ struct dsi_pll_db *pdb;
+ struct dsi_pll_output *pout;
if (is_gdsc_disabled(pll))
return 0;
+ pdb = (struct dsi_pll_db *)pll->priv;
+ pout = &pdb->out;
+
rc = mdss_pll_resource_enable(pll, true);
if (rc) {
pr_err("Failed to enable mdss dsi pll=%d resources\n",
@@ -247,15 +263,27 @@ int n2_div_get_div(struct div_clk *clk)
n2div = MDSS_PLL_REG_R(pll->pll_base, DSIPHY_CMN_CLK_CFG0);
n2div >>= 4;
n2div &= 0x0f;
-
+ /*
+ * initialize n2div here, it will get updated when
+ * corresponding set_div is called.
+ */
+ pout->pll_n2div = n2div;
mdss_pll_resource_enable(pll, false);
- pr_debug("ndx=%d div=%d\n", pll->index, n2div);
+ *div = n2div;
+
+ /* common clock framework will add one to the divider value sent */
+ if (*div == 0)
+ *div = 1; /* value of zero means div is 2 as per SWI */
+ else
+ *div -= 1;
+
+ pr_debug("ndx=%d div=%d\n", pll->index, *div);
- return n2div;
+ return rc;
}
-static bool pll_is_pll_locked_8996(struct mdss_pll_resources *pll)
+static bool pll_is_pll_locked_14nm(struct mdss_pll_resources *pll)
{
u32 status;
bool pll_locked;
@@ -286,7 +314,7 @@ static bool pll_is_pll_locked_8996(struct mdss_pll_resources *pll)
return pll_locked;
}
-static void dsi_pll_start_8996(void __iomem *pll_base)
+static void dsi_pll_start_14nm(void __iomem *pll_base)
{
pr_debug("start PLL at base=%p\n", pll_base);
@@ -294,14 +322,14 @@ static void dsi_pll_start_8996(void __iomem *pll_base)
MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_PLL_CNTRL, 1);
}
-static void dsi_pll_stop_8996(void __iomem *pll_base)
+static void dsi_pll_stop_14nm(void __iomem *pll_base)
{
pr_debug("stop PLL at base=%p\n", pll_base);
MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_PLL_CNTRL, 0);
}
-int dsi_pll_enable_seq_8996(struct mdss_pll_resources *pll)
+int dsi_pll_enable_seq_14nm(struct mdss_pll_resources *pll)
{
int rc = 0;
@@ -310,14 +338,14 @@ int dsi_pll_enable_seq_8996(struct mdss_pll_resources *pll)
return -EINVAL;
}
- dsi_pll_start_8996(pll->pll_base);
+ dsi_pll_start_14nm(pll->pll_base);
/*
* both DSIPHY_PLL_CLKBUFLR_EN and DSIPHY_CMN_GLBL_TEST_CTRL
- * enabled at mdss_dsi_8996_phy_config()
+ * enabled at mdss_dsi_14nm_phy_config()
*/
- if (!pll_is_pll_locked_8996(pll)) {
+ if (!pll_is_pll_locked_14nm(pll)) {
pr_err("DSI PLL ndx=%d lock failed\n", pll->index);
rc = -EINVAL;
goto init_lock_err;
@@ -329,10 +357,10 @@ init_lock_err:
return rc;
}
-static int dsi_pll_enable(struct clk *c)
+static int dsi_pll_enable(struct clk_hw *hw)
{
int i, rc = 0;
- struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+ struct dsi_pll_vco_clk *vco = to_vco_hw(hw);
struct mdss_pll_resources *pll = vco->priv;
/* Try all enable sequences until one succeeds */
@@ -352,9 +380,9 @@ static int dsi_pll_enable(struct clk *c)
return rc;
}
-static void dsi_pll_disable(struct clk *c)
+static void dsi_pll_disable(struct clk_hw *hw)
{
- struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+ struct dsi_pll_vco_clk *vco = to_vco_hw(hw);
struct mdss_pll_resources *pll = vco->priv;
struct mdss_pll_resources *slave;
@@ -367,7 +395,7 @@ static void dsi_pll_disable(struct clk *c)
pll->handoff_resources = false;
slave = pll->slave;
- dsi_pll_stop_8996(pll->pll_base);
+ dsi_pll_stop_14nm(pll->pll_base);
mdss_pll_resource_enable(pll, false);
@@ -376,7 +404,7 @@ static void dsi_pll_disable(struct clk *c)
pr_debug("DSI PLL ndx=%d Disabled\n", pll->index);
}
-static void mdss_dsi_pll_8996_input_init(struct mdss_pll_resources *pll,
+static void mdss_dsi_pll_14nm_input_init(struct mdss_pll_resources *pll,
struct dsi_pll_db *pdb)
{
pdb->in.fref = 19200000; /* 19.2 Mhz*/
@@ -414,9 +442,10 @@ static void mdss_dsi_pll_8996_input_init(struct mdss_pll_resources *pll,
pdb->in.pll_iptat_trim = 7;
pdb->in.pll_c3ctrl = 2; /* 2 */
pdb->in.pll_r3ctrl = 1; /* 1 */
+ pdb->out.pll_postdiv = 1;
}
-static void pll_8996_ssc_calc(struct mdss_pll_resources *pll,
+static void pll_14nm_ssc_calc(struct mdss_pll_resources *pll,
struct dsi_pll_db *pdb)
{
u32 period, ssc_period;
@@ -457,7 +486,7 @@ static void pll_8996_ssc_calc(struct mdss_pll_resources *pll,
pdb->out.ssc_step_size = step_size;
}
-static void pll_8996_dec_frac_calc(struct mdss_pll_resources *pll,
+static void pll_14nm_dec_frac_calc(struct mdss_pll_resources *pll,
struct dsi_pll_db *pdb)
{
struct dsi_pll_input *pin = &pdb->in;
@@ -501,7 +530,7 @@ static void pll_8996_dec_frac_calc(struct mdss_pll_resources *pll,
pout->cmn_ldo_cntrl = 0x1c;
}
-static u32 pll_8996_kvco_slop(u32 vrate)
+static u32 pll_14nm_kvco_slop(u32 vrate)
{
u32 slop = 0;
@@ -515,7 +544,7 @@ static u32 pll_8996_kvco_slop(u32 vrate)
return slop;
}
-static void pll_8996_calc_vco_count(struct dsi_pll_db *pdb,
+static void pll_14nm_calc_vco_count(struct dsi_pll_db *pdb,
s64 vco_clk_rate, s64 fref)
{
struct dsi_pll_input *pin = &pdb->in;
@@ -540,7 +569,7 @@ static void pll_8996_calc_vco_count(struct dsi_pll_db *pdb,
data -= 1;
pout->pll_kvco_div_ref = data;
- cnt = pll_8996_kvco_slop(vco_clk_rate);
+ cnt = pll_14nm_kvco_slop(vco_clk_rate);
cnt *= 2;
do_div(cnt, 100);
cnt *= pin->kvco_measure_time;
@@ -659,7 +688,7 @@ static void pll_db_commit_common(struct mdss_pll_resources *pll,
MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLL_CRCTRL, data);
}
-static void pll_db_commit_8996(struct mdss_pll_resources *pll,
+static void pll_db_commit_14nm(struct mdss_pll_resources *pll,
struct dsi_pll_db *pdb)
{
void __iomem *pll_base = pll->pll_base;
@@ -753,7 +782,7 @@ static void pll_db_commit_8996(struct mdss_pll_resources *pll,
/*
* pll_source_finding:
* Both GLBL_TEST_CTRL and CLKBUFLR_EN are configured
- * at mdss_dsi_8996_phy_config()
+ * at mdss_dsi_14nm_phy_config()
*/
static int pll_source_finding(struct mdss_pll_resources *pll)
{
@@ -820,10 +849,59 @@ static void pll_source_setup(struct mdss_pll_resources *pll)
other->slave = pll;
}
-int pll_vco_set_rate_8996(struct clk *c, unsigned long rate)
+unsigned long pll_vco_recalc_rate_14nm(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct dsi_pll_vco_clk *vco = to_vco_hw(hw);
+ struct mdss_pll_resources *pll = vco->priv;
+ u64 vco_rate, multiplier = BIT(20);
+ s32 div_frac_start;
+ u32 dec_start;
+ u64 ref_clk = vco->ref_clk_rate;
+ int rc;
+
+ if (pll->vco_current_rate)
+ return (unsigned long)pll->vco_current_rate;
+
+ if (is_gdsc_disabled(pll))
+ return 0;
+
+ rc = mdss_pll_resource_enable(pll, true);
+ if (rc) {
+ pr_err("Failed to enable mdss dsi pll=%d\n", pll->index);
+ return rc;
+ }
+
+ dec_start = MDSS_PLL_REG_R(pll->pll_base,
+ DSIPHY_PLL_DEC_START);
+ dec_start &= 0x0ff;
+ pr_debug("dec_start = 0x%x\n", dec_start);
+
+ div_frac_start = (MDSS_PLL_REG_R(pll->pll_base,
+ DSIPHY_PLL_DIV_FRAC_START3) & 0x0f) << 16;
+ div_frac_start |= (MDSS_PLL_REG_R(pll->pll_base,
+ DSIPHY_PLL_DIV_FRAC_START2) & 0x0ff) << 8;
+ div_frac_start |= MDSS_PLL_REG_R(pll->pll_base,
+ DSIPHY_PLL_DIV_FRAC_START1) & 0x0ff;
+ pr_debug("div_frac_start = 0x%x\n", div_frac_start);
+
+ vco_rate = ref_clk * dec_start;
+ vco_rate += ((ref_clk * div_frac_start) / multiplier);
+
+ pr_debug("returning vco rate = %lu\n", (unsigned long)vco_rate);
+
+ mdss_pll_resource_enable(pll, false);
+
+ pr_debug("%s: returning vco rate as %lu\n",
+ __func__, (unsigned long)vco_rate);
+ return (unsigned long)vco_rate;
+}
+
+int pll_vco_set_rate_14nm(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
{
int rc;
- struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+ struct dsi_pll_vco_clk *vco = to_vco_hw(hw);
struct mdss_pll_resources *pll = vco->priv;
struct mdss_pll_resources *slave;
struct dsi_pll_db *pdb;
@@ -848,30 +926,30 @@ int pll_vco_set_rate_8996(struct clk *c, unsigned long rate)
pll->vco_current_rate = rate;
pll->vco_ref_clk_rate = vco->ref_clk_rate;
- mdss_dsi_pll_8996_input_init(pll, pdb);
+ mdss_dsi_pll_14nm_input_init(pll, pdb);
- pll_8996_dec_frac_calc(pll, pdb);
+ pll_14nm_dec_frac_calc(pll, pdb);
if (pll->ssc_en)
- pll_8996_ssc_calc(pll, pdb);
+ pll_14nm_ssc_calc(pll, pdb);
- pll_8996_calc_vco_count(pdb, pll->vco_current_rate,
+ pll_14nm_calc_vco_count(pdb, pll->vco_current_rate,
pll->vco_ref_clk_rate);
/* commit slave if split display is enabled */
slave = pll->slave;
if (slave)
- pll_db_commit_8996(slave, pdb);
+ pll_db_commit_14nm(slave, pdb);
/* commit master itself */
- pll_db_commit_8996(pll, pdb);
+ pll_db_commit_14nm(pll, pdb);
mdss_pll_resource_enable(pll, false);
return rc;
}
-static void shadow_pll_dynamic_refresh_8996(struct mdss_pll_resources *pll,
+static void shadow_pll_dynamic_refresh_14nm(struct mdss_pll_resources *pll,
struct dsi_pll_db *pdb)
{
struct dsi_pll_output *pout = &pdb->out;
@@ -931,10 +1009,11 @@ static void shadow_pll_dynamic_refresh_8996(struct mdss_pll_resources *pll,
wmb();
}
-int shadow_pll_vco_set_rate_8996(struct clk *c, unsigned long rate)
+int shadow_pll_vco_set_rate_14nm(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
{
int rc;
- struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+ struct dsi_pll_vco_clk *vco = to_vco_hw(hw);
struct mdss_pll_resources *pll = vco->priv;
struct dsi_pll_db *pdb;
s64 vco_clk_rate = (s64)rate;
@@ -968,14 +1047,14 @@ int shadow_pll_vco_set_rate_8996(struct clk *c, unsigned long rate)
pll->vco_current_rate = rate;
pll->vco_ref_clk_rate = vco->ref_clk_rate;
- mdss_dsi_pll_8996_input_init(pll, pdb);
+ mdss_dsi_pll_14nm_input_init(pll, pdb);
- pll_8996_dec_frac_calc(pll, pdb);
+ pll_14nm_dec_frac_calc(pll, pdb);
- pll_8996_calc_vco_count(pdb, pll->vco_current_rate,
+ pll_14nm_calc_vco_count(pdb, pll->vco_current_rate,
pll->vco_ref_clk_rate);
- shadow_pll_dynamic_refresh_8996(pll, pdb);
+ shadow_pll_dynamic_refresh_14nm(pll, pdb);
rc = mdss_pll_resource_enable(pll, false);
if (rc) {
@@ -986,53 +1065,12 @@ int shadow_pll_vco_set_rate_8996(struct clk *c, unsigned long rate)
return rc;
}
-unsigned long pll_vco_get_rate_8996(struct clk *c)
-{
- u64 vco_rate, multiplier = BIT(20);
- s32 div_frac_start;
- u32 dec_start;
- struct dsi_pll_vco_clk *vco = to_vco_clk(c);
- u64 ref_clk = vco->ref_clk_rate;
- int rc;
- struct mdss_pll_resources *pll = vco->priv;
-
- if (is_gdsc_disabled(pll))
- return 0;
-
- rc = mdss_pll_resource_enable(pll, true);
- if (rc) {
- pr_err("Failed to enable mdss dsi pll=%d\n", pll->index);
- return rc;
- }
-
- dec_start = MDSS_PLL_REG_R(pll->pll_base,
- DSIPHY_PLL_DEC_START);
- dec_start &= 0x0ff;
- pr_debug("dec_start = 0x%x\n", dec_start);
-
- div_frac_start = (MDSS_PLL_REG_R(pll->pll_base,
- DSIPHY_PLL_DIV_FRAC_START3) & 0x0f) << 16;
- div_frac_start |= (MDSS_PLL_REG_R(pll->pll_base,
- DSIPHY_PLL_DIV_FRAC_START2) & 0x0ff) << 8;
- div_frac_start |= MDSS_PLL_REG_R(pll->pll_base,
- DSIPHY_PLL_DIV_FRAC_START1) & 0x0ff;
- pr_debug("div_frac_start = 0x%x\n", div_frac_start);
-
- vco_rate = ref_clk * dec_start;
- vco_rate += ((ref_clk * div_frac_start) / multiplier);
-
- pr_debug("returning vco rate = %lu\n", (unsigned long)vco_rate);
-
- mdss_pll_resource_enable(pll, false);
-
- return (unsigned long)vco_rate;
-}
-
-long pll_vco_round_rate_8996(struct clk *c, unsigned long rate)
+long pll_vco_round_rate_14nm(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
{
unsigned long rrate = rate;
u32 div;
- struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+ struct dsi_pll_vco_clk *vco = to_vco_hw(hw);
div = vco->min_rate / rate;
if (div > 15) {
@@ -1046,46 +1084,14 @@ long pll_vco_round_rate_8996(struct clk *c, unsigned long rate)
if (rate > vco->max_rate)
rrate = vco->max_rate;
+ *parent_rate = rrate;
return rrate;
}
-enum handoff pll_vco_handoff_8996(struct clk *c)
-{
- int rc;
- enum handoff ret = HANDOFF_DISABLED_CLK;
- struct dsi_pll_vco_clk *vco = to_vco_clk(c);
- struct mdss_pll_resources *pll = vco->priv;
-
- if (is_gdsc_disabled(pll))
- return HANDOFF_DISABLED_CLK;
-
- rc = mdss_pll_resource_enable(pll, true);
- if (rc) {
- pr_err("Failed to enable mdss dsi pll=%d\n", pll->index);
- return ret;
- }
-
- if (pll_is_pll_locked_8996(pll)) {
- pll->handoff_resources = true;
- pll->pll_on = true;
- c->rate = pll_vco_get_rate_8996(c);
- ret = HANDOFF_ENABLED_CLK;
- } else {
- mdss_pll_resource_enable(pll, false);
- }
-
- return ret;
-}
-
-enum handoff shadow_pll_vco_handoff_8996(struct clk *c)
-{
- return HANDOFF_DISABLED_CLK;
-}
-
-int pll_vco_prepare_8996(struct clk *c)
+int pll_vco_prepare_14nm(struct clk_hw *hw)
{
int rc = 0;
- struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+ struct dsi_pll_vco_clk *vco = to_vco_hw(hw);
struct mdss_pll_resources *pll = vco->priv;
if (!pll) {
@@ -1101,8 +1107,9 @@ int pll_vco_prepare_8996(struct clk *c)
}
if ((pll->vco_cached_rate != 0)
- && (pll->vco_cached_rate == c->rate)) {
- rc = c->ops->set_rate(c, pll->vco_cached_rate);
+ && (pll->vco_cached_rate == clk_hw_get_rate(hw))) {
+ rc = hw->init->ops->set_rate(hw, pll->vco_cached_rate,
+ pll->vco_cached_rate);
if (rc) {
pr_err("index=%d vco_set_rate failed. rc=%d\n",
rc, pll->index);
@@ -1111,7 +1118,7 @@ int pll_vco_prepare_8996(struct clk *c)
}
}
- rc = dsi_pll_enable(c);
+ rc = dsi_pll_enable(hw);
if (rc) {
mdss_pll_resource_enable(pll, false);
@@ -1122,9 +1129,9 @@ error:
return rc;
}
-void pll_vco_unprepare_8996(struct clk *c)
+void pll_vco_unprepare_14nm(struct clk_hw *hw)
{
- struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+ struct dsi_pll_vco_clk *vco = to_vco_hw(hw);
struct mdss_pll_resources *pll = vco->priv;
if (!pll) {
@@ -1132,6 +1139,17 @@ void pll_vco_unprepare_8996(struct clk *c)
return;
}
- pll->vco_cached_rate = c->rate;
- dsi_pll_disable(c);
+ pll->vco_cached_rate = clk_hw_get_rate(hw);
+ dsi_pll_disable(hw);
+}
+
+int dsi_mux_set_parent_14nm(void *context, unsigned int reg, unsigned int val)
+{
+ return 0;
+}
+
+int dsi_mux_get_parent_14nm(void *context, unsigned int reg, unsigned int *val)
+{
+ *val = 0;
+ return 0;
}
diff --git a/drivers/clk/qcom/mdss/mdss-dsi-pll-14nm.c b/drivers/clk/qcom/mdss/mdss-dsi-pll-14nm.c
new file mode 100644
index 000000000000..667a1512d54f
--- /dev/null
+++ b/drivers/clk/qcom/mdss/mdss-dsi-pll-14nm.c
@@ -0,0 +1,614 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/workqueue.h>
+
+#include "mdss-pll.h"
+#include "mdss-dsi-pll.h"
+#include "mdss-dsi-pll-14nm.h"
+
+#define VCO_DELAY_USEC 1
+
+static struct dsi_pll_db pll_db[DSI_PLL_NUM];
+
+static struct regmap_config dsi_pll_14nm_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0x588,
+};
+
+static struct regmap_bus post_n1_div_regmap_bus = {
+ .reg_write = post_n1_div_set_div,
+ .reg_read = post_n1_div_get_div,
+};
+
+static struct regmap_bus n2_div_regmap_bus = {
+ .reg_write = n2_div_set_div,
+ .reg_read = n2_div_get_div,
+};
+
+static struct regmap_bus shadow_n2_div_regmap_bus = {
+ .reg_write = shadow_n2_div_set_div,
+ .reg_read = n2_div_get_div,
+};
+
+static struct regmap_bus dsi_mux_regmap_bus = {
+ .reg_write = dsi_mux_set_parent_14nm,
+ .reg_read = dsi_mux_get_parent_14nm,
+};
+
+/* Op structures */
+static struct clk_ops clk_ops_dsi_vco = {
+ .recalc_rate = pll_vco_recalc_rate_14nm,
+ .set_rate = pll_vco_set_rate_14nm,
+ .round_rate = pll_vco_round_rate_14nm,
+ .prepare = pll_vco_prepare_14nm,
+ .unprepare = pll_vco_unprepare_14nm,
+};
+
+/* Shadow ops for dynamic refresh */
+static struct clk_ops clk_ops_shadow_dsi_vco = {
+ .recalc_rate = pll_vco_recalc_rate_14nm,
+ .set_rate = shadow_pll_vco_set_rate_14nm,
+ .round_rate = pll_vco_round_rate_14nm,
+};
+
+static struct dsi_pll_vco_clk dsi0pll_vco_clk = {
+ .ref_clk_rate = 19200000UL,
+ .min_rate = 1300000000UL,
+ .max_rate = 2600000000UL,
+ .pll_en_seq_cnt = 1,
+ .pll_enable_seqs[0] = dsi_pll_enable_seq_14nm,
+ .hw.init = &(struct clk_init_data){
+ .name = "dsi0pll_vco_clk_14nm",
+ .parent_names = (const char *[]){ "xo_board" },
+ .num_parents = 1,
+ .ops = &clk_ops_dsi_vco,
+ },
+};
+
+static struct dsi_pll_vco_clk dsi0pll_shadow_vco_clk = {
+ .ref_clk_rate = 19200000u,
+ .min_rate = 1300000000u,
+ .max_rate = 2600000000u,
+ .hw.init = &(struct clk_init_data){
+ .name = "dsi0pll_shadow_vco_clk_14nm",
+ .parent_names = (const char *[]){ "xo_board" },
+ .num_parents = 1,
+ .ops = &clk_ops_shadow_dsi_vco,
+ },
+};
+
+static struct dsi_pll_vco_clk dsi1pll_vco_clk = {
+ .ref_clk_rate = 19200000UL,
+ .min_rate = 1300000000UL,
+ .max_rate = 2600000000UL,
+ .pll_en_seq_cnt = 1,
+ .pll_enable_seqs[0] = dsi_pll_enable_seq_14nm,
+ .hw.init = &(struct clk_init_data){
+ .name = "dsi1pll_vco_clk_14nm",
+ .parent_names = (const char *[]){ "xo_board" },
+ .num_parents = 1,
+ .ops = &clk_ops_dsi_vco,
+ },
+};
+
+static struct dsi_pll_vco_clk dsi1pll_shadow_vco_clk = {
+ .ref_clk_rate = 19200000u,
+ .min_rate = 1300000000u,
+ .max_rate = 2600000000u,
+ .pll_en_seq_cnt = 1,
+ .pll_enable_seqs[0] = dsi_pll_enable_seq_14nm,
+ .hw.init = &(struct clk_init_data){
+ .name = "dsi1pll_shadow_vco_clk_14nm",
+ .parent_names = (const char *[]){ "xo_board" },
+ .num_parents = 1,
+ .ops = &clk_ops_shadow_dsi_vco,
+ },
+};
+
+static struct clk_regmap_div dsi0pll_post_n1_div_clk = {
+ .reg = 0x48,
+ .shift = 0,
+ .width = 4,
+
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "dsi0pll_post_n1_div_clk",
+ .parent_names =
+ (const char *[]){ "dsi0pll_vco_clk_14nm" },
+ .num_parents = 1,
+ .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
+ .ops = &clk_regmap_div_ops,
+ },
+ },
+};
+
+static struct clk_regmap_div dsi0pll_shadow_post_n1_div_clk = {
+ .reg = 0x48,
+ .shift = 0,
+ .width = 4,
+
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "dsi0pll_shadow_post_n1_div_clk",
+ .parent_names =
+ (const char *[]){"dsi0pll_shadow_vco_clk_14nm"},
+ .num_parents = 1,
+ .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
+ .ops = &clk_regmap_div_ops,
+ },
+ },
+};
+
+static struct clk_regmap_div dsi1pll_post_n1_div_clk = {
+ .reg = 0x48,
+ .shift = 0,
+ .width = 4,
+
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "dsi1pll_post_n1_div_clk",
+ .parent_names =
+ (const char *[]){ "dsi1pll_vco_clk_14nm" },
+ .num_parents = 1,
+ .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
+ .ops = &clk_regmap_div_ops,
+ },
+ },
+};
+
+static struct clk_regmap_div dsi1pll_shadow_post_n1_div_clk = {
+ .reg = 0x48,
+ .shift = 0,
+ .width = 4,
+
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "dsi1pll_shadow_post_n1_div_clk",
+ .parent_names =
+ (const char *[]){"dsi1pll_shadow_vco_clk_14nm"},
+ .num_parents = 1,
+ .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
+ .ops = &clk_regmap_div_ops,
+ },
+ },
+};
+
+static struct clk_regmap_div dsi0pll_n2_div_clk = {
+ .reg = 0x48,
+ .shift = 0,
+ .width = 4,
+
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "dsi0pll_n2_div_clk",
+ .parent_names =
+ (const char *[]){ "dsi0pll_post_n1_div_clk" },
+ .num_parents = 1,
+ .flags = CLK_GET_RATE_NOCACHE,
+ .ops = &clk_regmap_div_ops,
+ },
+ },
+};
+
+static struct clk_regmap_div dsi0pll_shadow_n2_div_clk = {
+ .reg = 0x48,
+ .shift = 0,
+ .width = 4,
+
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "dsi0pll_shadow_n2_div_clk",
+ .parent_names =
+ (const char *[]){ "dsi0pll_shadow_post_n1_div_clk" },
+ .num_parents = 1,
+ .flags = CLK_GET_RATE_NOCACHE,
+ .ops = &clk_regmap_div_ops,
+ },
+ },
+};
+
+static struct clk_regmap_div dsi1pll_n2_div_clk = {
+ .reg = 0x48,
+ .shift = 0,
+ .width = 4,
+
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "dsi1pll_n2_div_clk",
+ .parent_names =
+ (const char *[]){ "dsi1pll_post_n1_div_clk" },
+ .num_parents = 1,
+ .flags = CLK_GET_RATE_NOCACHE,
+ .ops = &clk_regmap_div_ops,
+ },
+ },
+};
+
+static struct clk_regmap_div dsi1pll_shadow_n2_div_clk = {
+ .reg = 0x48,
+ .shift = 0,
+ .width = 4,
+
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "dsi1pll_shadow_n2_div_clk",
+ .parent_names =
+ (const char *[]){ "dsi1pll_shadow_post_n1_div_clk" },
+ .num_parents = 1,
+ .flags = CLK_GET_RATE_NOCACHE,
+ .ops = &clk_regmap_div_ops,
+ },
+ },
+};
+
+static struct clk_fixed_factor dsi0pll_pixel_clk_src = {
+ .div = 2,
+ .mult = 1,
+
+ .hw.init = &(struct clk_init_data){
+ .name = "dsi0pll_pixel_clk_src",
+ .parent_names = (const char *[]){ "dsi0pll_n2_div_clk" },
+ .num_parents = 1,
+ .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
+ .ops = &clk_fixed_factor_ops,
+ },
+};
+
+static struct clk_fixed_factor dsi0pll_shadow_pixel_clk_src = {
+ .div = 2,
+ .mult = 1,
+
+ .hw.init = &(struct clk_init_data){
+ .name = "dsi0pll_shadow_pixel_clk_src",
+ .parent_names = (const char *[]){ "dsi0pll_shadow_n2_div_clk" },
+ .num_parents = 1,
+ .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
+ .ops = &clk_fixed_factor_ops,
+ },
+};
+
+static struct clk_fixed_factor dsi1pll_pixel_clk_src = {
+ .div = 2,
+ .mult = 1,
+
+ .hw.init = &(struct clk_init_data){
+ .name = "dsi1pll_pixel_clk_src",
+ .parent_names = (const char *[]){ "dsi1pll_n2_div_clk" },
+ .num_parents = 1,
+ .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
+ .ops = &clk_fixed_factor_ops,
+ },
+};
+
+static struct clk_fixed_factor dsi1pll_shadow_pixel_clk_src = {
+ .div = 2,
+ .mult = 1,
+
+ .hw.init = &(struct clk_init_data){
+ .name = "dsi1pll_shadow_pixel_clk_src",
+ .parent_names = (const char *[]){ "dsi1pll_shadow_n2_div_clk" },
+ .num_parents = 1,
+ .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
+ .ops = &clk_fixed_factor_ops,
+ },
+};
+
+static struct clk_regmap_mux dsi0pll_pixel_clk_mux = {
+ .reg = 0x48,
+ .shift = 0,
+ .width = 1,
+
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "dsi0pll_pixel_clk_mux",
+ .parent_names =
+ (const char *[]){ "dsi0pll_pixel_clk_src",
+ "dsi0pll_shadow_pixel_clk_src"},
+ .num_parents = 2,
+ .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
+ .ops = &clk_regmap_mux_closest_ops,
+ },
+ },
+};
+
+static struct clk_regmap_mux dsi1pll_pixel_clk_mux = {
+ .reg = 0x48,
+ .shift = 0,
+ .width = 1,
+
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "dsi1pll_pixel_clk_mux",
+ .parent_names =
+ (const char *[]){ "dsi1pll_pixel_clk_src",
+ "dsi1pll_shadow_pixel_clk_src"},
+ .num_parents = 2,
+ .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
+ .ops = &clk_regmap_mux_closest_ops,
+ },
+ },
+};
+
+static struct clk_fixed_factor dsi0pll_byte_clk_src = {
+ .div = 8,
+ .mult = 1,
+
+ .hw.init = &(struct clk_init_data){
+ .name = "dsi0pll_byte_clk_src",
+ .parent_names = (const char *[]){ "dsi0pll_post_n1_div_clk" },
+ .num_parents = 1,
+ .flags = (CLK_SET_RATE_PARENT),
+ .ops = &clk_fixed_factor_ops,
+ },
+};
+
+static struct clk_fixed_factor dsi0pll_shadow_byte_clk_src = {
+ .div = 8,
+ .mult = 1,
+
+ .hw.init = &(struct clk_init_data){
+ .name = "dsi0pll_shadow_byte_clk_src",
+ .parent_names =
+ (const char *[]){ "dsi0pll_shadow_post_n1_div_clk" },
+ .num_parents = 1,
+ .flags = (CLK_SET_RATE_PARENT),
+ .ops = &clk_fixed_factor_ops,
+ },
+};
+
+static struct clk_fixed_factor dsi1pll_byte_clk_src = {
+ .div = 8,
+ .mult = 1,
+
+ .hw.init = &(struct clk_init_data){
+ .name = "dsi1pll_byte_clk_src",
+ .parent_names = (const char *[]){ "dsi1pll_post_n1_div_clk" },
+ .num_parents = 1,
+ .flags = (CLK_SET_RATE_PARENT),
+ .ops = &clk_fixed_factor_ops,
+ },
+};
+
+static struct clk_fixed_factor dsi1pll_shadow_byte_clk_src = {
+ .div = 8,
+ .mult = 1,
+
+ .hw.init = &(struct clk_init_data){
+ .name = "dsi1pll_shadow_byte_clk_src",
+ .parent_names =
+ (const char *[]){ "dsi1pll_shadow_post_n1_div_clk" },
+ .num_parents = 1,
+ .flags = (CLK_SET_RATE_PARENT),
+ .ops = &clk_fixed_factor_ops,
+ },
+};
+
+static struct clk_regmap_mux dsi0pll_byte_clk_mux = {
+ .reg = 0x48,
+ .shift = 0,
+ .width = 1,
+
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "dsi0pll_byte_clk_mux",
+ .parent_names =
+ (const char *[]){"dsi0pll_byte_clk_src",
+ "dsi0pll_shadow_byte_clk_src"},
+ .num_parents = 2,
+ .ops = &clk_regmap_mux_closest_ops,
+ .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
+ },
+ },
+};
+
+static struct clk_regmap_mux dsi1pll_byte_clk_mux = {
+ .reg = 0x48,
+ .shift = 0,
+ .width = 1,
+
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "dsi1pll_byte_clk_mux",
+ .parent_names =
+ (const char *[]){"dsi1pll_byte_clk_src",
+ "dsi1pll_shadow_byte_clk_src"},
+ .num_parents = 2,
+ .ops = &clk_regmap_mux_closest_ops,
+ .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
+ },
+ },
+};
+
+static struct clk_hw *mdss_dsi_pllcc_14nm[] = {
+ [BYTE0_MUX_CLK] = &dsi0pll_byte_clk_mux.clkr.hw,
+ [BYTE0_SRC_CLK] = &dsi0pll_byte_clk_src.hw,
+ [PIX0_MUX_CLK] = &dsi0pll_pixel_clk_mux.clkr.hw,
+ [PIX0_SRC_CLK] = &dsi0pll_pixel_clk_src.hw,
+ [N2_DIV_0_CLK] = &dsi0pll_n2_div_clk.clkr.hw,
+ [POST_N1_DIV_0_CLK] = &dsi0pll_post_n1_div_clk.clkr.hw,
+ [VCO_CLK_0_CLK] = &dsi0pll_vco_clk.hw,
+ [SHADOW_BYTE0_SRC_CLK] = &dsi0pll_shadow_byte_clk_src.hw,
+ [SHADOW_PIX0_SRC_CLK] = &dsi0pll_shadow_pixel_clk_src.hw,
+ [SHADOW_N2_DIV_0_CLK] = &dsi0pll_shadow_n2_div_clk.clkr.hw,
+ [SHADOW_POST_N1_DIV_0_CLK] = &dsi0pll_shadow_post_n1_div_clk.clkr.hw,
+ [SHADOW_VCO_CLK_0_CLK] = &dsi0pll_shadow_vco_clk.hw,
+ [BYTE1_MUX_CLK] = &dsi1pll_byte_clk_mux.clkr.hw,
+ [BYTE1_SRC_CLK] = &dsi1pll_byte_clk_src.hw,
+ [PIX1_MUX_CLK] = &dsi1pll_pixel_clk_mux.clkr.hw,
+ [PIX1_SRC_CLK] = &dsi1pll_pixel_clk_src.hw,
+ [N2_DIV_1_CLK] = &dsi1pll_n2_div_clk.clkr.hw,
+ [POST_N1_DIV_1_CLK] = &dsi1pll_post_n1_div_clk.clkr.hw,
+ [VCO_CLK_1_CLK] = &dsi1pll_vco_clk.hw,
+ [SHADOW_BYTE1_SRC_CLK] = &dsi1pll_shadow_byte_clk_src.hw,
+ [SHADOW_PIX1_SRC_CLK] = &dsi1pll_shadow_pixel_clk_src.hw,
+ [SHADOW_N2_DIV_1_CLK] = &dsi1pll_shadow_n2_div_clk.clkr.hw,
+ [SHADOW_POST_N1_DIV_1_CLK] = &dsi1pll_shadow_post_n1_div_clk.clkr.hw,
+ [SHADOW_VCO_CLK_1_CLK] = &dsi1pll_shadow_vco_clk.hw,
+};
+
+int dsi_pll_clock_register_14nm(struct platform_device *pdev,
+ struct mdss_pll_resources *pll_res)
+{
+ int rc = 0, ndx, i;
+ int const ssc_freq_default = 31500; /* default h/w recommended value */
+ int const ssc_ppm_default = 5000; /* default h/w recommended value */
+ struct dsi_pll_db *pdb;
+ struct clk_onecell_data *clk_data;
+ struct clk *clk;
+ struct regmap *regmap;
+ int num_clks = ARRAY_SIZE(mdss_dsi_pllcc_14nm);
+
+ if (!pdev || !pdev->dev.of_node) {
+ pr_err("Invalid input parameters\n");
+ return -EINVAL;
+ }
+
+ if (!pll_res || !pll_res->pll_base) {
+ pr_err("Invalid PLL resources\n");
+ return -EPROBE_DEFER;
+ }
+
+ if (pll_res->index >= DSI_PLL_NUM) {
+ pr_err("pll ndx=%d is NOT supported\n", pll_res->index);
+ return -EINVAL;
+ }
+
+ ndx = pll_res->index;
+ pdb = &pll_db[ndx];
+ pll_res->priv = pdb;
+ pdb->pll = pll_res;
+ ndx++;
+ ndx %= DSI_PLL_NUM;
+ pdb->next = &pll_db[ndx];
+
+ if (pll_res->ssc_en) {
+ if (!pll_res->ssc_freq)
+ pll_res->ssc_freq = ssc_freq_default;
+ if (!pll_res->ssc_ppm)
+ pll_res->ssc_ppm = ssc_ppm_default;
+ }
+
+ clk_data = devm_kzalloc(&pdev->dev, sizeof(struct clk_onecell_data),
+ GFP_KERNEL);
+ if (!clk_data)
+ return -ENOMEM;
+
+ clk_data->clks = devm_kzalloc(&pdev->dev, (num_clks *
+ sizeof(struct clk *)), GFP_KERNEL);
+ if (!clk_data->clks) {
+ devm_kfree(&pdev->dev, clk_data);
+ return -ENOMEM;
+ }
+
+ clk_data->clk_num = num_clks;
+
+ /* Set client data to mux, div and vco clocks. */
+ if (pll_res->index == DSI_PLL_1) {
+ regmap = devm_regmap_init(&pdev->dev, &post_n1_div_regmap_bus,
+ pll_res, &dsi_pll_14nm_config);
+ dsi1pll_post_n1_div_clk.clkr.regmap = regmap;
+ dsi1pll_shadow_post_n1_div_clk.clkr.regmap = regmap;
+
+ regmap = devm_regmap_init(&pdev->dev, &n2_div_regmap_bus,
+ pll_res, &dsi_pll_14nm_config);
+ dsi1pll_n2_div_clk.clkr.regmap = regmap;
+
+ regmap = devm_regmap_init(&pdev->dev, &shadow_n2_div_regmap_bus,
+ pll_res, &dsi_pll_14nm_config);
+ dsi1pll_shadow_n2_div_clk.clkr.regmap = regmap;
+
+ regmap = devm_regmap_init(&pdev->dev, &dsi_mux_regmap_bus,
+ pll_res, &dsi_pll_14nm_config);
+ dsi1pll_byte_clk_mux.clkr.regmap = regmap;
+ dsi1pll_pixel_clk_mux.clkr.regmap = regmap;
+
+ dsi1pll_vco_clk.priv = pll_res;
+ dsi1pll_shadow_vco_clk.priv = pll_res;
+
+ pll_res->vco_delay = VCO_DELAY_USEC;
+
+ for (i = BYTE1_MUX_CLK; i <= SHADOW_VCO_CLK_1_CLK; i++) {
+ pr_debug("register clk: %d index: %d\n",
+ i, pll_res->index);
+ clk = devm_clk_register(&pdev->dev,
+ mdss_dsi_pllcc_14nm[i]);
+ if (IS_ERR(clk)) {
+ pr_err("clk registration failed for DSI: %d\n",
+ pll_res->index);
+ rc = -EINVAL;
+ goto clk_reg_fail;
+ }
+ clk_data->clks[i] = clk;
+ }
+
+ rc = of_clk_add_provider(pdev->dev.of_node,
+ of_clk_src_onecell_get, clk_data);
+ } else {
+ regmap = devm_regmap_init(&pdev->dev, &post_n1_div_regmap_bus,
+ pll_res, &dsi_pll_14nm_config);
+ dsi0pll_post_n1_div_clk.clkr.regmap = regmap;
+ dsi0pll_shadow_post_n1_div_clk.clkr.regmap = regmap;
+
+ regmap = devm_regmap_init(&pdev->dev, &n2_div_regmap_bus,
+ pll_res, &dsi_pll_14nm_config);
+ dsi0pll_n2_div_clk.clkr.regmap = regmap;
+
+ regmap = devm_regmap_init(&pdev->dev, &shadow_n2_div_regmap_bus,
+ pll_res, &dsi_pll_14nm_config);
+ dsi0pll_shadow_n2_div_clk.clkr.regmap = regmap;
+
+ regmap = devm_regmap_init(&pdev->dev, &dsi_mux_regmap_bus,
+ pll_res, &dsi_pll_14nm_config);
+ dsi0pll_byte_clk_mux.clkr.regmap = regmap;
+ dsi0pll_pixel_clk_mux.clkr.regmap = regmap;
+
+ dsi0pll_vco_clk.priv = pll_res;
+ dsi0pll_shadow_vco_clk.priv = pll_res;
+ pll_res->vco_delay = VCO_DELAY_USEC;
+
+ for (i = BYTE0_MUX_CLK; i <= SHADOW_VCO_CLK_0_CLK; i++) {
+ pr_debug("reg clk: %d index: %d\n", i, pll_res->index);
+ clk = devm_clk_register(&pdev->dev,
+ mdss_dsi_pllcc_14nm[i]);
+ if (IS_ERR(clk)) {
+ pr_err("clk registration failed for DSI: %d\n",
+ pll_res->index);
+ rc = -EINVAL;
+ goto clk_reg_fail;
+ }
+ clk_data->clks[i] = clk;
+ }
+
+ rc = of_clk_add_provider(pdev->dev.of_node,
+ of_clk_src_onecell_get, clk_data);
+ }
+
+ if (!rc) {
+ pr_info("Registered DSI PLL ndx=%d clocks successfully\n",
+ pll_res->index);
+ return rc;
+ }
+
+clk_reg_fail:
+ devm_kfree(&pdev->dev, clk_data->clks);
+ devm_kfree(&pdev->dev, clk_data);
+ return rc;
+}
diff --git a/drivers/clk/qcom/mdss/mdss-dsi-pll-8996.h b/drivers/clk/qcom/mdss/mdss-dsi-pll-14nm.h
index 611e79101d4f..c2a3b12d8174 100644
--- a/drivers/clk/qcom/mdss/mdss-dsi-pll-8996.h
+++ b/drivers/clk/qcom/mdss/mdss-dsi-pll-14nm.h
@@ -10,8 +10,8 @@
* GNU General Public License for more details.
*/
-#ifndef MDSS_DSI_PLL_8996_H
-#define MDSS_DSI_PLL_8996_H
+#ifndef MDSS_DSI_PLL_14NM_H
+#define MDSS_DSI_PLL_14NM_H
#define DSIPHY_CMN_CLK_CFG0 0x0010
#define DSIPHY_CMN_CLK_CFG1 0x0014
@@ -197,25 +197,31 @@ enum {
PLL_MASTER
};
-int pll_vco_set_rate_8996(struct clk *c, unsigned long rate);
-long pll_vco_round_rate_8996(struct clk *c, unsigned long rate);
-enum handoff pll_vco_handoff_8996(struct clk *c);
-enum handoff shadow_pll_vco_handoff_8996(struct clk *c);
-int shadow_post_n1_div_set_div(struct div_clk *clk, int div);
-int shadow_post_n1_div_get_div(struct div_clk *clk);
-int shadow_n2_div_set_div(struct div_clk *clk, int div);
-int shadow_n2_div_get_div(struct div_clk *clk);
-int shadow_pll_vco_set_rate_8996(struct clk *c, unsigned long rate);
-int pll_vco_prepare_8996(struct clk *c);
-void pll_vco_unprepare_8996(struct clk *c);
-int set_mdss_byte_mux_sel_8996(struct mux_clk *clk, int sel);
-int get_mdss_byte_mux_sel_8996(struct mux_clk *clk);
-int set_mdss_pixel_mux_sel_8996(struct mux_clk *clk, int sel);
-int get_mdss_pixel_mux_sel_8996(struct mux_clk *clk);
-int post_n1_div_set_div(struct div_clk *clk, int div);
-int post_n1_div_get_div(struct div_clk *clk);
-int n2_div_set_div(struct div_clk *clk, int div);
-int n2_div_get_div(struct div_clk *clk);
-int dsi_pll_enable_seq_8996(struct mdss_pll_resources *pll);
-
-#endif /* MDSS_DSI_PLL_8996_H */
+int pll_vco_set_rate_14nm(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate);
+int shadow_pll_vco_set_rate_14nm(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate);
+long pll_vco_round_rate_14nm(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate);
+unsigned long pll_vco_recalc_rate_14nm(struct clk_hw *hw,
+ unsigned long parent_rate);
+
+int pll_vco_prepare_14nm(struct clk_hw *hw);
+void pll_vco_unprepare_14nm(struct clk_hw *hw);
+
+int shadow_post_n1_div_set_div(void *context,
+ unsigned int reg, unsigned int div);
+int shadow_post_n1_div_get_div(void *context,
+ unsigned int reg, unsigned int *div);
+int shadow_n2_div_set_div(void *context, unsigned int reg, unsigned int div);
+int shadow_n2_div_get_div(void *context, unsigned int reg, unsigned int *div);
+
+int post_n1_div_set_div(void *context, unsigned int reg, unsigned int div);
+int post_n1_div_get_div(void *context, unsigned int reg, unsigned int *div);
+int n2_div_set_div(void *context, unsigned int reg, unsigned int div);
+int n2_div_get_div(void *context, unsigned int reg, unsigned int *div);
+int dsi_pll_enable_seq_14nm(struct mdss_pll_resources *pll);
+int dsi_mux_set_parent_14nm(void *context, unsigned int reg, unsigned int val);
+int dsi_mux_get_parent_14nm(void *context, unsigned int reg, unsigned int *val);
+
+#endif /* MDSS_DSI_PLL_14NM_H */
diff --git a/drivers/clk/qcom/mdss/mdss-dsi-pll-8996.c b/drivers/clk/qcom/mdss/mdss-dsi-pll-8996.c
deleted file mode 100644
index 1de1b997a041..000000000000
--- a/drivers/clk/qcom/mdss/mdss-dsi-pll-8996.c
+++ /dev/null
@@ -1,566 +0,0 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#define pr_fmt(fmt) "%s: " fmt, __func__
-
-#include <linux/kernel.h>
-#include <linux/err.h>
-#include <linux/delay.h>
-#include <linux/clk/msm-clk-provider.h>
-#include <linux/clk/msm-clk.h>
-#include <linux/workqueue.h>
-#include <linux/clk/msm-clock-generic.h>
-#include <dt-bindings/clock/msm-clocks-8996.h>
-
-#include "mdss-pll.h"
-#include "mdss-dsi-pll.h"
-#include "mdss-dsi-pll-8996.h"
-
-#define VCO_DELAY_USEC 1
-
-static struct dsi_pll_db pll_db[DSI_PLL_NUM];
-
-static struct clk_ops n2_clk_src_ops;
-static struct clk_ops shadow_n2_clk_src_ops;
-static struct clk_ops byte_clk_src_ops;
-static struct clk_ops post_n1_div_clk_src_ops;
-static struct clk_ops shadow_post_n1_div_clk_src_ops;
-
-static struct clk_ops clk_ops_gen_mux_dsi;
-
-/* Op structures */
-static struct clk_ops clk_ops_dsi_vco = {
- .set_rate = pll_vco_set_rate_8996,
- .round_rate = pll_vco_round_rate_8996,
- .handoff = pll_vco_handoff_8996,
- .prepare = pll_vco_prepare_8996,
- .unprepare = pll_vco_unprepare_8996,
-};
-
-static struct clk_div_ops post_n1_div_ops = {
- .set_div = post_n1_div_set_div,
- .get_div = post_n1_div_get_div,
-};
-
-static struct clk_div_ops n2_div_ops = { /* hr_oclk3 */
- .set_div = n2_div_set_div,
- .get_div = n2_div_get_div,
-};
-
-static struct clk_mux_ops mdss_byte_mux_ops = {
- .set_mux_sel = set_mdss_byte_mux_sel_8996,
- .get_mux_sel = get_mdss_byte_mux_sel_8996,
-};
-
-static struct clk_mux_ops mdss_pixel_mux_ops = {
- .set_mux_sel = set_mdss_pixel_mux_sel_8996,
- .get_mux_sel = get_mdss_pixel_mux_sel_8996,
-};
-
-/* Shadow ops for dynamic refresh */
-static struct clk_ops clk_ops_shadow_dsi_vco = {
- .set_rate = shadow_pll_vco_set_rate_8996,
- .round_rate = pll_vco_round_rate_8996,
- .handoff = shadow_pll_vco_handoff_8996,
-};
-
-static struct clk_div_ops shadow_post_n1_div_ops = {
- .set_div = post_n1_div_set_div,
-};
-
-static struct clk_div_ops shadow_n2_div_ops = {
- .set_div = shadow_n2_div_set_div,
-};
-
-static struct dsi_pll_vco_clk dsi0pll_vco_clk = {
- .ref_clk_rate = 19200000UL,
- .min_rate = 1300000000UL,
- .max_rate = 2600000000UL,
- .pll_en_seq_cnt = 1,
- .pll_enable_seqs[0] = dsi_pll_enable_seq_8996,
- .c = {
- .dbg_name = "dsi0pll_vco_clk_8996",
- .ops = &clk_ops_dsi_vco,
- CLK_INIT(dsi0pll_vco_clk.c),
- },
-};
-
-static struct dsi_pll_vco_clk dsi0pll_shadow_vco_clk = {
- .ref_clk_rate = 19200000u,
- .min_rate = 1300000000u,
- .max_rate = 2600000000u,
- .c = {
- .dbg_name = "dsi0pll_shadow_vco_clk",
- .ops = &clk_ops_shadow_dsi_vco,
- CLK_INIT(dsi0pll_shadow_vco_clk.c),
- },
-};
-
-static struct dsi_pll_vco_clk dsi1pll_vco_clk = {
- .ref_clk_rate = 19200000UL,
- .min_rate = 1300000000UL,
- .max_rate = 2600000000UL,
- .pll_en_seq_cnt = 1,
- .pll_enable_seqs[0] = dsi_pll_enable_seq_8996,
- .c = {
- .dbg_name = "dsi1pll_vco_clk_8996",
- .ops = &clk_ops_dsi_vco,
- CLK_INIT(dsi1pll_vco_clk.c),
- },
-};
-
-static struct dsi_pll_vco_clk dsi1pll_shadow_vco_clk = {
- .ref_clk_rate = 19200000u,
- .min_rate = 1300000000u,
- .max_rate = 2600000000u,
- .pll_en_seq_cnt = 1,
- .pll_enable_seqs[0] = dsi_pll_enable_seq_8996,
- .c = {
- .dbg_name = "dsi1pll_shadow_vco_clk",
- .ops = &clk_ops_shadow_dsi_vco,
- CLK_INIT(dsi1pll_shadow_vco_clk.c),
- },
-};
-
-static struct div_clk dsi0pll_post_n1_div_clk = {
- .data = {
- .max_div = 15,
- .min_div = 1,
- },
- .ops = &post_n1_div_ops,
- .c = {
- .parent = &dsi0pll_vco_clk.c,
- .dbg_name = "dsi0pll_post_n1_div_clk",
- .ops = &post_n1_div_clk_src_ops,
- .flags = CLKFLAG_NO_RATE_CACHE,
- CLK_INIT(dsi0pll_post_n1_div_clk.c),
- },
-};
-
-static struct div_clk dsi0pll_shadow_post_n1_div_clk = {
- .data = {
- .max_div = 15,
- .min_div = 1,
- },
- .ops = &shadow_post_n1_div_ops,
- .c = {
- .parent = &dsi0pll_shadow_vco_clk.c,
- .dbg_name = "dsi0pll_shadow_post_n1_div_clk",
- .ops = &shadow_post_n1_div_clk_src_ops,
- .flags = CLKFLAG_NO_RATE_CACHE,
- CLK_INIT(dsi0pll_shadow_post_n1_div_clk.c),
- },
-};
-
-static struct div_clk dsi1pll_post_n1_div_clk = {
- .data = {
- .max_div = 15,
- .min_div = 1,
- },
- .ops = &post_n1_div_ops,
- .c = {
- .parent = &dsi1pll_vco_clk.c,
- .dbg_name = "dsi1pll_post_n1_div_clk",
- .ops = &post_n1_div_clk_src_ops,
- .flags = CLKFLAG_NO_RATE_CACHE,
- CLK_INIT(dsi1pll_post_n1_div_clk.c),
- },
-};
-
-static struct div_clk dsi1pll_shadow_post_n1_div_clk = {
- .data = {
- .max_div = 15,
- .min_div = 1,
- },
- .ops = &shadow_post_n1_div_ops,
- .c = {
- .parent = &dsi1pll_shadow_vco_clk.c,
- .dbg_name = "dsi1pll_shadow_post_n1_div_clk",
- .ops = &shadow_post_n1_div_clk_src_ops,
- .flags = CLKFLAG_NO_RATE_CACHE,
- CLK_INIT(dsi1pll_shadow_post_n1_div_clk.c),
- },
-};
-
-static struct div_clk dsi0pll_n2_div_clk = {
- .data = {
- .max_div = 15,
- .min_div = 1,
- },
- .ops = &n2_div_ops,
- .c = {
- .parent = &dsi0pll_post_n1_div_clk.c,
- .dbg_name = "dsi0pll_n2_div_clk",
- .ops = &n2_clk_src_ops,
- .flags = CLKFLAG_NO_RATE_CACHE,
- CLK_INIT(dsi0pll_n2_div_clk.c),
- },
-};
-
-static struct div_clk dsi0pll_shadow_n2_div_clk = {
- .data = {
- .max_div = 15,
- .min_div = 1,
- },
- .ops = &shadow_n2_div_ops,
- .c = {
- .parent = &dsi0pll_shadow_post_n1_div_clk.c,
- .dbg_name = "dsi0pll_shadow_n2_div_clk",
- .ops = &shadow_n2_clk_src_ops,
- .flags = CLKFLAG_NO_RATE_CACHE,
- CLK_INIT(dsi0pll_shadow_n2_div_clk.c),
- },
-};
-
-static struct div_clk dsi1pll_n2_div_clk = {
- .data = {
- .max_div = 15,
- .min_div = 1,
- },
- .ops = &n2_div_ops,
- .c = {
- .parent = &dsi1pll_post_n1_div_clk.c,
- .dbg_name = "dsi1pll_n2_div_clk",
- .ops = &n2_clk_src_ops,
- .flags = CLKFLAG_NO_RATE_CACHE,
- CLK_INIT(dsi1pll_n2_div_clk.c),
- },
-};
-
-static struct div_clk dsi1pll_shadow_n2_div_clk = {
- .data = {
- .max_div = 15,
- .min_div = 1,
- },
- .ops = &shadow_n2_div_ops,
- .c = {
- .parent = &dsi1pll_shadow_post_n1_div_clk.c,
- .dbg_name = "dsi1pll_shadow_n2_div_clk",
- .ops = &shadow_n2_clk_src_ops,
- .flags = CLKFLAG_NO_RATE_CACHE,
- CLK_INIT(dsi1pll_shadow_n2_div_clk.c),
- },
-};
-
-static struct div_clk dsi0pll_pixel_clk_src = {
- .data = {
- .div = 2,
- .min_div = 2,
- .max_div = 2,
- },
- .c = {
- .parent = &dsi0pll_n2_div_clk.c,
- .dbg_name = "dsi0pll_pixel_clk_src",
- .ops = &clk_ops_div,
- .flags = CLKFLAG_NO_RATE_CACHE,
- CLK_INIT(dsi0pll_pixel_clk_src.c),
- },
-};
-
-static struct div_clk dsi0pll_shadow_pixel_clk_src = {
- .data = {
- .div = 2,
- .min_div = 2,
- .max_div = 2,
- },
- .c = {
- .parent = &dsi0pll_shadow_n2_div_clk.c,
- .dbg_name = "dsi0pll_shadow_pixel_clk_src",
- .ops = &clk_ops_div,
- .flags = CLKFLAG_NO_RATE_CACHE,
- CLK_INIT(dsi0pll_shadow_pixel_clk_src.c),
- },
-};
-
-static struct div_clk dsi1pll_pixel_clk_src = {
- .data = {
- .div = 2,
- .min_div = 2,
- .max_div = 2,
- },
- .c = {
- .parent = &dsi1pll_n2_div_clk.c,
- .dbg_name = "dsi1pll_pixel_clk_src",
- .ops = &clk_ops_div,
- .flags = CLKFLAG_NO_RATE_CACHE,
- CLK_INIT(dsi1pll_pixel_clk_src.c),
- },
-};
-
-static struct div_clk dsi1pll_shadow_pixel_clk_src = {
- .data = {
- .div = 2,
- .min_div = 2,
- .max_div = 2,
- },
- .c = {
- .parent = &dsi1pll_shadow_n2_div_clk.c,
- .dbg_name = "dsi1pll_shadow_pixel_clk_src",
- .ops = &clk_ops_div,
- .flags = CLKFLAG_NO_RATE_CACHE,
- CLK_INIT(dsi1pll_shadow_pixel_clk_src.c),
- },
-};
-
-static struct mux_clk dsi0pll_pixel_clk_mux = {
- .num_parents = 2,
- .parents = (struct clk_src[]) {
- {&dsi0pll_pixel_clk_src.c, 0},
- {&dsi0pll_shadow_pixel_clk_src.c, 1},
- },
- .ops = &mdss_pixel_mux_ops,
- .c = {
- .parent = &dsi0pll_pixel_clk_src.c,
- .dbg_name = "dsi0pll_pixel_clk_mux",
- .ops = &clk_ops_gen_mux_dsi,
- .flags = CLKFLAG_NO_RATE_CACHE,
- CLK_INIT(dsi0pll_pixel_clk_mux.c),
- }
-};
-
-static struct mux_clk dsi1pll_pixel_clk_mux = {
- .num_parents = 2,
- .parents = (struct clk_src[]) {
- {&dsi1pll_pixel_clk_src.c, 0},
- {&dsi1pll_shadow_pixel_clk_src.c, 1},
- },
- .ops = &mdss_pixel_mux_ops,
- .c = {
- .parent = &dsi1pll_pixel_clk_src.c,
- .dbg_name = "dsi1pll_pixel_clk_mux",
- .ops = &clk_ops_gen_mux_dsi,
- .flags = CLKFLAG_NO_RATE_CACHE,
- CLK_INIT(dsi1pll_pixel_clk_mux.c),
- }
-};
-
-static struct div_clk dsi0pll_byte_clk_src = {
- .data = {
- .div = 8,
- .min_div = 8,
- .max_div = 8,
- },
- .c = {
- .parent = &dsi0pll_post_n1_div_clk.c,
- .dbg_name = "dsi0pll_byte_clk_src",
- .ops = &clk_ops_div,
- CLK_INIT(dsi0pll_byte_clk_src.c),
- },
-};
-
-static struct div_clk dsi0pll_shadow_byte_clk_src = {
- .data = {
- .div = 8,
- .min_div = 8,
- .max_div = 8,
- },
- .c = {
- .parent = &dsi0pll_shadow_post_n1_div_clk.c,
- .dbg_name = "dsi0pll_shadow_byte_clk_src",
- .ops = &clk_ops_div,
- CLK_INIT(dsi0pll_shadow_byte_clk_src.c),
- },
-};
-
-static struct div_clk dsi1pll_byte_clk_src = {
- .data = {
- .div = 8,
- .min_div = 8,
- .max_div = 8,
- },
- .c = {
- .parent = &dsi1pll_post_n1_div_clk.c,
- .dbg_name = "dsi1pll_byte_clk_src",
- .ops = &clk_ops_div,
- CLK_INIT(dsi1pll_byte_clk_src.c),
- },
-};
-
-static struct div_clk dsi1pll_shadow_byte_clk_src = {
- .data = {
- .div = 8,
- .min_div = 8,
- .max_div = 8,
- },
- .c = {
- .parent = &dsi1pll_shadow_post_n1_div_clk.c,
- .dbg_name = "dsi1pll_shadow_byte_clk_src",
- .ops = &clk_ops_div,
- CLK_INIT(dsi1pll_shadow_byte_clk_src.c),
- },
-};
-
-static struct mux_clk dsi0pll_byte_clk_mux = {
- .num_parents = 2,
- .parents = (struct clk_src[]) {
- {&dsi0pll_byte_clk_src.c, 0},
- {&dsi0pll_shadow_byte_clk_src.c, 1},
- },
- .ops = &mdss_byte_mux_ops,
- .c = {
- .parent = &dsi0pll_byte_clk_src.c,
- .dbg_name = "dsi0pll_byte_clk_mux",
- .ops = &clk_ops_gen_mux_dsi,
- .flags = CLKFLAG_NO_RATE_CACHE,
- CLK_INIT(dsi0pll_byte_clk_mux.c),
- }
-};
-static struct mux_clk dsi1pll_byte_clk_mux = {
- .num_parents = 2,
- .parents = (struct clk_src[]) {
- {&dsi1pll_byte_clk_src.c, 0},
- {&dsi1pll_shadow_byte_clk_src.c, 1},
- },
- .ops = &mdss_byte_mux_ops,
- .c = {
- .parent = &dsi1pll_byte_clk_src.c,
- .dbg_name = "dsi1pll_byte_clk_mux",
- .ops = &clk_ops_gen_mux_dsi,
- .flags = CLKFLAG_NO_RATE_CACHE,
- CLK_INIT(dsi1pll_byte_clk_mux.c),
- }
-};
-
-static struct clk_lookup mdss_dsi_pllcc_8996[] = {
- CLK_LIST(dsi0pll_byte_clk_mux),
- CLK_LIST(dsi0pll_byte_clk_src),
- CLK_LIST(dsi0pll_pixel_clk_mux),
- CLK_LIST(dsi0pll_pixel_clk_src),
- CLK_LIST(dsi0pll_n2_div_clk),
- CLK_LIST(dsi0pll_post_n1_div_clk),
- CLK_LIST(dsi0pll_vco_clk),
- CLK_LIST(dsi0pll_shadow_byte_clk_src),
- CLK_LIST(dsi0pll_shadow_pixel_clk_src),
- CLK_LIST(dsi0pll_shadow_n2_div_clk),
- CLK_LIST(dsi0pll_shadow_post_n1_div_clk),
- CLK_LIST(dsi0pll_shadow_vco_clk),
-};
-
-static struct clk_lookup mdss_dsi_pllcc_8996_1[] = {
- CLK_LIST(dsi1pll_byte_clk_mux),
- CLK_LIST(dsi1pll_byte_clk_src),
- CLK_LIST(dsi1pll_pixel_clk_mux),
- CLK_LIST(dsi1pll_pixel_clk_src),
- CLK_LIST(dsi1pll_n2_div_clk),
- CLK_LIST(dsi1pll_post_n1_div_clk),
- CLK_LIST(dsi1pll_vco_clk),
- CLK_LIST(dsi1pll_shadow_byte_clk_src),
- CLK_LIST(dsi1pll_shadow_pixel_clk_src),
- CLK_LIST(dsi1pll_shadow_n2_div_clk),
- CLK_LIST(dsi1pll_shadow_post_n1_div_clk),
- CLK_LIST(dsi1pll_shadow_vco_clk),
-};
-
-int dsi_pll_clock_register_8996(struct platform_device *pdev,
- struct mdss_pll_resources *pll_res)
-{
- int rc = 0, ndx;
- int const ssc_freq_default = 31500; /* default h/w recommended value */
- int const ssc_ppm_default = 5000; /* default h/w recommended value */
- struct dsi_pll_db *pdb;
-
- if (!pdev || !pdev->dev.of_node) {
- pr_err("Invalid input parameters\n");
- return -EINVAL;
- }
-
- if (!pll_res || !pll_res->pll_base) {
- pr_err("Invalid PLL resources\n");
- return -EPROBE_DEFER;
- }
-
- if (pll_res->index >= DSI_PLL_NUM) {
- pr_err("pll ndx=%d is NOT supported\n", pll_res->index);
- return -EINVAL;
- }
-
- ndx = pll_res->index;
- pdb = &pll_db[ndx];
- pll_res->priv = pdb;
- pdb->pll = pll_res;
- ndx++;
- ndx %= DSI_PLL_NUM;
- pdb->next = &pll_db[ndx];
-
- /* Set clock source operations */
-
- /* hr_oclk3, pixel */
- n2_clk_src_ops = clk_ops_slave_div;
- n2_clk_src_ops.prepare = mdss_pll_div_prepare;
-
- shadow_n2_clk_src_ops = clk_ops_slave_div;
-
- /* hr_ockl2, byte, vco pll */
- post_n1_div_clk_src_ops = clk_ops_div;
- post_n1_div_clk_src_ops.prepare = mdss_pll_div_prepare;
-
- shadow_post_n1_div_clk_src_ops = clk_ops_div;
-
- byte_clk_src_ops = clk_ops_div;
- byte_clk_src_ops.prepare = mdss_pll_div_prepare;
-
- clk_ops_gen_mux_dsi = clk_ops_gen_mux;
- clk_ops_gen_mux_dsi.round_rate = parent_round_rate;
- clk_ops_gen_mux_dsi.set_rate = parent_set_rate;
-
- if (pll_res->ssc_en) {
- if (!pll_res->ssc_freq)
- pll_res->ssc_freq = ssc_freq_default;
- if (!pll_res->ssc_ppm)
- pll_res->ssc_ppm = ssc_ppm_default;
- }
-
- /* Set client data to mux, div and vco clocks. */
- if (pll_res->index == DSI_PLL_1) {
- dsi1pll_byte_clk_src.priv = pll_res;
- dsi1pll_pixel_clk_src.priv = pll_res;
- dsi1pll_post_n1_div_clk.priv = pll_res;
- dsi1pll_n2_div_clk.priv = pll_res;
- dsi1pll_vco_clk.priv = pll_res;
-
- dsi1pll_shadow_byte_clk_src.priv = pll_res;
- dsi1pll_shadow_pixel_clk_src.priv = pll_res;
- dsi1pll_shadow_post_n1_div_clk.priv = pll_res;
- dsi1pll_shadow_n2_div_clk.priv = pll_res;
- dsi1pll_shadow_vco_clk.priv = pll_res;
-
- pll_res->vco_delay = VCO_DELAY_USEC;
- rc = of_msm_clock_register(pdev->dev.of_node,
- mdss_dsi_pllcc_8996_1,
- ARRAY_SIZE(mdss_dsi_pllcc_8996_1));
- } else {
- dsi0pll_byte_clk_src.priv = pll_res;
- dsi0pll_pixel_clk_src.priv = pll_res;
- dsi0pll_post_n1_div_clk.priv = pll_res;
- dsi0pll_n2_div_clk.priv = pll_res;
- dsi0pll_vco_clk.priv = pll_res;
-
- dsi0pll_shadow_byte_clk_src.priv = pll_res;
- dsi0pll_shadow_pixel_clk_src.priv = pll_res;
- dsi0pll_shadow_post_n1_div_clk.priv = pll_res;
- dsi0pll_shadow_n2_div_clk.priv = pll_res;
- dsi0pll_shadow_vco_clk.priv = pll_res;
-
- pll_res->vco_delay = VCO_DELAY_USEC;
- rc = of_msm_clock_register(pdev->dev.of_node,
- mdss_dsi_pllcc_8996,
- ARRAY_SIZE(mdss_dsi_pllcc_8996));
- }
-
- if (!rc) {
- pr_info("Registered DSI PLL ndx=%d clocks successfully\n",
- pll_res->index);
- }
-
- return rc;
-}
diff --git a/drivers/clk/qcom/mdss/mdss-dsi-pll.h b/drivers/clk/qcom/mdss/mdss-dsi-pll.h
index 286c99e339c6..822d5181435d 100644
--- a/drivers/clk/qcom/mdss/mdss-dsi-pll.h
+++ b/drivers/clk/qcom/mdss/mdss-dsi-pll.h
@@ -31,6 +31,8 @@ struct lpfr_cfg {
};
struct dsi_pll_vco_clk {
+ struct clk_hw hw;
+
unsigned long ref_clk_rate;
unsigned long min_rate;
unsigned long max_rate;
@@ -39,72 +41,15 @@ struct dsi_pll_vco_clk {
u32 lpfr_lut_size;
void *priv;
- struct clk c;
-
int (*pll_enable_seqs[MAX_DSI_PLL_EN_SEQS])
(struct mdss_pll_resources *dsi_pll_Res);
};
-static inline struct dsi_pll_vco_clk *to_vco_clk(struct clk *clk)
+static inline struct dsi_pll_vco_clk *to_vco_hw(struct clk_hw *hw)
{
- return container_of(clk, struct dsi_pll_vco_clk, c);
+ return container_of(hw, struct dsi_pll_vco_clk, hw);
}
-int dsi_pll_clock_register_hpm(struct platform_device *pdev,
- struct mdss_pll_resources *pll_res);
-int dsi_pll_clock_register_20nm(struct platform_device *pdev,
- struct mdss_pll_resources *pll_res);
-int dsi_pll_clock_register_lpm(struct platform_device *pdev,
- struct mdss_pll_resources *pll_res);
-int dsi_pll_clock_register_8996(struct platform_device *pdev,
+int dsi_pll_clock_register_14nm(struct platform_device *pdev,
struct mdss_pll_resources *pll_res);
-int dsi_pll_clock_register_8998(struct platform_device *pdev,
- struct mdss_pll_resources *pll_res);
-
-int set_byte_mux_sel(struct mux_clk *clk, int sel);
-int get_byte_mux_sel(struct mux_clk *clk);
-int dsi_pll_mux_prepare(struct clk *c);
-int fixed_4div_set_div(struct div_clk *clk, int div);
-int fixed_4div_get_div(struct div_clk *clk);
-int digital_set_div(struct div_clk *clk, int div);
-int digital_get_div(struct div_clk *clk);
-int analog_set_div(struct div_clk *clk, int div);
-int analog_get_div(struct div_clk *clk);
-int dsi_pll_lock_status(struct mdss_pll_resources *dsi_pll_res);
-int vco_set_rate(struct dsi_pll_vco_clk *vco, unsigned long rate);
-unsigned long vco_get_rate(struct clk *c);
-long vco_round_rate(struct clk *c, unsigned long rate);
-enum handoff vco_handoff(struct clk *c);
-int vco_prepare(struct clk *c);
-void vco_unprepare(struct clk *c);
-
-/* APIs for 20nm PHY PLL */
-int pll_20nm_vco_set_rate(struct dsi_pll_vco_clk *vco, unsigned long rate);
-int shadow_pll_20nm_vco_set_rate(struct dsi_pll_vco_clk *vco,
- unsigned long rate);
-long pll_20nm_vco_round_rate(struct clk *c, unsigned long rate);
-enum handoff pll_20nm_vco_handoff(struct clk *c);
-int pll_20nm_vco_prepare(struct clk *c);
-void pll_20nm_vco_unprepare(struct clk *c);
-int pll_20nm_vco_enable_seq(struct mdss_pll_resources *dsi_pll_res);
-
-int set_bypass_lp_div_mux_sel(struct mux_clk *clk, int sel);
-int set_shadow_bypass_lp_div_mux_sel(struct mux_clk *clk, int sel);
-int get_bypass_lp_div_mux_sel(struct mux_clk *clk);
-int fixed_hr_oclk2_set_div(struct div_clk *clk, int div);
-int shadow_fixed_hr_oclk2_set_div(struct div_clk *clk, int div);
-int fixed_hr_oclk2_get_div(struct div_clk *clk);
-int hr_oclk3_set_div(struct div_clk *clk, int div);
-int shadow_hr_oclk3_set_div(struct div_clk *clk, int div);
-int hr_oclk3_get_div(struct div_clk *clk);
-int ndiv_set_div(struct div_clk *clk, int div);
-int shadow_ndiv_set_div(struct div_clk *clk, int div);
-int ndiv_get_div(struct div_clk *clk);
-void __dsi_pll_disable(void __iomem *pll_base);
-
-int set_mdss_pixel_mux_sel(struct mux_clk *clk, int sel);
-int get_mdss_pixel_mux_sel(struct mux_clk *clk);
-int set_mdss_byte_mux_sel(struct mux_clk *clk, int sel);
-int get_mdss_byte_mux_sel(struct mux_clk *clk);
-
#endif
diff --git a/drivers/clk/qcom/mdss/mdss-pll-util.c b/drivers/clk/qcom/mdss/mdss-pll-util.c
index 690c53f30eb7..881c973ec1b6 100644
--- a/drivers/clk/qcom/mdss/mdss-pll-util.c
+++ b/drivers/clk/qcom/mdss/mdss-pll-util.c
@@ -16,7 +16,6 @@
#include <linux/kernel.h>
#include <linux/err.h>
#include <linux/string.h>
-#include <linux/clk/msm-clock-generic.h>
#include <linux/of_address.h>
#include <linux/dma-mapping.h>
#include <linux/vmalloc.h>
diff --git a/drivers/clk/qcom/mdss/mdss-pll.c b/drivers/clk/qcom/mdss/mdss-pll.c
index 8264d2e5a3cd..b4b73ea4211a 100644
--- a/drivers/clk/qcom/mdss/mdss-pll.c
+++ b/drivers/clk/qcom/mdss/mdss-pll.c
@@ -19,12 +19,9 @@
#include <linux/err.h>
#include <linux/delay.h>
#include <linux/iopoll.h>
-#include <linux/clk/msm-clock-generic.h>
#include "mdss-pll.h"
#include "mdss-dsi-pll.h"
-#include "mdss-hdmi-pll.h"
-#include "mdss-dp-pll.h"
int mdss_pll_resource_enable(struct mdss_pll_resources *pll_res, bool enable)
{
@@ -175,27 +172,7 @@ static int mdss_pll_clock_register(struct platform_device *pdev,
switch (pll_res->pll_interface_type) {
case MDSS_DSI_PLL_8996:
- rc = dsi_pll_clock_register_8996(pdev, pll_res);
- break;
- case MDSS_DSI_PLL_8998:
- rc = dsi_pll_clock_register_8998(pdev, pll_res);
- case MDSS_DP_PLL_8998:
- rc = dp_pll_clock_register_8998(pdev, pll_res);
- break;
- case MDSS_HDMI_PLL_8996:
- rc = hdmi_8996_v1_pll_clock_register(pdev, pll_res);
- break;
- case MDSS_HDMI_PLL_8996_V2:
- rc = hdmi_8996_v2_pll_clock_register(pdev, pll_res);
- break;
- case MDSS_HDMI_PLL_8996_V3:
- rc = hdmi_8996_v3_pll_clock_register(pdev, pll_res);
- break;
- case MDSS_HDMI_PLL_8996_V3_1_8:
- rc = hdmi_8996_v3_1p8_pll_clock_register(pdev, pll_res);
- break;
- case MDSS_HDMI_PLL_8998:
- rc = hdmi_8998_pll_clock_register(pdev, pll_res);
+ rc = dsi_pll_clock_register_14nm(pdev, pll_res);
break;
case MDSS_UNKNOWN_PLL:
default:
diff --git a/drivers/clk/qcom/mdss/mdss-pll.h b/drivers/clk/qcom/mdss/mdss-pll.h
index 8fffaf30d4ec..3528dcfd0cb5 100644
--- a/drivers/clk/qcom/mdss/mdss-pll.h
+++ b/drivers/clk/qcom/mdss/mdss-pll.h
@@ -14,8 +14,16 @@
#define __MDSS_PLL_H
#include <linux/mdss_io_util.h>
-#include <linux/clk/msm-clock-generic.h>
+#include <linux/clk-provider.h>
#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/regmap.h>
+
+#include "../clk-regmap.h"
+#include "../clk-regmap-divider.h"
+#include "../clk-regmap-mux.h"
+#include <dt-bindings/clock/mdss-pll-clk.h>
#define MDSS_PLL_REG_W(base, offset, data) \
writel_relaxed((data), (base) + (offset))
@@ -200,21 +208,12 @@ static inline bool is_gdsc_disabled(struct mdss_pll_resources *pll_res)
(!(readl_relaxed(pll_res->gdsc_base) & BIT(0)))) ? false : true;
}
-static inline int mdss_pll_div_prepare(struct clk *c)
+static inline int mdss_pll_div_prepare(struct clk_hw *hw)
{
- struct div_clk *div = to_div_clk(c);
+ struct clk_hw *parent_hw = clk_hw_get_parent(hw);
/* Restore the divider's value */
- return div->ops->set_div(div, div->data.div);
-}
-
-static inline int mdss_set_mux_sel(struct mux_clk *clk, int sel)
-{
- return 0;
-}
-
-static inline int mdss_get_mux_sel(struct mux_clk *clk)
-{
- return 0;
+ return hw->init->ops->set_rate(hw, clk_hw_get_rate(hw),
+ clk_hw_get_rate(parent_hw));
}
int mdss_pll_resource_enable(struct mdss_pll_resources *pll_res, bool enable);
diff --git a/drivers/clk/qcom/mmcc-msmfalcon.c b/drivers/clk/qcom/mmcc-msmfalcon.c
index e4a84765430a..1d874f6db464 100644
--- a/drivers/clk/qcom/mmcc-msmfalcon.c
+++ b/drivers/clk/qcom/mmcc-msmfalcon.c
@@ -906,7 +906,7 @@ static struct clk_rcg2 dp_crypto_clk_src = {
static const struct freq_tbl ftbl_dp_gtc_clk_src[] = {
F(40000000, P_GPLL0_OUT_MAIN_DIV, 7.5, 0, 0),
- F(300000000, P_GPLL0_OUT_MAIN_DIV, 1, 0, 0),
+ F(60000000, P_GPLL0_OUT_MAIN, 10, 0, 0),
{ }
};
@@ -923,7 +923,7 @@ static struct clk_rcg2 dp_gtc_clk_src = {
.ops = &clk_rcg2_ops,
VDD_DIG_FMAX_MAP2(
LOWER, 40000000,
- LOW, 300000000),
+ LOW, 60000000),
},
};
@@ -1136,9 +1136,10 @@ static struct clk_rcg2 mdp_clk_src = {
.parent_names = mmcc_parent_names_7,
.num_parents = 7,
.ops = &clk_rcg2_ops,
- VDD_DIG_FMAX_MAP4(
+ VDD_DIG_FMAX_MAP5(
LOWER, 171428571,
LOW, 275000000,
+ LOW_L1, 300000000,
NOMINAL, 330000000,
HIGH, 412500000),
},
@@ -1183,6 +1184,7 @@ static struct clk_rcg2 pclk1_clk_src = {
static const struct freq_tbl ftbl_rot_clk_src[] = {
F(171428571, P_GPLL0_OUT_MAIN, 3.5, 0, 0),
F(275000000, P_MMPLL5_PLL_OUT_MAIN, 3, 0, 0),
+ F(300000000, P_GPLL0_OUT_MAIN, 2, 0, 0),
F(330000000, P_MMPLL5_PLL_OUT_MAIN, 2.5, 0, 0),
F(412500000, P_MMPLL5_PLL_OUT_MAIN, 2, 0, 0),
{ }
@@ -1199,9 +1201,10 @@ static struct clk_rcg2 rot_clk_src = {
.parent_names = mmcc_parent_names_7,
.num_parents = 7,
.ops = &clk_rcg2_ops,
- VDD_DIG_FMAX_MAP4(
+ VDD_DIG_FMAX_MAP5(
LOWER, 171428571,
LOW, 275000000,
+ LOW_L1, 300000000,
NOMINAL, 330000000,
HIGH, 412500000),
},
diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c
index cb4108b4e1f9..18c05e930216 100644
--- a/drivers/gpu/msm/adreno_dispatch.c
+++ b/drivers/gpu/msm/adreno_dispatch.c
@@ -359,6 +359,13 @@ static inline void _pop_drawobj(struct adreno_context *drawctxt)
drawctxt->queued--;
}
+static void _retire_sparseobj(struct kgsl_drawobj_sparse *sparseobj,
+ struct adreno_context *drawctxt)
+{
+ kgsl_sparse_bind(drawctxt->base.proc_priv, sparseobj);
+ _retire_timestamp(DRAWOBJ(sparseobj));
+}
+
static int _retire_markerobj(struct kgsl_drawobj_cmd *cmdobj,
struct adreno_context *drawctxt)
{
@@ -436,6 +443,8 @@ static struct kgsl_drawobj *_process_drawqueue_get_next_drawobj(
return drawobj;
} else if (drawobj->type == SYNCOBJ_TYPE)
ret = _retire_syncobj(SYNCOBJ(drawobj), drawctxt);
+ else
+ return ERR_PTR(-EINVAL);
if (ret == -EAGAIN)
return ERR_PTR(-EAGAIN);
@@ -670,6 +679,76 @@ static int sendcmd(struct adreno_device *adreno_dev,
return 0;
}
+
+/*
+ * Retires all sync objs from the sparse context
+ * queue and returns one of the below
+ * a) next sparseobj
+ * b) -EAGAIN for syncobj with syncpoints pending
+ * c) -EINVAL for unexpected drawobj
+ * d) NULL for no sparseobj
+ */
+static struct kgsl_drawobj_sparse *_get_next_sparseobj(
+ struct adreno_context *drawctxt)
+{
+ struct kgsl_drawobj *drawobj;
+ unsigned int i = drawctxt->drawqueue_head;
+ int ret = 0;
+
+ if (drawctxt->drawqueue_head == drawctxt->drawqueue_tail)
+ return NULL;
+
+ for (i = drawctxt->drawqueue_head; i != drawctxt->drawqueue_tail;
+ i = DRAWQUEUE_NEXT(i, ADRENO_CONTEXT_DRAWQUEUE_SIZE)) {
+
+ drawobj = drawctxt->drawqueue[i];
+
+ if (drawobj == NULL)
+ return NULL;
+
+ if (drawobj->type == SYNCOBJ_TYPE)
+ ret = _retire_syncobj(SYNCOBJ(drawobj), drawctxt);
+ else if (drawobj->type == SPARSEOBJ_TYPE)
+ return SPARSEOBJ(drawobj);
+ else
+ return ERR_PTR(-EINVAL);
+
+ if (ret == -EAGAIN)
+ return ERR_PTR(-EAGAIN);
+
+ continue;
+ }
+
+ return NULL;
+}
+
+static int _process_drawqueue_sparse(
+ struct adreno_context *drawctxt)
+{
+ struct kgsl_drawobj_sparse *sparseobj;
+ int ret = 0;
+ unsigned int i;
+
+ for (i = 0; i < ADRENO_CONTEXT_DRAWQUEUE_SIZE; i++) {
+
+ spin_lock(&drawctxt->lock);
+ sparseobj = _get_next_sparseobj(drawctxt);
+ if (IS_ERR_OR_NULL(sparseobj)) {
+ if (IS_ERR(sparseobj))
+ ret = PTR_ERR(sparseobj);
+ spin_unlock(&drawctxt->lock);
+ return ret;
+ }
+
+ _pop_drawobj(drawctxt);
+ spin_unlock(&drawctxt->lock);
+
+ _retire_sparseobj(sparseobj, drawctxt);
+ }
+
+ return 0;
+}
+
/**
* dispatcher_context_sendcmds() - Send commands from a context to the GPU
* @adreno_dev: Pointer to the adreno device struct
@@ -689,6 +768,9 @@ static int dispatcher_context_sendcmds(struct adreno_device *adreno_dev,
int inflight = _drawqueue_inflight(dispatch_q);
unsigned int timestamp;
+ if (drawctxt->base.flags & KGSL_CONTEXT_SPARSE)
+ return _process_drawqueue_sparse(drawctxt);
+
if (dispatch_q->inflight >= inflight) {
spin_lock(&drawctxt->lock);
_process_drawqueue_get_next_drawobj(drawctxt);
@@ -1124,6 +1206,31 @@ static void _queue_drawobj(struct adreno_context *drawctxt,
trace_adreno_cmdbatch_queued(drawobj, drawctxt->queued);
}
+static int _queue_sparseobj(struct adreno_device *adreno_dev,
+ struct adreno_context *drawctxt, struct kgsl_drawobj_sparse *sparseobj,
+ uint32_t *timestamp, unsigned int user_ts)
+{
+ struct kgsl_drawobj *drawobj = DRAWOBJ(sparseobj);
+ int ret;
+
+ ret = get_timestamp(drawctxt, drawobj, timestamp, user_ts);
+ if (ret)
+ return ret;
+
+ /*
+ * See if we can fastpath this thing - if nothing is
+ * queued bind/unbind without queueing the context
+ */
+ if (!drawctxt->queued)
+ return 1;
+
+ drawctxt->queued_timestamp = *timestamp;
+ _queue_drawobj(drawctxt, drawobj);
+
+ return 0;
+}
+
+
static int _queue_markerobj(struct adreno_device *adreno_dev,
struct adreno_context *drawctxt, struct kgsl_drawobj_cmd *markerobj,
uint32_t *timestamp, unsigned int user_ts)
@@ -1141,7 +1248,6 @@ static int _queue_markerobj(struct adreno_device *adreno_dev,
*/
if (!drawctxt->queued && kgsl_check_timestamp(drawobj->device,
drawobj->context, drawctxt->queued_timestamp)) {
- trace_adreno_cmdbatch_queued(drawobj, drawctxt->queued);
_retire_timestamp(drawobj);
return 1;
}
@@ -1212,7 +1318,7 @@ static void _queue_syncobj(struct adreno_context *drawctxt,
}
/**
- * adreno_dispactcher_queue_drawobj() - Queue a new draw object in the context
+ * adreno_dispactcher_queue_cmds() - Queue a new draw object in the context
* @dev_priv: Pointer to the device private struct
* @context: Pointer to the kgsl draw context
* @drawobj: Pointer to the array of drawobj's being submitted
@@ -1234,6 +1340,9 @@ int adreno_dispatcher_queue_cmds(struct kgsl_device_private *dev_priv,
int ret;
unsigned int i, user_ts;
+ if (!count)
+ return -EINVAL;
+
ret = _check_context_state(&drawctxt->base);
if (ret)
return ret;
@@ -1283,6 +1392,20 @@ int adreno_dispatcher_queue_cmds(struct kgsl_device_private *dev_priv,
_queue_syncobj(drawctxt, SYNCOBJ(drawobj[i]),
timestamp);
break;
+ case SPARSEOBJ_TYPE:
+ ret = _queue_sparseobj(adreno_dev, drawctxt,
+ SPARSEOBJ(drawobj[i]),
+ timestamp, user_ts);
+ if (ret == 1) {
+ spin_unlock(&drawctxt->lock);
+ _retire_sparseobj(SPARSEOBJ(drawobj[i]),
+ drawctxt);
+ return 0;
+ } else if (ret) {
+ spin_unlock(&drawctxt->lock);
+ return ret;
+ }
+ break;
default:
spin_unlock(&drawctxt->lock);
return -EINVAL;
diff --git a/drivers/gpu/msm/adreno_drawctxt.c b/drivers/gpu/msm/adreno_drawctxt.c
index 3a110ed221a8..1cbd2ef4b6b4 100644
--- a/drivers/gpu/msm/adreno_drawctxt.c
+++ b/drivers/gpu/msm/adreno_drawctxt.c
@@ -351,7 +351,8 @@ adreno_drawctxt_create(struct kgsl_device_private *dev_priv,
KGSL_CONTEXT_IFH_NOP |
KGSL_CONTEXT_SECURE |
KGSL_CONTEXT_PREEMPT_STYLE_MASK |
- KGSL_CONTEXT_NO_SNAPSHOT);
+ KGSL_CONTEXT_NO_SNAPSHOT |
+ KGSL_CONTEXT_SPARSE);
/* Check for errors before trying to initialize */
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 993f22b26294..bae3884aa277 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -1439,6 +1439,17 @@ long kgsl_ioctl_device_waittimestamp_ctxtid(
return result;
}
+static inline bool _check_context_is_sparse(struct kgsl_context *context,
+ uint64_t flags)
+{
+ if ((context->flags & KGSL_CONTEXT_SPARSE) ||
+ (flags & KGSL_DRAWOBJ_SPARSE))
+ return true;
+
+ return false;
+}
+
+
long kgsl_ioctl_rb_issueibcmds(struct kgsl_device_private *dev_priv,
unsigned int cmd, void *data)
{
@@ -1463,6 +1474,11 @@ long kgsl_ioctl_rb_issueibcmds(struct kgsl_device_private *dev_priv,
if (context == NULL)
return -EINVAL;
+ if (_check_context_is_sparse(context, param->flags)) {
+ kgsl_context_put(context);
+ return -EINVAL;
+ }
+
cmdobj = kgsl_drawobj_cmd_create(device, context, param->flags,
CMDOBJ_TYPE);
if (IS_ERR(cmdobj)) {
@@ -1558,6 +1574,11 @@ long kgsl_ioctl_submit_commands(struct kgsl_device_private *dev_priv,
if (context == NULL)
return -EINVAL;
+ if (_check_context_is_sparse(context, param->flags)) {
+ kgsl_context_put(context);
+ return -EINVAL;
+ }
+
if (type & SYNCOBJ_TYPE) {
struct kgsl_drawobj_sync *syncobj =
kgsl_drawobj_sync_create(device, context);
@@ -1632,6 +1653,11 @@ long kgsl_ioctl_gpu_command(struct kgsl_device_private *dev_priv,
if (context == NULL)
return -EINVAL;
+ if (_check_context_is_sparse(context, param->flags)) {
+ kgsl_context_put(context);
+ return -EINVAL;
+ }
+
if (type & SYNCOBJ_TYPE) {
struct kgsl_drawobj_sync *syncobj =
kgsl_drawobj_sync_create(device, context);
@@ -3742,6 +3768,128 @@ long kgsl_ioctl_sparse_bind(struct kgsl_device_private *dev_priv,
return ret;
}
+long kgsl_ioctl_gpu_sparse_command(struct kgsl_device_private *dev_priv,
+ unsigned int cmd, void *data)
+{
+ struct kgsl_gpu_sparse_command *param = data;
+ struct kgsl_device *device = dev_priv->device;
+ struct kgsl_context *context;
+ struct kgsl_drawobj *drawobj[2];
+ struct kgsl_drawobj_sparse *sparseobj;
+ long result;
+ unsigned int i = 0;
+
+ /* Make sure sparse and syncpoint count isn't too big */
+ if (param->numsparse > KGSL_MAX_SPARSE ||
+ param->numsyncs > KGSL_MAX_SYNCPOINTS)
+ return -EINVAL;
+
+ /* Make sure there is atleast one sparse or sync */
+ if (param->numsparse == 0 && param->numsyncs == 0)
+ return -EINVAL;
+
+ /* Only Sparse commands are supported in this ioctl */
+ if (!(param->flags & KGSL_DRAWOBJ_SPARSE) || (param->flags &
+ (KGSL_DRAWOBJ_SUBMIT_IB_LIST | KGSL_DRAWOBJ_MARKER
+ | KGSL_DRAWOBJ_SYNC)))
+ return -EINVAL;
+
+ context = kgsl_context_get_owner(dev_priv, param->context_id);
+ if (context == NULL)
+ return -EINVAL;
+
+ /* Restrict bind commands to bind context */
+ if (!(context->flags & KGSL_CONTEXT_SPARSE)) {
+ kgsl_context_put(context);
+ return -EINVAL;
+ }
+
+ if (param->numsyncs) {
+ struct kgsl_drawobj_sync *syncobj = kgsl_drawobj_sync_create(
+ device, context);
+ if (IS_ERR(syncobj)) {
+ result = PTR_ERR(syncobj);
+ goto done;
+ }
+
+ drawobj[i++] = DRAWOBJ(syncobj);
+ result = kgsl_drawobj_sync_add_synclist(device, syncobj,
+ to_user_ptr(param->synclist),
+ param->syncsize, param->numsyncs);
+ if (result)
+ goto done;
+ }
+
+ if (param->numsparse) {
+ sparseobj = kgsl_drawobj_sparse_create(device, context,
+ param->flags);
+ if (IS_ERR(sparseobj)) {
+ result = PTR_ERR(sparseobj);
+ goto done;
+ }
+
+ sparseobj->id = param->id;
+ drawobj[i++] = DRAWOBJ(sparseobj);
+ result = kgsl_drawobj_sparse_add_sparselist(device, sparseobj,
+ param->id, to_user_ptr(param->sparselist),
+ param->sparsesize, param->numsparse);
+ if (result)
+ goto done;
+ }
+
+ result = dev_priv->device->ftbl->queue_cmds(dev_priv, context,
+ drawobj, i, &param->timestamp);
+
+done:
+ /*
+ * -EPROTO is a "success" error - it just tells the user that the
+ * context had previously faulted
+ */
+ if (result && result != -EPROTO)
+ while (i--)
+ kgsl_drawobj_destroy(drawobj[i]);
+
+ kgsl_context_put(context);
+ return result;
+}
+
+void kgsl_sparse_bind(struct kgsl_process_private *private,
+ struct kgsl_drawobj_sparse *sparseobj)
+{
+ struct kgsl_sparseobj_node *sparse_node;
+ struct kgsl_mem_entry *virt_entry = NULL;
+ long ret = 0;
+ char *name;
+
+ virt_entry = kgsl_sharedmem_find_id_flags(private, sparseobj->id,
+ KGSL_MEMFLAGS_SPARSE_VIRT);
+ if (virt_entry == NULL)
+ return;
+
+ list_for_each_entry(sparse_node, &sparseobj->sparselist, node) {
+ if (sparse_node->obj.flags & KGSL_SPARSE_BIND) {
+ ret = sparse_bind_range(private, &sparse_node->obj,
+ virt_entry);
+ name = "bind";
+ } else {
+ ret = sparse_unbind_range(&sparse_node->obj,
+ virt_entry);
+ name = "unbind";
+ }
+
+ if (ret)
+ KGSL_CORE_ERR("kgsl: Unable to '%s' ret %ld virt_id %d, phys_id %d, virt_offset %16.16llX, phys_offset %16.16llX, size %16.16llX, flags %16.16llX\n",
+ name, ret, sparse_node->virt_id,
+ sparse_node->obj.id,
+ sparse_node->obj.virtoffset,
+ sparse_node->obj.physoffset,
+ sparse_node->obj.size, sparse_node->obj.flags);
+ }
+
+ kgsl_mem_entry_put(virt_entry);
+}
+EXPORT_SYMBOL(kgsl_sparse_bind);
+
long kgsl_ioctl_gpuobj_info(struct kgsl_device_private *dev_priv,
unsigned int cmd, void *data)
{
@@ -4656,7 +4804,7 @@ static void kgsl_core_exit(void)
kgsl_driver.class = NULL;
}
- kgsl_drawobj_exit();
+ kgsl_drawobjs_cache_exit();
kgsl_memfree_exit();
unregister_chrdev_region(kgsl_driver.major, KGSL_DEVICE_MAX);
@@ -4732,7 +4880,7 @@ static int __init kgsl_core_init(void)
kgsl_events_init();
- result = kgsl_drawobj_init();
+ result = kgsl_drawobjs_cache_init();
if (result)
goto err;
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index fbf9197b6d1b..2a9ac899725c 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -100,6 +100,7 @@ static inline void KGSL_STATS_ADD(uint64_t size, atomic_long_t *stat,
#define KGSL_MAX_NUMIBS 100000
#define KGSL_MAX_SYNCPOINTS 32
+#define KGSL_MAX_SPARSE 1000
struct kgsl_device;
struct kgsl_context;
@@ -432,6 +433,8 @@ long kgsl_ioctl_sparse_bind(struct kgsl_device_private *dev_priv,
unsigned int cmd, void *data);
long kgsl_ioctl_sparse_unbind(struct kgsl_device_private *dev_priv,
unsigned int cmd, void *data);
+long kgsl_ioctl_gpu_sparse_command(struct kgsl_device_private *dev_priv,
+ unsigned int cmd, void *data);
void kgsl_mem_entry_destroy(struct kref *kref);
diff --git a/drivers/gpu/msm/kgsl_compat.c b/drivers/gpu/msm/kgsl_compat.c
index 028a9566fa14..6b8d8d34a988 100644
--- a/drivers/gpu/msm/kgsl_compat.c
+++ b/drivers/gpu/msm/kgsl_compat.c
@@ -382,6 +382,8 @@ static const struct kgsl_ioctl kgsl_compat_ioctl_funcs[] = {
kgsl_ioctl_sparse_virt_free),
KGSL_IOCTL_FUNC(IOCTL_KGSL_SPARSE_BIND,
kgsl_ioctl_sparse_bind),
+ KGSL_IOCTL_FUNC(IOCTL_KGSL_GPU_SPARSE_COMMAND,
+ kgsl_ioctl_gpu_sparse_command),
};
long kgsl_compat_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index 7d68c23ad5b7..cb7ffd51460a 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -203,6 +203,18 @@ struct kgsl_memobj_node {
unsigned long priv;
};
+/**
+ * struct kgsl_sparseobj_node - Sparse object descriptor
+ * @node: Local list node for the sparse cmdbatch
+ * @virt_id: Virtual ID to bind/unbind
+ * @obj: struct kgsl_sparse_binding_object
+ */
+struct kgsl_sparseobj_node {
+ struct list_head node;
+ unsigned int virt_id;
+ struct kgsl_sparse_binding_object obj;
+};
+
struct kgsl_device {
struct device *dev;
const char *name;
@@ -639,6 +651,9 @@ long kgsl_ioctl_copy_in(unsigned int kernel_cmd, unsigned int user_cmd,
long kgsl_ioctl_copy_out(unsigned int kernel_cmd, unsigned int user_cmd,
unsigned long, unsigned char *ptr);
+void kgsl_sparse_bind(struct kgsl_process_private *private,
+ struct kgsl_drawobj_sparse *sparse);
+
/**
* kgsl_context_put() - Release context reference count
* @context: Pointer to the KGSL context to be released
diff --git a/drivers/gpu/msm/kgsl_drawobj.c b/drivers/gpu/msm/kgsl_drawobj.c
index 7840daa6a3e2..f8f0e7ccb0d3 100644
--- a/drivers/gpu/msm/kgsl_drawobj.c
+++ b/drivers/gpu/msm/kgsl_drawobj.c
@@ -37,10 +37,12 @@
#include "kgsl_compat.h"
/*
- * Define an kmem cache for the memobj structures since we allocate and free
- * them so frequently
+ * Define an kmem cache for the memobj & sparseobj structures since we
+ * allocate and free them so frequently
*/
static struct kmem_cache *memobjs_cache;
+static struct kmem_cache *sparseobjs_cache;
+
static void drawobj_destroy_object(struct kref *kref)
{
@@ -60,6 +62,9 @@ static void drawobj_destroy_object(struct kref *kref)
case MARKEROBJ_TYPE:
kfree(CMDOBJ(drawobj));
break;
+ case SPARSEOBJ_TYPE:
+ kfree(SPARSEOBJ(drawobj));
+ break;
}
}
@@ -211,6 +216,18 @@ static inline void memobj_list_free(struct list_head *list)
}
}
+static void drawobj_destroy_sparse(struct kgsl_drawobj *drawobj)
+{
+ struct kgsl_sparseobj_node *mem, *tmpmem;
+ struct list_head *list = &SPARSEOBJ(drawobj)->sparselist;
+
+ /* Free the sparse mem here */
+ list_for_each_entry_safe(mem, tmpmem, list, node) {
+ list_del_init(&mem->node);
+ kmem_cache_free(sparseobjs_cache, mem);
+ }
+}
+
static void drawobj_destroy_sync(struct kgsl_drawobj *drawobj)
{
struct kgsl_drawobj_sync *syncobj = SYNCOBJ(drawobj);
@@ -297,6 +314,8 @@ void kgsl_drawobj_destroy(struct kgsl_drawobj *drawobj)
drawobj_destroy_sync(drawobj);
else if (drawobj->type & (CMDOBJ_TYPE | MARKEROBJ_TYPE))
drawobj_destroy_cmd(drawobj);
+ else if (drawobj->type == SPARSEOBJ_TYPE)
+ drawobj_destroy_sparse(drawobj);
else
return;
@@ -610,16 +629,26 @@ int kgsl_drawobj_cmd_add_ibdesc(struct kgsl_device *device,
return 0;
}
-static inline int drawobj_init(struct kgsl_device *device,
- struct kgsl_context *context, struct kgsl_drawobj *drawobj,
+static void *_drawobj_create(struct kgsl_device *device,
+ struct kgsl_context *context, unsigned int size,
unsigned int type)
{
+ void *obj = kzalloc(size, GFP_KERNEL);
+ struct kgsl_drawobj *drawobj;
+
+ if (obj == NULL)
+ return ERR_PTR(-ENOMEM);
+
/*
* Increase the reference count on the context so it doesn't disappear
* during the lifetime of this object
*/
- if (!_kgsl_context_get(context))
- return -ENOENT;
+ if (!_kgsl_context_get(context)) {
+ kfree(obj);
+ return ERR_PTR(-ENOENT);
+ }
+
+ drawobj = obj;
kref_init(&drawobj->refcount);
@@ -627,7 +656,28 @@ static inline int drawobj_init(struct kgsl_device *device,
drawobj->context = context;
drawobj->type = type;
- return 0;
+ return obj;
+}
+
+/**
+ * kgsl_drawobj_sparse_create() - Create a new sparse obj structure
+ * @device: Pointer to a KGSL device struct
+ * @context: Pointer to a KGSL context struct
+ * @flags: Flags for the sparse obj
+ *
+ * Allocate an new kgsl_drawobj_sparse structure
+ */
+struct kgsl_drawobj_sparse *kgsl_drawobj_sparse_create(
+ struct kgsl_device *device,
+ struct kgsl_context *context, unsigned int flags)
+{
+ struct kgsl_drawobj_sparse *sparseobj = _drawobj_create(device,
+ context, sizeof(*sparseobj), SPARSEOBJ_TYPE);
+
+ if (!IS_ERR(sparseobj))
+ INIT_LIST_HEAD(&sparseobj->sparselist);
+
+ return sparseobj;
}
/**
@@ -641,18 +691,13 @@ static inline int drawobj_init(struct kgsl_device *device,
struct kgsl_drawobj_sync *kgsl_drawobj_sync_create(struct kgsl_device *device,
struct kgsl_context *context)
{
- struct kgsl_drawobj_sync *syncobj = kzalloc(sizeof(*syncobj),
- GFP_KERNEL);
- if (syncobj == NULL)
- return ERR_PTR(-ENOMEM);
-
- if (drawobj_init(device, context, DRAWOBJ(syncobj), SYNCOBJ_TYPE)) {
- kfree(syncobj);
- return ERR_PTR(-ENOENT);
- }
+ struct kgsl_drawobj_sync *syncobj = _drawobj_create(device,
+ context, sizeof(*syncobj), SYNCOBJ_TYPE);
/* Add a timer to help debug sync deadlocks */
- setup_timer(&syncobj->timer, syncobj_timer, (unsigned long) syncobj);
+ if (!IS_ERR(syncobj))
+ setup_timer(&syncobj->timer, syncobj_timer,
+ (unsigned long) syncobj);
return syncobj;
}
@@ -671,27 +716,13 @@ struct kgsl_drawobj_cmd *kgsl_drawobj_cmd_create(struct kgsl_device *device,
struct kgsl_context *context, unsigned int flags,
unsigned int type)
{
- struct kgsl_drawobj_cmd *cmdobj = kzalloc(sizeof(*cmdobj), GFP_KERNEL);
- struct kgsl_drawobj *drawobj;
-
- if (cmdobj == NULL)
- return ERR_PTR(-ENOMEM);
-
- type &= CMDOBJ_TYPE | MARKEROBJ_TYPE;
- if (type == 0) {
- kfree(cmdobj);
- return ERR_PTR(-EINVAL);
- }
-
- drawobj = DRAWOBJ(cmdobj);
-
- if (drawobj_init(device, context, drawobj, type)) {
- kfree(cmdobj);
- return ERR_PTR(-ENOENT);
- }
+ struct kgsl_drawobj_cmd *cmdobj = _drawobj_create(device,
+ context, sizeof(*cmdobj),
+ (type & (CMDOBJ_TYPE | MARKEROBJ_TYPE)));
- /* sanitize our flags for drawobj's */
- drawobj->flags = flags & (KGSL_DRAWOBJ_CTX_SWITCH
+ if (!IS_ERR(cmdobj)) {
+ /* sanitize our flags for drawobj's */
+ cmdobj->base.flags = flags & (KGSL_DRAWOBJ_CTX_SWITCH
| KGSL_DRAWOBJ_MARKER
| KGSL_DRAWOBJ_END_OF_FRAME
| KGSL_DRAWOBJ_PWR_CONSTRAINT
@@ -699,8 +730,9 @@ struct kgsl_drawobj_cmd *kgsl_drawobj_cmd_create(struct kgsl_device *device,
| KGSL_DRAWOBJ_PROFILING
| KGSL_DRAWOBJ_PROFILING_KTIME);
- INIT_LIST_HEAD(&cmdobj->cmdlist);
- INIT_LIST_HEAD(&cmdobj->memlist);
+ INIT_LIST_HEAD(&cmdobj->cmdlist);
+ INIT_LIST_HEAD(&cmdobj->memlist);
+ }
return cmdobj;
}
@@ -864,7 +896,7 @@ int kgsl_drawobj_sync_add_syncpoints(struct kgsl_device *device,
return 0;
}
-static int drawobj_add_object(struct list_head *head,
+static int kgsl_drawobj_add_memobject(struct list_head *head,
struct kgsl_command_object *obj)
{
struct kgsl_memobj_node *mem;
@@ -884,6 +916,62 @@ static int drawobj_add_object(struct list_head *head,
return 0;
}
+static int kgsl_drawobj_add_sparseobject(struct list_head *head,
+ struct kgsl_sparse_binding_object *obj, unsigned int virt_id)
+{
+ struct kgsl_sparseobj_node *mem;
+
+ mem = kmem_cache_alloc(sparseobjs_cache, GFP_KERNEL);
+ if (mem == NULL)
+ return -ENOMEM;
+
+ mem->virt_id = virt_id;
+ mem->obj.id = obj->id;
+ mem->obj.virtoffset = obj->virtoffset;
+ mem->obj.physoffset = obj->physoffset;
+ mem->obj.size = obj->size;
+ mem->obj.flags = obj->flags;
+
+ list_add_tail(&mem->node, head);
+ return 0;
+}
+
+int kgsl_drawobj_sparse_add_sparselist(struct kgsl_device *device,
+ struct kgsl_drawobj_sparse *sparseobj, unsigned int id,
+ void __user *ptr, unsigned int size, unsigned int count)
+{
+ struct kgsl_sparse_binding_object obj;
+ int i, ret = 0;
+
+ ret = _verify_input_list(count, ptr, size);
+ if (ret <= 0)
+ return ret;
+
+ for (i = 0; i < count; i++) {
+ memset(&obj, 0, sizeof(obj));
+
+ ret = _copy_from_user(&obj, ptr, sizeof(obj), size);
+ if (ret)
+ return ret;
+
+ if (!(obj.flags & (KGSL_SPARSE_BIND | KGSL_SPARSE_UNBIND)))
+ return -EINVAL;
+
+ ret = kgsl_drawobj_add_sparseobject(&sparseobj->sparselist,
+ &obj, id);
+ if (ret)
+ return ret;
+
+ ptr += sizeof(obj);
+ }
+
+ sparseobj->size = size;
+ sparseobj->count = count;
+
+ return 0;
+}
+
+
#define CMDLIST_FLAGS \
(KGSL_CMDLIST_IB | \
KGSL_CMDLIST_CTXTSWITCH_PREAMBLE | \
@@ -922,7 +1010,7 @@ int kgsl_drawobj_cmd_add_cmdlist(struct kgsl_device *device,
return -EINVAL;
}
- ret = drawobj_add_object(&cmdobj->cmdlist, &obj);
+ ret = kgsl_drawobj_add_memobject(&cmdobj->cmdlist, &obj);
if (ret)
return ret;
@@ -967,7 +1055,8 @@ int kgsl_drawobj_cmd_add_memlist(struct kgsl_device *device,
add_profiling_buffer(device, cmdobj, obj.gpuaddr,
obj.size, obj.id, obj.offset);
else {
- ret = drawobj_add_object(&cmdobj->memlist, &obj);
+ ret = kgsl_drawobj_add_memobject(&cmdobj->memlist,
+ &obj);
if (ret)
return ret;
}
@@ -1018,19 +1107,19 @@ int kgsl_drawobj_sync_add_synclist(struct kgsl_device *device,
return 0;
}
-void kgsl_drawobj_exit(void)
+void kgsl_drawobjs_cache_exit(void)
{
- if (memobjs_cache != NULL)
- kmem_cache_destroy(memobjs_cache);
+ kmem_cache_destroy(memobjs_cache);
+ kmem_cache_destroy(sparseobjs_cache);
}
-int kgsl_drawobj_init(void)
+int kgsl_drawobjs_cache_init(void)
{
memobjs_cache = KMEM_CACHE(kgsl_memobj_node, 0);
- if (memobjs_cache == NULL) {
- KGSL_CORE_ERR("failed to create memobjs_cache");
+ sparseobjs_cache = KMEM_CACHE(kgsl_sparseobj_node, 0);
+
+ if (!memobjs_cache || !sparseobjs_cache)
return -ENOMEM;
- }
return 0;
}
diff --git a/drivers/gpu/msm/kgsl_drawobj.h b/drivers/gpu/msm/kgsl_drawobj.h
index 89ed944c539a..fd9d2bc93f41 100644
--- a/drivers/gpu/msm/kgsl_drawobj.h
+++ b/drivers/gpu/msm/kgsl_drawobj.h
@@ -18,10 +18,13 @@
container_of(obj, struct kgsl_drawobj_sync, base)
#define CMDOBJ(obj) \
container_of(obj, struct kgsl_drawobj_cmd, base)
+#define SPARSEOBJ(obj) \
+ container_of(obj, struct kgsl_drawobj_sparse, base)
#define CMDOBJ_TYPE BIT(0)
#define MARKEROBJ_TYPE BIT(1)
#define SYNCOBJ_TYPE BIT(2)
+#define SPARSEOBJ_TYPE BIT(3)
/**
* struct kgsl_drawobj - KGSL drawobj descriptor
@@ -45,7 +48,7 @@ struct kgsl_drawobj {
* struct kgsl_drawobj_cmd - KGSL command obj, This covers marker
* cmds also since markers are special form of cmds that do not
* need their cmds to be executed.
- * @base: Base kgsl_drawobj
+ * @base: Base kgsl_drawobj, this needs to be the first entry
* @priv: Internal flags
* @global_ts: The ringbuffer timestamp corresponding to this
* command obj
@@ -123,6 +126,22 @@ struct kgsl_drawobj_sync_event {
struct kgsl_device *device;
};
+/**
+ * struct kgsl_drawobj_sparse - KGSl sparse obj descriptor
+ * @base: Base kgsl_obj, this needs to be the first entry
+ * @id: virtual id of the bind/unbind
+ * @sparselist: list of binds/unbinds
+ * @size: Size of kgsl_sparse_bind_object
+ * @count: Number of elements in list
+ */
+struct kgsl_drawobj_sparse {
+ struct kgsl_drawobj base;
+ unsigned int id;
+ struct list_head sparselist;
+ unsigned int size;
+ unsigned int count;
+};
+
#define KGSL_DRAWOBJ_FLAGS \
{ KGSL_DRAWOBJ_MARKER, "MARKER" }, \
{ KGSL_DRAWOBJ_CTX_SWITCH, "CTX_SWITCH" }, \
@@ -172,9 +191,15 @@ int kgsl_drawobj_sync_add_synclist(struct kgsl_device *device,
int kgsl_drawobj_sync_add_sync(struct kgsl_device *device,
struct kgsl_drawobj_sync *syncobj,
struct kgsl_cmd_syncpoint *sync);
-
-int kgsl_drawobj_init(void);
-void kgsl_drawobj_exit(void);
+struct kgsl_drawobj_sparse *kgsl_drawobj_sparse_create(
+ struct kgsl_device *device,
+ struct kgsl_context *context, unsigned int flags);
+int kgsl_drawobj_sparse_add_sparselist(struct kgsl_device *device,
+ struct kgsl_drawobj_sparse *sparseobj, unsigned int id,
+ void __user *ptr, unsigned int size, unsigned int count);
+
+int kgsl_drawobjs_cache_init(void);
+void kgsl_drawobjs_cache_exit(void);
void kgsl_dump_syncpoints(struct kgsl_device *device,
struct kgsl_drawobj_sync *syncobj);
diff --git a/drivers/gpu/msm/kgsl_ioctl.c b/drivers/gpu/msm/kgsl_ioctl.c
index 894e6a4a146b..f7876335d95e 100644
--- a/drivers/gpu/msm/kgsl_ioctl.c
+++ b/drivers/gpu/msm/kgsl_ioctl.c
@@ -100,6 +100,8 @@ static const struct kgsl_ioctl kgsl_ioctl_funcs[] = {
kgsl_ioctl_sparse_virt_free),
KGSL_IOCTL_FUNC(IOCTL_KGSL_SPARSE_BIND,
kgsl_ioctl_sparse_bind),
+ KGSL_IOCTL_FUNC(IOCTL_KGSL_GPU_SPARSE_COMMAND,
+ kgsl_ioctl_gpu_sparse_command),
};
long kgsl_ioctl_copy_in(unsigned int kernel_cmd, unsigned int user_cmd,
diff --git a/drivers/hwtracing/coresight/Kconfig b/drivers/hwtracing/coresight/Kconfig
index 8c92a564299d..ed70a980d9ac 100644
--- a/drivers/hwtracing/coresight/Kconfig
+++ b/drivers/hwtracing/coresight/Kconfig
@@ -79,7 +79,6 @@ config CORESIGHT_SOURCE_ETM3X
config CORESIGHT_SOURCE_ETM4X
bool "CoreSight Embedded Trace Macrocell 4.x driver"
- depends on ARM64
select CORESIGHT_LINKS_AND_SINKS
help
This driver provides support for the ETM4.x tracer module, tracing the
@@ -113,7 +112,7 @@ config CORESIGHT_QCOM_REPLICATOR
config CORESIGHT_STM
bool "CoreSight System Trace Macrocell driver"
- depends on CORESIGHT_LINKS_AND_SINKS
+ select CORESIGHT_LINKS_AND_SINKS
help
This driver provides support for hardware assisted software
instrumentation based tracing. This is primarily useful for
diff --git a/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.c b/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.c
index 3e3143be0a13..b045d6c6e8da 100644
--- a/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.c
+++ b/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.c
@@ -972,6 +972,11 @@ static int cam_smmu_map_buffer_and_add_to_list(int idx, int ion_fd,
struct dma_buf_attachment *attach = NULL;
struct sg_table *table = NULL;
+ if (!paddr_ptr) {
+ rc = -EINVAL;
+ goto err_out;
+ }
+
/* allocate memory for each buffer information */
buf = dma_buf_get(ion_fd);
if (IS_ERR_OR_NULL(buf)) {
diff --git a/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c b/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c
index a56e42dc1c6f..31568da21fee 100644
--- a/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c
+++ b/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c
@@ -266,8 +266,10 @@ static void msm_fd_stop_streaming(struct vb2_queue *q)
{
struct fd_ctx *ctx = vb2_get_drv_priv(q);
+ mutex_lock(&ctx->fd_device->recovery_lock);
msm_fd_hw_remove_buffers_from_queue(ctx->fd_device, q);
msm_fd_hw_put(ctx->fd_device);
+ mutex_unlock(&ctx->fd_device->recovery_lock);
}
/* Videobuf2 queue callbacks. */
@@ -329,6 +331,68 @@ static struct vb2_mem_ops msm_fd_vb2_mem_ops = {
};
/*
+ * msm_fd_vbif_error_handler - FD VBIF Error handler
+ * @handle: FD Device handle
+ * @error: CPP-VBIF Error code
+ */
+static int msm_fd_vbif_error_handler(void *handle, uint32_t error)
+{
+ struct fd_ctx *ctx;
+ struct msm_fd_device *fd;
+ struct msm_fd_buffer *active_buf;
+ int ret;
+
+ if (handle == NULL)
+ return 0;
+
+ ctx = (struct fd_ctx *)handle;
+ fd = (struct msm_fd_device *)ctx->fd_device;
+
+ if (error == CPP_VBIF_ERROR_HANG) {
+ mutex_lock(&fd->recovery_lock);
+ dev_err(fd->dev, "Handling FD VBIF Hang\n");
+ if (fd->state != MSM_FD_DEVICE_RUNNING) {
+ dev_err(fd->dev, "FD is not FD_DEVICE_RUNNING, %d\n",
+ fd->state);
+ mutex_unlock(&fd->recovery_lock);
+ return 0;
+ }
+ fd->recovery_mode = 1;
+
+ /* Halt and reset */
+ msm_fd_hw_put(fd);
+ msm_fd_hw_get(fd, ctx->settings.speed);
+
+ /* Get active buffer */
+ active_buf = msm_fd_hw_get_active_buffer(fd);
+
+ if (active_buf == NULL) {
+ dev_dbg(fd->dev, "no active buffer, return\n");
+ fd->recovery_mode = 0;
+ mutex_unlock(&fd->recovery_lock);
+ return 0;
+ }
+
+ dev_dbg(fd->dev, "Active Buffer present.. Start re-schedule\n");
+
+ /* Queue the buffer again */
+ msm_fd_hw_add_buffer(fd, active_buf);
+
+ /* Schedule and restart */
+ ret = msm_fd_hw_schedule_next_buffer(fd);
+ if (ret) {
+ dev_err(fd->dev, "Cannot reschedule buffer, recovery failed\n");
+ fd->recovery_mode = 0;
+ mutex_unlock(&fd->recovery_lock);
+ return ret;
+ }
+ dev_dbg(fd->dev, "Restarted FD after VBIF HAng\n");
+ mutex_unlock(&fd->recovery_lock);
+ }
+ return 0;
+}
+
+/*
* msm_fd_open - Fd device open method.
* @file: Pointer to file struct.
*/
@@ -391,6 +455,10 @@ static int msm_fd_open(struct file *file)
goto error_ahb_config;
}
+ /* Register with CPP VBIF error handler */
+ msm_cpp_vbif_register_error_handler((void *)ctx,
+ VBIF_CLIENT_FD, msm_fd_vbif_error_handler);
+
return 0;
error_ahb_config:
@@ -412,6 +480,10 @@ static int msm_fd_release(struct file *file)
{
struct fd_ctx *ctx = msm_fd_ctx_from_fh(file->private_data);
+ /* Un-register with CPP VBIF error handler */
+ msm_cpp_vbif_register_error_handler((void *)ctx,
+ VBIF_CLIENT_FD, NULL);
+
vb2_queue_release(&ctx->vb2_q);
vfree(ctx->stats);
@@ -468,7 +540,7 @@ static long msm_fd_private_ioctl(struct file *file, void *fh,
struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh);
struct msm_fd_stats *stats;
int stats_idx;
- int ret;
+ int ret = 0;
int i;
switch (cmd) {
@@ -1176,6 +1248,12 @@ static void msm_fd_wq_handler(struct work_struct *work)
/* Stats are ready, set correct frame id */
atomic_set(&stats->frame_id, ctx->sequence);
+ /* If Recovery mode is on, we got IRQ after recovery, reset it */
+ if (fd->recovery_mode) {
+ fd->recovery_mode = 0;
+ dev_dbg(fd->dev, "Got IRQ after Recovery\n");
+ }
+
/* We have the data from fd hw, we can start next processing */
msm_fd_hw_schedule_next_buffer(fd);
@@ -1213,6 +1291,7 @@ static int fd_probe(struct platform_device *pdev)
mutex_init(&fd->lock);
spin_lock_init(&fd->slock);
+ mutex_init(&fd->recovery_lock);
init_completion(&fd->hw_halt_completion);
INIT_LIST_HEAD(&fd->buf_queue);
fd->pdev = pdev;
diff --git a/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.h b/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.h
index b96c33b3fd07..7505f0585d42 100644
--- a/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.h
+++ b/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.h
@@ -23,6 +23,8 @@
#include <linux/msm_ion.h>
#include "cam_soc_api.h"
#include "cam_hw_ops.h"
+#include "msm_cpp.h"
+
/* Maximum number of result buffers */
#define MSM_FD_MAX_RESULT_BUFS 5
/* Max number of clocks defined in device tree */
@@ -214,12 +216,14 @@ enum msm_fd_mem_resources {
* @work_queue: Pointer to FD device IRQ bottom half workqueue.
* @work: IRQ bottom half work struct.
* @hw_halt_completion: Completes when face detection hw halt completes.
+ * @recovery_mode: Indicates if FD is in recovery mode
*/
struct msm_fd_device {
u32 hw_revision;
struct mutex lock;
spinlock_t slock;
+ struct mutex recovery_lock;
int ref_count;
int irq_num;
@@ -248,6 +252,8 @@ struct msm_fd_device {
struct workqueue_struct *work_queue;
struct work_struct work;
struct completion hw_halt_completion;
+ int recovery_mode;
+ uint32_t clk_rate_idx;
};
#endif /* __MSM_FD_DEV_H__ */
diff --git a/drivers/media/platform/msm/camera_v2/fd/msm_fd_hw.c b/drivers/media/platform/msm/camera_v2/fd/msm_fd_hw.c
index 08268d98fc13..21d42a77accb 100644
--- a/drivers/media/platform/msm/camera_v2/fd/msm_fd_hw.c
+++ b/drivers/media/platform/msm/camera_v2/fd/msm_fd_hw.c
@@ -38,7 +38,7 @@
/* Face detection bus client name */
#define MSM_FD_BUS_CLIENT_NAME "msm_face_detect"
/* Face detection processing timeout in ms */
-#define MSM_FD_PROCESSING_TIMEOUT_MS 500
+#define MSM_FD_PROCESSING_TIMEOUT_MS 150
/* Face detection halt timeout in ms */
#define MSM_FD_HALT_TIMEOUT_MS 100
/* Smmu callback name */
@@ -822,6 +822,45 @@ static int msm_fd_hw_set_clock_rate_idx(struct msm_fd_device *fd,
return 0;
}
+
+/**
+ * msm_fd_hw_update_settings() - API to set clock rate and bus settings
+ * @fd: Pointer to fd device.
+ * @buf: fd buffer
+ */
+static int msm_fd_hw_update_settings(struct msm_fd_device *fd,
+ struct msm_fd_buffer *buf)
+{
+ int ret = 0;
+ uint32_t clk_rate_idx;
+
+ if (!buf)
+ return 0;
+
+ clk_rate_idx = buf->settings.speed;
+ if (fd->clk_rate_idx == clk_rate_idx)
+ return 0;
+
+ if (fd->bus_client) {
+ ret = msm_fd_hw_bus_request(fd, clk_rate_idx);
+ if (ret < 0) {
+ dev_err(fd->dev, "Fail bus scale update %d\n", ret);
+ return -EINVAL;
+ }
+ }
+
+ ret = msm_fd_hw_set_clock_rate_idx(fd, clk_rate_idx);
+ if (ret < 0) {
+ dev_err(fd->dev, "Fail to set clock rate idx\n");
+ goto end;
+ }
+ dev_dbg(fd->dev, "set clk %d %d", fd->clk_rate_idx, clk_rate_idx);
+ fd->clk_rate_idx = clk_rate_idx;
+
+end:
+ return ret;
+}
+
/*
* msm_fd_hw_get - Get fd hw for performing any hw operation.
* @fd: Pointer to fd device.
@@ -868,6 +907,8 @@ int msm_fd_hw_get(struct msm_fd_device *fd, unsigned int clock_rate_idx)
ret = msm_fd_hw_set_dt_parms(fd);
if (ret < 0)
goto error_set_dt;
+
+ fd->clk_rate_idx = clock_rate_idx;
}
fd->ref_count++;
@@ -924,7 +965,7 @@ void msm_fd_hw_put(struct msm_fd_device *fd)
*/
static int msm_fd_hw_attach_iommu(struct msm_fd_device *fd)
{
- int ret;
+ int ret = -EINVAL;
mutex_lock(&fd->lock);
@@ -1058,6 +1099,8 @@ static int msm_fd_hw_enable(struct msm_fd_device *fd,
msm_fd_hw_set_direction_angle(fd, buffer->settings.direction_index,
buffer->settings.angle_index);
msm_fd_hw_run(fd);
+ if (fd->recovery_mode)
+ dev_err(fd->dev, "Scheduled buffer in recovery mode\n");
return 1;
}
@@ -1153,6 +1196,9 @@ void msm_fd_hw_remove_buffers_from_queue(struct msm_fd_device *fd,
time = wait_for_completion_timeout(&active_buffer->completion,
msecs_to_jiffies(MSM_FD_PROCESSING_TIMEOUT_MS));
if (!time) {
+ /* Do a vb2 buffer done since it timed out */
+ vb2_buffer_done(&active_buffer->vb_v4l2_buf.vb2_buf,
+ VB2_BUF_STATE_DONE);
/* Remove active buffer */
msm_fd_hw_get_active_buffer(fd);
/* Schedule if other buffers are present in device */
@@ -1224,6 +1270,8 @@ int msm_fd_hw_schedule_and_start(struct msm_fd_device *fd)
spin_unlock(&fd->slock);
+ msm_fd_hw_update_settings(fd, buf);
+
return 0;
}
@@ -1257,8 +1305,12 @@ int msm_fd_hw_schedule_next_buffer(struct msm_fd_device *fd)
}
} else {
fd->state = MSM_FD_DEVICE_IDLE;
+ if (fd->recovery_mode)
+ dev_err(fd->dev, "No Buffer in recovery mode.Device Idle\n");
}
spin_unlock(&fd->slock);
+ msm_fd_hw_update_settings(fd, buf);
+
return 0;
}
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c
index 56056849e140..8793745aac71 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c
@@ -1523,6 +1523,8 @@ void msm_vfe47_update_camif_state(struct vfe_device *vfe_dev,
if ((vfe_dev->hvx_cmd > HVX_DISABLE) &&
(vfe_dev->hvx_cmd <= HVX_ROUND_TRIP))
msm_vfe47_configure_hvx(vfe_dev, 1);
+ else
+ msm_vfe47_configure_hvx(vfe_dev, 0);
bus_en =
((vfe_dev->axi_data.
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 59b875d6e464..778df297f93c 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
@@ -450,9 +450,7 @@ static int msm_isp_cfg_pix(struct vfe_device *vfe_dev,
}
pix_cfg = &input_cfg->d.pix_cfg;
- if ((pix_cfg->hvx_cmd > HVX_DISABLE) &&
- (pix_cfg->hvx_cmd <= HVX_ROUND_TRIP))
- vfe_dev->hvx_cmd = pix_cfg->hvx_cmd;
+ vfe_dev->hvx_cmd = pix_cfg->hvx_cmd;
vfe_dev->is_split = input_cfg->d.pix_cfg.is_split;
vfe_dev->axi_data.src_info[VFE_PIX_0].pixel_clock =
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 7e452e9e4ee2..b7724b4bf936 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
@@ -102,6 +102,7 @@
#define IS_DEFAULT_OUTPUT_BUF_INDEX(index) \
((index == DEFAULT_OUTPUT_BUF_INDEX) ? 1 : 0)
+static struct msm_cpp_vbif_data cpp_vbif;
static int msm_cpp_buffer_ops(struct cpp_device *cpp_dev,
uint32_t buff_mgr_ops, uint32_t ids, void *arg);
@@ -121,6 +122,7 @@ static void msm_cpp_flush_queue_and_release_buffer(struct cpp_device *cpp_dev,
static int msm_cpp_dump_frame_cmd(struct msm_cpp_frame_info_t *frame_info);
static int msm_cpp_dump_addr(struct cpp_device *cpp_dev,
struct msm_cpp_frame_info_t *frame_info);
+static int32_t msm_cpp_reset_vbif_and_load_fw(struct cpp_device *cpp_dev);
#if CONFIG_MSM_CPP_DBG
#define CPP_DBG(fmt, args...) pr_err(fmt, ##args)
@@ -171,6 +173,26 @@ struct msm_cpp_timer_t {
struct msm_cpp_timer_t cpp_timer;
static void msm_cpp_set_vbif_reg_values(struct cpp_device *cpp_dev);
+
+void msm_cpp_vbif_register_error_handler(void *dev,
+ enum cpp_vbif_client client,
+ int (*client_vbif_error_handler)(void *, uint32_t))
+{
+ if (dev == NULL || client >= VBIF_CLIENT_MAX) {
+ pr_err("%s: Fail to register handler! dev = %p, client %d\n",
+ __func__, dev, client);
+ return;
+ }
+
+ if (client_vbif_error_handler != NULL) {
+ cpp_vbif.dev[client] = dev;
+ cpp_vbif.err_handler[client] = client_vbif_error_handler;
+ } else {
+ /* if handler = NULL, is unregister case */
+ cpp_vbif.dev[client] = NULL;
+ cpp_vbif.err_handler[client] = NULL;
+ }
+}
static int msm_cpp_init_bandwidth_mgr(struct cpp_device *cpp_dev)
{
int rc = 0;
@@ -755,6 +777,7 @@ static void msm_cpp_iommu_fault_handler(struct iommu_domain *domain,
struct msm_cpp_frame_info_t *processed_frame[MAX_CPP_PROCESSING_FRAME];
int32_t i = 0, queue_len = 0;
struct msm_device_queue *queue = NULL;
+ int32_t rc = 0;
if (token) {
cpp_dev = token;
@@ -765,7 +788,16 @@ static void msm_cpp_iommu_fault_handler(struct iommu_domain *domain,
}
mutex_lock(&cpp_dev->mutex);
tasklet_kill(&cpp_dev->cpp_tasklet);
- cpp_load_fw(cpp_dev, cpp_dev->fw_name_bin);
+ rc = cpp_load_fw(cpp_dev, cpp_dev->fw_name_bin);
+ if (rc < 0) {
+ pr_err("load fw failure %d-retry\n", rc);
+ rc = msm_cpp_reset_vbif_and_load_fw(cpp_dev);
+ if (rc < 0) {
+ msm_cpp_set_micro_irq_mask(cpp_dev, 1, 0x8);
+ mutex_unlock(&cpp_dev->mutex);
+ return;
+ }
+ }
queue = &cpp_timer.data.cpp_dev->processing_q;
queue_len = queue->len;
if (!queue_len) {
@@ -1022,11 +1054,16 @@ static int cpp_init_hardware(struct cpp_device *cpp_dev)
if (cpp_dev->fw_name_bin) {
msm_camera_enable_irq(cpp_dev->irq, false);
rc = cpp_load_fw(cpp_dev, cpp_dev->fw_name_bin);
- msm_camera_enable_irq(cpp_dev->irq, true);
if (rc < 0) {
- pr_err("%s: load firmware failure %d\n", __func__, rc);
- goto pwr_collapse_reset;
+ pr_err("%s: load firmware failure %d-retry\n",
+ __func__, rc);
+ rc = msm_cpp_reset_vbif_and_load_fw(cpp_dev);
+ if (rc < 0) {
+ msm_camera_enable_irq(cpp_dev->irq, true);
+ goto pwr_collapse_reset;
+ }
}
+ msm_camera_enable_irq(cpp_dev->irq, true);
msm_camera_io_w_mb(0x7C8, cpp_dev->base +
MSM_CPP_MICRO_IRQGEN_MASK);
msm_camera_io_w_mb(0xFFFF, cpp_dev->base +
@@ -1038,6 +1075,7 @@ static int cpp_init_hardware(struct cpp_device *cpp_dev)
pwr_collapse_reset:
msm_cpp_update_gdscr_status(cpp_dev, false);
+ msm_camera_unregister_irq(cpp_dev->pdev, cpp_dev->irq, cpp_dev);
req_irq_fail:
if (cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CPP,
CAM_AHB_SUSPEND_VOTE) < 0)
@@ -1081,7 +1119,7 @@ static int32_t cpp_load_fw(struct cpp_device *cpp_dev, char *fw_name_bin)
{
uint32_t i;
uint32_t *ptr_bin = NULL;
- int32_t rc = 0;
+ int32_t rc = 0, ret = 0;
if (!fw_name_bin) {
pr_err("%s:%d] invalid fw name", __func__, __LINE__);
@@ -1207,14 +1245,70 @@ static int32_t cpp_load_fw(struct cpp_device *cpp_dev, char *fw_name_bin)
}
vote:
- rc = cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CPP,
+ ret = cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CPP,
CAM_AHB_SVS_VOTE);
- if (rc < 0)
+ if (ret < 0) {
pr_err("%s:%d: failed to vote for AHB\n", __func__, __LINE__);
+ rc = ret;
+ }
end:
return rc;
}
+int32_t msm_cpp_reset_vbif_clients(struct cpp_device *cpp_dev)
+{
+ uint32_t i;
+
+ pr_warn("%s: handle vbif hang...\n", __func__);
+ for (i = 0; i < VBIF_CLIENT_MAX; i++) {
+ if (cpp_dev->vbif_data->err_handler[i] == NULL)
+ continue;
+
+ cpp_dev->vbif_data->err_handler[i](
+ cpp_dev->vbif_data->dev[i], CPP_VBIF_ERROR_HANG);
+ }
+ return 0;
+}
+
+int32_t msm_cpp_reset_vbif_and_load_fw(struct cpp_device *cpp_dev)
+{
+ int32_t rc = 0;
+
+ msm_cpp_reset_vbif_clients(cpp_dev);
+
+ rc = cpp_load_fw(cpp_dev, cpp_dev->fw_name_bin);
+ if (rc < 0)
+ pr_err("Reset and load fw failed %d\n", rc);
+
+ return rc;
+}
+
+int cpp_vbif_error_handler(void *dev, uint32_t vbif_error)
+{
+ struct cpp_device *cpp_dev = NULL;
+
+ if (dev == NULL || vbif_error >= CPP_VBIF_ERROR_MAX) {
+ pr_err("failed: dev %p, vbif error %d\n", dev, vbif_error);
+ return -EINVAL;
+ }
+
+ cpp_dev = (struct cpp_device *) dev;
+
+ /* MMSS_A_CPP_IRQ_STATUS_0 = 0x10 */
+ pr_err("%s: before reset halt... read MMSS_A_CPP_IRQ_STATUS_0 = 0x%x",
+ __func__, msm_camera_io_r(cpp_dev->cpp_hw_base + 0x10));
+
+ pr_err("%s: start reset bus bridge on FD + CPP!\n", __func__);
+ /* MMSS_A_CPP_RST_CMD_0 = 0x8, firmware reset = 0x3DF77 */
+ msm_camera_io_w(0x3DF77, cpp_dev->cpp_hw_base + 0x8);
+
+ /* MMSS_A_CPP_IRQ_STATUS_0 = 0x10 */
+ pr_err("%s: after reset halt... read MMSS_A_CPP_IRQ_STATUS_0 = 0x%x",
+ __func__, msm_camera_io_r(cpp_dev->cpp_hw_base + 0x10));
+
+ return 0;
+}
+
static int cpp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
int rc;
@@ -1255,6 +1349,10 @@ static int cpp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
CPP_DBG("open %d %pK\n", i, &fh->vfh);
cpp_dev->cpp_open_cnt++;
+
+ msm_cpp_vbif_register_error_handler(cpp_dev,
+ VBIF_CLIENT_CPP, cpp_vbif_error_handler);
+
if (cpp_dev->cpp_open_cnt == 1) {
rc = cpp_init_hardware(cpp_dev);
if (rc < 0) {
@@ -1284,6 +1382,7 @@ static int cpp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
rc = -ENOMEM;
}
}
+
mutex_unlock(&cpp_dev->mutex);
return 0;
}
@@ -1383,6 +1482,9 @@ static int cpp_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
}
}
+ /* unregister vbif error handler */
+ msm_cpp_vbif_register_error_handler(cpp_dev,
+ VBIF_CLIENT_CPP, NULL);
mutex_unlock(&cpp_dev->mutex);
return 0;
}
@@ -1641,8 +1743,12 @@ static void msm_cpp_do_timeout_work(struct work_struct *work)
rc = cpp_load_fw(cpp_timer.data.cpp_dev,
cpp_timer.data.cpp_dev->fw_name_bin);
if (rc) {
- pr_warn("Firmware loading failed\n");
- goto error;
+ pr_warn("Firmware loading failed-retry\n");
+ rc = msm_cpp_reset_vbif_and_load_fw(cpp_dev);
+ if (rc < 0) {
+ pr_err("Firmware loading failed\n");
+ goto error;
+ }
} else {
pr_debug("Firmware loading done\n");
}
@@ -2926,11 +3032,14 @@ long msm_cpp_subdev_ioctl(struct v4l2_subdev *sd,
msm_camera_enable_irq(cpp_dev->irq, false);
rc = cpp_load_fw(cpp_dev, cpp_dev->fw_name_bin);
if (rc < 0) {
- pr_err("%s: load firmware failure %d\n",
+ pr_err("%s: load firmware failure %d-retry\n",
__func__, rc);
- enable_irq(cpp_dev->irq->start);
- mutex_unlock(&cpp_dev->mutex);
- return rc;
+ rc = msm_cpp_reset_vbif_and_load_fw(cpp_dev);
+ if (rc < 0) {
+ enable_irq(cpp_dev->irq->start);
+ mutex_unlock(&cpp_dev->mutex);
+ return rc;
+ }
}
rc = msm_cpp_fw_version(cpp_dev);
if (rc < 0) {
@@ -4195,6 +4304,8 @@ static int cpp_probe(struct platform_device *pdev)
spin_lock_init(&cpp_timer.data.processed_frame_lock);
cpp_dev->pdev = pdev;
+ memset(&cpp_vbif, 0, sizeof(struct msm_cpp_vbif_data));
+ cpp_dev->vbif_data = &cpp_vbif;
cpp_dev->camss_cpp_base =
msm_camera_get_reg_base(pdev, "camss_cpp", true);
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
index f46cc10cef46..470c0cf1131b 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
@@ -23,6 +23,7 @@
#include "msm_sd.h"
#include "cam_soc_api.h"
#include "cam_hw_ops.h"
+#include <media/msmb_pproc.h>
/* hw version info:
31:28 Major version
@@ -95,6 +96,22 @@
#define MSM_CPP_TX_FIFO_LEVEL 16
#define MSM_CPP_RX_FIFO_LEVEL 512
+enum cpp_vbif_error {
+ CPP_VBIF_ERROR_HANG,
+ CPP_VBIF_ERROR_MAX,
+};
+
+enum cpp_vbif_client {
+ VBIF_CLIENT_CPP,
+ VBIF_CLIENT_FD,
+ VBIF_CLIENT_MAX,
+};
+
+struct msm_cpp_vbif_data {
+ int (*err_handler[VBIF_CLIENT_MAX])(void *, uint32_t);
+ void *dev[VBIF_CLIENT_MAX];
+};
+
struct cpp_subscribe_info {
struct v4l2_fh *vfh;
uint32_t active;
@@ -266,6 +283,7 @@ struct cpp_device {
uint32_t bus_master_flag;
uint32_t micro_reset;
struct msm_cpp_payload_params payload_params;
+ struct msm_cpp_vbif_data *vbif_data;
};
int msm_cpp_set_micro_clk(struct cpp_device *cpp_dev);
@@ -274,5 +292,8 @@ int msm_cpp_get_clock_index(struct cpp_device *cpp_dev, const char *clk_name);
long msm_cpp_set_core_clk(struct cpp_device *cpp_dev, long rate, int idx);
void msm_cpp_fetch_dt_params(struct cpp_device *cpp_dev);
int msm_cpp_read_payload_params_from_dt(struct cpp_device *cpp_dev);
+void msm_cpp_vbif_register_error_handler(void *dev,
+ enum cpp_vbif_client client,
+ int (*client_vbif_error_handler)(void *, uint32_t));
#endif /* __MSM_CPP_H__ */
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
index e4cee1fa4ffc..a7cd44636d1d 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
@@ -1600,7 +1600,7 @@ static const struct v4l2_subdev_ops msm_csiphy_subdev_ops = {
static int msm_csiphy_get_clk_info(struct csiphy_device *csiphy_dev,
struct platform_device *pdev)
{
- int i, rc;
+ int i, rc = 0;
char *csi_3p_clk_name = "csi_phy_3p_clk";
char *csi_3p_clk_src_name = "csiphy_3p_clk_src";
uint32_t clk_cnt = 0;
@@ -1616,6 +1616,7 @@ static int msm_csiphy_get_clk_info(struct csiphy_device *csiphy_dev,
if (csiphy_dev->num_all_clk > CSIPHY_NUM_CLK_MAX) {
pr_err("%s: invalid count=%zu, max is %d\n", __func__,
csiphy_dev->num_all_clk, CSIPHY_NUM_CLK_MAX);
+ rc = -EINVAL;
goto MAX_CLK_ERROR;
}
@@ -1659,13 +1660,14 @@ static int msm_csiphy_get_clk_info(struct csiphy_device *csiphy_dev,
}
csiphy_dev->num_clk = clk_cnt;
+ return rc;
MAX_CLK_ERROR:
msm_camera_put_clk_info(csiphy_dev->pdev,
&csiphy_dev->csiphy_all_clk_info,
&csiphy_dev->csiphy_all_clk,
csiphy_dev->num_all_clk);
- return 0;
+ return rc;
}
static int csiphy_probe(struct platform_device *pdev)
diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c
index 86e7837cc02a..c1c25b655d1f 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c
@@ -381,9 +381,6 @@ static int32_t msm_sensor_fill_slave_info_init_params(
if (!slave_info || !sensor_info)
return -EINVAL;
- if (!slave_info->is_init_params_valid)
- return 0;
-
sensor_init_params = &slave_info->sensor_init_params;
if (INVALID_CAMERA_B != sensor_init_params->position)
sensor_info->position =
@@ -754,8 +751,6 @@ int32_t msm_sensor_driver_probe(void *setting,
slave_info->power_setting_array.power_down_setting =
compat_ptr(slave_info32->
power_setting_array.power_down_setting);
- slave_info->is_init_params_valid =
- slave_info32->is_init_params_valid;
slave_info->sensor_init_params =
slave_info32->sensor_init_params;
slave_info->output_format =
@@ -783,13 +778,10 @@ int32_t msm_sensor_driver_probe(void *setting,
CDBG("power up size %d power down size %d\n",
slave_info->power_setting_array.size,
slave_info->power_setting_array.size_down);
-
- if (slave_info->is_init_params_valid) {
- CDBG("position %d",
- slave_info->sensor_init_params.position);
- CDBG("mount %d",
- slave_info->sensor_init_params.sensor_mount_angle);
- }
+ CDBG("position %d",
+ slave_info->sensor_init_params.position);
+ CDBG("mount %d",
+ slave_info->sensor_init_params.sensor_mount_angle);
/* Validate camera id */
if (slave_info->camera_id >= MAX_CAMERAS) {
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 a0195ac400f8..0188637af85c 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
@@ -928,7 +928,7 @@ static int mpq_map_buffer_to_kernel(
MPQ_DVB_DBG_PRINT("%s: secured buffer\n", __func__);
*kernel_mem = NULL;
} else {
- unsigned long tmp;
+ size_t tmp;
*kernel_mem = ion_map_kernel(client, ion_handle);
if (IS_ERR_OR_NULL(*kernel_mem)) {
ret = PTR_ERR(*kernel_mem);
@@ -940,7 +940,7 @@ static int mpq_map_buffer_to_kernel(
}
ion_handle_get_size(client, ion_handle, &tmp);
MPQ_DVB_DBG_PRINT(
- "%s: mapped to address 0x%p, size=%lu\n",
+ "%s: mapped to address 0x%p, size=%zu\n",
__func__, *kernel_mem, tmp);
}
diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c
index 88a3b4b6f7ba..3835a2e45882 100644
--- a/drivers/media/platform/msm/vidc/hfi_response_handler.c
+++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c
@@ -1369,6 +1369,22 @@ static int hfi_process_session_flush_done(u32 device_id,
cmd_done.status = hfi_map_err_status(pkt->error_type);
cmd_done.size = sizeof(u32);
+ switch (pkt->flush_type) {
+ case HFI_FLUSH_OUTPUT:
+ cmd_done.data.flush_type = HAL_FLUSH_OUTPUT;
+ break;
+ case HFI_FLUSH_INPUT:
+ cmd_done.data.flush_type = HAL_FLUSH_INPUT;
+ break;
+ case HFI_FLUSH_ALL:
+ cmd_done.data.flush_type = HAL_FLUSH_ALL;
+ break;
+ default:
+ dprintk(VIDC_ERR,
+ "%s: invalid flush type!", __func__);
+ return -EINVAL;
+ }
+
*info = (struct msm_vidc_cb_info) {
.response_type = HAL_SESSION_FLUSH_DONE,
.response.cmd = cmd_done,
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index a2edbb6a8270..c5b4872b8e23 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -1505,6 +1505,9 @@ static void handle_session_flush(enum hal_command_response cmd, void *data)
{
struct msm_vidc_cb_cmd_done *response = data;
struct msm_vidc_inst *inst;
+ struct v4l2_event flush_event = {0};
+ u32 *ptr = NULL;
+ enum hal_flush flush_type;
int rc;
if (!response) {
@@ -1532,8 +1535,31 @@ static void handle_session_flush(enum hal_command_response cmd, void *data)
}
}
atomic_dec(&inst->in_flush);
- dprintk(VIDC_DBG, "Notify flush complete to client\n");
- msm_vidc_queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_FLUSH_DONE);
+ flush_event.type = V4L2_EVENT_MSM_VIDC_FLUSH_DONE;
+ ptr = (u32 *)flush_event.u.data;
+
+ flush_type = response->data.flush_type;
+ switch (flush_type) {
+ case HAL_FLUSH_INPUT:
+ ptr[0] = V4L2_QCOM_CMD_FLUSH_OUTPUT;
+ break;
+ case HAL_FLUSH_OUTPUT:
+ ptr[0] = V4L2_QCOM_CMD_FLUSH_CAPTURE;
+ break;
+ case HAL_FLUSH_ALL:
+ ptr[0] |= V4L2_QCOM_CMD_FLUSH_CAPTURE;
+ ptr[0] |= V4L2_QCOM_CMD_FLUSH_OUTPUT;
+ break;
+ default:
+ dprintk(VIDC_ERR, "Invalid flush type received!");
+ goto exit;
+ }
+
+ dprintk(VIDC_DBG,
+ "Notify flush complete, flush_type: %x\n", flush_type);
+ v4l2_event_queue_fh(&inst->event_handler, &flush_event);
+
+exit:
put_inst(inst);
}
@@ -2455,7 +2481,6 @@ static int msm_comm_session_abort(struct msm_vidc_inst *inst)
}
hdev = inst->core->device;
abort_completion = SESSION_MSG_INDEX(HAL_SESSION_ABORT_DONE);
- init_completion(&inst->completions[abort_completion]);
rc = call_hfi_op(hdev, session_abort, (void *)inst->session);
if (rc) {
@@ -2637,8 +2662,6 @@ static int msm_comm_init_core(struct msm_vidc_inst *inst)
__func__);
}
- init_completion(&core->completions
- [SYS_MSG_INDEX(HAL_SYS_INIT_DONE)]);
rc = call_hfi_op(hdev, core_init, hdev->hfi_device_data);
if (rc) {
dprintk(VIDC_ERR, "Failed to init core, id = %d\n",
@@ -2742,8 +2765,6 @@ static int msm_comm_session_init(int flipped_state,
dprintk(VIDC_ERR, "Invalid session\n");
return -EINVAL;
}
- init_completion(
- &inst->completions[SESSION_MSG_INDEX(HAL_SESSION_INIT_DONE)]);
rc = call_hfi_op(hdev, session_init, hdev->hfi_device_data,
inst, get_hal_domain(inst->session_type),
@@ -2881,8 +2902,6 @@ static int msm_vidc_start(int flipped_state, struct msm_vidc_inst *inst)
inst, inst->state);
goto exit;
}
- init_completion(
- &inst->completions[SESSION_MSG_INDEX(HAL_SESSION_START_DONE)]);
rc = call_hfi_op(hdev, session_start, (void *) inst->session);
if (rc) {
dprintk(VIDC_ERR,
@@ -2912,8 +2931,6 @@ static int msm_vidc_stop(int flipped_state, struct msm_vidc_inst *inst)
goto exit;
}
dprintk(VIDC_DBG, "Send Stop to hal\n");
- init_completion(
- &inst->completions[SESSION_MSG_INDEX(HAL_SESSION_STOP_DONE)]);
rc = call_hfi_op(hdev, session_stop, (void *) inst->session);
if (rc) {
dprintk(VIDC_ERR, "Failed to send stop\n");
@@ -2943,8 +2960,6 @@ static int msm_vidc_release_res(int flipped_state, struct msm_vidc_inst *inst)
}
dprintk(VIDC_DBG,
"Send release res to hal\n");
- init_completion(&inst->completions[
- SESSION_MSG_INDEX(HAL_SESSION_RELEASE_RESOURCE_DONE)]);
rc = call_hfi_op(hdev, session_release_res, (void *) inst->session);
if (rc) {
dprintk(VIDC_ERR,
@@ -2975,8 +2990,6 @@ static int msm_comm_session_close(int flipped_state,
}
dprintk(VIDC_DBG,
"Send session close to hal\n");
- init_completion(
- &inst->completions[SESSION_MSG_INDEX(HAL_SESSION_END_DONE)]);
rc = call_hfi_op(hdev, session_end, (void *) inst->session);
if (rc) {
dprintk(VIDC_ERR,
@@ -4022,8 +4035,6 @@ int msm_comm_try_get_prop(struct msm_vidc_inst *inst, enum hal_property ptype,
}
mutex_unlock(&inst->sync_lock);
- init_completion(&inst->completions[
- SESSION_MSG_INDEX(HAL_SESSION_PROPERTY_INFO)]);
switch (ptype) {
case HAL_PARAM_PROFILE_LEVEL_CURRENT:
case HAL_CONFIG_VDEC_ENTROPY:
@@ -4253,8 +4264,6 @@ int msm_comm_release_scratch_buffers(struct msm_vidc_inst *inst,
if (inst->state != MSM_VIDC_CORE_INVALID &&
core->state != VIDC_CORE_INVALID) {
buffer_info.response_required = true;
- init_completion(&inst->completions[SESSION_MSG_INDEX
- (HAL_SESSION_RELEASE_BUFFER_DONE)]);
rc = call_hfi_op(hdev, session_release_buffers,
(void *)inst->session, &buffer_info);
if (rc) {
@@ -4325,9 +4334,6 @@ int msm_comm_release_persist_buffers(struct msm_vidc_inst *inst)
if (inst->state != MSM_VIDC_CORE_INVALID &&
core->state != VIDC_CORE_INVALID) {
buffer_info.response_required = true;
- init_completion(
- &inst->completions[SESSION_MSG_INDEX
- (HAL_SESSION_RELEASE_BUFFER_DONE)]);
rc = call_hfi_op(hdev, session_release_buffers,
(void *)inst->session, &buffer_info);
if (rc) {
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index eceb86b01a7c..9970c4152ef9 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -934,8 +934,6 @@ err_create_pkt:
return rc;
}
-static DECLARE_COMPLETION(release_resources_done);
-
static int __alloc_imem(struct venus_hfi_device *device, unsigned long size)
{
struct imem *imem = NULL;
@@ -2172,8 +2170,6 @@ static int venus_hfi_core_init(void *device)
dev = device;
mutex_lock(&dev->lock);
- init_completion(&release_resources_done);
-
rc = __load_fw(dev);
if (rc) {
dprintk(VIDC_ERR, "Failed to load Venus FW\n");
@@ -3460,7 +3456,6 @@ static int __response_handler(struct venus_hfi_device *device)
break;
case HAL_SYS_RELEASE_RESOURCE_DONE:
dprintk(VIDC_DBG, "Received SYS_RELEASE_RESOURCE\n");
- complete(&release_resources_done);
break;
case HAL_SYS_INIT_DONE:
dprintk(VIDC_DBG, "Received SYS_INIT_DONE\n");
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index 116ce12c8dba..820c8685a75b 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -1351,6 +1351,7 @@ struct msm_vidc_cb_cmd_done {
struct vidc_hal_session_init_done session_init_done;
struct hal_buffer_info buffer_info;
union hal_get_property property;
+ enum hal_flush flush_type;
} data;
};
diff --git a/drivers/nfc/nq-nci.c b/drivers/nfc/nq-nci.c
index 2dd18dd78677..17b6d1aea4c7 100644
--- a/drivers/nfc/nq-nci.c
+++ b/drivers/nfc/nq-nci.c
@@ -47,6 +47,7 @@ MODULE_DEVICE_TABLE(of, msm_match_table);
#define MAX_BUFFER_SIZE (320)
#define WAKEUP_SRC_TIMEOUT (2000)
+#define MAX_RETRY_COUNT 3
struct nqx_dev {
wait_queue_head_t read_wq;
@@ -264,6 +265,35 @@ out:
return ret;
}
+/**
+ * nqx_standby_write()
+ * @buf: pointer to data buffer
+ * @len: # of bytes need to transfer
+ *
+ * write data buffer over I2C and retry
+ * if NFCC is in stand by mode
+ *
+ * Return: # of bytes written or -ve value in case of error
+ */
+static int nqx_standby_write(struct nqx_dev *nqx_dev,
+ const unsigned char *buf, size_t len)
+{
+ int ret = -EINVAL;
+ int retry_cnt;
+
+ for (retry_cnt = 1; retry_cnt <= MAX_RETRY_COUNT; retry_cnt++) {
+ ret = i2c_master_send(nqx_dev->client, buf, len);
+ if (ret < 0) {
+ dev_err(&nqx_dev->client->dev,
+ "%s: write failed, Maybe in Standby Mode - Retry(%d)\n",
+ __func__, retry_cnt);
+ usleep_range(1000, 1100);
+ } else if (ret == len)
+ break;
+ }
+ return ret;
+}
+
/*
* Power management of the eSE
* NFC & eSE ON : NFC_EN high and eSE_pwr_req high.
@@ -273,39 +303,95 @@ out:
static int nqx_ese_pwr(struct nqx_dev *nqx_dev, unsigned long int arg)
{
int r = -1;
+ const unsigned char svdd_off_cmd_warn[] = {0x2F, 0x31, 0x01, 0x01};
+ const unsigned char svdd_off_cmd_done[] = {0x2F, 0x31, 0x01, 0x00};
+
+ if (!gpio_is_valid(nqx_dev->ese_gpio)) {
+ dev_err(&nqx_dev->client->dev,
+ "%s: ese_gpio is not valid\n", __func__);
+ return -EINVAL;
+ }
- /* Let's store the NFC_EN pin state */
if (arg == 0) {
/*
* We want to power on the eSE and to do so we need the
* eSE_pwr_req pin and the NFC_EN pin to be high
*/
- nqx_dev->nfc_ven_enabled = gpio_get_value(nqx_dev->en_gpio);
- if (!nqx_dev->nfc_ven_enabled) {
- gpio_set_value(nqx_dev->en_gpio, 1);
- /* hardware dependent delay */
- usleep_range(1000, 1100);
- }
- if (gpio_is_valid(nqx_dev->ese_gpio)) {
+ if (gpio_get_value(nqx_dev->ese_gpio)) {
+ dev_dbg(&nqx_dev->client->dev, "ese_gpio is already high\n");
+ r = 0;
+ } else {
+ /**
+ * Let's store the NFC_EN pin state
+ * only if the eSE is not yet on
+ */
+ nqx_dev->nfc_ven_enabled =
+ gpio_get_value(nqx_dev->en_gpio);
+ if (!nqx_dev->nfc_ven_enabled) {
+ gpio_set_value(nqx_dev->en_gpio, 1);
+ /* hardware dependent delay */
+ usleep_range(1000, 1100);
+ }
+ gpio_set_value(nqx_dev->ese_gpio, 1);
if (gpio_get_value(nqx_dev->ese_gpio)) {
- dev_dbg(&nqx_dev->client->dev, "ese_gpio is already high\n");
+ dev_dbg(&nqx_dev->client->dev, "ese_gpio is enabled\n");
r = 0;
- } else {
- gpio_set_value(nqx_dev->ese_gpio, 1);
- if (gpio_get_value(nqx_dev->ese_gpio)) {
- dev_dbg(&nqx_dev->client->dev, "ese_gpio is enabled\n");
- r = 0;
- }
}
}
} else if (arg == 1) {
- if (gpio_is_valid(nqx_dev->ese_gpio)) {
+ if (nqx_dev->nfc_ven_enabled &&
+ ((nqx_dev->nqx_info.info.chip_type == NFCC_NQ_220) ||
+ (nqx_dev->nqx_info.info.chip_type == NFCC_PN66T))) {
+ /**
+ * Let's inform the CLF we're
+ * powering off the eSE
+ */
+ r = nqx_standby_write(nqx_dev, svdd_off_cmd_warn,
+ sizeof(svdd_off_cmd_warn));
+ if (r < 0) {
+ dev_err(&nqx_dev->client->dev,
+ "%s: write failed after max retry\n",
+ __func__);
+ return -ENXIO;
+ }
+ dev_dbg(&nqx_dev->client->dev,
+ "%s: svdd_off_cmd_warn sent\n", __func__);
+
+ /* let's power down the eSE */
gpio_set_value(nqx_dev->ese_gpio, 0);
- if (!gpio_get_value(nqx_dev->ese_gpio)) {
- dev_dbg(&nqx_dev->client->dev, "ese_gpio is disabled\n");
- r = 0;
+ dev_dbg(&nqx_dev->client->dev,
+ "%s: nqx_dev->ese_gpio set to 0\n", __func__);
+
+ /**
+ * Time needed for the SVDD capacitor
+ * to get discharged
+ */
+ usleep_range(8000, 8100);
+
+ /* Let's inform the CLF the eSE is now off */
+ r = nqx_standby_write(nqx_dev, svdd_off_cmd_done,
+ sizeof(svdd_off_cmd_done));
+ if (r < 0) {
+ dev_err(&nqx_dev->client->dev,
+ "%s: write failed after max retry\n",
+ __func__);
+ return -ENXIO;
}
+ dev_dbg(&nqx_dev->client->dev,
+ "%s: svdd_off_cmd_done sent\n", __func__);
+ } else {
+ /**
+ * In case the NFC is off,
+ * there's no need to send the i2c commands
+ */
+ gpio_set_value(nqx_dev->ese_gpio, 0);
}
+
+ if (!gpio_get_value(nqx_dev->ese_gpio)) {
+ dev_dbg(&nqx_dev->client->dev, "ese_gpio is disabled\n");
+ r = 0;
+ }
+
if (!nqx_dev->nfc_ven_enabled) {
/* hardware dependent delay */
usleep_range(1000, 1100);
@@ -313,12 +399,7 @@ static int nqx_ese_pwr(struct nqx_dev *nqx_dev, unsigned long int arg)
gpio_set_value(nqx_dev->en_gpio, 0);
}
} else if (arg == 3) {
- if (!nqx_dev->nfc_ven_enabled)
- r = 0;
- else {
- if (gpio_is_valid(nqx_dev->ese_gpio))
- r = gpio_get_value(nqx_dev->ese_gpio);
- }
+ r = gpio_get_value(nqx_dev->ese_gpio);
}
return r;
}
@@ -624,6 +705,10 @@ static int nfcc_hw_check(struct i2c_client *client, struct nqx_dev *nqx_dev)
dev_dbg(&client->dev,
"%s: ## NFCC == NQ330 ##\n", __func__);
break;
+ case NFCC_PN66T:
+ dev_dbg(&client->dev,
+ "%s: ## NFCC == PN66T ##\n", __func__);
+ break;
default:
dev_err(&client->dev,
"%s: - NFCC HW not Supported\n", __func__);
diff --git a/drivers/nfc/nq-nci.h b/drivers/nfc/nq-nci.h
index c635e818b1f3..f34c4d987143 100644
--- a/drivers/nfc/nq-nci.h
+++ b/drivers/nfc/nq-nci.h
@@ -48,7 +48,7 @@ enum nfcc_chip_variant {
NFCC_NQ_220 = 0x58, /**< NFCC NQ220 */
NFCC_NQ_310 = 0x40, /**< NFCC NQ310 */
NFCC_NQ_330 = 0x51, /**< NFCC NQ330 */
+ NFCC_PN66T = 0x18, /**< NFCC PN66T */
NFCC_NOT_SUPPORTED = 0xFF /**< NFCC is not supported */
};
-
#endif
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index 70cabc7080b3..223339ff119d 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -46,6 +46,7 @@ obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-20nm.o
obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-14nm.o
obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-v3.o
obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qrbtc-v2.o
+obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-v3-falcon.o
obj-$(CONFIG_PHY_TUSB1210) += phy-tusb1210.o
obj-$(CONFIG_PHY_BRCMSTB_SATA) += phy-brcmstb-sata.o
obj-$(CONFIG_PHY_PISTACHIO_USB) += phy-pistachio-usb.o
diff --git a/drivers/phy/phy-qcom-ufs-qmp-v3-falcon.c b/drivers/phy/phy-qcom-ufs-qmp-v3-falcon.c
new file mode 100644
index 000000000000..e88c00e01e0b
--- /dev/null
+++ b/drivers/phy/phy-qcom-ufs-qmp-v3-falcon.c
@@ -0,0 +1,260 @@
+/*
+ * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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 "phy-qcom-ufs-qmp-v3-falcon.h"
+
+#define UFS_PHY_NAME "ufs_phy_qmp_v3_falcon"
+
+static
+int ufs_qcom_phy_qmp_v3_falcon_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy,
+ bool is_rate_B)
+{
+ int err;
+ int tbl_size_A, tbl_size_B;
+ struct ufs_qcom_phy_calibration *tbl_A, *tbl_B;
+ u8 major = ufs_qcom_phy->host_ctrl_rev_major;
+ u16 minor = ufs_qcom_phy->host_ctrl_rev_minor;
+ u16 step = ufs_qcom_phy->host_ctrl_rev_step;
+
+ tbl_size_B = ARRAY_SIZE(phy_cal_table_rate_B);
+ tbl_B = phy_cal_table_rate_B;
+
+ if ((major == 0x3) && (minor == 0x001) && (step == 0x001)) {
+ tbl_A = phy_cal_table_rate_A_3_1_1;
+ tbl_size_A = ARRAY_SIZE(phy_cal_table_rate_A_3_1_1);
+ } else {
+ dev_err(ufs_qcom_phy->dev,
+ "%s: Unknown UFS-PHY version (major 0x%x minor 0x%x step 0x%x), no calibration values\n",
+ __func__, major, minor, step);
+ err = -ENODEV;
+ goto out;
+ }
+
+ err = ufs_qcom_phy_calibrate(ufs_qcom_phy,
+ tbl_A, tbl_size_A,
+ tbl_B, tbl_size_B,
+ is_rate_B);
+
+ if (err)
+ dev_err(ufs_qcom_phy->dev,
+ "%s: ufs_qcom_phy_calibrate() failed %d\n",
+ __func__, err);
+
+out:
+ return err;
+}
+
+static int ufs_qcom_phy_qmp_v3_falcon_init(struct phy *generic_phy)
+{
+ struct ufs_qcom_phy_qmp_v3_falcon *phy = phy_get_drvdata(generic_phy);
+ struct ufs_qcom_phy *phy_common = &phy->common_cfg;
+ int err;
+
+ err = ufs_qcom_phy_init_clks(generic_phy, phy_common);
+ if (err) {
+ dev_err(phy_common->dev, "%s: ufs_qcom_phy_init_clks() failed %d\n",
+ __func__, err);
+ goto out;
+ }
+
+ err = ufs_qcom_phy_init_vregulators(generic_phy, phy_common);
+ if (err) {
+ dev_err(phy_common->dev, "%s: ufs_qcom_phy_init_vregulators() failed %d\n",
+ __func__, err);
+ goto out;
+ }
+
+out:
+ return err;
+}
+
+static
+void ufs_qcom_phy_qmp_v3_falcon_power_control(struct ufs_qcom_phy *phy,
+ bool power_ctrl)
+{
+ if (!power_ctrl) {
+ /* apply analog power collapse */
+ writel_relaxed(0x0, phy->mmio + UFS_PHY_POWER_DOWN_CONTROL);
+ /*
+ * Make sure that PHY knows its analog rail is going to be
+ * powered OFF.
+ */
+ mb();
+ } else {
+ /* bring PHY out of analog power collapse */
+ writel_relaxed(0x1, phy->mmio + UFS_PHY_POWER_DOWN_CONTROL);
+
+ /*
+ * Before any transactions involving PHY, ensure PHY knows
+ * that it's analog rail is powered ON.
+ */
+ mb();
+ }
+}
+
+static inline
+void ufs_qcom_phy_qmp_v3_falcon_set_tx_lane_enable(struct ufs_qcom_phy *phy,
+ u32 val)
+{
+ /*
+ * v3 PHY does not have TX_LANE_ENABLE register.
+ * Implement this function so as not to propagate error to caller.
+ */
+}
+
+static
+void ufs_qcom_phy_qmp_v3_falcon_ctrl_rx_linecfg(struct ufs_qcom_phy *phy,
+ bool ctrl)
+{
+ u32 temp;
+
+ temp = readl_relaxed(phy->mmio + UFS_PHY_LINECFG_DISABLE);
+
+ if (ctrl) /* enable RX LineCfg */
+ temp &= ~UFS_PHY_RX_LINECFG_DISABLE_BIT;
+ else /* disable RX LineCfg */
+ temp |= UFS_PHY_RX_LINECFG_DISABLE_BIT;
+
+ writel_relaxed(temp, phy->mmio + UFS_PHY_LINECFG_DISABLE);
+ /* Make sure that RX LineCfg config applied before we return */
+ mb();
+}
+
+static inline void ufs_qcom_phy_qmp_v3_falcon_start_serdes(
+ struct ufs_qcom_phy *phy)
+{
+ u32 tmp;
+
+ tmp = readl_relaxed(phy->mmio + UFS_PHY_PHY_START);
+ tmp &= ~MASK_SERDES_START;
+ tmp |= (1 << OFFSET_SERDES_START);
+ writel_relaxed(tmp, phy->mmio + UFS_PHY_PHY_START);
+ /* Ensure register value is committed */
+ mb();
+}
+
+static int ufs_qcom_phy_qmp_v3_falcon_is_pcs_ready(
+ struct ufs_qcom_phy *phy_common)
+{
+ int err = 0;
+ u32 val;
+
+ err = readl_poll_timeout(phy_common->mmio + UFS_PHY_PCS_READY_STATUS,
+ val, (val & MASK_PCS_READY), 10, 1000000);
+ if (err)
+ dev_err(phy_common->dev, "%s: poll for pcs failed err = %d\n",
+ __func__, err);
+ return err;
+}
+
+static void ufs_qcom_phy_qmp_v3_falcon_dbg_register_dump(
+ struct ufs_qcom_phy *phy)
+{
+ ufs_qcom_phy_dump_regs(phy, COM_BASE, COM_SIZE,
+ "PHY QSERDES COM Registers ");
+ ufs_qcom_phy_dump_regs(phy, PHY_BASE, PHY_SIZE,
+ "PHY Registers ");
+ ufs_qcom_phy_dump_regs(phy, RX_BASE, RX_SIZE,
+ "PHY RX0 Registers ");
+ ufs_qcom_phy_dump_regs(phy, TX_BASE, TX_SIZE,
+ "PHY TX0 Registers ");
+}
+
+struct phy_ops ufs_qcom_phy_qmp_v3_falcon_phy_ops = {
+ .init = ufs_qcom_phy_qmp_v3_falcon_init,
+ .exit = ufs_qcom_phy_exit,
+ .power_on = ufs_qcom_phy_power_on,
+ .power_off = ufs_qcom_phy_power_off,
+ .owner = THIS_MODULE,
+};
+
+struct ufs_qcom_phy_specific_ops phy_v3_falcon_ops = {
+ .calibrate_phy = ufs_qcom_phy_qmp_v3_falcon_phy_calibrate,
+ .start_serdes = ufs_qcom_phy_qmp_v3_falcon_start_serdes,
+ .is_physical_coding_sublayer_ready =
+ ufs_qcom_phy_qmp_v3_falcon_is_pcs_ready,
+ .set_tx_lane_enable = ufs_qcom_phy_qmp_v3_falcon_set_tx_lane_enable,
+ .ctrl_rx_linecfg = ufs_qcom_phy_qmp_v3_falcon_ctrl_rx_linecfg,
+ .power_control = ufs_qcom_phy_qmp_v3_falcon_power_control,
+ .dbg_register_dump = ufs_qcom_phy_qmp_v3_falcon_dbg_register_dump,
+};
+
+static int ufs_qcom_phy_qmp_v3_falcon_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct phy *generic_phy;
+ struct ufs_qcom_phy_qmp_v3_falcon *phy;
+ int err = 0;
+
+ phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
+ if (!phy) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ generic_phy = ufs_qcom_phy_generic_probe(pdev, &phy->common_cfg,
+ &ufs_qcom_phy_qmp_v3_falcon_phy_ops,
+ &phy_v3_falcon_ops);
+
+ if (!generic_phy) {
+ dev_err(dev, "%s: ufs_qcom_phy_generic_probe() failed\n",
+ __func__);
+ err = -EIO;
+ goto out;
+ }
+
+ phy_set_drvdata(generic_phy, phy);
+
+ strlcpy(phy->common_cfg.name, UFS_PHY_NAME,
+ sizeof(phy->common_cfg.name));
+
+out:
+ return err;
+}
+
+static int ufs_qcom_phy_qmp_v3_falcon_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct phy *generic_phy = to_phy(dev);
+ struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(generic_phy);
+ int err = 0;
+
+ err = ufs_qcom_phy_remove(generic_phy, ufs_qcom_phy);
+ if (err)
+ dev_err(dev, "%s: ufs_qcom_phy_remove failed = %d\n",
+ __func__, err);
+
+ return err;
+}
+
+static const struct of_device_id ufs_qcom_phy_qmp_v3_falcon_of_match[] = {
+ {.compatible = "qcom,ufs-phy-qmp-v3-falcon"},
+ {},
+};
+MODULE_DEVICE_TABLE(of, ufs_qcom_phy_qmp_v3_falcon_of_match);
+
+static struct platform_driver ufs_qcom_phy_qmp_v3_falcon_driver = {
+ .probe = ufs_qcom_phy_qmp_v3_falcon_probe,
+ .remove = ufs_qcom_phy_qmp_v3_falcon_remove,
+ .driver = {
+ .of_match_table = ufs_qcom_phy_qmp_v3_falcon_of_match,
+ .name = "ufs_qcom_phy_qmp_v3_falcon",
+ .owner = THIS_MODULE,
+ },
+};
+
+module_platform_driver(ufs_qcom_phy_qmp_v3_falcon_driver);
+
+MODULE_DESCRIPTION("Universal Flash Storage (UFS) QCOM PHY QMP v3 falcon");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/phy/phy-qcom-ufs-qmp-v3-falcon.h b/drivers/phy/phy-qcom-ufs-qmp-v3-falcon.h
new file mode 100644
index 000000000000..e64601cc6b22
--- /dev/null
+++ b/drivers/phy/phy-qcom-ufs-qmp-v3-falcon.h
@@ -0,0 +1,283 @@
+/*
+ * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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 UFS_QCOM_PHY_QMP_V3_FALCON_H_
+#define UFS_QCOM_PHY_QMP_V3_FALCON_H_
+
+#include "phy-qcom-ufs-i.h"
+
+/* QCOM UFS PHY control registers */
+#define COM_BASE 0x000
+#define COM_OFF(x) (COM_BASE + x)
+#define COM_SIZE 0x1C0
+
+#define TX_BASE 0x400
+#define TX_OFF(x) (TX_BASE + x)
+#define TX_SIZE 0x128
+
+#define RX_BASE 0x600
+#define RX_OFF(x) (RX_BASE + x)
+#define RX_SIZE 0x1FC
+
+#define PHY_BASE 0xC00
+#define PHY_OFF(x) (PHY_BASE + x)
+#define PHY_SIZE 0x1B4
+
+/* UFS PHY QSERDES COM registers */
+#define QSERDES_COM_ATB_SEL1 COM_OFF(0x00)
+#define QSERDES_COM_ATB_SEL2 COM_OFF(0x04)
+#define QSERDES_COM_FREQ_UPDATE COM_OFF(0x08)
+#define QSERDES_COM_BG_TIMER COM_OFF(0x0C)
+#define QSERDES_COM_SSC_EN_CENTER COM_OFF(0x10)
+#define QSERDES_COM_SSC_ADJ_PER1 COM_OFF(0x14)
+#define QSERDES_COM_SSC_ADJ_PER2 COM_OFF(0x18)
+#define QSERDES_COM_SSC_PER1 COM_OFF(0x1C)
+#define QSERDES_COM_SSC_PER2 COM_OFF(0x20)
+#define QSERDES_COM_SSC_STEP_SIZE1 COM_OFF(0x24)
+#define QSERDES_COM_SSC_STEP_SIZE2 COM_OFF(0x28)
+#define QSERDES_COM_POST_DIV COM_OFF(0x2C)
+#define QSERDES_COM_POST_DIV_MUX COM_OFF(0x30)
+#define QSERDES_COM_BIAS_EN_CLKBUFLR_EN COM_OFF(0x34)
+#define QSERDES_COM_CLK_ENABLE1 COM_OFF(0x38)
+#define QSERDES_COM_SYS_CLK_CTRL COM_OFF(0x3C)
+#define QSERDES_COM_SYSCLK_BUF_ENABLE COM_OFF(0x40)
+#define QSERDES_COM_PLL_EN COM_OFF(0x44)
+#define QSERDES_COM_PLL_IVCO COM_OFF(0x48)
+#define QSERDES_COM_LOCK_CMP1_MODE0 COM_OFF(0X4C)
+#define QSERDES_COM_LOCK_CMP2_MODE0 COM_OFF(0X50)
+#define QSERDES_COM_LOCK_CMP3_MODE0 COM_OFF(0X54)
+#define QSERDES_COM_LOCK_CMP1_MODE1 COM_OFF(0X58)
+#define QSERDES_COM_LOCK_CMP2_MODE1 COM_OFF(0X5C)
+#define QSERDES_COM_LOCK_CMP3_MODE1 COM_OFF(0X60)
+#define QSERDES_COM_CMD_RSVD0 COM_OFF(0x64)
+#define QSERDES_COM_EP_CLOCK_DETECT_CTRL COM_OFF(0x68)
+#define QSERDES_COM_SYSCLK_DET_COMP_STATUS COM_OFF(0x6C)
+#define QSERDES_COM_BG_TRIM COM_OFF(0x70)
+#define QSERDES_COM_CLK_EP_DIV COM_OFF(0x74)
+#define QSERDES_COM_CP_CTRL_MODE0 COM_OFF(0x78)
+#define QSERDES_COM_CP_CTRL_MODE1 COM_OFF(0x7C)
+#define QSERDES_COM_CMN_RSVD1 COM_OFF(0x80)
+#define QSERDES_COM_PLL_RCTRL_MODE0 COM_OFF(0x84)
+#define QSERDES_COM_PLL_RCTRL_MODE1 COM_OFF(0x88)
+#define QSERDES_COM_CMN_RSVD2 COM_OFF(0x8C)
+#define QSERDES_COM_PLL_CCTRL_MODE0 COM_OFF(0x90)
+#define QSERDES_COM_PLL_CCTRL_MODE1 COM_OFF(0x94)
+#define QSERDES_COM_CMN_RSVD3 COM_OFF(0x98)
+#define QSERDES_COM_PLL_CNTRL COM_OFF(0x9C)
+#define QSERDES_COM_PHASE_SEL_CTRL COM_OFF(0xA0)
+#define QSERDES_COM_PHASE_SEL_DC COM_OFF(0xA4)
+#define QSERDES_COM_BIAS_EN_CTRL_BY_PSM COM_OFF(0xA8)
+#define QSERDES_COM_SYSCLK_EN_SEL COM_OFF(0xAC)
+#define QSERDES_COM_CML_SYSCLK_SEL COM_OFF(0xB0)
+#define QSERDES_COM_RESETSM_CNTRL COM_OFF(0xB4)
+#define QSERDES_COM_RESETSM_CNTRL2 COM_OFF(0xB8)
+#define QSERDES_COM_RESTRIM_CTRL COM_OFF(0xBC)
+#define QSERDES_COM_RESTRIM_CTRL2 COM_OFF(0xC0)
+#define QSERDES_COM_LOCK_CMP_EN COM_OFF(0xC8)
+#define QSERDES_COM_LOCK_CMP_CFG COM_OFF(0xCC)
+#define QSERDES_COM_DEC_START_MODE0 COM_OFF(0xD0)
+#define QSERDES_COM_DEC_START_MODE1 COM_OFF(0xD4)
+#define QSERDES_COM_VCOCAL_DEADMAN_CTRL COM_OFF(0xD8)
+#define QSERDES_COM_DIV_FRAC_START1_MODE0 COM_OFF(0xDC)
+#define QSERDES_COM_DIV_FRAC_START2_MODE0 COM_OFF(0xE0)
+#define QSERDES_COM_DIV_FRAC_START3_MODE0 COM_OFF(0xE4)
+#define QSERDES_COM_DIV_FRAC_START1_MODE1 COM_OFF(0xE8)
+#define QSERDES_COM_DIV_FRAC_START2_MODE1 COM_OFF(0xEC)
+#define QSERDES_COM_DIV_FRAC_START3_MODE1 COM_OFF(0xF0)
+#define QSERDES_COM_VCO_TUNE_MINVAL1 COM_OFF(0xF4)
+#define QSERDES_COM_VCO_TUNE_MINVAL2 COM_OFF(0xF8)
+#define QSERDES_COM_CMN_RSVD4 COM_OFF(0xFC)
+#define QSERDES_COM_INTEGLOOP_INITVAL COM_OFF(0x100)
+#define QSERDES_COM_INTEGLOOP_EN COM_OFF(0x104)
+#define QSERDES_COM_INTEGLOOP_GAIN0_MODE0 COM_OFF(0x108)
+#define QSERDES_COM_INTEGLOOP_GAIN1_MODE0 COM_OFF(0x10C)
+#define QSERDES_COM_INTEGLOOP_GAIN0_MODE1 COM_OFF(0x110)
+#define QSERDES_COM_INTEGLOOP_GAIN1_MODE1 COM_OFF(0x114)
+#define QSERDES_COM_VCO_TUNE_MAXVAL1 COM_OFF(0x118)
+#define QSERDES_COM_VCO_TUNE_MAXVAL2 COM_OFF(0x11C)
+#define QSERDES_COM_RES_TRIM_CONTROL2 COM_OFF(0x120)
+#define QSERDES_COM_VCO_TUNE_CTRL COM_OFF(0x124)
+#define QSERDES_COM_VCO_TUNE_MAP COM_OFF(0x128)
+#define QSERDES_COM_VCO_TUNE1_MODE0 COM_OFF(0x12C)
+#define QSERDES_COM_VCO_TUNE2_MODE0 COM_OFF(0x130)
+#define QSERDES_COM_VCO_TUNE1_MODE1 COM_OFF(0x134)
+#define QSERDES_COM_VCO_TUNE2_MODE1 COM_OFF(0x138)
+#define QSERDES_COM_VCO_TUNE_INITVAL1 COM_OFF(0x13C)
+#define QSERDES_COM_VCO_TUNE_INITVAL2 COM_OFF(0x140)
+#define QSERDES_COM_VCO_TUNE_TIMER1 COM_OFF(0x144)
+#define QSERDES_COM_VCO_TUNE_TIMER2 COM_OFF(0x148)
+#define QSERDES_COM_SAR COM_OFF(0x14C)
+#define QSERDES_COM_SAR_CLK COM_OFF(0x150)
+#define QSERDES_COM_SAR_CODE_OUT_STATUS COM_OFF(0x154)
+#define QSERDES_COM_SAR_CODE_READY_STATUS COM_OFF(0x158)
+#define QSERDES_COM_CMN_STATUS COM_OFF(0x15C)
+#define QSERDES_COM_RESET_SM_STATUS COM_OFF(0x160)
+#define QSERDES_COM_RESTRIM_CODE_STATUS COM_OFF(0x164)
+#define QSERDES_COM_PLLCAL_CODE1_STATUS COM_OFF(0x168)
+#define QSERDES_COM_PLLCAL_CODE2_STATUS COM_OFF(0x16C)
+#define QSERDES_COM_BG_CTRL COM_OFF(0x170)
+#define QSERDES_COM_CLK_SELECT COM_OFF(0x174)
+#define QSERDES_COM_HSCLK_SEL COM_OFF(0x178)
+#define QSERDES_COM_INTEGLOOP_BINCODE_STATUS COM_OFF(0x17C)
+#define QSERDES_COM_PLL_ANALOG COM_OFF(0x180)
+#define QSERDES_COM_CORECLK_DIV COM_OFF(0x184)
+#define QSERDES_COM_SW_RESET COM_OFF(0x188)
+#define QSERDES_COM_CORE_CLK_EN COM_OFF(0x18C)
+#define QSERDES_COM_C_READY_STATUS COM_OFF(0x190)
+#define QSERDES_COM_CMN_CONFIG COM_OFF(0x194)
+#define QSERDES_COM_CMN_RATE_OVERRIDE COM_OFF(0x198)
+#define QSERDES_COM_SVS_MODE_CLK_SEL COM_OFF(0x19C)
+#define QSERDES_COM_DEBUG_BUS0 COM_OFF(0x1A0)
+#define QSERDES_COM_DEBUG_BUS1 COM_OFF(0x1A4)
+#define QSERDES_COM_DEBUG_BUS2 COM_OFF(0x1A8)
+#define QSERDES_COM_DEBUG_BUS3 COM_OFF(0x1AC)
+#define QSERDES_COM_DEBUG_BUS_SEL COM_OFF(0x1B0)
+#define QSERDES_COM_CMN_MISC1 COM_OFF(0x1B4)
+#define QSERDES_COM_CORECLK_DIV_MODE1 COM_OFF(0x1BC)
+#define QSERDES_COM_CMN_RSVD5 COM_OFF(0x1C0)
+
+/* UFS PHY registers */
+#define UFS_PHY_PHY_START PHY_OFF(0x00)
+#define UFS_PHY_POWER_DOWN_CONTROL PHY_OFF(0x04)
+#define UFS_PHY_TX_LARGE_AMP_DRV_LVL PHY_OFF(0x34)
+#define UFS_PHY_TX_SMALL_AMP_DRV_LVL PHY_OFF(0x3C)
+#define UFS_PHY_RX_MIN_STALL_NOCONFIG_TIME_CAP PHY_OFF(0xCC)
+#define UFS_PHY_LINECFG_DISABLE PHY_OFF(0x138)
+#define UFS_PHY_RX_SYM_RESYNC_CTRL PHY_OFF(0x13C)
+#define UFS_PHY_RX_SIGDET_CTRL2 PHY_OFF(0x148)
+#define UFS_PHY_RX_PWM_GEAR_BAND PHY_OFF(0x154)
+#define UFS_PHY_PCS_READY_STATUS PHY_OFF(0x168)
+
+/* UFS PHY TX registers */
+#define QSERDES_TX_HIGHZ_TRANSCEIVER_BIAS_DRVR_EN TX_OFF(0x68)
+#define QSERDES_TX_LANE_MODE TX_OFF(0x94)
+
+/* UFS PHY RX registers */
+#define QSERDES_RX_UCDR_SVS_SO_GAIN_HALF RX_OFF(0x30)
+#define QSERDES_RX_UCDR_SVS_SO_GAIN_QUARTER RX_OFF(0x34)
+#define QSERDES_RX_UCDR_SVS_SO_GAIN_EIGHTH RX_OFF(0x38)
+#define QSERDES_RX_UCDR_SVS_SO_GAIN RX_OFF(0x3C)
+#define QSERDES_RX_UCDR_FASTLOCK_FO_GAIN RX_OFF(0x40)
+#define QSERDES_RX_UCDR_SO_SATURATION_ENABLE RX_OFF(0x48)
+#define QSERDES_RX_RX_TERM_BW RX_OFF(0x90)
+#define QSERDES_RX_RX_EQ_GAIN1_LSB RX_OFF(0xC4)
+#define QSERDES_RX_RX_EQ_GAIN1_MSB RX_OFF(0xC8)
+#define QSERDES_RX_RX_EQ_GAIN2_LSB RX_OFF(0xCC)
+#define QSERDES_RX_RX_EQ_GAIN2_MSB RX_OFF(0xD0)
+#define QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2 RX_OFF(0xD8)
+#define QSERDES_RX_SIGDET_CNTRL RX_OFF(0x114)
+#define QSERDES_RX_SIGDET_LVL RX_OFF(0x118)
+#define QSERDES_RX_SIGDET_DEGLITCH_CNTRL RX_OFF(0x11C)
+#define QSERDES_RX_RX_INTERFACE_MODE RX_OFF(0x12C)
+
+
+#define UFS_PHY_RX_LINECFG_DISABLE_BIT BIT(1)
+
+/*
+ * This structure represents the v3 falcon specific phy.
+ * common_cfg MUST remain the first field in this structure
+ * in case extra fields are added. This way, when calling
+ * get_ufs_qcom_phy() of generic phy, we can extract the
+ * common phy structure (struct ufs_qcom_phy) out of it
+ * regardless of the relevant specific phy.
+ */
+struct ufs_qcom_phy_qmp_v3_falcon {
+ struct ufs_qcom_phy common_cfg;
+};
+
+static struct ufs_qcom_phy_calibration phy_cal_table_rate_A_3_1_1[] = {
+ UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_POWER_DOWN_CONTROL, 0x01),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CMN_CONFIG, 0x0e),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_SYSCLK_EN_SEL, 0x14),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CLK_SELECT, 0x30),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_SYS_CLK_CTRL, 0x02),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x08),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_BG_TIMER, 0x0a),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_HSCLK_SEL, 0x00),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CORECLK_DIV, 0x0a),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CORECLK_DIV_MODE1, 0x0a),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP_EN, 0x01),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_CTRL, 0x00),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_RESETSM_CNTRL, 0x20),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CORE_CLK_EN, 0x00),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP_CFG, 0x00),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_TIMER1, 0xff),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_TIMER2, 0x3f),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_MAP, 0x04),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_SVS_MODE_CLK_SEL, 0x05),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DEC_START_MODE0, 0x82),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START1_MODE0, 0x00),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START2_MODE0, 0x00),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START3_MODE0, 0x00),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CP_CTRL_MODE0, 0x0b),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_RCTRL_MODE0, 0x16),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CCTRL_MODE0, 0x28),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN0_MODE0, 0x80),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN1_MODE0, 0x00),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE1_MODE0, 0x28),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE2_MODE0, 0x02),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP1_MODE0, 0xff),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP2_MODE0, 0x0c),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP3_MODE0, 0x00),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DEC_START_MODE1, 0x98),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START1_MODE1, 0x00),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START2_MODE1, 0x00),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START3_MODE1, 0x00),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CP_CTRL_MODE1, 0x0b),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_RCTRL_MODE1, 0x16),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CCTRL_MODE1, 0x28),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN0_MODE1, 0x80),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN1_MODE1, 0x00),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE1_MODE1, 0xd6),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE2_MODE1, 0x00),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP1_MODE1, 0x32),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP2_MODE1, 0x0f),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP3_MODE1, 0x00),
+
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_TX_HIGHZ_TRANSCEIVER_BIAS_DRVR_EN, 0x45),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_TX_LANE_MODE, 0x06),
+
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_SIGDET_LVL, 0x24),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_SIGDET_CNTRL, 0x0F),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_INTERFACE_MODE, 0x40),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_SIGDET_DEGLITCH_CNTRL, 0x1E),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_UCDR_FASTLOCK_FO_GAIN, 0x0B),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_TERM_BW, 0x5B),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN1_LSB, 0xFF),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN1_MSB, 0x3F),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN2_LSB, 0xFF),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN2_MSB, 0x3F),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2, 0x0D),
+
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_IVCO, 0x0F),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_BG_TRIM, 0x0F),
+ UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_RX_PWM_GEAR_BAND, 0x15),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_UCDR_SVS_SO_GAIN_HALF, 0x04),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_UCDR_SVS_SO_GAIN_QUARTER, 0x04),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_UCDR_SVS_SO_GAIN, 0x04),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_UCDR_SO_SATURATION_ENABLE, 0x4B),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_INITVAL1, 0xFF),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_INITVAL2, 0x00),
+ UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_RX_SIGDET_CTRL2, 0x6c),
+ UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_TX_LARGE_AMP_DRV_LVL, 0x0A),
+ UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_TX_SMALL_AMP_DRV_LVL, 0x02),
+ UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_RX_MIN_STALL_NOCONFIG_TIME_CAP, 0x28),
+ UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_RX_SYM_RESYNC_CTRL, 0x03),
+};
+
+static struct ufs_qcom_phy_calibration phy_cal_table_rate_B[] = {
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_MAP, 0x44),
+};
+
+#endif
diff --git a/drivers/power/qcom-charger/fg-core.h b/drivers/power/qcom-charger/fg-core.h
index 9ddd18800f9d..d8b6754a465f 100644
--- a/drivers/power/qcom-charger/fg-core.h
+++ b/drivers/power/qcom-charger/fg-core.h
@@ -39,6 +39,12 @@
pr_debug(fmt, ##__VA_ARGS__); \
} while (0)
+#define is_between(left, right, value) \
+ (((left) >= (right) && (left) >= (value) \
+ && (value) >= (right)) \
+ || ((left) <= (right) && (left) <= (value) \
+ && (value) <= (right)))
+
/* Awake votable reasons */
#define SRAM_READ "fg_sram_read"
#define SRAM_WRITE "fg_sram_write"
@@ -205,10 +211,10 @@ struct fg_dt_props {
int recharge_soc_thr;
int recharge_volt_thr_mv;
int rsense_sel;
- int jeita_thresholds[NUM_JEITA_LEVELS];
int esr_timer_charging;
int esr_timer_awake;
int esr_timer_asleep;
+ int rconn_mohms;
int cl_start_soc;
int cl_max_temp;
int cl_min_temp;
@@ -218,6 +224,7 @@ struct fg_dt_props {
int cl_min_cap_limit;
int jeita_hyst_temp;
int batt_temp_delta;
+ int jeita_thresholds[NUM_JEITA_LEVELS];
int ki_coeff_soc[KI_COEFF_SOC_LEVELS];
int ki_coeff_med_dischg[KI_COEFF_SOC_LEVELS];
int ki_coeff_hi_dischg[KI_COEFF_SOC_LEVELS];
@@ -310,8 +317,9 @@ struct fg_chip {
u32 batt_soc_base;
u32 batt_info_base;
u32 mem_if_base;
+ u32 rradc_base;
u32 wa_flags;
- int batt_id_kohms;
+ int batt_id_ohms;
int charge_status;
int prev_charge_status;
int charge_done;
diff --git a/drivers/power/qcom-charger/fg-reg.h b/drivers/power/qcom-charger/fg-reg.h
index ffc46f328f91..7ad26215e469 100644
--- a/drivers/power/qcom-charger/fg-reg.h
+++ b/drivers/power/qcom-charger/fg-reg.h
@@ -13,6 +13,10 @@
#ifndef __FG_REG_H__
#define __FG_REG_H__
+/* FG_ADC_RR register definitions used only for READ */
+#define ADC_RR_FAKE_BATT_LOW_LSB(chip) (chip->rradc_base + 0x58)
+#define ADC_RR_FAKE_BATT_HIGH_LSB(chip) (chip->rradc_base + 0x5A)
+
/* FG_BATT_SOC register definitions */
#define BATT_SOC_FG_ALG_STS(chip) (chip->batt_soc_base + 0x06)
#define BATT_SOC_FG_ALG_AUX_STS0(chip) (chip->batt_soc_base + 0x07)
diff --git a/drivers/power/qcom-charger/qpnp-fg-gen3.c b/drivers/power/qcom-charger/qpnp-fg-gen3.c
index 84204163f076..22025ac27ffa 100644
--- a/drivers/power/qcom-charger/qpnp-fg-gen3.c
+++ b/drivers/power/qcom-charger/qpnp-fg-gen3.c
@@ -62,6 +62,10 @@
#define ESR_TIMER_CHG_INIT_OFFSET 2
#define PROFILE_LOAD_WORD 24
#define PROFILE_LOAD_OFFSET 0
+#define ESR_RSLOW_DISCHG_WORD 34
+#define ESR_RSLOW_DISCHG_OFFSET 0
+#define ESR_RSLOW_CHG_WORD 51
+#define ESR_RSLOW_CHG_OFFSET 0
#define NOM_CAP_WORD 58
#define NOM_CAP_OFFSET 0
#define ACT_BATT_CAP_BKUP_WORD 74
@@ -69,6 +73,7 @@
#define CYCLE_COUNT_WORD 75
#define CYCLE_COUNT_OFFSET 0
#define PROFILE_INTEGRITY_WORD 79
+#define SW_CONFIG_OFFSET 0
#define PROFILE_INTEGRITY_OFFSET 3
#define BATT_SOC_WORD 91
#define BATT_SOC_OFFSET 0
@@ -564,21 +569,21 @@ static int fg_get_battery_esr(struct fg_chip *chip, int *val)
static int fg_get_battery_resistance(struct fg_chip *chip, int *val)
{
- int rc, esr, rslow;
+ int rc, esr_uohms, rslow_uohms;
- rc = fg_get_battery_esr(chip, &esr);
+ rc = fg_get_battery_esr(chip, &esr_uohms);
if (rc < 0) {
pr_err("failed to get ESR, rc=%d\n", rc);
return rc;
}
- rc = fg_get_sram_prop(chip, FG_SRAM_RSLOW, &rslow);
+ rc = fg_get_sram_prop(chip, FG_SRAM_RSLOW, &rslow_uohms);
if (rc < 0) {
pr_err("failed to get Rslow, rc=%d\n", rc);
return rc;
}
- *val = esr + rslow;
+ *val = esr_uohms + rslow_uohms;
return 0;
}
@@ -693,18 +698,57 @@ static bool is_batt_empty(struct fg_chip *chip)
return ((vbatt_uv < chip->dt.cutoff_volt_mv * 1000) ? true : false);
}
-#define DEBUG_BATT_ID_KOHMS 7
+static int fg_get_debug_batt_id(struct fg_chip *chip, int *batt_id)
+{
+ int rc;
+ u64 temp;
+ u8 buf[2];
+
+ rc = fg_read(chip, ADC_RR_FAKE_BATT_LOW_LSB(chip), buf, 2);
+ if (rc < 0) {
+ pr_err("failed to read addr=0x%04x, rc=%d\n",
+ ADC_RR_FAKE_BATT_LOW_LSB(chip), rc);
+ return rc;
+ }
+
+ /*
+ * Fake battery threshold is encoded in the following format.
+ * Threshold (code) = (battery_id in Ohms) * 0.00015 * 2^10 / 2.5
+ */
+ temp = (buf[1] << 8 | buf[0]) * 2500000;
+ do_div(temp, 150 * 1024);
+ batt_id[0] = temp;
+ rc = fg_read(chip, ADC_RR_FAKE_BATT_HIGH_LSB(chip), buf, 2);
+ if (rc < 0) {
+ pr_err("failed to read addr=0x%04x, rc=%d\n",
+ ADC_RR_FAKE_BATT_HIGH_LSB(chip), rc);
+ return rc;
+ }
+
+ temp = (buf[1] << 8 | buf[0]) * 2500000;
+ do_div(temp, 150 * 1024);
+ batt_id[1] = temp;
+ pr_debug("debug batt_id range: [%d %d]\n", batt_id[0], batt_id[1]);
+ return 0;
+}
+
static bool is_debug_batt_id(struct fg_chip *chip)
{
- int batt_id_delta = 0;
+ int debug_batt_id[2], rc;
- if (!chip->batt_id_kohms)
+ if (!chip->batt_id_ohms)
return false;
- batt_id_delta = abs(chip->batt_id_kohms - DEBUG_BATT_ID_KOHMS);
- if (batt_id_delta <= 1) {
- fg_dbg(chip, FG_POWER_SUPPLY, "Debug battery id: %dKohms\n",
- chip->batt_id_kohms);
+ rc = fg_get_debug_batt_id(chip, debug_batt_id);
+ if (rc < 0) {
+ pr_err("Failed to get debug batt_id, rc=%d\n", rc);
+ return false;
+ }
+
+ if (is_between(debug_batt_id[0], debug_batt_id[1],
+ chip->batt_id_ohms)) {
+ fg_dbg(chip, FG_POWER_SUPPLY, "Debug battery id: %dohms\n",
+ chip->batt_id_ohms);
return true;
}
@@ -792,8 +836,8 @@ static int fg_get_batt_profile(struct fg_chip *chip)
return rc;
}
+ chip->batt_id_ohms = batt_id;
batt_id /= 1000;
- chip->batt_id_kohms = batt_id;
batt_node = of_find_node_by_name(node, "qcom,battery-data");
if (!batt_node) {
pr_err("Batterydata not available\n");
@@ -824,10 +868,10 @@ static int fg_get_batt_profile(struct fg_chip *chip)
chip->bp.float_volt_uv = -EINVAL;
}
- rc = of_property_read_u32(profile_node, "qcom,nom-batt-capacity-mah",
+ rc = of_property_read_u32(profile_node, "qcom,fastchg-current-ma",
&chip->bp.fastchg_curr_ma);
if (rc < 0) {
- pr_err("battery nominal capacity unavailable, rc:%d\n", rc);
+ pr_err("battery fastchg current unavailable, rc:%d\n", rc);
chip->bp.fastchg_curr_ma = -EINVAL;
}
@@ -1368,6 +1412,80 @@ static int fg_charge_full_update(struct fg_chip *chip)
return 0;
}
+#define RCONN_CONFIG_BIT BIT(0)
+static int fg_rconn_config(struct fg_chip *chip)
+{
+ int rc, esr_uohms;
+ u64 scaling_factor;
+ u32 val = 0;
+
+ rc = fg_sram_read(chip, PROFILE_INTEGRITY_WORD,
+ SW_CONFIG_OFFSET, (u8 *)&val, 1, FG_IMA_DEFAULT);
+ if (rc < 0) {
+ pr_err("Error in reading SW_CONFIG_OFFSET, rc=%d\n", rc);
+ return rc;
+ }
+
+ if (val & RCONN_CONFIG_BIT) {
+ fg_dbg(chip, FG_STATUS, "Rconn already configured: %x\n", val);
+ return 0;
+ }
+
+ rc = fg_get_battery_esr(chip, &esr_uohms);
+ if (rc < 0) {
+ pr_err("failed to get ESR, rc=%d\n", rc);
+ return rc;
+ }
+
+ scaling_factor = div64_u64((u64)esr_uohms * 1000,
+ esr_uohms + (chip->dt.rconn_mohms * 1000));
+
+ rc = fg_sram_read(chip, ESR_RSLOW_CHG_WORD,
+ ESR_RSLOW_CHG_OFFSET, (u8 *)&val, 1, FG_IMA_DEFAULT);
+ if (rc < 0) {
+ pr_err("Error in reading ESR_RSLOW_CHG_OFFSET, rc=%d\n", rc);
+ return rc;
+ }
+
+ val *= scaling_factor;
+ do_div(val, 1000);
+ rc = fg_sram_write(chip, ESR_RSLOW_CHG_WORD,
+ ESR_RSLOW_CHG_OFFSET, (u8 *)&val, 1, FG_IMA_DEFAULT);
+ if (rc < 0) {
+ pr_err("Error in writing ESR_RSLOW_CHG_OFFSET, rc=%d\n", rc);
+ return rc;
+ }
+ fg_dbg(chip, FG_STATUS, "esr_rslow_chg modified to %x\n", val & 0xFF);
+
+ rc = fg_sram_read(chip, ESR_RSLOW_DISCHG_WORD,
+ ESR_RSLOW_DISCHG_OFFSET, (u8 *)&val, 1, FG_IMA_DEFAULT);
+ if (rc < 0) {
+ pr_err("Error in reading ESR_RSLOW_DISCHG_OFFSET, rc=%d\n", rc);
+ return rc;
+ }
+
+ val *= scaling_factor;
+ do_div(val, 1000);
+ rc = fg_sram_write(chip, ESR_RSLOW_DISCHG_WORD,
+ ESR_RSLOW_DISCHG_OFFSET, (u8 *)&val, 1, FG_IMA_DEFAULT);
+ if (rc < 0) {
+ pr_err("Error in writing ESR_RSLOW_DISCHG_OFFSET, rc=%d\n", rc);
+ return rc;
+ }
+ fg_dbg(chip, FG_STATUS, "esr_rslow_dischg modified to %x\n",
+ val & 0xFF);
+
+ val = RCONN_CONFIG_BIT;
+ rc = fg_sram_write(chip, PROFILE_INTEGRITY_WORD,
+ SW_CONFIG_OFFSET, (u8 *)&val, 1, FG_IMA_DEFAULT);
+ if (rc < 0) {
+ pr_err("Error in writing SW_CONFIG_OFFSET, rc=%d\n", rc);
+ return rc;
+ }
+
+ return 0;
+}
+
static int fg_set_recharge_soc(struct fg_chip *chip, int recharge_soc)
{
u8 buf[4];
@@ -2330,6 +2448,9 @@ static int fg_notifier_cb(struct notifier_block *nb,
if (event != PSY_EVENT_PROP_CHANGED)
return NOTIFY_OK;
+ if (work_pending(&chip->status_change_work))
+ return NOTIFY_OK;
+
if ((strcmp(psy->desc->name, "battery") == 0)
|| (strcmp(psy->desc->name, "usb") == 0)) {
/*
@@ -2575,6 +2696,14 @@ static int fg_hw_init(struct fg_chip *chip)
return rc;
}
+ if (chip->dt.rconn_mohms > 0) {
+ rc = fg_rconn_config(chip);
+ if (rc < 0) {
+ pr_err("Error in configuring Rconn, rc=%d\n", rc);
+ return rc;
+ }
+ }
+
return 0;
}
@@ -3076,10 +3205,17 @@ static int fg_parse_dt(struct fg_chip *chip)
}
}
+ rc = of_property_read_u32(node, "qcom,rradc-base", &base);
+ if (rc < 0) {
+ dev_err(chip->dev, "rradc-base not specified, rc=%d\n", rc);
+ return rc;
+ }
+ chip->rradc_base = base;
+
rc = fg_get_batt_profile(chip);
if (rc < 0)
pr_warn("profile for batt_id=%dKOhms not found..using OTP, rc:%d\n",
- chip->batt_id_kohms, rc);
+ chip->batt_id_ohms / 1000, rc);
/* Read all the optional properties below */
rc = of_property_read_u32(node, "qcom,fg-cutoff-voltage", &temp);
@@ -3236,6 +3372,12 @@ static int fg_parse_dt(struct fg_chip *chip)
if (rc < 0)
pr_err("Error in parsing Ki coefficients, rc=%d\n", rc);
+ rc = of_property_read_u32(node, "qcom,fg-rconn-mohms", &temp);
+ if (rc < 0)
+ chip->dt.rconn_mohms = -EINVAL;
+ else
+ chip->dt.rconn_mohms = temp;
+
return 0;
}
@@ -3362,7 +3504,7 @@ static int fg_gen3_probe(struct platform_device *pdev)
if (!rc)
pr_info("battery SOC:%d voltage: %duV temp: %d id: %dKOhms\n",
- msoc, volt_uv, batt_temp, chip->batt_id_kohms);
+ msoc, volt_uv, batt_temp, chip->batt_id_ohms / 1000);
device_init_wakeup(chip->dev, true);
if (chip->profile_available)
diff --git a/drivers/power/qcom-charger/smb-lib.c b/drivers/power/qcom-charger/smb-lib.c
index 0faf8aee8aa0..507704dd469a 100644
--- a/drivers/power/qcom-charger/smb-lib.c
+++ b/drivers/power/qcom-charger/smb-lib.c
@@ -2452,12 +2452,9 @@ irqreturn_t smblib_handle_usb_plugin(int irq, void *data)
rc);
}
} else {
- if (chg->wa_flags & BOOST_BACK_WA) {
+ if (chg->wa_flags & BOOST_BACK_WA)
vote(chg->usb_suspend_votable,
BOOST_BACK_VOTER, false, 0);
- vote(chg->dc_suspend_votable,
- BOOST_BACK_VOTER, false, 0);
- }
if (chg->dpdm_reg && regulator_is_enabled(chg->dpdm_reg)) {
smblib_dbg(chg, PR_MISC, "disabling DPDM regulator\n");
@@ -2941,14 +2938,12 @@ irqreturn_t smblib_handle_switcher_power_ok(int irq, void *data)
get_effective_result(chg->usb_suspend_votable))
return IRQ_HANDLED;
- if ((stat & USE_DCIN_BIT) &&
- get_effective_result(chg->dc_suspend_votable))
+ if (stat & USE_DCIN_BIT)
return IRQ_HANDLED;
if (is_storming(&irq_data->storm_data)) {
- smblib_dbg(chg, PR_MISC, "reverse boost detected; suspending input\n");
+ smblib_err(chg, "Reverse boost detected: suspending input\n");
vote(chg->usb_suspend_votable, BOOST_BACK_VOTER, true, 0);
- vote(chg->dc_suspend_votable, BOOST_BACK_VOTER, true, 0);
}
return IRQ_HANDLED;
diff --git a/drivers/soc/qcom/glink.c b/drivers/soc/qcom/glink.c
index 21ff179b7c0b..65ce7d791a47 100644
--- a/drivers/soc/qcom/glink.c
+++ b/drivers/soc/qcom/glink.c
@@ -1670,6 +1670,14 @@ void ch_purge_intent_lists(struct channel_ctx *ctx)
}
spin_unlock_irqrestore(&ctx->tx_lists_lock_lhc3, flags);
+ spin_lock_irqsave(&ctx->tx_pending_rmt_done_lock_lhc4, flags);
+ list_for_each_entry_safe(tx_info, tx_info_temp,
+ &ctx->tx_pending_remote_done, list_done) {
+ ctx->notify_tx_abort(ctx, ctx->user_priv, tx_info->pkt_priv);
+ rwref_put(&tx_info->pkt_ref);
+ }
+ spin_unlock_irqrestore(&ctx->tx_pending_rmt_done_lock_lhc4, flags);
+
spin_lock_irqsave(&ctx->local_rx_intent_lst_lock_lhc1, flags);
list_for_each_entry_safe(ptr_intent, tmp_intent,
&ctx->local_rx_intent_list, list) {
diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c
index 37204dcbc065..7067c5733773 100644
--- a/drivers/soc/qcom/icnss.c
+++ b/drivers/soc/qcom/icnss.c
@@ -3557,18 +3557,16 @@ unsigned int icnss_socinfo_get_serial_number(struct device *dev)
}
EXPORT_SYMBOL(icnss_socinfo_get_serial_number);
-int icnss_set_wlan_mac_address(struct device *dev,
- const u8 *in, uint32_t len)
+int icnss_set_wlan_mac_address(const u8 *in, const uint32_t len)
{
- struct icnss_priv *priv = dev_get_drvdata(dev);
+ struct icnss_priv *priv = penv;
uint32_t no_of_mac_addr;
struct icnss_wlan_mac_addr *addr = NULL;
int iter;
u8 *temp = NULL;
- if (priv->magic != ICNSS_MAGIC) {
- icnss_pr_err("Invalid drvdata: dev %p, data %p, magic 0x%x\n",
- dev, priv, priv->magic);
+ if (!priv) {
+ icnss_pr_err("Priv data is NULL\n");
return -EINVAL;
}
diff --git a/drivers/soc/qcom/pil-msa.c b/drivers/soc/qcom/pil-msa.c
index 3c3ae693f615..bbd77d8e0650 100644
--- a/drivers/soc/qcom/pil-msa.c
+++ b/drivers/soc/qcom/pil-msa.c
@@ -278,6 +278,7 @@ int pil_mss_shutdown(struct pil_desc *pil)
struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
int ret = 0;
+ dev_info(pil->dev, "MSS is shutting down\n");
if (drv->axi_halt_base) {
pil_q6v5_halt_axi_port(pil,
drv->axi_halt_base + MSS_Q6_HALT_BASE);
@@ -542,7 +543,7 @@ int pil_mss_reset_load_mba(struct pil_desc *pil)
{
struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
struct modem_data *md = dev_get_drvdata(pil->dev);
- const struct firmware *fw, *dp_fw;
+ const struct firmware *fw, *dp_fw = NULL;
char fw_name_legacy[10] = "mba.b00";
char fw_name[10] = "mba.mbn";
char *dp_name = "msadp";
diff --git a/drivers/soc/qcom/pil-q6v5.c b/drivers/soc/qcom/pil-q6v5.c
index a1cd3b1eeaff..43e3adeb0732 100644
--- a/drivers/soc/qcom/pil-q6v5.c
+++ b/drivers/soc/qcom/pil-q6v5.c
@@ -149,7 +149,7 @@ err_vreg_pll:
err_cx_enable:
regulator_set_load(drv->vreg_cx, 0);
err_cx_mode:
- regulator_set_voltage(drv->vreg_cx, RPM_REGULATOR_CORNER_NONE, uv);
+ regulator_set_voltage(drv->vreg_cx, RPM_REGULATOR_CORNER_NONE, INT_MAX);
err_cx_voltage:
clk_disable_unprepare(drv->qdss_clk);
err_qdss_vote:
@@ -179,7 +179,7 @@ void pil_q6v5_remove_proxy_votes(struct pil_desc *pil)
}
regulator_disable(drv->vreg_cx);
regulator_set_load(drv->vreg_cx, 0);
- regulator_set_voltage(drv->vreg_cx, RPM_REGULATOR_CORNER_NONE, uv);
+ regulator_set_voltage(drv->vreg_cx, RPM_REGULATOR_CORNER_NONE, INT_MAX);
clk_disable_unprepare(drv->xo);
clk_disable_unprepare(drv->pnoc_clk);
clk_disable_unprepare(drv->qdss_clk);
@@ -512,6 +512,8 @@ static int __pil_q6v55_reset(struct pil_desc *pil)
val |= BIT(i);
writel_relaxed(val, drv->reg_base +
QDSP6V6SS_MEM_PWR_CTL);
+ val = readl_relaxed(drv->reg_base +
+ QDSP6V6SS_MEM_PWR_CTL);
/*
* Wait for 1us for both memory peripheral and
* data array to turn on.
diff --git a/drivers/soc/qcom/smcinvoke.c b/drivers/soc/qcom/smcinvoke.c
index 6de73217bf86..d4be8c641ad8 100644
--- a/drivers/soc/qcom/smcinvoke.c
+++ b/drivers/soc/qcom/smcinvoke.c
@@ -235,7 +235,7 @@ static int marshal_out(void *buf, uint32_t buf_size,
pr_err("%s: buffer overflow detected\n", __func__);
goto out;
}
- if (copy_to_user((void __user *)(args_buf[i].b.addr),
+ if (copy_to_user((void __user *)(uintptr_t)(args_buf[i].b.addr),
(uint8_t *)(buf) + tz_args->b.offset,
tz_args->b.size)) {
pr_err("Error %d copying ctxt to user\n", ret);
@@ -320,7 +320,7 @@ static int marshal_in(const struct smcinvoke_cmd_req *req,
tz_args++;
if (copy_from_user(buf+offset,
- (void __user *)(args_buf[i].b.addr),
+ (void __user *)(uintptr_t)(args_buf[i].b.addr),
args_buf[i].b.size))
goto out;
@@ -389,7 +389,7 @@ long smcinvoke_ioctl(struct file *filp, unsigned cmd, unsigned long arg)
}
ret = copy_from_user(args_buf,
- (void __user *)(req.args),
+ (void __user *)(uintptr_t)(req.args),
nr_args * req.argsize);
if (ret) {
@@ -424,8 +424,8 @@ long smcinvoke_ioctl(struct file *filp, unsigned cmd, unsigned long arg)
ret = marshal_out(in_msg, inmsg_size, &req, args_buf);
- ret |= copy_to_user((void __user *)(req.args), args_buf,
- nr_args * req.argsize);
+ ret |= copy_to_user((void __user *)(uintptr_t)(req.args),
+ args_buf, nr_args * req.argsize);
ret |= copy_to_user((void __user *)arg, &req, sizeof(req));
if (ret)
goto out;
diff --git a/drivers/soc/qcom/spcom.c b/drivers/soc/qcom/spcom.c
index 0c5f3b84162b..5fee83f8ada4 100644
--- a/drivers/soc/qcom/spcom.c
+++ b/drivers/soc/qcom/spcom.c
@@ -352,11 +352,11 @@ static void spcom_link_state_notif_cb(struct glink_link_state_cb_info *cb_info,
switch (cb_info->link_state) {
case GLINK_LINK_STATE_UP:
- pr_debug("GLINK_LINK_STATE_UP.\n");
+ pr_info("GLINK_LINK_STATE_UP.\n");
spcom_create_predefined_channels_chardev();
break;
case GLINK_LINK_STATE_DOWN:
- pr_debug("GLINK_LINK_STATE_DOWN.\n");
+ pr_err("GLINK_LINK_STATE_DOWN.\n");
break;
default:
pr_err("unknown link_state [%d].\n", cb_info->link_state);
@@ -466,7 +466,7 @@ static void spcom_notify_state(void *handle, const void *priv, unsigned event)
* This is not expected on normal operation.
* This may happen upon remote SSR.
*/
- pr_debug("GLINK_REMOTE_DISCONNECTED, ch [%s].\n", ch->name);
+ pr_err("GLINK_REMOTE_DISCONNECTED, ch [%s].\n", ch->name);
/*
* after glink_close(),
* expecting notify GLINK_LOCAL_DISCONNECTED
@@ -731,7 +731,9 @@ static int spcom_close(struct spcom_channel *ch)
ch->glink_handle = NULL;
ch->ref_count = 0;
-
+ ch->rx_abort = false;
+ ch->tx_abort = false;
+ ch->glink_state = GLINK_LOCAL_DISCONNECTED;
ch->txn_id = INITIAL_TXN_ID; /* use non-zero nonce for debug */
ch->pid = 0;
@@ -1333,6 +1335,16 @@ static int spcom_handle_send_command(struct spcom_channel *ch,
pr_debug("send req/resp ch [%s] size [%d] .\n", ch->name, size);
+ /*
+ * check that cmd buf size is at least struct size,
+ * to allow access to struct fields.
+ */
+ if (size < sizeof(*cmd)) {
+ pr_err("ch [%s] invalid cmd buf.\n",
+ ch->name);
+ return -EINVAL;
+ }
+
/* Check if remote side connect */
if (!spcom_is_channel_connected(ch)) {
pr_err("ch [%s] remote side not connect.\n", ch->name);
@@ -1344,6 +1356,18 @@ static int spcom_handle_send_command(struct spcom_channel *ch,
buf_size = cmd->buf_size;
timeout_msec = cmd->timeout_msec;
+ /* Check param validity */
+ if (buf_size > SPCOM_MAX_RESPONSE_SIZE) {
+ pr_err("ch [%s] invalid buf size [%d].\n",
+ ch->name, buf_size);
+ return -EINVAL;
+ }
+ if (size != sizeof(*cmd) + buf_size) {
+ pr_err("ch [%s] invalid cmd size [%d].\n",
+ ch->name, size);
+ return -EINVAL;
+ }
+
/* Allocate Buffers*/
tx_buf_size = sizeof(*hdr) + buf_size;
tx_buf = kzalloc(tx_buf_size, GFP_KERNEL);
@@ -1407,6 +1431,11 @@ static int modify_ion_addr(void *buf,
return -ENODEV;
}
+ if (buf_size < sizeof(uint64_t)) {
+ pr_err("buf size too small [%d].\n", buf_size);
+ return -ENODEV;
+ }
+
if (buf_offset > buf_size - sizeof(uint64_t)) {
pr_err("invalid buf_offset [%d].\n", buf_offset);
return -ENODEV;
@@ -1469,6 +1498,16 @@ static int spcom_handle_send_modified_command(struct spcom_channel *ch,
pr_debug("send req/resp ch [%s] size [%d] .\n", ch->name, size);
+ /*
+ * check that cmd buf size is at least struct size,
+ * to allow access to struct fields.
+ */
+ if (size < sizeof(*cmd)) {
+ pr_err("ch [%s] invalid cmd buf.\n",
+ ch->name);
+ return -EINVAL;
+ }
+
/* Check if remote side connect */
if (!spcom_is_channel_connected(ch)) {
pr_err("ch [%s] remote side not connect.\n", ch->name);
@@ -1481,6 +1520,18 @@ static int spcom_handle_send_modified_command(struct spcom_channel *ch,
timeout_msec = cmd->timeout_msec;
memcpy(ion_info, cmd->ion_info, sizeof(ion_info));
+ /* Check param validity */
+ if (buf_size > SPCOM_MAX_RESPONSE_SIZE) {
+ pr_err("ch [%s] invalid buf size [%d].\n",
+ ch->name, buf_size);
+ return -EINVAL;
+ }
+ if (size != sizeof(*cmd) + buf_size) {
+ pr_err("ch [%s] invalid cmd size [%d].\n",
+ ch->name, size);
+ return -EINVAL;
+ }
+
/* Allocate Buffers*/
tx_buf_size = sizeof(*hdr) + buf_size;
tx_buf = kzalloc(tx_buf_size, GFP_KERNEL);
@@ -1539,13 +1590,18 @@ static int spcom_handle_lock_ion_buf_command(struct spcom_channel *ch,
struct ion_handle *ion_handle;
int i;
+ if (size != sizeof(*cmd)) {
+ pr_err("cmd size [%d] , expected [%d].\n",
+ (int) size, (int) sizeof(*cmd));
+ return -EINVAL;
+ }
+
/* Check ION client */
if (spcom_dev->ion_client == NULL) {
pr_err("invalid ion client.\n");
return -ENODEV;
}
-
/* Get ION handle from fd - this increments the ref count */
ion_handle = ion_import_dma_buf(spcom_dev->ion_client, fd);
if (ion_handle == NULL) {
@@ -1591,6 +1647,12 @@ static int spcom_handle_unlock_ion_buf_command(struct spcom_channel *ch,
struct ion_client *ion_client = spcom_dev->ion_client;
int i;
+ if (size != sizeof(*cmd)) {
+ pr_err("cmd size [%d] , expected [%d].\n",
+ (int) size, (int) sizeof(*cmd));
+ return -EINVAL;
+ }
+
/* Check ION client */
if (ion_client == NULL) {
pr_err("fail to create ion client.\n");
@@ -1746,6 +1808,13 @@ static int spcom_handle_read_req_resp(struct spcom_channel *ch,
return -ENOTCONN;
}
+ /* Check param validity */
+ if (size > SPCOM_MAX_RESPONSE_SIZE) {
+ pr_err("ch [%s] inavlid size [%d].\n",
+ ch->name, size);
+ return -EINVAL;
+ }
+
/* Allocate Buffers*/
rx_buf_size = sizeof(*hdr) + size;
rx_buf = kzalloc(rx_buf_size, GFP_KERNEL);
diff --git a/drivers/staging/android/ion/msm/msm_ion.c b/drivers/staging/android/ion/msm/msm_ion.c
index 176f22ba570c..c2ef091d72ce 100644
--- a/drivers/staging/android/ion/msm/msm_ion.c
+++ b/drivers/staging/android/ion/msm/msm_ion.c
@@ -157,6 +157,15 @@ int msm_ion_do_cache_op(struct ion_client *client, struct ion_handle *handle,
}
EXPORT_SYMBOL(msm_ion_do_cache_op);
+int msm_ion_do_cache_offset_op(
+ struct ion_client *client, struct ion_handle *handle,
+ void *vaddr, unsigned int offset, unsigned long len,
+ unsigned int cmd)
+{
+ return ion_do_cache_op(client, handle, vaddr, offset, len, cmd);
+}
+EXPORT_SYMBOL(msm_ion_do_cache_offset_op);
+
static int ion_no_pages_cache_ops(struct ion_client *client,
struct ion_handle *handle,
void *vaddr,
@@ -305,13 +314,23 @@ static int ion_pages_cache_ops(struct ion_client *client,
};
for_each_sg(table->sgl, sg, table->nents, i) {
+ unsigned int sg_offset, sg_left, size = 0;
+
len += sg->length;
- if (len < offset)
+ if (len <= offset)
continue;
- __do_cache_ops(sg_page(sg), sg->offset, sg->length, op);
+ sg_left = len - offset;
+ sg_offset = sg->length - sg_left;
+
+ size = (length < sg_left) ? length : sg_left;
+
+ __do_cache_ops(sg_page(sg), sg_offset, size, op);
+
+ offset += size;
+ length -= size;
- if (len > length + offset)
+ if (length == 0)
break;
}
return 0;
diff --git a/drivers/staging/android/ion/msm/msm_ion.h b/drivers/staging/android/ion/msm/msm_ion.h
index d8677b2fb55a..098104d56fdb 100644
--- a/drivers/staging/android/ion/msm/msm_ion.h
+++ b/drivers/staging/android/ion/msm/msm_ion.h
@@ -1,3 +1,16 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
#ifndef _MSM_MSM_ION_H
#define _MSM_MSM_ION_H
@@ -157,6 +170,11 @@ int ion_handle_get_size(struct ion_client *client, struct ion_handle *handle,
int msm_ion_do_cache_op(struct ion_client *client, struct ion_handle *handle,
void *vaddr, unsigned long len, unsigned int cmd);
+int msm_ion_do_cache_offset_op(
+ struct ion_client *client, struct ion_handle *handle,
+ void *vaddr, unsigned int offset, unsigned long len,
+ unsigned int cmd);
+
#else
static inline struct ion_client *msm_ion_client_create(const char *name)
{
@@ -176,6 +194,14 @@ static inline int msm_ion_do_cache_op(struct ion_client *client,
return -ENODEV;
}
+int msm_ion_do_cache_offset_op(
+ struct ion_client *client, struct ion_handle *handle,
+ void *vaddr, unsigned int offset, unsigned long len,
+ unsigned int cmd)
+{
+ return -ENODEV;
+}
+
#endif /* CONFIG_ION */
#endif
diff --git a/drivers/usb/dwc3/dbm.c b/drivers/usb/dwc3/dbm.c
index fc91bfb8b8d5..0fbb1fb39f5c 100644
--- a/drivers/usb/dwc3/dbm.c
+++ b/drivers/usb/dwc3/dbm.c
@@ -315,9 +315,6 @@ int dbm_ep_config(struct dbm *dbm, u8 usb_ep, u8 bam_pipe, bool producer,
return -ENODEV;
}
- /* First, reset the dbm endpoint */
- ep_soft_reset(dbm, dbm_ep, 0);
-
/* Set ioc bit for dbm_ep if needed */
msm_dbm_write_reg_field(dbm, DBM_DBG_CNFG,
DBM_ENABLE_IOC_MASK & 1 << dbm_ep, ioc ? 1 : 0);
@@ -398,23 +395,10 @@ int dbm_ep_unconfig(struct dbm *dbm, u8 usb_ep)
data &= (~0x1);
msm_dbm_write_ep_reg(dbm, DBM_EP_CFG, dbm_ep, data);
- /* Reset the dbm endpoint */
- ep_soft_reset(dbm, dbm_ep, true);
/*
- * The necessary delay between asserting and deasserting the dbm ep
- * reset is based on the number of active endpoints. If there is more
- * than one endpoint, a 1 msec delay is required. Otherwise, a shorter
- * delay will suffice.
- *
- * As this function can be called in atomic context, sleeping variants
- * for delay are not possible - albeit a 1ms delay.
+ * ep_soft_reset is not required during disconnect as pipe reset on
+ * next connect will take care of the same.
*/
- if (dbm_get_num_of_eps_configured(dbm) > 1)
- udelay(1000);
- else
- udelay(10);
- ep_soft_reset(dbm, dbm_ep, false);
-
return 0;
}
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index b2085af28374..8a1b0d870e7a 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -210,6 +210,8 @@ struct dwc3_msm {
struct notifier_block vbus_nb;
struct notifier_block id_nb;
+ struct notifier_block host_nb;
+
int pwr_event_irq;
atomic_t in_p3;
unsigned int lpm_to_suspend_delay;
@@ -632,18 +634,36 @@ static int dwc3_msm_ep_queue(struct usb_ep *ep,
struct dwc3_msm_req_complete *req_complete;
unsigned long flags;
int ret = 0, size;
- u8 bam_pipe;
- bool producer;
- bool disable_wb;
- bool internal_mem;
- bool ioc;
bool superspeed;
+ /*
+ * We must obtain the lock of the dwc3 core driver,
+ * including disabling interrupts, so we will be sure
+ * that we are the only ones that configure the HW device
+ * core and ensure that we queuing the request will finish
+ * as soon as possible so we will release back the lock.
+ */
+ spin_lock_irqsave(&dwc->lock, flags);
+ if (!dep->endpoint.desc) {
+ dev_err(mdwc->dev,
+ "%s: trying to queue request %p to disabled ep %s\n",
+ __func__, request, ep->name);
+ spin_unlock_irqrestore(&dwc->lock, flags);
+ return -EPERM;
+ }
+
+ if (!request) {
+ dev_err(mdwc->dev, "%s: request is NULL\n", __func__);
+ spin_unlock_irqrestore(&dwc->lock, flags);
+ return -EINVAL;
+ }
+
if (!(request->udc_priv & MSM_SPS_MODE)) {
/* Not SPS mode, call original queue */
dev_vdbg(mdwc->dev, "%s: not sps mode, use regular queue\n",
__func__);
+ spin_unlock_irqrestore(&dwc->lock, flags);
return (mdwc->original_ep_ops[dep->number])->queue(ep,
request,
gfp_flags);
@@ -652,9 +672,29 @@ static int dwc3_msm_ep_queue(struct usb_ep *ep,
/* HW restriction regarding TRB size (8KB) */
if (req->request.length < 0x2000) {
dev_err(mdwc->dev, "%s: Min TRB size is 8KB\n", __func__);
+ spin_unlock_irqrestore(&dwc->lock, flags);
return -EINVAL;
}
+ if (dep->number == 0 || dep->number == 1) {
+ dev_err(mdwc->dev,
+ "%s: trying to queue dbm request %p to control ep %s\n",
+ __func__, request, ep->name);
+ spin_unlock_irqrestore(&dwc->lock, flags);
+ return -EPERM;
+ }
+
+ if (dep->busy_slot != dep->free_slot || !list_empty(&dep->request_list)
+ || !list_empty(&dep->req_queued)) {
+ dev_err(mdwc->dev,
+ "%s: trying to queue dbm request %p tp ep %s\n",
+ __func__, request, ep->name);
+ spin_unlock_irqrestore(&dwc->lock, flags);
+ return -EPERM;
+ }
+ dep->busy_slot = 0;
+ dep->free_slot = 0;
+
/*
* Override req->complete function, but before doing that,
* store it's original pointer in the req_complete_list.
@@ -662,6 +702,7 @@ static int dwc3_msm_ep_queue(struct usb_ep *ep,
req_complete = kzalloc(sizeof(*req_complete), gfp_flags);
if (!req_complete) {
dev_err(mdwc->dev, "%s: not enough memory\n", __func__);
+ spin_unlock_irqrestore(&dwc->lock, flags);
return -ENOMEM;
}
req_complete->req = request;
@@ -669,23 +710,6 @@ static int dwc3_msm_ep_queue(struct usb_ep *ep,
list_add_tail(&req_complete->list_item, &mdwc->req_complete_list);
request->complete = dwc3_msm_req_complete_func;
- /*
- * Configure the DBM endpoint
- */
- bam_pipe = request->udc_priv & MSM_PIPE_ID_MASK;
- producer = ((request->udc_priv & MSM_PRODUCER) ? true : false);
- disable_wb = ((request->udc_priv & MSM_DISABLE_WB) ? true : false);
- internal_mem = ((request->udc_priv & MSM_INTERNAL_MEM) ? true : false);
- ioc = ((request->udc_priv & MSM_ETD_IOC) ? true : false);
-
- ret = dbm_ep_config(mdwc->dbm, dep->number, bam_pipe, producer,
- disable_wb, internal_mem, ioc);
- if (ret < 0) {
- dev_err(mdwc->dev,
- "error %d after calling dbm_ep_config\n", ret);
- return ret;
- }
-
dev_vdbg(dwc->dev, "%s: queing request %p to ep %s length %d\n",
__func__, request, ep->name, request->length);
size = dwc3_msm_read_reg(mdwc->base, DWC3_GEVNTSIZ(0));
@@ -694,43 +718,6 @@ static int dwc3_msm_ep_queue(struct usb_ep *ep,
dwc3_msm_read_reg(mdwc->base, DWC3_GEVNTADRHI(0)),
DWC3_GEVNTSIZ_SIZE(size));
- /*
- * We must obtain the lock of the dwc3 core driver,
- * including disabling interrupts, so we will be sure
- * that we are the only ones that configure the HW device
- * core and ensure that we queuing the request will finish
- * as soon as possible so we will release back the lock.
- */
- spin_lock_irqsave(&dwc->lock, flags);
- if (!dep->endpoint.desc) {
- dev_err(mdwc->dev,
- "%s: trying to queue request %p to disabled ep %s\n",
- __func__, request, ep->name);
- ret = -EPERM;
- goto err;
- }
-
- if (dep->number == 0 || dep->number == 1) {
- dev_err(mdwc->dev,
- "%s: trying to queue dbm request %p to control ep %s\n",
- __func__, request, ep->name);
- ret = -EPERM;
- goto err;
- }
-
-
- if (dep->busy_slot != dep->free_slot || !list_empty(&dep->request_list)
- || !list_empty(&dep->req_queued)) {
- dev_err(mdwc->dev,
- "%s: trying to queue dbm request %p tp ep %s\n",
- __func__, request, ep->name);
- ret = -EPERM;
- goto err;
- } else {
- dep->busy_slot = 0;
- dep->free_slot = 0;
- }
-
ret = __dwc3_msm_ep_queue(dep, req);
if (ret < 0) {
dev_err(mdwc->dev,
@@ -1356,12 +1343,19 @@ static int dwc3_msm_gsi_ep_op(struct usb_ep *ep,
*
* @return int - 0 on success, negetive on error.
*/
-int msm_ep_config(struct usb_ep *ep)
+int msm_ep_config(struct usb_ep *ep, struct usb_request *request,
+ gfp_t gfp_flags)
{
struct dwc3_ep *dep = to_dwc3_ep(ep);
struct dwc3 *dwc = dep->dwc;
struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent);
struct usb_ep_ops *new_ep_ops;
+ int ret = 0;
+ u8 bam_pipe;
+ bool producer;
+ bool disable_wb;
+ bool internal_mem;
+ bool ioc;
/* Save original ep ops for future restore*/
@@ -1374,7 +1368,7 @@ int msm_ep_config(struct usb_ep *ep)
mdwc->original_ep_ops[dep->number] = ep->ops;
/* Set new usb ops as we like */
- new_ep_ops = kzalloc(sizeof(struct usb_ep_ops), GFP_ATOMIC);
+ new_ep_ops = kzalloc(sizeof(struct usb_ep_ops), gfp_flags);
if (!new_ep_ops) {
dev_err(mdwc->dev,
"%s: unable to allocate mem for new usb ep ops\n",
@@ -1386,10 +1380,25 @@ int msm_ep_config(struct usb_ep *ep)
new_ep_ops->gsi_ep_op = dwc3_msm_gsi_ep_op;
ep->ops = new_ep_ops;
+ if (!mdwc->dbm || !request || (dep->endpoint.ep_type == EP_TYPE_GSI))
+ return 0;
+
/*
- * Do HERE more usb endpoint configurations
- * which are specific to MSM.
+ * Configure the DBM endpoint if required.
*/
+ bam_pipe = request->udc_priv & MSM_PIPE_ID_MASK;
+ producer = ((request->udc_priv & MSM_PRODUCER) ? true : false);
+ disable_wb = ((request->udc_priv & MSM_DISABLE_WB) ? true : false);
+ internal_mem = ((request->udc_priv & MSM_INTERNAL_MEM) ? true : false);
+ ioc = ((request->udc_priv & MSM_ETD_IOC) ? true : false);
+
+ ret = dbm_ep_config(mdwc->dbm, dep->number, bam_pipe, producer,
+ disable_wb, internal_mem, ioc);
+ if (ret < 0) {
+ dev_err(mdwc->dev,
+ "error %d after calling dbm_ep_config\n", ret);
+ return ret;
+ }
return 0;
}
@@ -1762,6 +1771,7 @@ static void dwc3_msm_power_collapse_por(struct dwc3_msm *mdwc)
{
struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3);
u32 val;
+ int ret;
/* Configure AHB2PHY for one wait state read/write */
if (mdwc->ahb2phy_base) {
@@ -1780,7 +1790,11 @@ static void dwc3_msm_power_collapse_por(struct dwc3_msm *mdwc)
if (!mdwc->init) {
dbg_event(0xFF, "dwc3 init",
atomic_read(&mdwc->dev->power.usage_count));
- dwc3_core_pre_init(dwc);
+ ret = dwc3_core_pre_init(dwc);
+ if (ret) {
+ dev_err(mdwc->dev, "dwc3_core_pre_init failed\n");
+ return;
+ }
mdwc->init = true;
}
@@ -2395,12 +2409,15 @@ static int dwc3_msm_get_clk_gdsc(struct dwc3_msm *mdwc)
return ret;
}
- if (!of_property_read_u32(mdwc->dev->of_node, "qcom,core-clk-rate",
+ if (of_property_read_u32(mdwc->dev->of_node, "qcom,core-clk-rate",
(u32 *)&mdwc->core_clk_rate)) {
- mdwc->core_clk_rate = clk_round_rate(mdwc->core_clk,
- mdwc->core_clk_rate);
+ dev_err(mdwc->dev, "USB core-clk-rate is not present\n");
+ return -EINVAL;
}
+ mdwc->core_clk_rate = clk_round_rate(mdwc->core_clk,
+ mdwc->core_clk_rate);
+
dev_dbg(mdwc->dev, "USB core frequency = %ld\n",
mdwc->core_clk_rate);
ret = clk_set_rate(mdwc->core_clk, mdwc->core_clk_rate);
@@ -2543,8 +2560,12 @@ static int dwc3_msm_extcon_register(struct dwc3_msm *mdwc)
struct extcon_dev *edev;
int ret = 0;
- if (!of_property_read_bool(node, "extcon"))
- return 0;
+ if (!of_property_read_bool(node, "extcon")) {
+ if (usb_get_dr_mode(&mdwc->dwc3->dev) == USB_DR_MODE_HOST)
+ return 0;
+ dev_err(mdwc->dev, "extcon property doesn't exist\n");
+ return -EINVAL;
+ }
edev = extcon_get_edev_by_phandle(mdwc->dev, 0);
if (IS_ERR(edev) && PTR_ERR(edev) != -ENODEV)
@@ -3037,6 +3058,53 @@ static int dwc3_msm_remove(struct platform_device *pdev)
return 0;
}
+static int dwc3_msm_host_notifier(struct notifier_block *nb,
+ unsigned long event, void *ptr)
+{
+ struct dwc3_msm *mdwc = container_of(nb, struct dwc3_msm, host_nb);
+ struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3);
+ struct usb_device *udev = ptr;
+ union power_supply_propval pval;
+ unsigned max_power;
+
+ if (event != USB_DEVICE_ADD && event != USB_DEVICE_REMOVE)
+ return NOTIFY_DONE;
+
+ if (!mdwc->usb_psy) {
+ mdwc->usb_psy = power_supply_get_by_name("usb");
+ if (!mdwc->usb_psy)
+ return NOTIFY_DONE;
+ }
+
+ /*
+ * For direct-attach devices, new udev is direct child of root hub
+ * i.e. dwc -> xhci -> root_hub -> udev
+ * root_hub's udev->parent==NULL, so traverse struct device hierarchy
+ */
+ if (udev->parent && !udev->parent->parent &&
+ udev->dev.parent->parent == &dwc->xhci->dev) {
+ if (event == USB_DEVICE_ADD && udev->actconfig) {
+ if (udev->speed >= USB_SPEED_SUPER)
+ max_power = udev->actconfig->desc.bMaxPower * 8;
+ else
+ max_power = udev->actconfig->desc.bMaxPower * 2;
+ dev_dbg(mdwc->dev, "%s configured bMaxPower:%d (mA)\n",
+ dev_name(&udev->dev), max_power);
+
+ /* inform PMIC of max power so it can optimize boost */
+ pval.intval = max_power * 1000;
+ power_supply_set_property(mdwc->usb_psy,
+ POWER_SUPPLY_PROP_BOOST_CURRENT, &pval);
+ } else {
+ pval.intval = 0;
+ power_supply_set_property(mdwc->usb_psy,
+ POWER_SUPPLY_PROP_BOOST_CURRENT, &pval);
+ }
+ }
+
+ return NOTIFY_DONE;
+}
+
#define VBUS_REG_CHECK_DELAY (msecs_to_jiffies(1000))
/**
@@ -3097,6 +3165,9 @@ static int dwc3_otg_start_host(struct dwc3_msm *mdwc, int on)
dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST);
+ mdwc->host_nb.notifier_call = dwc3_msm_host_notifier;
+ usb_register_notify(&mdwc->host_nb);
+
/*
* FIXME If micro A cable is disconnected during system suspend,
* xhci platform device will be removed before runtime pm is
@@ -3117,6 +3188,7 @@ static int dwc3_otg_start_host(struct dwc3_msm *mdwc, int on)
pm_runtime_put_sync(mdwc->dev);
dbg_event(0xFF, "pdeverr psync",
atomic_read(&mdwc->dev->power.usage_count));
+ usb_unregister_notify(&mdwc->host_nb);
return ret;
}
@@ -3153,6 +3225,7 @@ static int dwc3_otg_start_host(struct dwc3_msm *mdwc, int on)
mdwc->hs_phy->flags &= ~PHY_HOST_MODE;
mdwc->ss_phy->flags &= ~PHY_HOST_MODE;
platform_device_del(dwc->xhci);
+ usb_unregister_notify(&mdwc->host_nb);
/*
* Perform USB hardware RESET (both core reset and DBM reset)
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 2858388fe8d1..251ae0a7a5ee 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -213,7 +213,8 @@ int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc)
* use mult as 3 for GSI IN endpoint always irrespective
* USB speed.
*/
- if (dep->endpoint.ep_type == EP_TYPE_GSI)
+ if (dep->endpoint.ep_type == EP_TYPE_GSI ||
+ dep->endpoint.endless)
mult = 3;
if (!(dep->flags & DWC3_EP_ENABLED)) {
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index a480b0a9a238..9360b0613154 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -1670,8 +1670,10 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
value = min(w_length, (u16) value);
break;
case USB_DT_STRING:
+ spin_lock(&cdev->lock);
value = get_string(cdev, req->buf,
w_index, w_value & 0xff);
+ spin_unlock(&cdev->lock);
if (value >= 0)
value = min(w_length, (u16) value);
break;
diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c
index af20033b621f..84b60ec771a4 100644
--- a/drivers/usb/gadget/function/f_gsi.c
+++ b/drivers/usb/gadget/function/f_gsi.c
@@ -2245,7 +2245,7 @@ skip_string_id_alloc:
if (!ep)
goto fail;
gsi->d_port.in_ep = ep;
- msm_ep_config(gsi->d_port.in_ep);
+ msm_ep_config(gsi->d_port.in_ep, NULL, GFP_KERNEL);
ep->driver_data = cdev; /* claim */
}
@@ -2255,7 +2255,7 @@ skip_string_id_alloc:
if (!ep)
goto fail;
gsi->d_port.out_ep = ep;
- msm_ep_config(gsi->d_port.out_ep);
+ msm_ep_config(gsi->d_port.out_ep, NULL, GFP_KERNEL);
ep->driver_data = cdev; /* claim */
}
diff --git a/drivers/usb/gadget/function/u_data_ipa.c b/drivers/usb/gadget/function/u_data_ipa.c
index 2da0c59fdfc2..1850aa6ea19d 100644
--- a/drivers/usb/gadget/function/u_data_ipa.c
+++ b/drivers/usb/gadget/function/u_data_ipa.c
@@ -457,7 +457,7 @@ static void ipa_data_connect_work(struct work_struct *w)
configure_fifo(port->usb_bam_type,
port->src_connection_idx,
port->port_usb->out);
- ret = msm_ep_config(gport->out);
+ ret = msm_ep_config(gport->out, port->rx_req, GFP_ATOMIC);
if (ret) {
pr_err("msm_ep_config() failed for OUT EP\n");
usb_bam_free_fifos(port->usb_bam_type,
@@ -475,7 +475,7 @@ static void ipa_data_connect_work(struct work_struct *w)
port->tx_req->udc_priv = sps_params;
configure_fifo(port->usb_bam_type,
port->dst_connection_idx, gport->in);
- ret = msm_ep_config(gport->in);
+ ret = msm_ep_config(gport->in, port->tx_req, GFP_ATOMIC);
if (ret) {
pr_err("msm_ep_config() failed for IN EP\n");
goto unconfig_msm_ep_out;
diff --git a/drivers/usb/gadget/function/u_qdss.c b/drivers/usb/gadget/function/u_qdss.c
index 8f5fcc16eb15..e26f0977b9b7 100644
--- a/drivers/usb/gadget/function/u_qdss.c
+++ b/drivers/usb/gadget/function/u_qdss.c
@@ -94,11 +94,12 @@ int set_qdss_data_connection(struct usb_gadget *gadget,
static int init_data(struct usb_ep *ep)
{
+ struct f_qdss *qdss = ep->driver_data;
int res = 0;
pr_debug("init_data\n");
- res = msm_ep_config(ep);
+ res = msm_ep_config(ep, qdss->endless_req, GFP_ATOMIC);
if (res)
pr_err("msm_ep_config failed\n");
diff --git a/drivers/video/fbdev/msm/mdss_compat_utils.c b/drivers/video/fbdev/msm/mdss_compat_utils.c
index d3eb3db48eb7..9f1a24431de9 100644
--- a/drivers/video/fbdev/msm/mdss_compat_utils.c
+++ b/drivers/video/fbdev/msm/mdss_compat_utils.c
@@ -846,6 +846,7 @@ static int __from_user_pcc_coeff_v17(
return -EFAULT;
}
+ memset(&pcc_cfg_payload, 0, sizeof(pcc_cfg_payload));
pcc_cfg_payload.r.b = pcc_cfg_payload32.r.b;
pcc_cfg_payload.r.g = pcc_cfg_payload32.r.g;
pcc_cfg_payload.r.c = pcc_cfg_payload32.r.c;
@@ -1127,6 +1128,8 @@ static int __from_user_igc_lut_data_v17(
pr_err("failed to copy payload from user for igc\n");
return -EFAULT;
}
+
+ memset(&igc_cfg_payload, 0, sizeof(igc_cfg_payload));
igc_cfg_payload.c0_c1_data = compat_ptr(igc_cfg_payload_32.c0_c1_data);
igc_cfg_payload.c2_data = compat_ptr(igc_cfg_payload_32.c2_data);
igc_cfg_payload.len = igc_cfg_payload_32.len;
@@ -1261,6 +1264,7 @@ static int __from_user_pgc_lut_data_v1_7(
pr_err("failed to copy from user the pgc32 payload\n");
return -EFAULT;
}
+ memset(&pgc_cfg_payload, 0, sizeof(pgc_cfg_payload));
pgc_cfg_payload.c0_data = compat_ptr(pgc_cfg_payload_32.c0_data);
pgc_cfg_payload.c1_data = compat_ptr(pgc_cfg_payload_32.c1_data);
pgc_cfg_payload.c2_data = compat_ptr(pgc_cfg_payload_32.c2_data);
@@ -1470,6 +1474,7 @@ static int __from_user_hist_lut_data_v1_7(
return -EFAULT;
}
+ memset(&hist_lut_cfg_payload, 0, sizeof(hist_lut_cfg_payload));
hist_lut_cfg_payload.len = hist_lut_cfg_payload32.len;
hist_lut_cfg_payload.data = compat_ptr(hist_lut_cfg_payload32.data);
@@ -2024,6 +2029,7 @@ static int __from_user_pa_data_v1_7(
return -EFAULT;
}
+ memset(&pa_cfg_payload, 0, sizeof(pa_cfg_payload));
pa_cfg_payload.mode = pa_cfg_payload32.mode;
pa_cfg_payload.global_hue_adj = pa_cfg_payload32.global_hue_adj;
pa_cfg_payload.global_sat_adj = pa_cfg_payload32.global_sat_adj;
@@ -2280,6 +2286,8 @@ static int __from_user_gamut_cfg_data_v17(
pr_err("failed to copy the gamut payload from userspace\n");
return -EFAULT;
}
+
+ memset(&gamut_cfg_payload, 0, sizeof(gamut_cfg_payload));
gamut_cfg_payload.mode = gamut_cfg_payload32.mode;
for (i = 0; i < MDP_GAMUT_TABLE_NUM_V1_7; i++) {
gamut_cfg_payload.tbl_size[i] =
diff --git a/include/dt-bindings/clock/mdss-pll-clk.h b/include/dt-bindings/clock/mdss-pll-clk.h
new file mode 100644
index 000000000000..8cd0b2a9bc98
--- /dev/null
+++ b/include/dt-bindings/clock/mdss-pll-clk.h
@@ -0,0 +1,42 @@
+/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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_PLL_CLK_H
+#define __MDSS_PLL_CLK_H
+
+/* DSI PLL clocks */
+#define BYTE0_MUX_CLK 0
+#define BYTE0_SRC_CLK 1
+#define PIX0_MUX_CLK 2
+#define PIX0_SRC_CLK 3
+#define N2_DIV_0_CLK 4
+#define POST_N1_DIV_0_CLK 5
+#define VCO_CLK_0_CLK 6
+#define SHADOW_BYTE0_SRC_CLK 7
+#define SHADOW_PIX0_SRC_CLK 8
+#define SHADOW_N2_DIV_0_CLK 9
+#define SHADOW_POST_N1_DIV_0_CLK 10
+#define SHADOW_VCO_CLK_0_CLK 11
+#define BYTE1_MUX_CLK 12
+#define BYTE1_SRC_CLK 13
+#define PIX1_MUX_CLK 14
+#define PIX1_SRC_CLK 15
+#define N2_DIV_1_CLK 16
+#define POST_N1_DIV_1_CLK 17
+#define VCO_CLK_1_CLK 18
+#define SHADOW_BYTE1_SRC_CLK 19
+#define SHADOW_PIX1_SRC_CLK 20
+#define SHADOW_N2_DIV_1_CLK 21
+#define SHADOW_POST_N1_DIV_1_CLK 22
+#define SHADOW_VCO_CLK_1_CLK 23
+
+#endif
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index 5cd588fa9f6a..744167a9ca8b 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -33,6 +33,7 @@
#define CLK_GET_ACCURACY_NOCACHE BIT(8) /* do not use the cached clk accuracy */
#define CLK_RECALC_NEW_RATES BIT(9) /* recalc rates after notifications */
#define CLK_IS_CRITICAL BIT(11) /* do not gate, ever */
+#define CLK_IS_MEASURE BIT(14) /* measure clock */
struct clk;
struct clk_hw;
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index 44b6222db9a3..1eb442f8dc6c 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -296,7 +296,8 @@ static inline void msm_usb_irq_disable(bool disable)
#endif
#ifdef CONFIG_USB_DWC3_QCOM
-int msm_ep_config(struct usb_ep *ep);
+int msm_ep_config(struct usb_ep *ep, struct usb_request *request,
+ gfp_t gfp_flags);
int msm_ep_unconfig(struct usb_ep *ep);
void dwc3_tx_fifo_resize_request(struct usb_ep *ep, bool qdss_enable);
int msm_data_fifo_config(struct usb_ep *ep, phys_addr_t addr, u32 size,
@@ -311,7 +312,8 @@ static inline int msm_data_fifo_config(struct usb_ep *ep, phys_addr_t addr,
return -ENODEV;
}
-static inline int msm_ep_config(struct usb_ep *ep)
+static inline int msm_ep_config(struct usb_ep *ep, struct usb_request *request,
+ gfp_t gfp_flags)
{
return -ENODEV;
}
diff --git a/include/soc/qcom/icnss.h b/include/soc/qcom/icnss.h
index 29990f036552..9c38b9aa5627 100644
--- a/include/soc/qcom/icnss.h
+++ b/include/soc/qcom/icnss.h
@@ -124,8 +124,7 @@ extern int icnss_get_wlan_unsafe_channel(u16 *unsafe_ch_list, u16 *ch_count,
extern int icnss_wlan_set_dfs_nol(const void *info, u16 info_len);
extern int icnss_wlan_get_dfs_nol(void *info, u16 info_len);
extern bool icnss_is_qmi_disable(void);
-extern int icnss_set_wlan_mac_address(struct device *dev,
- const u8 *in, uint32_t len);
+extern int icnss_set_wlan_mac_address(const u8 *in, const uint32_t len);
extern u8 *icnss_get_wlan_mac_address(struct device *dev, uint32_t *num);
#endif /* _ICNSS_WLAN_H_ */
diff --git a/include/uapi/linux/msm_kgsl.h b/include/uapi/linux/msm_kgsl.h
index aac11dbe5984..71fdf6d6e9e5 100644
--- a/include/uapi/linux/msm_kgsl.h
+++ b/include/uapi/linux/msm_kgsl.h
@@ -50,6 +50,7 @@
#define KGSL_CONTEXT_IFH_NOP 0x00010000
#define KGSL_CONTEXT_SECURE 0x00020000
#define KGSL_CONTEXT_NO_SNAPSHOT 0x00040000
+#define KGSL_CONTEXT_SPARSE 0x00080000
#define KGSL_CONTEXT_PREEMPT_STYLE_MASK 0x0E000000
#define KGSL_CONTEXT_PREEMPT_STYLE_SHIFT 25
@@ -89,6 +90,7 @@
#define KGSL_CMDBATCH_END_OF_FRAME KGSL_CONTEXT_END_OF_FRAME /* 0x100 */
#define KGSL_CMDBATCH_SYNC KGSL_CONTEXT_SYNC /* 0x400 */
#define KGSL_CMDBATCH_PWR_CONSTRAINT KGSL_CONTEXT_PWR_CONSTRAINT /* 0x800 */
+#define KGSL_CMDBATCH_SPARSE 0x1000 /* 0x1000 */
/*
* Reserve bits [16:19] and bits [28:31] for possible bits shared between
@@ -1556,4 +1558,34 @@ struct kgsl_sparse_bind {
#define IOCTL_KGSL_SPARSE_BIND \
_IOW(KGSL_IOC_TYPE, 0x54, struct kgsl_sparse_bind)
+/**
+ * struct kgsl_gpu_sparse_command - Argument for
+ * IOCTL_KGSL_GPU_SPARSE_COMMAND
+ * @flags: Current flags for the object
+ * @sparselist: List of kgsl_sparse_binding_object to bind/unbind
+ * @synclist: List of kgsl_command_syncpoints
+ * @sparsesize: Size of kgsl_sparse_binding_object
+ * @numsparse: Number of elements in list
+ * @sync_size: Size of kgsl_command_syncpoint structure
+ * @numsyncs: Number of kgsl_command_syncpoints in syncpoint list
+ * @context_id: Context ID submitting the kgsl_gpu_command
+ * @timestamp: Timestamp for the submitted commands
+ * @id: Virtual ID to bind/unbind
+ */
+struct kgsl_gpu_sparse_command {
+ uint64_t flags;
+ uint64_t __user sparselist;
+ uint64_t __user synclist;
+ unsigned int sparsesize;
+ unsigned int numsparse;
+ unsigned int syncsize;
+ unsigned int numsyncs;
+ unsigned int context_id;
+ unsigned int timestamp;
+ unsigned int id;
+};
+
+#define IOCTL_KGSL_GPU_SPARSE_COMMAND \
+ _IOWR(KGSL_IOC_TYPE, 0x55, struct kgsl_gpu_sparse_command)
+
#endif /* _UAPI_MSM_KGSL_H */
diff --git a/mm/cma.c b/mm/cma.c
index 9ff71db72bc5..b55caef2454a 100644
--- a/mm/cma.c
+++ b/mm/cma.c
@@ -392,6 +392,9 @@ struct page *cma_alloc(struct cma *cma, size_t count, unsigned int align)
bitmap_maxno = cma_bitmap_maxno(cma);
bitmap_count = cma_bitmap_pages_to_bits(cma, count);
+ if (bitmap_count > bitmap_maxno)
+ return NULL;
+
for (;;) {
mutex_lock(&cma->lock);
bitmap_no = bitmap_find_next_zero_area_off(cma->bitmap,
diff --git a/sound/soc/msm/msmfalcon-common.c b/sound/soc/msm/msmfalcon-common.c
index c82319539f39..b4b35ee144ff 100644
--- a/sound/soc/msm/msmfalcon-common.c
+++ b/sound/soc/msm/msmfalcon-common.c
@@ -2746,8 +2746,6 @@ static int msm_asoc_machine_probe(struct platform_device *pdev)
ret);
goto err;
}
- if (pdata->snd_card_val != INT_SND_CARD)
- msm_ext_register_audio_notifier();
return 0;
err:
if (pdata->us_euro_gpio > 0) {