diff options
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, ®val); + + /* Wait for timer to become ready. */ + while ((regval & BIT(25)) != 0) { + cpu_relax(); + regmap_read(regmap, status_reg, ®val); + } + + /* Run measurement and wait for completion. */ + regmap_write(regmap, ctl_reg, (BIT(20)|ticks)); + regmap_read(regmap, ctl_reg, ®val); + + regmap_read(regmap, status_reg, ®val); + + while ((regval & BIT(25)) == 0) { + cpu_relax(); + regmap_read(regmap, status_reg, ®val); + } + + /* Return measured ticks. */ + regmap_read(regmap, status_reg, ®val); + 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, ®val); + + 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, ®val); + + /* 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, ¶m->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 */ @@ -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) { |
